Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x1AE710b6459AE57D3a9fccd777CEAD48741c816c
Balance 0 ETH
Nonce 1
Code Size 8810 bytes
Indexed Transactions 0
External Etherscan · Sourcify

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