Address Contract Verified
Address
0x1AE710b6459AE57D3a9fccd777CEAD48741c816c
Balance
0 ETH
Nonce
1
Code Size
8810 bytes
Creator
0xde091fc5...81F6 at tx 0xbaa00fc0...cab3ac
Indexed Transactions
0
Contract Bytecode
8810 bytes
0x60a0604052600436101561001b575b361561001957600080fd5b005b6000803560e01c806316c38b3c1461191f5780631b11d0ff14610c395780634782f77914610b135780635073ae38146108ef5780636065c245146103ff578063735de9f7146103d65780638da5cb5b146103ad578063ad5c46481461037e578063b187bd261461035b578063b2d2c1de146101b7578063e9240c2d1461018e578063f2fde38b146100fd5763fe94df88146100b6575061000e565b346100fa57806003193601126100fa576040517f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e26001600160a01b03168152602090f35b80fd5b50346100fa5760203660031901126100fa57610117611a09565b600154906001600160a01b03906101313383851614611a1f565b1690811561014a576001600160a01b0319161760015580f35b606460405162461bcd60e51b815260206004820152602060248201527f4e6577206f776e65722063616e6e6f74206265207a65726f20616464726573736044820152fd5b50346100fa57806003193601126100fa576003546040516001600160a01b039091168152602090f35b50346100fa5760403660031901126100fa576101d1611a09565b602435906001600160a01b0390818316830361034f576101f682600154163314611a1f565b6040516370a0823160e01b815230600482015291169160208083602481875afa9283156102df578593610327575b5082156102ea5760405163a9059cbb60e01b81526001600160a01b0383166004820152602481018490529381908590604490829089905af19384156102df577f016e128b6bdadd9e9068abd0b18db2fc8b27ed3dbced50e4aa6cc0a6934251ab946102b1575b5050604080516001600160a01b039092168252602082019290925290819081015b0390a180f35b816102d092903d106102d8575b6102c88183611ac3565b810190611ca4565b50388061028a565b503d6102be565b6040513d87823e3d90fd5b6064906040519062461bcd60e51b8252600482015260166024820152754e6f2062616c616e636520746f20776974686472617760501b6044820152fd5b9080935081813d8311610354575b61033f8183611ac3565b8101031261034f57519138610224565b600080fd5b503d610335565b50346100fa57806003193601126100fa57602060ff600654166040519015158152f35b50346100fa57806003193601126100fa57602060405173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28152f35b50346100fa57806003193601126100fa576001546040516001600160a01b039091168152602090f35b50346100fa57806003193601126100fa576002546040516001600160a01b039091168152602090f35b50346100fa57600319906040368301126100fa5761041b611a09565b9060249283359060018060a01b039061043982600154163314611a1f565b60ff600654166108b657821561087257600454600019811461085f576001016004556040519261046884611a75565b600184526020958636818701376040519361048285611a75565b600185528736818701376040519161049983611a75565b600183528836818501377f0697505e0a10c3a1b04f5a7e23f0d665f2b8b36de7447814f9a9060f6df9334489836104cf8a611b2d565b93169586809452806104e08a611b2d565b528a6104eb87611b2d565b52604051908152a2604051928884015287835261050783611a75565b7f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e21693843b1561085b5795886105a582979583979561059060e0966105806105709d6040519e8f9c8b8e9c9a63ab9c4b5d8e9c1b8c523060048d01528b015260e48a0190611b60565b90868983030160448a0152611b9d565b9084878303016064880152611b9d565b913060848601528483030160a4850152611b08565b8260c483015203925af19182610830575b50906107dd57506105c5611bd1565b6308c379a0146106be575b601f606492600080516020612215833981519152604051604081528061062561061960408301604090600f81526e233630b9b42637b0b71022b93937b960891b60208201520190565b82810388840152611c61565b0390a16000805160206121d583398151915260405160408152601a60408201527f4c6f772d6c6576656c20666c617368206c6f616e206572726f7200000000000060608201526080858201528061067e60808201611c61565b0390a16040519262461bcd60e51b845260048401528201527f466c6173684c6f616e206661696c65643a20556e6b6e6f776e206572726f72006044820152fd5b6106c6611bef565b806106d157506105d0565b6107d990600080516020612215833981519152604051604081528061072661071960408301604090600f81526e233630b9b42637b0b71022b93937b960891b60208201520190565b8281038884015285611b08565b0390a16000805160206121d5833981519152604051604081526011604082015270119b185cda081b1bd85b8819985a5b1959607a1b6060820152608085820152806107746080820185611b08565b0390a16107bd60326040518093710233630b9b42637b0b7103330b4b632b21d160751b878301526107ad81518092898686019101611ae5565b8101036012810184520182611ac3565b60405193849362461bcd60e51b85526004850152830190611b08565b0390fd5b60008051602061221583398151915260c083608060405191604083526009604084015268233630b9b42637b0b760b91b606084015282015260076080820152665375636365737360c81b60a0820152a180f35b67ffffffffffffffff811161084857604052386105b6565b634e487b7160e01b825260416004528482fd5b8680fd5b634e487b7160e01b855260116004528685fd5b60405162461bcd60e51b815260206004820152601d818801527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b60405162461bcd60e51b8152602060048201526012818801527110dbdb9d1c9858dd081a5cc81c185d5cd95960721b6044820152606490fd5b50346100fa5760603660031901126100fa57610909611a09565b60243590604435906001600160a01b038083169190828403610b0f57848161096f9361093c602094600154163314611a1f565b60405163095ea7b360e01b81526001600160a01b0390971660048801526024870192909252169391829081906044820190565b038188875af180156102df57610af1575b506040519161098e83611aa7565b6002835260403660208501376109a383611b2d565b5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26109c283611b50565b5260405163d06ca61f60e01b8152836004820152604060248201528481806109ed6044820187611b60565b0381855afa80156102df57610a09918691610ad7575b50611b50565b5191606283029280840460621490151715610ac3576104b0420193844211610aaf57908580949392610a57604051978896879586946338ed173960e01b865260643093049060048701611d80565b03925af1908115610aa45790610a78918360209492610a81575b5050611b50565b51604051908152f35b610a9d92503d8091833e610a958183611ac3565b810190611d04565b3880610a71565b6040513d84823e3d90fd5b634e487b7160e01b86526011600452602486fd5b634e487b7160e01b85526011600452602485fd5b610aeb91503d8088833e610a958183611ac3565b38610a03565b610b089060203d81116102d8576102c88183611ac3565b5038610980565b8580fd5b50346100fa5760403660031901126100fa576001600160a01b0360043581811690819003610c3557610b4d60243592600154163314611a1f565b814710610bf0578280809381935af13d15610beb573d67ffffffffffffffff8111610bd75760405190610b8a601f8201601f191660200183611ac3565b81528260203d92013e5b15610b9c5780f35b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b634e487b7160e01b83526041600452602483fd5b610b94565b60405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152606490fd5b8280fd5b50346100fa5760a03660031901126100fa57610c53611a09565b906064356001600160a01b038116908190036112735760843567ffffffffffffffff80821161191b573660238301121561191b57816004013590811161191b573691016024011161127357600282541461190957600282557f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e26001600160a01b031633036118ce5730036118995760008051602061221583398151915260c060405160408152601360408201527222bc32b1baba34b7339027b832b930ba34b7b760691b606082015260806020820152600560808201526414dd185c9d60da1b60a0820152a17fb3f7d6c63a62ab0e6ae5263ef1deb9c5a64f4689288c380db949c116314a55406080604051604081526005604082015264105cdcd95d60da1b606082015260018060a01b0385166020820152a16000805160206121f58339815191526080604051604081526006604082015265105b5bdd5b9d60d21b60608201526024356020820152a16000805160206121f583398151915260806040516040815260076040820152665072656d69756d60c81b60608201526044356020820152a1604051610e0281611aa7565b6002815260403660208301376001600160a01b038316610e2182611b2d565b5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2610e4082611b50565b5260018060a01b03600254169060405163d06ca61f60e01b815260243560048201526040602482015283808280610e7a6044820187611b60565b0381875afa8092829361187d575b5061186a57610ecb915080925b60018060a01b0360035416604051808095819463d06ca61f60e01b83526024356004840152604060248401526044830190611b60565b03915afa84918161184e575b5061183e575082915b6000805160206121f5833981519152608060405160408152600d60408201526c556e697377617020507269636560981b6060820152846020820152a16000805160206121f5833981519152608060405160408152600f60408201526e53757368697377617020507269636560881b6060820152856020820152a1828211156114ed575050610f6c611cbc565b6064610f7f610f79611ce1565b936121be565b60035460405163095ea7b360e01b81526001600160a01b03909116600482015260248035908201529190049060208180604481010381886001600160a01b038b165af180156102df576114ce575b5060405190610fdb82611aa7565b6002825260403660208401376001600160a01b038616610ffa83611b2d565b5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261101983611b50565b526003546001600160a01b031690426104b0810110610aaf57918591611063959493836040518098819582946338ed173960e01b84526104b0420191309160243560048701611d80565b03925af18493816114b2575b50611427575050506001611081611bd1565b6308c379a014611357575b61127f575b6040516370a0823160e01b8152306004820152916020836024816001600160a01b0385165afa928315610aa4578293611247575b506110d4604435602435611c81565b8093106111f65760405163095ea7b360e01b81526001600160a01b037f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e21660048201526024810184905260208180604481010381866001600160a01b0387165af180156111eb576001946000805160206121f5833981519152926080926111cc575b506040519060408252600f60408301526e151bdd185b0814995c185e5b595b9d608a1b60608301526020820152a17f61268d74931c41c9775dffb6169a5208aab1d09cb2eb6aabe8b97162801e5dfa604080519260243584526044356020850152858060a01b031692a255602060405160018152f35b6111e49060203d6020116102d8576102c88183611ac3565b5038611156565b6040513d85823e3d90fd5b60405162461bcd60e51b815260206004820152602360248201527f4e6f7420656e6f75676820746f6b656e7320746f20726570617920746865206c60448201526237b0b760e91b6064820152608490fd5b9092506020813d602011611277575b8161126360209383611ac3565b81010312611273575191386110c5565b5080fd5b3d9150611256565b6000805160206121d583398151915260405160408152601960408201527f537573686973776170206c6f772d6c6576656c206572726f7200000000000000606082015260806020820152806112d660808201611c61565b0390a1600080516020612215833981519152604051604081528061134f61131d60408301604090600f81526e29bab9b434b9bbb0b81022b93937b960891b60208201520190565b8281036020840152604090601681527504661696c656420746f206578656375746520737761760541b60208201520190565b0390a1611091565b61135f611bef565b8061136b575b5061108c565b905060008051602061221583398151915261141e83926000805160206121d583398151915260405160408152601960408201527f53757368697377617020657865637574696f6e206572726f7200000000000000606082015260806020820152806113d96080820185611b08565b0390a16040519182916040835261141060408401604090600f81526e29bab9b434b9bbb0b81022b93937b960891b60208201520190565b908382036020850152611b08565b0390a138611365565b6114936114ad937fa52cbc5a20811c4461ab347563548f6a74ce1299a68c7a39d39f1e9d98f6e38260405160408152601060408201526f14dd5cda1a5cddd85c0813dd5d1c1d5d60821b6060820152608060208201528061148b6080820185611b9d565b0390a1611b50565b516002546001600160a01b03169060443560243588611db9565b611091565b6114c79194503d8087833e610a958183611ac3565b923861106f565b6114e69060203d6020116102d8576102c88183611ac3565b5038610fcd565b9091506114f8611ce1565b90606461150c611506611cbc565b946121be565b0461158e60206040519361151f85611aa7565b60028552604036838701376001600160a01b03891661153d86611b2d565b5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261155c86611b50565b5260405163095ea7b360e01b81526001600160a01b039091166004820152602480359082015291829081906044820190565b0381896001600160a01b038c165af1801561183357611814575b506002546001600160a01b031690426104b0810110610aaf579185916115f2959493836040518098819582946338ed173960e01b84526104b0420191309160243560048701611d80565b03925af18493816117f8575b5061177c575050506001611610611bd1565b6308c379a0146116bc575b15611091576000805160206121d583398151915260405160408152601760408201527f556e6973776170206c6f772d6c6576656c206572726f720000000000000000006060820152608060208201528061167760808201611c61565b0390a1600080516020612215833981519152604051604081528061134f61131d60408301604090600d81526c2ab734b9bbb0b81022b93937b960991b60208201520190565b6116c4611bef565b806116d0575b5061161b565b905060008051602061221583398151915261177383926000805160206121d583398151915260405160408152601760408201527f556e697377617020657865637574696f6e206572726f720000000000000000006060820152608060208201528061173e6080820185611b08565b0390a16040519182916040835261141060408401604090600d81526c2ab734b9bbb0b81022b93937b960991b60208201520190565b0390a1386116ca565b6117de6114ad937fa52cbc5a20811c4461ab347563548f6a74ce1299a68c7a39d39f1e9d98f6e38260405160408152600e60408201526d155b9a5cddd85c0813dd5d1c1d5d60921b6060820152608060208201528061148b6080820185611b9d565b516003546001600160a01b03169060443560243588611db9565b61180d9194503d8087833e610a958183611ac3565b92386115fe565b61182c9060203d6020116102d8576102c88183611ac3565b50386115a8565b6040513d88823e3d90fd5b61184790611b50565b5191610ee0565b6118639192503d8087833e610a958183611ac3565b9038610ed7565b611876610ecb92611b50565b5192610e95565b6118929193503d8084833e610a958183611ac3565b9138610e88565b60405162461bcd60e51b815260206004820152600d60248201526c2130b21034b734ba34b0ba37b960991b6044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527210d85b1b195c881b5d5cdd08189948141bdbdb606a1b6044820152606490fd5b604051633ee5aeb560e01b8152600490fd5b8380fd5b50346100fa5760203660031901126100fa57600435801515808203610c355761195360018060a01b03600154163314611a1f565b60ff8019600654169116176006556000146119d1576000805160206122158339815191526102ab60405161198681611a75565b600681526514185d5cd95960d21b60208201525b60405191829160408352600c60408401526b50617573652053746174757360a01b6060840152608060208401526080830190611b08565b6000805160206122158339815191526102ab6040516119ef81611a75565b6008815267155b9c185d5cd95960c21b602082015261199a565b600435906001600160a01b038216820361034f57565b15611a2657565b60405162461bcd60e51b815260206004820152602160248201527f4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f6044820152603760f91b6064820152608490fd5b6040810190811067ffffffffffffffff821117611a9157604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117611a9157604052565b90601f8019910116810190811067ffffffffffffffff821117611a9157604052565b60005b838110611af85750506000910152565b8181015183820152602001611ae8565b90602091611b2181518092818552858086019101611ae5565b601f01601f1916010190565b805115611b3a5760200190565b634e487b7160e01b600052603260045260246000fd5b805160011015611b3a5760400190565b90815180825260208080930193019160005b828110611b80575050505090565b83516001600160a01b031685529381019392810192600101611b72565b90815180825260208080930193019160005b828110611bbd575050505090565b835185529381019392810192600101611baf565b60009060033d11611bde57565b905060046000803e60005160e01c90565b600060443d10611c4d57604051600319913d83016004833e815167ffffffffffffffff918282113d602484011117611c5057818401948551938411611c58573d85010160208487010111611c505750611c4d92910160200190611ac3565b90565b949350505050565b50949350505050565b600d81526c2ab735b737bbb71032b93937b960991b602082015260400190565b91908201809211611c8e57565b634e487b7160e01b600052601160045260246000fd5b9081602091031261034f5751801515810361034f5790565b60405190611cc982611a75565b600982526805375736869737761760bc1b6020830152565b60405190611cee82611a75565b60078252660556e69737761760cc1b6020830152565b90602090818382031261034f57825167ffffffffffffffff9384821161034f570181601f8201121561034f578051938411611a91578360051b9060405194611d4e85840187611ac3565b8552838086019282010192831161034f578301905b828210611d71575050505090565b81518152908301908301611d63565b9192608093611da592979695978452602084015260a0604084015260a0830190611b60565b6001600160a01b0390951660608201520152565b929490939591604096875190611dce82611aa7565b600282528836602084013773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29788611df984611b2d565b52611e0383611b50565b6001600160a01b0388169052611e198489611c81565b611e22906121be565b8a5163095ea7b360e01b81526001600160a01b038416600482015260248101839052600060809081529a60649092049391816044815a602094600091f180156121b257612193575b506104b042019384421161217d578a611e9c8d51968795869485946338ed173960e01b86525198309260048701611d80565b8c51919003926001600160a01b03165af187519181612162575b5061203c575050505050506001611ecb611bd1565b6308c379a014611f7f575b611ede575050565b816000805160206121d5833981519152611f4561131d936000805160206122158339815191529551918291858352601b868401527f5365636f6e642073776170206c6f772d6c6576656c206572726f72000000000060608401528060208401528201611c61565b0390a1611f7a81519282849384528301604090601181527029b2b1b7b7321029bbb0b81022b93937b960791b60208201520190565b0390a1565b611f87611bef565b80611f93575b50611ed6565b90506000805160206122158339815191526120338351926000805160206121d58339815191528651878152601b888201527f5365636f6e64207377617020657865637574696f6e206572726f720000000000606082015286602082015280611ffd88820185611b08565b0390a18551918291878352611410888401604090601181527029b2b1b7b7321029bbb0b81022b93937b960791b60208201520190565b0390a138611f8d565b6120a76120af917fa52cbc5a20811c4461ab347563548f6a74ce1299a68c7a39d39f1e9d98f6e38261148b8a8c969798999a9b9d9c519182918883526012898401527114d958dbdb990814ddd85c0813dd5d1c1d5d60721b6060840152806020840152820185611b9d565b519287611c81565b8083116120c2575b505050505050509050565b820391821161214c577f634093973ab4c9034998777c7386757af34d850e23f76d521c7771593eddec4a9697928261212f9261210461213c9795600554611c81565b600555805198899860018060a01b03168952602089015287015260a0606087015260a0860190611b08565b9184830390850152611b08565b0390a180388080808080806120b7565b602488634e487b7160e01b815152601160045251fd5b61217691923d8091833e610a958183611ac3565b9038611eb6565b60248b634e487b7160e01b815152601160045251fd5b6121ab9060203d6020116102d8576102c88183611ac3565b5038611e6a565b8c518c513d90823e3d90fd5b90606282029180830460621490151715611c8e5756fe346afbb33f94dca869e4631b36123428958d077a897f976db4028ea3b3a224932c78221d853bf45521bf53ad2802eb4470185a3cad34373f42e4639a8fdeb197a57bb8357696c0239aa116d4ee1079a34c9ef41b001ce54c57d611f24536111aa2646970667358221220d753dc53ce528b2f17e3c6edf051032c98b434ac4077fd5c0639050ae455eb3064736f6c63430008140033
Verified Source Code Full Match
Compiler: v0.8.20+commit.a1b79de6
EVM: paris
Optimization: Yes (200 runs)
FlashLoanArbitrage.sol 415 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
interface IUniswapV2Router {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function getAmountsOut(
uint amountIn,
address[] calldata path
) external view returns (uint[] memory amounts);
}
interface IPool {
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
}
contract FlashLoanArbitrage is ReentrancyGuard {
address public owner;
address public immutable POOL_ADDRESS;
address public uniswapRouter;
address public sushiswapRouter;
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
// Tracking variables
uint256 private executionCount = 0;
uint256 private totalProfit = 0;
// Circuit breaker flag
bool public isPaused = false;
// Events for debugging and monitoring
event DebugString(string label, string message);
event DebugUint(string label, uint256 value);
event DebugAddress(string label, address addr);
event DebugArray(string label, uint256[] values);
event FlashLoanStarted(address indexed asset, uint amount);
event FlashLoanExecuted(address indexed asset, uint amount, uint premium);
event ArbitrageExecuted(
address tokenAddress,
uint256 flashLoanAmount,
uint256 profit,
string buyDex,
string sellDex
);
event ProfitWithdrawn(address recipient, uint256 amount);
event ErrorOccurred(string errorType, string reason);
constructor(address _pool, address _uniswap, address _sushiswap) {
owner = msg.sender;
POOL_ADDRESS = _pool;
uniswapRouter = _uniswap;
sushiswapRouter = _sushiswap;
}
// Modifier to restrict functions to owner
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}
// Function to set emergency pause
function setPaused(bool _isPaused) external onlyOwner {
isPaused = _isPaused;
emit DebugString("Pause Status", _isPaused ? "Paused" : "Unpaused");
}
receive() external payable {}
function executeFlashLoan(address asset, uint256 amount) external onlyOwner {
require(!isPaused, "Contract is paused");
require(amount > 0, "Amount must be greater than 0");
// Track execution count
executionCount++;
address[] memory assets = new address[](1);
uint256[] memory amounts = new uint256[](1);
uint256[] memory modes = new uint256[](1);
assets[0] = asset;
amounts[0] = amount;
modes[0] = 0;
emit FlashLoanStarted(asset, amount);
bytes memory params = abi.encode(asset);
try IPool(POOL_ADDRESS).flashLoan(
address(this),
assets,
amounts,
modes,
address(this),
params,
0
) {
emit DebugString("FlashLoan", "Success");
} catch Error(string memory reason) {
emit DebugString("FlashLoan Error", reason);
emit ErrorOccurred("Flash loan failed", reason);
revert(string(abi.encodePacked("FlashLoan failed: ", reason)));
} catch {
emit DebugString("FlashLoan Error", "Unknown error");
emit ErrorOccurred("Low-level flash loan error", "Unknown error");
revert("FlashLoan failed: Unknown error");
}
}
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external nonReentrant returns (bool) {
require(msg.sender == POOL_ADDRESS, "Caller must be Pool");
require(initiator == address(this), "Bad initiator");
emit DebugString("Executing Operation", "Start");
emit DebugAddress("Asset", asset);
emit DebugUint("Amount", amount);
emit DebugUint("Premium", premium);
// Execute arbitrage
_executeArbitrage(asset, amount, premium);
// Ensure we have enough to repay
uint256 tokenBalance = IERC20(asset).balanceOf(address(this));
uint256 totalRepay = amount + premium;
require(tokenBalance >= totalRepay, "Not enough tokens to repay the loan");
// Approve repayment
IERC20(asset).approve(POOL_ADDRESS, totalRepay);
emit DebugUint("Total Repayment", totalRepay);
emit FlashLoanExecuted(asset, amount, premium);
return true;
}
// Separated to avoid stack too deep errors
function _executeArbitrage(address asset, uint256 amount, uint256 premium) internal {
// Check prices on both DEXes to determine optimal path
(uint256 uniswapPrice, uint256 sushiswapPrice) = checkPrices(asset, amount);
emit DebugUint("Uniswap Price", uniswapPrice);
emit DebugUint("Sushiswap Price", sushiswapPrice);
if (uniswapPrice > sushiswapPrice) {
_executeSushiToUniArbitrage(asset, amount, premium, uniswapPrice, sushiswapPrice);
} else {
_executeUniToSushiArbitrage(asset, amount, premium, uniswapPrice, sushiswapPrice);
}
}
// Arbitrage from Sushiswap to Uniswap
function _executeSushiToUniArbitrage(
address asset,
uint256 amount,
uint256 premium,
uint256 uniswapPrice,
uint256 sushiswapPrice
) internal {
string memory buyDex = "Sushiswap";
string memory sellDex = "Uniswap";
// Calculate minimum amounts with slippage protection (2%)
uint256 minOutput = calculateMinimumAmountOut(sushiswapPrice, 98);
// Execute swaps with slippage protection
IERC20(asset).approve(sushiswapRouter, amount);
// Path: asset -> WETH
address[] memory path = new address[](2);
path[0] = asset;
path[1] = WETH;
uint[] memory sushiOut;
try IUniswapV2Router(sushiswapRouter).swapExactTokensForTokens(
amount,
minOutput,
path,
address(this),
block.timestamp + 20 minutes
) returns (uint[] memory amounts) {
sushiOut = amounts;
emit DebugArray("Sushiswap Output", sushiOut);
// Execute second part of arbitrage
_executeSecondSwap(
asset,
amount,
premium,
sushiOut[1], // WETH amount
uniswapRouter, // Sell on Uniswap
buyDex,
sellDex
);
} catch Error(string memory reason) {
emit ErrorOccurred("Sushiswap execution error", reason);
emit DebugString("Sushiswap Error", reason);
} catch {
emit ErrorOccurred("Sushiswap low-level error", "Unknown error");
emit DebugString("Sushiswap Error", "Failed to execute swap");
}
}
// Arbitrage from Uniswap to Sushiswap
function _executeUniToSushiArbitrage(
address asset,
uint256 amount,
uint256 premium,
uint256 uniswapPrice,
uint256 sushiswapPrice
) internal {
string memory buyDex = "Uniswap";
string memory sellDex = "Sushiswap";
// Calculate minimum amounts with slippage protection (2%)
uint256 minOutput = calculateMinimumAmountOut(uniswapPrice, 98);
// Path: asset -> WETH
address[] memory path = new address[](2);
path[0] = asset;
path[1] = WETH;
IERC20(asset).approve(uniswapRouter, amount);
uint[] memory uniOut;
try IUniswapV2Router(uniswapRouter).swapExactTokensForTokens(
amount,
minOutput,
path,
address(this),
block.timestamp + 20 minutes
) returns (uint[] memory amounts) {
uniOut = amounts;
emit DebugArray("Uniswap Output", uniOut);
// Execute second part of arbitrage
_executeSecondSwap(
asset,
amount,
premium,
uniOut[1], // WETH amount
sushiswapRouter, // Sell on Sushiswap
buyDex,
sellDex
);
} catch Error(string memory reason) {
emit ErrorOccurred("Uniswap execution error", reason);
emit DebugString("Uniswap Error", reason);
} catch {
emit ErrorOccurred("Uniswap low-level error", "Unknown error");
emit DebugString("Uniswap Error", "Failed to execute swap");
}
}
// Second swap for arbitrage
function _executeSecondSwap(
address asset,
uint256 amount,
uint256 premium,
uint256 wethAmount,
address router,
string memory buyDex,
string memory sellDex
) internal {
// Path: WETH -> asset
address[] memory path = new address[](2);
path[0] = WETH;
path[1] = asset;
// Calculate minimum amounts with slippage protection (2%)
uint256 minTokenOutput = calculateMinimumAmountOut(amount + premium, 98);
IERC20(WETH).approve(router, wethAmount);
try IUniswapV2Router(router).swapExactTokensForTokens(
wethAmount,
minTokenOutput,
path,
address(this),
block.timestamp + 20 minutes
) returns (uint[] memory amounts) {
emit DebugArray("Second Swap Output", amounts);
// Calculate profit
uint256 finalTokenAmount = amounts[1];
uint256 totalRepay = amount + premium;
if (finalTokenAmount > totalRepay) {
uint256 profit = finalTokenAmount - totalRepay;
totalProfit += profit;
emit ArbitrageExecuted(asset, amount, profit, buyDex, sellDex);
}
} catch Error(string memory reason) {
emit ErrorOccurred("Second swap execution error", reason);
emit DebugString("Second Swap Error", reason);
} catch {
emit ErrorOccurred("Second swap low-level error", "Unknown error");
emit DebugString("Second Swap Error", "Failed to execute swap");
}
}
/**
* @dev Check prices on both DEXes
*/
function checkPrices(address tokenAddress, uint256 amount) internal view returns (uint256, uint256) {
// Create path
address[] memory path = new address[](2);
path[0] = tokenAddress;
path[1] = WETH;
// Get price on Uniswap
uint256 uniswapPrice;
try IUniswapV2Router(uniswapRouter).getAmountsOut(amount, path) returns (uint256[] memory amounts) {
uniswapPrice = amounts[1];
} catch {
uniswapPrice = 0;
}
// Get price on Sushiswap
uint256 sushiswapPrice;
try IUniswapV2Router(sushiswapRouter).getAmountsOut(amount, path) returns (uint256[] memory amounts) {
sushiswapPrice = amounts[1];
} catch {
sushiswapPrice = 0;
}
return (uniswapPrice, sushiswapPrice);
}
/**
* @dev Calculate minimum amount out with given percentage of desired amount
*/
function calculateMinimumAmountOut(uint256 amount, uint256 percentage) internal pure returns (uint256) {
return amount * percentage / 100;
}
/**
* @dev Test function for simple swaps
*/
function testSwap(
address tokenAddress,
uint256 amountIn,
address routerAddress
) external onlyOwner returns (uint256) {
// Approve router to spend tokens
IERC20(tokenAddress).approve(routerAddress, amountIn);
// Prepare swap path
address[] memory path = new address[](2);
path[0] = tokenAddress;
path[1] = WETH; // WETH address
// Get minimum amount out with 2% slippage
uint256[] memory amountsOut = IUniswapV2Router(routerAddress).getAmountsOut(amountIn, path);
uint256 minAmountOut = amountsOut[1] * 98 / 100; // 2% slippage
// Execute swap with deadline 20 minutes in the future
uint256[] memory amounts = IUniswapV2Router(routerAddress).swapExactTokensForTokens(
amountIn,
minAmountOut,
path,
address(this),
block.timestamp + 20 minutes
);
return amounts[1]; // Return amount of WETH received
}
/**
* @dev Allow owner to withdraw profits
*/
function withdrawProfit(address token, address recipient) external onlyOwner {
uint256 balance = IERC20(token).balanceOf(address(this));
require(balance > 0, "No balance to withdraw");
IERC20(token).transfer(recipient, balance);
emit ProfitWithdrawn(recipient, balance);
}
/**
* @dev Allow owner to withdraw ETH
*/
function withdrawETH(address payable recipient, uint256 amount) external onlyOwner {
require(address(this).balance >= amount, "Insufficient ETH balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "ETH transfer failed");
}
/**
* @dev Reset owner in case of emergency
*/
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "New owner cannot be zero address");
owner = newOwner;
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
Read Contract
POOL_ADDRESS 0xfe94df88 → address
WETH 0xad5c4648 → address
isPaused 0xb187bd26 → bool
owner 0x8da5cb5b → address
sushiswapRouter 0xe9240c2d → address
uniswapRouter 0x735de9f7 → address
Write Contract 7 functions
These functions modify contract state and require a wallet transaction to execute.
executeFlashLoan 0x6065c245
address asset
uint256 amount
executeOperation 0x1b11d0ff
address asset
uint256 amount
uint256 premium
address initiator
bytes params
returns: bool
setPaused 0x16c38b3c
bool _isPaused
testSwap 0x5073ae38
address tokenAddress
uint256 amountIn
address routerAddress
returns: uint256
transferOwnership 0xf2fde38b
address newOwner
withdrawETH 0x4782f779
address recipient
uint256 amount
withdrawProfit 0xb2d2c1de
address token
address recipient
Recent Transactions
No transactions found for this address