Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x5ABbd344fcbdA0565bd7041747316ee77a9815CD
Balance 0 ETH
Nonce 1
Code Size 9200 bytes
Indexed Transactions 0
External Etherscan · Sourcify

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