Address Contract Partially Verified
Address
0x5ABbd344fcbdA0565bd7041747316ee77a9815CD
Balance
0 ETH
Nonce
1
Code Size
9200 bytes
Creator
0xcb09C07C...ddB3 at tx 0xa67e8321...d344e6
Indexed Transactions
0
Contract Bytecode
9200 bytes
0x608060405234801561000f575f80fd5b50600436106100b1575f3560e01c8063a1db97821161006e578063a1db97821461016a578063ae0d1b811461017d578063b6d67a5214610190578063d6b735b5146101a3578063f14210a6146101ba578063fa461e33146101cd575f80fd5b806316f0115b146100b55780631b11d0ff146100e5578063385ad0a4146101085780633fc8cef31461011b57806358d0ee58146101425780636e52151d14610157575b5f80fd5b6001546100c8906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100f86100f3366004611923565b6101e0565b60405190151581526020016100dc565b6002546100c8906001600160a01b031681565b6100c87f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b610155610150366004611999565b61039e565b005b610155610165366004611a14565b6103eb565b610155610178366004611b0f565b61059f565b61015561018b366004611b39565b6106e9565b61015561019e366004611999565b61079f565b6101ac60045481565b6040519081526020016100dc565b6101556101c8366004611999565b610994565b6101556101db366004611b5b565b610aa6565b6001545f906001600160a01b031633146102325760405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21031b0b63632b960911b60448201526064015b60405180910390fd5b6001600160a01b038416301461027e5760405162461bcd60e51b815260206004820152601160248201527024b73b30b634b21034b734ba34b0ba37b960791b6044820152606401610229565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316876001600160a01b0316146102f55760405162461bcd60e51b815260206004820152601360248201527213db9b1e4815d15512081cdd5c1c1bdc9d1959606a1b6044820152606401610229565b5f861161033a5760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59081b1bd85b88185b5bdd5b9d606a1b6044820152606401610229565b5f6103458484610c0e565b90505f6040518060800160405280898152602001888152602001888a61036b9190611bbd565b81526020015f81525090506103808289610cdd565b606082015261038f8282610fe7565b50600198975050505050505050565b336001600160a01b037f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb316146103e65760405162461bcd60e51b815260040161022990611bd6565b600455565b6003546001600160a01b031633146104155760405162461bcd60e51b815260040161022990611bd6565b6001600160a01b038b161580159061043557506001600160a01b038a1615155b6104725760405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b2103937baba32b960911b6044820152606401610229565b600489600481111561048657610486611bfe565b60ff1611156104ca5760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420444558207479706560801b6044820152606401610229565b6001546001600160a01b03166342b0b77c307f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28f8f8f8f600481111561051257610512611bfe565b8f8f8f8f8f8f8f8f6040516020016105349b9a99989796959493929190611c3a565b6040516020818303038152906040525f6040518663ffffffff1660e01b8152600401610564959493929190611d2c565b5f604051808303815f87803b15801561057b575f80fd5b505af115801561058d573d5f803e3d5ffd5b50505050505050505050505050505050565b336001600160a01b037f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb316146105e75760405162461bcd60e51b815260040161022990611bd6565b6105ef6112e2565b6040516370a0823160e01b8152306004820152829082906001600160a01b038316906370a0823190602401602060405180830381865afa158015610635573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106599190611d74565b10156106a75760405162461bcd60e51b815260206004820152601a60248201527f496e73756666696369656e7420746f6b656e2062616c616e63650000000000006044820152606401610229565b6106db6001600160a01b0382167f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb384611339565b506106e560015f55565b5050565b336001600160a01b037f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb316146107315760405162461bcd60e51b815260040161022990611bd6565b6001600160a01b03811661077d5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420626f74206164647265737360681b6044820152606401610229565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b336001600160a01b037f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb31614806107e057506003546001600160a01b031633145b6107fc5760405162461bcd60e51b815260040161022990611bd6565b6108046112e2565b6002546001600160a01b031661086b5760405162461bcd60e51b815260206004820152602660248201527f57726170706564546f6b656e47617465776179563320636f6e7472616374206e6044820152651bdd081cd95d60d21b6064820152608401610229565b60025460405163095ea7b360e01b81526001600160a01b039182166004820152602481018390527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29091169063095ea7b3906044016020604051808303815f875af11580156108dc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109009190611d8b565b50600254604051630402806960e51b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28116600483015260248201849052306044830152909116906380500d20906064015f604051808303815f87803b158015610972575f80fd5b505af1158015610984573d5f803e3d5ffd5b5050505061099160015f55565b50565b336001600160a01b037f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb31614806109d557506003546001600160a01b031633145b6109f15760405162461bcd60e51b815260040161022990611bd6565b6109f96112e2565b80471015610a495760405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e74204554482062616c616e636500000000000000006044820152606401610229565b6040516001600160a01b037f000000000000000000000000cb09c07c661180c5116993f0c32954113041ddb3169082156108fc029083905f818181858888f19350505050158015610a9c573d5f803e3d5ffd5b5061099160015f55565b5f8080610ab584860186611daa565b91945092509050336001600160a01b03841614610b0d5760405162461bcd60e51b815260206004820152601660248201527510d85b1b189858dace881a5b9d985b1a59081c1bdbdb60521b6044820152606401610229565b5f871315610b8b5760405163a9059cbb60e01b81526001600160a01b0384811660048301526024820189905283169063a9059cbb906044016020604051808303815f875af1158015610b61573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b859190611d8b565b50610c05565b5f861315610c055760405163a9059cbb60e01b81526001600160a01b0384811660048301526024820188905282169063a9059cbb906044016020604051808303815f875af1158015610bdf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c039190611d8b565b505b50505050505050565b60408051610100810182525f8082526020820181905291810182905260608082018190526080820181905260a082015260c0810182905260e0810182905290610c5984840185611f4f565b6001600160801b0390811660e08b01521660c089015260a0880152608087015260608601526001600160a01b03918216602086015291168352905060ff81166004811115610ca957610ca9611bfe565b82604001906004811115610cbf57610cbf611bfe565b90816004811115610cd257610cd2611bfe565b815250505092915050565b815160405163095ea7b360e01b81526001600160a01b039182166004820152602481018390525f917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169063095ea7b3906044016020604051808303815f875af1158015610d4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d719190611d8b565b505f80845f01516001600160a01b03168560600151604051610d93919061202c565b5f604051808303815f865af19150503d805f8114610dcc576040519150601f19603f3d011682016040523d82523d5f602084013e610dd1565b606091505b509150915081610e105760405162461bcd60e51b815260206004820152600a602482015269109d5e4819985a5b195960b21b6044820152606401610229565b602081511115610e60575f81806020019051810190610e2f9190612042565b90508060018251610e4091906120d2565b81518110610e5057610e506120e5565b6020026020010151935050610f10565b8051602003610e845780806020019051810190610e7d9190611d74565b9250610f10565b8460a00151600181518110610e9b57610e9b6120e5565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610ee9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0d9190611d74565b92505b828560a00151600181518110610f2857610f286120e5565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610f76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9a9190611d74565b1015610fdf5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610229565b505092915050565b8160a00151600181518110610ffe57610ffe6120e5565b60200260200101516001600160a01b031663095ea7b3836020015183606001516040518363ffffffff1660e01b815260040161104f9291906001600160a01b03929092168252602082015260400190565b6020604051808303815f875af115801561106b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108f9190611d8b565b505f808360c001516001600160801b0316116110ad576004546110bc565b8260c001516001600160801b03165b90505f61271082845f01516110d191906120f9565b6110db9190612110565b90505f8184604001516110ee9190611bbd565b90505f6127108660e001516001600160801b03168361110d91906120f9565b6111179190612110565b90505f61113787604001518760600151848a60a001518b60800151611390565b90505f8088602001516001600160a01b031683604051611157919061202c565b5f604051808303815f865af19150503d805f8114611190576040519150601f19603f3d011682016040523d82523d5f602084013e611195565b606091505b5091509150816111a85780518060208301fd5b6040516370a0823160e01b81523060048201525f907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa15801561120c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112309190611d74565b905088604001518110156112865760405162461bcd60e51b815260206004820181905260248201527f4e6f7420656e6f7567682062616c616e636520746f207265706179206c6f616e6044820152606401610229565b858110156112d65760405162461bcd60e51b815260206004820152601b60248201527f5472616465206e6f742070726f66697461626c6520656e6f75676800000000006044820152606401610229565b50505050505050505050565b60025f54036113335760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610229565b60025f55565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261138b908490611849565b505050565b60605f8660048111156113a5576113a5611bfe565b036114c7575f83516001600160401b038111156113c4576113c4611e0b565b6040519080825280602002602001820160405280156113ed578160200160208202803683370190505b5090505f5b845181101561145f5784816001875161140b91906120d2565b61141591906120d2565b81518110611425576114256120e5565b602002602001015182828151811061143f5761143f6120e5565b6001600160a01b03909216602092830291909101909101526001016113f2565b506338ed173960e01b8686833061147842610e10611bbd565b60405160240161148c95949392919061212f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915291506118409050565b60018660048111156114db576114db611bfe565b036115b2575f828060200190518101906114f5919061219f565b905063414bf38960e01b6040518061010001604052808660018151811061151e5761151e6120e5565b60200260200101516001600160a01b03168152602001865f81518110611546576115466120e5565b60200260200101516001600160a01b031681526020018362ffffff168152602001306001600160a01b0316815260200142610e106115849190611bbd565b81526020018881526020018781526020015f6001600160a01b031681525060405160240161148c91906121c1565b60028660048111156115c6576115c6611bfe565b036116f2575f828060200190518101906115e0919061219f565b90505f846001815181106115f6576115f66120e5565b602002602001015182865f81518110611611576116116120e5565b602002602001015160405160200161166193929190606093841b6bffffffffffffffffffffffff19908116825260e89390931b6001600160e81b0319166014820152921b166017820152602b0190565b60408051601f1981840301815260a083018252808352306020840152925063c04b8d5960e01b9190810161169742610e10611bbd565b8152602001898152602001888152506040516024016116b6919061223e565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091529250611840915050565b600386600481111561170657611706611bfe565b036117f1575f80838060200190518101906117219190612295565b915091506352bbbe2960e01b6040518060c001604052808481526020018360ff1681526020018760018151811061175a5761175a6120e5565b60200260200101516001600160a01b03168152602001875f81518110611782576117826120e5565b6020908102919091018101516001600160a01b031682528181018b90526040805180830182525f80825293820152805160808101825230808252928101849052908101919091526060810191909152886117de42610e10611bbd565b6040516024016116b694939291906122c3565b5f80838060200190518101906118079190612389565b604051600f83810b602483015282900b6044820152606481018a9052608481018990529193509150630f7c084960e21b9060a4016116b6565b95945050505050565b5f8060205f8451602086015f885af180611868576040513d5f823e3d81fd5b50505f513d9150811561187f57806001141561188c565b6001600160a01b0384163b155b156118b557604051635274afe760e01b81526001600160a01b0385166004820152602401610229565b50505050565b6001600160a01b0381168114610991575f80fd5b80356118da816118bb565b919050565b5f8083601f8401126118ef575f80fd5b5081356001600160401b03811115611905575f80fd5b60208301915083602082850101111561191c575f80fd5b9250929050565b5f805f805f8060a08789031215611938575f80fd5b8635611943816118bb565b955060208701359450604087013593506060870135611961816118bb565b925060808701356001600160401b0381111561197b575f80fd5b61198789828a016118df565b979a9699509497509295939492505050565b5f602082840312156119a9575f80fd5b5035919050565b8035600581106118da575f80fd5b5f8083601f8401126119ce575f80fd5b5081356001600160401b038111156119e4575f80fd5b6020830191508360208260051b850101111561191c575f80fd5b80356001600160801b03811681146118da575f80fd5b5f805f805f805f805f805f806101208d8f031215611a30575f80fd5b8c359b50611a4060208e016118cf565b9a50611a4e60408e016118cf565b9950611a5c60608e016119b0565b98506001600160401b0360808e01351115611a75575f80fd5b611a858e60808f01358f016118df565b90985096506001600160401b0360a08e01351115611aa1575f80fd5b611ab18e60a08f01358f016118df565b90965094506001600160401b0360c08e01351115611acd575f80fd5b611add8e60c08f01358f016119be565b9094509250611aee60e08e016119fe565b9150611afd6101008e016119fe565b90509295989b509295989b509295989b565b5f8060408385031215611b20575f80fd5b8235611b2b816118bb565b946020939093013593505050565b5f60208284031215611b49575f80fd5b8135611b54816118bb565b9392505050565b5f805f8060608587031215611b6e575f80fd5b843593506020850135925060408501356001600160401b03811115611b91575f80fd5b611b9d878288016118df565b95989497509550505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115611bd057611bd0611ba9565b92915050565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b634e487b7160e01b5f52602160045260245ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b038c811682528b16602082015260ff8a166040820152610100606082018190525f90611c709083018a8c611c12565b8281036080840152611c8381898b611c12565b83810360a08501528681528791506020015f5b87811015611cc6578235611ca9816118bb565b6001600160a01b0316825260209283019290910190600101611c96565b506001600160801b03861660c08501529150611cdf9050565b6001600160801b03831660e08301529c9b505050505050505050505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038681168252851660208201526040810184905260a0606082018190525f90611d5e90830185611cfe565b905061ffff831660808301529695505050505050565b5f60208284031215611d84575f80fd5b5051919050565b5f60208284031215611d9b575f80fd5b81518015158114611b54575f80fd5b5f805f60608486031215611dbc575f80fd5b8335611dc7816118bb565b92506020840135611dd7816118bb565b91506040840135611de7816118bb565b809150509250925092565b60ff81168114610991575f80fd5b80356118da81611df2565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715611e4757611e47611e0b565b604052919050565b5f82601f830112611e5e575f80fd5b81356001600160401b03811115611e7757611e77611e0b565b611e8a601f8201601f1916602001611e1f565b818152846020838601011115611e9e575f80fd5b816020850160208301375f918101602001919091529392505050565b5f6001600160401b03821115611ed257611ed2611e0b565b5060051b60200190565b5f82601f830112611eeb575f80fd5b8135611efe611ef982611eba565b611e1f565b8082825260208201915060208360051b860101925085831115611f1f575f80fd5b602085015b83811015611f45578035611f37816118bb565b835260209283019201611f24565b5095945050505050565b5f805f805f805f80610100898b031215611f67575f80fd5b611f70896118cf565b9750611f7e60208a016118cf565b9650611f8c60408a01611e00565b955060608901356001600160401b03811115611fa6575f80fd5b611fb28b828c01611e4f565b95505060808901356001600160401b03811115611fcd575f80fd5b611fd98b828c01611e4f565b94505060a08901356001600160401b03811115611ff4575f80fd5b6120008b828c01611edc565b93505061200f60c08a016119fe565b915061201d60e08a016119fe565b90509295985092959890939650565b5f82518060208501845e5f920191825250919050565b5f60208284031215612052575f80fd5b81516001600160401b03811115612067575f80fd5b8201601f81018413612077575f80fd5b8051612085611ef982611eba565b8082825260208201915060208360051b8501019250868311156120a6575f80fd5b6020840193505b828410156120c85783518252602093840193909101906120ad565b9695505050505050565b81810381811115611bd057611bd0611ba9565b634e487b7160e01b5f52603260045260245ffd5b8082028115828204841417611bd057611bd0611ba9565b5f8261212a57634e487b7160e01b5f52601260045260245ffd5b500490565b5f60a0820187835286602084015260a0604084015280865180835260c0850191506020880192505f5b8181101561217f5783516001600160a01b0316835260209384019390920191600101612158565b50506001600160a01b039590951660608401525050608001529392505050565b5f602082840312156121af575f80fd5b815162ffffff81168114611b54575f80fd5b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff169083015260608084015191821690830152610100820190506080830151608083015260a083015160a083015260c083015160c083015260e083015161223760e08401826001600160a01b03169052565b5092915050565b602081525f825160a0602084015261225960c0840182611cfe565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b5f80604083850312156122a6575f80fd5b8251915060208301516122b881611df2565b809150509250929050565b60e0808252855190820152602085015160ff1661010082015260408501516001600160a01b03908116610120830152606086015116610140820152608085015161016082015260a085015160c06101808301525f906123266101a0840182611cfe565b915050612366602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b8051600f81900b81146118da575f80fd5b5f806040838503121561239a575f80fd5b6123a383612378565b91506123b160208401612378565b9050925092905056fea264697066735822122006115fa5fa2a3cf81ac820ea4860da4ce8b5d64216acf20c2da7e94647d0342164736f6c634300081a0033
Verified Source Code Partial Match
Compiler: v0.8.26+commit.8a97fa7a
EVM: cancun
Optimization: Yes (200 runs)
GGTest3.sol 1000 lines
// File: @openzeppelin/contracts/security/ReentrancyGuard.sol
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @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 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;
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
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// 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;
}
}
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol
// 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);
}
// File: @openzeppelin/contracts/interfaces/IERC20.sol
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
// File: @openzeppelin/contracts/utils/introspection/IERC165.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: @openzeppelin/contracts/interfaces/IERC165.sol
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
// File: @openzeppelin/contracts/interfaces/IERC1363.sol
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
// File: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
// File: contracts/GGTest3.sol
pragma solidity ^0.8.0;
// Enum to specify DEX type for sell operations
enum DexType {
UNISWAP_V2, // Includes SushiSwap V2 and ShibaSwap
UNISWAP_V3, // Includes SushiSwap V3
PANCAKESWAP_V3, // Uses IPancakeV3Router interface
BALANCER,
CURVE
}
// Interface for Uniswap V2 style routers
interface IUniswapV2Router {
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}
// Interface for Uniswap V3 style routers
interface IUniswapV3Router {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params)
external returns (uint256 amountOut);
}
// Interface for Uniswap V3 Swap Callback Interface (for Uniswap V3, SushiSwap V3, and PancakeSwap V3)
interface IUniswapV3SwapCallback {
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}
// Interface for PancakeSwap V3 router
interface IPancakeV3Router {
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(ExactInputParams calldata params)
external payable returns (uint256 amountOut);
}
// Interface for Balancer Vault
interface IBalancerVault {
struct SingleSwap {
bytes32 poolId;
uint8 kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
}
// Interface for Curve pools
interface ICurvePool {
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external;
}
// Interface for IWrappedTokenGatewayV3
interface IWrappedTokenGatewayV3 {
function withdrawETH(
address asset, // WETH address
uint256 amount,
address to
) external;
}
// Interface for AavePoolV3
interface IAavePoolV3 {
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external;
}
// Interface for Flash Loan Receiver to implement flash loan logic
interface IFlashLoanReceiver {
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external returns (bool);
}
// Main contract implementing arbitrage strategies using flash loans
contract GGTest3 is ReentrancyGuard, IFlashLoanReceiver, IUniswapV3SwapCallback {
using SafeERC20 for IERC20;
// State variables
address payable private immutable owner; // Contract owner (payable to allow ETH transfers)
IAavePoolV3 public pool; // AavePoolV3 contract address
address public immutable weth; // WETH contract address
IWrappedTokenGatewayV3 public unwrapWETH; // Wrapped Token GatewayV3 contract address
address private botAddress; // Bot address authorized to interact with the contract
// State minimum profit threshold
uint256 public minProfitBasisPoints = 100; // 1.0% minimum profit by default
// Memory struct for flash loan variables
struct FlashLoanVars {
address buyDexRouter;
address sellDexRouter;
DexType sellDexType;
bytes buyCalldata;
bytes sellParams;
address[] buyPath;
uint128 dynamicProfitFactor;
uint128 dynamicSlippageTolerance;
}
// Packed struct for execution results to minimize stack usage
struct ExecutionContext {
uint256 amountBorrowed;
uint256 premium;
uint256 amountOwed;
uint256 boughtAmount;
}
// Restrict certain functions to only be callable by contract owner
modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_;
}
// Restrict certain functions to only be callable by owner or bot
modifier onlyOwnerOrBot() {
require(msg.sender == owner || msg.sender == botAddress, "Not authorized");
_;
}
// Restrict certain functions to only be callable by bot
modifier onlyBot() {
require(msg.sender == botAddress, "Not authorized");
_;
}
// Initialize variables with default values
constructor(address _botAddress) {
require(_botAddress != address(0), "Invalid bot address");
owner = payable(msg.sender); // Set contract owner
botAddress = _botAddress; // Set bot address
pool = IAavePoolV3(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2); // AavePoolV3 contract address
weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH contract address (not token address)
unwrapWETH = IWrappedTokenGatewayV3(0xA434D495249abE33E031Fe71a969B81f3c07950D); // Wrapped Token Gateway contract address
IERC20(weth).approve(address(pool), type(uint256).max); // Set unlimited approval for WETH once during deployment
}
// Update bot address (only callable by owner)
function updateBotAddress(address newBotAddress) external onlyOwner {
require(newBotAddress != address(0), "Invalid bot address");
botAddress = newBotAddress;
}
// Update minimum profit threshold (only callable by owner)
function updateMinProfitThreshold(uint256 _minProfitBasisPoints) external onlyOwner {
minProfitBasisPoints = _minProfitBasisPoints;
}
// Initiate Arbitrage (uses uint128 for profit/slippage factors instead of uint256)
function initiateArbitrage(
uint256 amount, // Amount to borrow (WETH is implicit)
address buyDexRouter, // Router address for DEX 1
address sellDexRouter, // Router address for DEX 2
DexType sellDexType, // Type of DEX for sell operation
bytes calldata buyCalldata, // Encoded buy calldata on DEX 1
bytes calldata sellParams, // DEX-specific parameters for sell operation
address[] calldata buyPath, // Token swap path on DEX 1 (input token to output token)
uint128 dynamicProfitFactor, // Dynamic profit factor (in basis points)
uint128 dynamicSlippageTolerance // Dynamic slippage tolerance (in basis points)
) external onlyBot {
require(buyDexRouter != address(0) && sellDexRouter != address(0), "Invalid router");
require(uint8(sellDexType) <= 4, "Invalid DEX type");
// Initiate flash loan with packed parameters
pool.flashLoanSimple(
address(this), // Receiver address (this contract)
weth, // Asset to borrow (always WETH)
amount, // Amount to borrow
abi.encode(
buyDexRouter,
sellDexRouter,
uint8(sellDexType),
buyCalldata,
sellParams,
buyPath,
dynamicProfitFactor,
dynamicSlippageTolerance
),
0 // Referral code (0 for no referral)
);
}
// Execute Operation
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
require(msg.sender == address(pool), "Invalid caller");
require(initiator == address(this), "Invalid initiator");
require(asset == weth, "Only WETH supported");
require(amount > 0, "Invalid loan amount");
// Decode params into memory struct (not storage)
FlashLoanVars memory data = _decodeFlashLoanParams(params);
// Create execution context in memory to track state
ExecutionContext memory ctx = ExecutionContext({
amountBorrowed: amount,
premium: premium,
amountOwed: amount + premium,
boughtAmount: 0
});
// Execute trades using memory data
ctx.boughtAmount = _executeBuy(data, amount);
_executeSell(data, ctx);
return true;
}
// Decode parameters into memory struct
function _decodeFlashLoanParams(bytes calldata params)
private
pure
returns (FlashLoanVars memory data)
{
uint8 sellDexTypeUint; // Declare the variable first
(
data.buyDexRouter,
data.sellDexRouter,
sellDexTypeUint,
data.buyCalldata,
data.sellParams,
data.buyPath,
data.dynamicProfitFactor,
data.dynamicSlippageTolerance
) = abi.decode(params, (address, address, uint8, bytes, bytes, address[], uint128, uint128));
data.sellDexType = DexType(sellDexTypeUint);
}
// Execute buy operation using memory parameters
function _executeBuy(FlashLoanVars memory data, uint256 amount)
private
returns (uint256 boughtAmount)
{
// Approve DEX 1 to spend borrowed WETH
IERC20(weth).approve(data.buyDexRouter, amount);
// Execute DEX 1 buy swap
(bool success, bytes memory result) = data.buyDexRouter.call(data.buyCalldata);
require(success, "Buy failed");
// Decode swap result and get actual bought amount based on result length
if (result.length > 32) {
// V2 returns uint256[] array
uint256[] memory amounts = abi.decode(result, (uint256[]));
boughtAmount = amounts[amounts.length - 1];
} else if (result.length == 32) {
// V3 and Balancer return single uint256
boughtAmount = abi.decode(result, (uint256));
} else {
// Curve returns nothing - check balance
boughtAmount = IERC20(data.buyPath[1]).balanceOf(address(this));
}
// Verify we received the tokens
require(
IERC20(data.buyPath[1]).balanceOf(address(this)) >= boughtAmount,
"Insufficient balance"
);
}
// Execute sell operation using memory parameters
function _executeSell(FlashLoanVars memory data, ExecutionContext memory ctx)
private
{
// Approve DEX 2 to spend acquired tokens
IERC20(data.buyPath[1]).approve(data.sellDexRouter, ctx.boughtAmount);
// Choose profit basis points: dynamic if set, otherwise fallback
uint256 profitBP = data.dynamicProfitFactor > 0
? data.dynamicProfitFactor
: minProfitBasisPoints;
// Calculate minimum required output for profitability
uint256 minProfit = (ctx.amountBorrowed * profitBP) / 10000;
uint256 minRequiredOutput = ctx.amountOwed + minProfit;
// Apply dynamic slippage tolerance (using uint128 is sufficient for basis points)
uint256 adjustedMinOutput = (minRequiredOutput * data.dynamicSlippageTolerance) / 10000;
// Build sell calldata from scratch
bytes memory sellCalldata = _buildSellCalldata(
data.sellDexType,
ctx.boughtAmount,
adjustedMinOutput,
data.buyPath,
data.sellParams
);
// Execute sell swap
(bool success, bytes memory resultData) = data.sellDexRouter.call(sellCalldata);
if (!success) {
assembly ("memory-safe") {
let ptr := mload(0x40)
let size := mload(resultData)
revert(add(resultData, 0x20), size)
}
}
// Verify profitability
uint256 balance = IERC20(weth).balanceOf(address(this));
require(balance >= ctx.amountOwed, "Not enough balance to repay loan");
require(balance >= minRequiredOutput, "Trade not profitable enough");
}
// Consolidated sell calldata builder (single function for 5 DEX types)
function _buildSellCalldata(
DexType dexType,
uint256 amountIn,
uint256 minOut,
address[] memory path,
bytes memory params
) private view returns (bytes memory) {
if (dexType == DexType.UNISWAP_V2) {
// Build reversed path for Uniswap V2 sell
address[] memory sellPath = new address[](path.length);
for (uint256 i = 0; i < path.length; i++) {
sellPath[i] = path[path.length - 1 - i];
}
return abi.encodeWithSelector(
IUniswapV2Router.swapExactTokensForTokens.selector,
amountIn,
minOut,
sellPath,
address(this),
block.timestamp + 3600
);
}
else if (dexType == DexType.UNISWAP_V3) {
uint24 fee = abi.decode(params, (uint24));
return abi.encodeWithSelector(
IUniswapV3Router.exactInputSingle.selector,
IUniswapV3Router.ExactInputSingleParams({
tokenIn: path[1],
tokenOut: path[0],
fee: fee,
recipient: address(this),
deadline: block.timestamp + 3600,
amountIn: amountIn,
amountOutMinimum: minOut,
sqrtPriceLimitX96: 0
})
);
}
else if (dexType == DexType.PANCAKESWAP_V3) {
uint24 fee = abi.decode(params, (uint24));
// Encode path for PancakeSwap's exactInput
bytes memory encodedPath = abi.encodePacked(
path[1], // tokenIn (selling this)
fee, // fee tier
path[0] // tokenOut (want WETH back)
);
return abi.encodeWithSelector(
IPancakeV3Router.exactInput.selector,
IPancakeV3Router.ExactInputParams({
path: encodedPath,
recipient: address(this),
deadline: block.timestamp + 3600,
amountIn: amountIn,
amountOutMinimum: minOut
})
);
}
else if (dexType == DexType.BALANCER) {
(bytes32 poolId, uint8 kind) = abi.decode(params, (bytes32, uint8));
return abi.encodeWithSelector(
IBalancerVault.swap.selector,
IBalancerVault.SingleSwap({
poolId: poolId,
kind: kind,
assetIn: path[1],
assetOut: path[0],
amount: amountIn,
userData: ""
}),
IBalancerVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
}),
minOut,
block.timestamp + 3600
);
}
else {
// CURVE
(int128 i, int128 j) = abi.decode(params, (int128, int128));
return abi.encodeWithSelector(
ICurvePool.exchange.selector,
i, j, amountIn, minOut
);
}
}
// Uniswap V3 swap callback (for Uniswap V3, SushiSwap V3, and PancakeSwap V3)
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external override {
// Decode expected pool address from data
(address expectedPool, address tokenIn, address tokenOut) = abi.decode(data, (address, address, address));
require(msg.sender == expectedPool, "Callback: invalid pool");
// Pay whichever token the pool expects
if (amount0Delta > 0) {
// token0 is path[1] when buying (WETH > token), so here token0 = WETH
IERC20(tokenIn).transfer(expectedPool, uint256(amount0Delta));
} else if (amount1Delta > 0) {
// token1 is path[1] (the ERC20 token)
IERC20(tokenOut).transfer(expectedPool, uint256(amount1Delta));
}
}
// Unwrap WETH to ETH using WrappedTokenGatewayV3 contract (can be called manually or automatically)
function unwrapWETHToETH(uint256 wethAmount) external onlyOwnerOrBot nonReentrant {
require(address(unwrapWETH) != address(0), "WrappedTokenGatewayV3 contract not set");
IERC20(weth).approve(address(unwrapWETH), wethAmount);
unwrapWETH.withdrawETH(weth, wethAmount, address(this));
}
// Withdraw ETH to owner wallet (can be called manually or automatically)
function withdrawETH(uint256 amount) external onlyOwnerOrBot nonReentrant {
require(address(this).balance >= amount, "Insufficient ETH balance");
payable(owner).transfer(amount);
}
// Manually withdraw ERC-20 tokens (can only be done manually if needed)
function withdrawERC20(address tokenAddress, uint256 amount) external onlyOwner nonReentrant {
IERC20 tokenToWithdraw = IERC20(tokenAddress);
require(tokenToWithdraw.balanceOf(address(this)) >= amount, "Insufficient token balance");
tokenToWithdraw.safeTransfer(owner, amount);
}
}
Read Contract
minProfitBasisPoints 0xd6b735b5 → uint256
pool 0x16f0115b → address
unwrapWETH 0x385ad0a4 → address
weth 0x3fc8cef3 → address
Write Contract 8 functions
These functions modify contract state and require a wallet transaction to execute.
executeOperation 0x1b11d0ff
address asset
uint256 amount
uint256 premium
address initiator
bytes params
returns: bool
initiateArbitrage 0x6e52151d
uint256 amount
address buyDexRouter
address sellDexRouter
uint8 sellDexType
bytes buyCalldata
bytes sellParams
address[] buyPath
uint128 dynamicProfitFactor
uint128 dynamicSlippageTolerance
uniswapV3SwapCallback 0xfa461e33
int256 amount0Delta
int256 amount1Delta
bytes data
unwrapWETHToETH 0xb6d67a52
uint256 wethAmount
updateBotAddress 0xae0d1b81
address newBotAddress
updateMinProfitThreshold 0x58d0ee58
uint256 _minProfitBasisPoints
withdrawERC20 0xa1db9782
address tokenAddress
uint256 amount
withdrawETH 0xf14210a6
uint256 amount
Recent Transactions
No transactions found for this address