Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xA6A239809018Eb268b6E043F32fF31516D7B6D08
Balance 0 ETH
Nonce 1
Code Size 18443 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

18443 bytes
0x608060405234801561000f575f5ffd5b50600436106100fd575f3560e01c80638456cb5911610095578063d109c09a11610064578063d109c09a14610248578063e9d0788f14610264578063edf7ae2114610282578063fa461e33146102b3576100fd565b80638456cb59146101e8578063853828b6146101f2578063a76f8ff3146101fc578063bd54a1d614610218576100fd565b80633dacc241116100d15780633dacc241146101865780633f4ba83a146101a45780634fa0c169146101ae5780635c975abb146101ca576100fd565b806274fe1c1461010157806301681a621461013257806323a69e751461014e5780632c8958f61461016a575b5f5ffd5b61011b600480360381019061011691906132d2565b6102cf565b604051610129929190613337565b60405180910390f35b61014c600480360381019061014791906133b8565b61034a565b005b6101686004803603810190610163919061346a565b6104dc565b005b610184600480360381019061017f919061346a565b6104ef565b005b61018e610502565b60405161019b91906134f5565b60405180910390f35b6101ac610514565b005b6101c860048036038101906101c391906133b8565b6105a0565b005b6101d261069c565b6040516101df91906134f5565b60405180910390f35b6101f06106b1565b005b6101fa61073d565b005b61021660048036038101906102119190613544565b610a55565b005b610232600480360381019061022d9190613582565b610bc5565b60405161023f91906135e6565b60405180910390f35b610262600480360381019061025d9190613629565b610f3c565b005b61026c611011565b6040516102799190613663565b60405180910390f35b61029c600480360381019061029791906133b8565b611035565b6040516102aa9291906136ef565b60405180910390f35b6102cd60048036038101906102c8919061346a565b61106d565b005b5f5f6102d9611080565b5f831161031b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031290613770565b60405180910390fd5b610324846110ca565b5f61032f858561133c565b905080848261033e91906137bb565b92509250509250929050565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103c390613845565b60405180910390fd5b6103d4611479565b5f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161040e9190613663565b602060405180830381865afa158015610429573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061044d9190613877565b90505f8111156104975761049673680d92e2ae066648aed78e6d6e468ad4514636fc828473ffffffffffffffffffffffffffffffffffffffff166114c69092919063ffffffff16565b5b7f23d6711a1d031134a36921253c75aa59e967d38e369ac625992824315e204f2082826040516104c89291906138a2565b60405180910390a1506104d9611545565b50565b6104e9338585858561154e565b50505050565b6104fc338585858561154e565b50505050565b60045f9054906101000a900460ff1681565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610596576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058d90613845565b60405180910390fd5b61059e611659565b565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610622576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061990613845565b60405180910390fd5b806001806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f5fc653936cb6417ca6b0aad40d0b8d9e82fe42ae0443abd953d0fda4cce6780c816040516106919190613663565b60405180910390a150565b5f60015f9054906101000a900460ff16905090565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610733576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072a90613845565b60405180910390fd5b61073b6116ba565b565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b690613845565b60405180910390fd5b6107c7611479565b5f73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016108159190613663565b602060405180830381865afa158015610830573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108549190613877565b90505f8111156108b2576108b173680d92e2ae066648aed78e6d6e468ad4514636fc8273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff166114c69092919063ffffffff16565b5b5f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109009190613663565b602060405180830381865afa15801561091b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061093f9190613877565b90505f81111561099d5761099c73680d92e2ae066648aed78e6d6e468ad4514636fc8273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff166114c69092919063ffffffff16565b5b5f8211156109f3577f23d6711a1d031134a36921253c75aa59e967d38e369ac625992824315e204f2073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48836040516109ea9291906138a2565b60405180910390a15b5f811115610a49577f23d6711a1d031134a36921253c75aa59e967d38e369ac625992824315e204f2073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc282604051610a409291906138a2565b60405180910390a15b5050610a53611545565b565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ace90613845565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610b45576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3c90613913565b60405180910390fd5b600280811115610b5857610b5761367c565b5b60ff168160ff161115610ba0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b979061397b565b60405180910390fd5b610bc16002838360ff166002811115610bbc57610bbb61367c565b5b61171b565b5050565b5f610bce611479565b610bd6611080565b5f8411610c18576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c0f90613770565b60405180910390fd5b610c21856110ca565b5f831115610c86575f610c34868661133c565b90508385610c429190613999565b811015610c84576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7b90613a16565b60405180910390fd5b505b5f5a90505f5f73ffffffffffffffffffffffffffffffffffffffff1687600260038110610cb657610cb5613a34565b5b602002016020810190610cc991906133b8565b73ffffffffffffffffffffffffffffffffffffffff1603610d4257610d3b875f60038110610cfa57610cf9613a34565b5b602002016020810190610d0d91906133b8565b88600160038110610d2157610d20613a34565b5b602002016020810190610d3491906133b8565b88876117d5565b9050610dc3565b610dc0875f60038110610d5857610d57613a34565b5b602002016020810190610d6b91906133b8565b88600160038110610d7f57610d7e613a34565b5b602002016020810190610d9291906133b8565b89600260038110610da657610da5613a34565b5b602002016020810190610db991906133b8565b8988611917565b90505b8581610dcf91906137bb565b92507fc0849e3406f5c646f95ae35d74f832948c870b18ed902bf24e0e998ed3d7d0db6040518060600160405280895f60038110610e1057610e0f613a34565b5b602002016020810190610e2391906133b8565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200189600160038110610e6857610e67613a34565b5b602002016020810190610e7b91906133b8565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200189600260038110610ec057610ebf613a34565b5b602002016020810190610ed391906133b8565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152508783865a87610f119190613a61565b604051610f22959493929190613b39565b60405180910390a15050610f34611545565b949350505050565b73680d92e2ae066648aed78e6d6e468ad4514636fc73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610fbe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb590613845565b60405180910390fd5b8060045f6101000a81548160ff0219169083151502179055507f201bb96e741fa1d26f4b0a42affc182d98607f3973e4e3b9e7209460c88fd9a18160405161100691906134f5565b60405180910390a150565b60018054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6002602052805f5260405f205f91509050805f015f9054906101000a900460ff1690805f0160019054906101000a900460ff16905082565b61107a338585858561154e565b50505050565b61108861069c565b156110c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110bf90613bd4565b60405180910390fd5b565b60025f825f600381106110e0576110df613a34565b5b6020020160208101906110f391906133b8565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160019054906101000a900460ff1661117b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117290613c3c565b60405180910390fd5b60025f8260016003811061119257611191613a34565b5b6020020160208101906111a591906133b8565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160019054906101000a900460ff1661122d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161122490613ca4565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168160026003811061125857611257613a34565b5b60200201602081019061126b91906133b8565b73ffffffffffffffffffffffffffffffffffffffff16146113395760025f8260026003811061129d5761129c613a34565b5b6020020160208101906112b091906133b8565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160019054906101000a900460ff16611338576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132f90613d0c565b60405180910390fd5b5b50565b5f5f73ffffffffffffffffffffffffffffffffffffffff168360026003811061136857611367613a34565b5b60200201602081019061137b91906133b8565b73ffffffffffffffffffffffffffffffffffffffff16036113f3576113ec835f600381106113ac576113ab613a34565b5b6020020160208101906113bf91906133b8565b846001600381106113d3576113d2613a34565b5b6020020160208101906113e691906133b8565b84611b65565b9050611473565b611470835f6003811061140957611408613a34565b5b60200201602081019061141c91906133b8565b846001600381106114305761142f613a34565b5b60200201602081019061144391906133b8565b8560026003811061145757611456613a34565b5b60200201602081019061146a91906133b8565b85611ca4565b90505b92915050565b60025f54036114bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b490613d74565b60405180910390fd5b60025f81905550565b611540838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016114f99291906138a2565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611eee565b505050565b60015f81905550565b60035f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166115d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115ce90613ddc565b60405180910390fd5b5f82828101906115e79190613e35565b90505f85131561161d5761161c86868373ffffffffffffffffffffffffffffffffffffffff166114c69092919063ffffffff16565b5b5f8413156116515761165086858373ffffffffffffffffffffffffffffffffffffffff166114c69092919063ffffffff16565b5b505050505050565b611661611f89565b5f60015f6101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6116a3611fd2565b6040516116b09190613663565b60405180910390a1565b6116c2611080565b6001805f6101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611704611fd2565b6040516117119190613663565b60405180910390a1565b60405180604001604052808260028111156117395761173861367c565b5b815260200160011515815250835f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f820151815f015f6101000a81548160ff021916908360028111156117a9576117a861367c565b5b02179055506020820151815f0160016101000a81548160ff021916908315150217905550905050505050565b5f5f61182c8660025f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff16611fd9565b90505f61189c8760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff1673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48858989612043565b905061190b8660025f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff168473a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488589612043565b92505050949350505050565b5f5f61196e8760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff16611fd9565b90505f6119de8860025f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff1673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48858989612043565b90505f611a378860025f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff16856126fa565b9050611a928860025f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff168584868a612043565b9150611aea8760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff1683612751565b611b578760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff168373a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48868a612043565b935050505095945050505050565b5f5f611bbc8560025f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff16611fd9565b90505f611c2b8660025f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff1673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4885886128a2565b9050611c998560025f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff168473a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48856128a2565b925050509392505050565b5f5f611cfb8660025f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff16611fd9565b90505f611d6a8760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff1673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4885886128a2565b90505f611dc38760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff16856126fa565b9050611e1d8760025f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff168584866128a2565b9150611e758660025f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff1683612751565b611ee18660025f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900460ff168373a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48866128a2565b9350505050949350505050565b5f5f60205f8451602086015f885af180611f0d576040513d5f823e3d81fd5b3d92505f519150505f8214611f26576001811415611f41565b5f8473ffffffffffffffffffffffffffffffffffffffff163b145b15611f8357836040517f5274afe7000000000000000000000000000000000000000000000000000000008152600401611f7a9190613663565b60405180910390fd5b50505050565b611f9161069c565b611fd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fc790613eaa565b60405180910390fd5b565b5f33905090565b5f5f5f611fe68585612d37565b9150915073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146120375781612039565b805b9250505092915050565b5f600160035f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555060045f9054906101000a900460ff161561223a575f8573ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e308a6040518363ffffffff1660e01b81526004016120e9929190613ec8565b602060405180830381865afa158015612104573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121289190613877565b905083811015612234575f8111156121b7578573ffffffffffffffffffffffffffffffffffffffff1663095ea7b3895f6040518363ffffffff1660e01b8152600401612175929190613f31565b6020604051808303815f875af1158015612191573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121b59190613f6c565b505b8573ffffffffffffffffffffffffffffffffffffffff1663095ea7b389866040518363ffffffff1660e01b81526004016121f29291906138a2565b6020604051808303815f875af115801561220e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122329190613f6c565b505b506123f1565b60055f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166123f0578473ffffffffffffffffffffffffffffffffffffffff1663095ea7b3887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b815260040161231e9291906138a2565b6020604051808303815f875af115801561233a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061235e9190613f6c565b50600160055f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b5b5f8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161090505f61243089898685612f5d565b90505f5f5f60028111156124475761244661367c565b5b8a600281111561245a5761245961367c565b5b148061248a5750600160028111156124755761247461367c565b5b8a60028111156124885761248761367c565b5b145b1561253b578a73ffffffffffffffffffffffffffffffffffffffff1663128acb0830868a878e6040516020016124c09190613663565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016124ef959493929190614016565b60408051808303815f875af115801561250a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061252e9190614082565b80925081935050506125e3565b8a73ffffffffffffffffffffffffffffffffffffffff1663128acb0830868a878e60405160200161256c9190613663565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161259b959493929190614016565b60408051808303815f875af11580156125b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125da9190614082565b80925081935050505b60045f9054906101000a900460ff1615612674578873ffffffffffffffffffffffffffffffffffffffff1663095ea7b38c5f6040518363ffffffff1660e01b8152600401612632929190613f31565b6020604051808303815f875af115801561264e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126729190613f6c565b505b5f60035f8d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555083156126df57806126d8906140c0565b94506126ec565b816126e9906140c0565b94505b505050509695505050505050565b5f5f5f6127078686612d37565b915091508373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146127445781612746565b805b925050509392505050565b5f5f61275d8585612d37565b915091508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156127db575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b8061285c57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614801561285b575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b5b61289b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161289290614150565b60405180910390fd5b5050505050565b5f5f5f6128af8888612d37565b915091508173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614801561291957508073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b8061298657508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614801561298557508173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b5b6129c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129bc906141b8565b60405180910390fd5b5f60028111156129d8576129d761367c565b5b8760028111156129eb576129ea61367c565b5b1480612a1b575060016002811115612a0657612a0561367c565b5b876002811115612a1957612a1861367c565b5b145b15612b8e575f8873ffffffffffffffffffffffffffffffffffffffff1663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a6a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a8e919061420e565b90505f612a9c888884613243565b90505f5f6002811115612ab257612ab161367c565b5b8a6002811115612ac557612ac461367c565b5b14612ae45773b048bbc1ee6b733fffcfb9e9cef7375518e25997612afa565b7361ffe014ba17989e743c5f6cb21bf9697530b21e5b90508073ffffffffffffffffffffffffffffffffffffffff1663cdca175383896040518363ffffffff1660e01b8152600401612b37929190614239565b6080604051808303815f875af1925050508015612b7257506040513d601f19601f82011682018060405250810190612b6f91906142ca565b60015b612b7e575f9550612b86565b839950505050505b505050612d2c565b5f73ffffffffffffffffffffffffffffffffffffffff1660018054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603612c1c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c1390614378565b60405180910390fd5b5f60405180608001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018681526020015f73ffffffffffffffffffffffffffffffffffffffff16815250905060018054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635e5e6e0f826040518263ffffffff1660e01b8152600401612cdb9190614407565b6080604051808303815f875af1925050508015612d1657506040513d601f19601f82011682018060405250810190612d1391906142ca565b60015b612d22575f9350612d2a565b839750505050505b505b505095945050505050565b5f5f5f6002811115612d4c57612d4b61367c565b5b836002811115612d5f57612d5e61367c565b5b1480612d8f575060016002811115612d7a57612d7961367c565b5b836002811115612d8d57612d8c61367c565b5b145b15612e77578373ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ddd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e019190614434565b91508373ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e4c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e709190614434565b9050612f56565b8373ffffffffffffffffffffffffffffffffffffffff16630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ec0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ee49190614434565b91508373ffffffffffffffffffffffffffffffffffffffff1663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f2f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f539190614434565b90505b9250929050565b5f5f8303612faa5781612f9057600173fffd8963efd1fc6a506488495d951d5263988d26612f8b919061445f565b612fa3565b60016401000276a3612fa291906144a6565b5b905061323b565b5f5f6002811115612fbe57612fbd61367c565b5b856002811115612fd157612fd061367c565b5b1480613001575060016002811115612fec57612feb61367c565b5b856002811115612fff57612ffe61367c565b5b145b15613091578573ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561304f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613073919061456e565b9091929394509091929350909192509091509050508091505061310d565b8573ffffffffffffffffffffffffffffffffffffffff1663e76c01e46040518163ffffffff1660e01b815260040160a060405180830381865afa1580156130da573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130fe919061460b565b90919250909150905050809150505b821561319a575f612710856127106131259190613a61565b8373ffffffffffffffffffffffffffffffffffffffff166131469190614682565b61315091906146f0565b90506401000276a373ffffffffffffffffffffffffffffffffffffffff168110156131905760016401000276a361318791906144a6565b9250505061323b565b809250505061323b565b5f612710856127106131ac9190613999565b8373ffffffffffffffffffffffffffffffffffffffff166131cd9190614682565b6131d791906146f0565b905073fffd8963efd1fc6a506488495d951d5263988d2673ffffffffffffffffffffffffffffffffffffffff1681111561323557600173fffd8963efd1fc6a506488495d951d5263988d2661322c919061445f565b9250505061323b565b80925050505b949350505050565b606083828460405160200161325a93929190614799565b60405160208183030381529060405290509392505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f819050826020600302820111156132995761329861327a565b5b92915050565b5f819050919050565b6132b18161329f565b81146132bb575f5ffd5b50565b5f813590506132cc816132a8565b92915050565b5f5f608083850312156132e8576132e7613272565b5b5f6132f58582860161327e565b9250506060613306858286016132be565b9150509250929050565b6133198161329f565b82525050565b5f819050919050565b6133318161331f565b82525050565b5f60408201905061334a5f830185613310565b6133576020830184613328565b9392505050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6133878261335e565b9050919050565b6133978161337d565b81146133a1575f5ffd5b50565b5f813590506133b28161338e565b92915050565b5f602082840312156133cd576133cc613272565b5b5f6133da848285016133a4565b91505092915050565b6133ec8161331f565b81146133f6575f5ffd5b50565b5f81359050613407816133e3565b92915050565b5f5ffd5b5f5ffd5b5f5f83601f84011261342a5761342961340d565b5b8235905067ffffffffffffffff81111561344757613446613411565b5b6020830191508360018202830111156134635761346261327a565b5b9250929050565b5f5f5f5f6060858703121561348257613481613272565b5b5f61348f878288016133f9565b94505060206134a0878288016133f9565b935050604085013567ffffffffffffffff8111156134c1576134c0613276565b5b6134cd87828801613415565b925092505092959194509250565b5f8115159050919050565b6134ef816134db565b82525050565b5f6020820190506135085f8301846134e6565b92915050565b5f60ff82169050919050565b6135238161350e565b811461352d575f5ffd5b50565b5f8135905061353e8161351a565b92915050565b5f5f6040838503121561355a57613559613272565b5b5f613567858286016133a4565b925050602061357885828601613530565b9150509250929050565b5f5f5f5f60c0858703121561359a57613599613272565b5b5f6135a78782880161327e565b94505060606135b8878288016132be565b93505060806135c9878288016132be565b92505060a06135da878288016132be565b91505092959194509250565b5f6020820190506135f95f830184613328565b92915050565b613608816134db565b8114613612575f5ffd5b50565b5f81359050613623816135ff565b92915050565b5f6020828403121561363e5761363d613272565b5b5f61364b84828501613615565b91505092915050565b61365d8161337d565b82525050565b5f6020820190506136765f830184613654565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600381106136ba576136b961367c565b5b50565b5f8190506136ca826136a9565b919050565b5f6136d9826136bd565b9050919050565b6136e9816136cf565b82525050565b5f6040820190506137025f8301856136e0565b61370f60208301846134e6565b9392505050565b5f82825260208201905092915050565b7f496e76616c696420616d6f756e740000000000000000000000000000000000005f82015250565b5f61375a600e83613716565b915061376582613726565b602082019050919050565b5f6020820190508181035f8301526137878161374e565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6137c58261331f565b91506137d08361331f565b925082820390508181125f8412168282135f8512151617156137f5576137f461378e565b5b92915050565b7f4f6e6c79206f776e6572000000000000000000000000000000000000000000005f82015250565b5f61382f600a83613716565b915061383a826137fb565b602082019050919050565b5f6020820190508181035f83015261385c81613823565b9050919050565b5f81519050613871816132a8565b92915050565b5f6020828403121561388c5761388b613272565b5b5f61389984828501613863565b91505092915050565b5f6040820190506138b55f830185613654565b6138c26020830184613310565b9392505050565b7f7a65726f000000000000000000000000000000000000000000000000000000005f82015250565b5f6138fd600483613716565b9150613908826138c9565b602082019050919050565b5f6020820190508181035f83015261392a816138f1565b9050919050565b7f62616420646578000000000000000000000000000000000000000000000000005f82015250565b5f613965600783613716565b915061397082613931565b602082019050919050565b5f6020820190508181035f83015261399281613959565b9050919050565b5f6139a38261329f565b91506139ae8361329f565b92508282019050808211156139c6576139c561378e565b5b92915050565b7f4e6f742070726f66697461626c650000000000000000000000000000000000005f82015250565b5f613a00600e83613716565b9150613a0b826139cc565b602082019050919050565b5f6020820190508181035f830152613a2d816139f4565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f613a6b8261329f565b9150613a768361329f565b9250828203905081811115613a8e57613a8d61378e565b5b92915050565b5f60039050919050565b5f81905092915050565b5f819050919050565b613aba8161337d565b82525050565b5f613acb8383613ab1565b60208301905092915050565b5f602082019050919050565b613aec81613a94565b613af68184613a9e565b9250613b0182613aa8565b805f5b83811015613b31578151613b188782613ac0565b9650613b2383613ad7565b925050600181019050613b04565b505050505050565b5f60e082019050613b4c5f830188613ae3565b613b596060830187613310565b613b666080830186613310565b613b7360a0830185613328565b613b8060c0830184613310565b9695505050505050565b7f5061757361626c653a20706175736564000000000000000000000000000000005f82015250565b5f613bbe601083613716565b9150613bc982613b8a565b602082019050919050565b5f6020820190508181035f830152613beb81613bb2565b9050919050565b7f506f6f6c312021657869737473000000000000000000000000000000000000005f82015250565b5f613c26600d83613716565b9150613c3182613bf2565b602082019050919050565b5f6020820190508181035f830152613c5381613c1a565b9050919050565b7f506f6f6c322021657869737473000000000000000000000000000000000000005f82015250565b5f613c8e600d83613716565b9150613c9982613c5a565b602082019050919050565b5f6020820190508181035f830152613cbb81613c82565b9050919050565b7f506f6f6c332021657869737473000000000000000000000000000000000000005f82015250565b5f613cf6600d83613716565b9150613d0182613cc2565b602082019050919050565b5f6020820190508181035f830152613d2381613cea565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c005f82015250565b5f613d5e601f83613716565b9150613d6982613d2a565b602082019050919050565b5f6020820190508181035f830152613d8b81613d52565b9050919050565b7f63616c6c6261636b2d696e76616c6964000000000000000000000000000000005f82015250565b5f613dc6601083613716565b9150613dd182613d92565b602082019050919050565b5f6020820190508181035f830152613df381613dba565b9050919050565b5f613e048261335e565b9050919050565b613e1481613dfa565b8114613e1e575f5ffd5b50565b5f81359050613e2f81613e0b565b92915050565b5f60208284031215613e4a57613e49613272565b5b5f613e5784828501613e21565b91505092915050565b7f5061757361626c653a206e6f74207061757365640000000000000000000000005f82015250565b5f613e94601483613716565b9150613e9f82613e60565b602082019050919050565b5f6020820190508181035f830152613ec181613e88565b9050919050565b5f604082019050613edb5f830185613654565b613ee86020830184613654565b9392505050565b5f819050919050565b5f819050919050565b5f613f1b613f16613f1184613eef565b613ef8565b61329f565b9050919050565b613f2b81613f01565b82525050565b5f604082019050613f445f830185613654565b613f516020830184613f22565b9392505050565b5f81519050613f66816135ff565b92915050565b5f60208284031215613f8157613f80613272565b5b5f613f8e84828501613f58565b91505092915050565b613fa08161335e565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613fe882613fa6565b613ff28185613fb0565b9350614002818560208601613fc0565b61400b81613fce565b840191505092915050565b5f60a0820190506140295f830188613654565b61403660208301876134e6565b6140436040830186613328565b6140506060830185613f97565b81810360808301526140628184613fde565b90509695505050505050565b5f8151905061407c816133e3565b92915050565b5f5f6040838503121561409857614097613272565b5b5f6140a58582860161406e565b92505060206140b68582860161406e565b9150509250929050565b5f6140ca8261331f565b91507f800000000000000000000000000000000000000000000000000000000000000082036140fc576140fb61378e565b5b815f039050919050565b7f496e76616c696420332d686f70207061746800000000000000000000000000005f82015250565b5f61413a601283613716565b915061414582614106565b602082019050919050565b5f6020820190508181035f8301526141678161412e565b9050919050565b7f71756f74653a20746f6b656e2070616972206e6f7420696e20706f6f6c0000005f82015250565b5f6141a2601d83613716565b91506141ad8261416e565b602082019050919050565b5f6020820190508181035f8301526141cf81614196565b9050919050565b5f62ffffff82169050919050565b6141ed816141d6565b81146141f7575f5ffd5b50565b5f81519050614208816141e4565b92915050565b5f6020828403121561422357614222613272565b5b5f614230848285016141fa565b91505092915050565b5f6040820190508181035f8301526142518185613fde565b90506142606020830184613310565b9392505050565b6142708161335e565b811461427a575f5ffd5b50565b5f8151905061428b81614267565b92915050565b5f63ffffffff82169050919050565b6142a981614291565b81146142b3575f5ffd5b50565b5f815190506142c4816142a0565b92915050565b5f5f5f5f608085870312156142e2576142e1613272565b5b5f6142ef87828801613863565b94505060206143008782880161427d565b9350506040614311878288016142b6565b925050606061432287828801613863565b91505092959194509250565b7f416c67656272612071756f746572206e6f7420736574000000000000000000005f82015250565b5f614362601683613716565b915061436d8261432e565b602082019050919050565b5f6020820190508181035f83015261438f81614356565b9050919050565b61439f8161329f565b82525050565b6143ae8161335e565b82525050565b608082015f8201516143c85f850182613ab1565b5060208201516143db6020850182613ab1565b5060408201516143ee6040850182614396565b50606082015161440160608501826143a5565b50505050565b5f60808201905061441a5f8301846143b4565b92915050565b5f8151905061442e8161338e565b92915050565b5f6020828403121561444957614448613272565b5b5f61445684828501614420565b91505092915050565b5f6144698261335e565b91506144748361335e565b9250828203905073ffffffffffffffffffffffffffffffffffffffff8111156144a05761449f61378e565b5b92915050565b5f6144b08261335e565b91506144bb8361335e565b9250828201905073ffffffffffffffffffffffffffffffffffffffff8111156144e7576144e661378e565b5b92915050565b5f8160020b9050919050565b614502816144ed565b811461450c575f5ffd5b50565b5f8151905061451d816144f9565b92915050565b5f61ffff82169050919050565b61453981614523565b8114614543575f5ffd5b50565b5f8151905061455481614530565b92915050565b5f815190506145688161351a565b92915050565b5f5f5f5f5f5f5f60e0888a03121561458957614588613272565b5b5f6145968a828b0161427d565b97505060206145a78a828b0161450f565b96505060406145b88a828b01614546565b95505060606145c98a828b01614546565b94505060806145da8a828b01614546565b93505060a06145eb8a828b0161455a565b92505060c06145fc8a828b01613f58565b91505092959891949750929550565b5f5f5f5f5f60a0868803121561462457614623613272565b5b5f6146318882890161427d565b95505060206146428882890161450f565b945050604061465388828901614546565b93505060606146648882890161455a565b92505060806146758882890161455a565b9150509295509295909350565b5f61468c8261329f565b91506146978361329f565b92508282026146a58161329f565b915082820484148315176146bc576146bb61378e565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6146fa8261329f565b91506147058361329f565b925082614715576147146146c3565b5b828204905092915050565b5f8160601b9050919050565b5f61473682614720565b9050919050565b5f6147478261472c565b9050919050565b61475f61475a8261337d565b61473d565b82525050565b5f8160e81b9050919050565b5f61477b82614765565b9050919050565b61479361478e826141d6565b614771565b82525050565b5f6147a4828661474e565b6014820191506147b48285614782565b6003820191506147c4828461474e565b60148201915081905094935050505056fea2646970667358221220d5b0c76d136732fbced01e8bbe6212d7691e6d3e30c89dd0ff40cbd95e32616c64736f6c634300081e0033

Verified Source Code Full Match

Compiler: v0.8.30+commit.73712a01 EVM: prague Optimization: No
EthArb.sol 548 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title ArbitrageV2_Mainnet
 * @notice 2–3 hop arbitrage across curated pools on Ethereum Mainnet.
 * @dev ADAPTED FOR ETHEREUM MAINNET.
 */

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./interfaces/ethInterfaces.sol";
import "./libraries/EthPoolRegistry.sol";

contract EthArb is ReentrancyGuard, Pausable {
    using SafeERC20 for IERC20;

    // ====== OWNER / TOKENS (Ethereum Mainnet) ======
    // SECURITY WARNING: Do not hardcode this in production if you want transferability.
    // Use Ownable.sol instead.
    address private constant OWNER_ADDRESS = 0x680D92E2AE066648aEd78e6d6E468aD4514636fC;

    // USDC (Mainnet): 6 decimals
    address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    // WETH (Mainnet): 18 decimals
    address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    // ====== SQRT PRICE LIMITS ======
    uint160 private constant MIN_SQRT_RATIO = 4295128739;
    uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    // ====== QUOTERS (Ethereum Mainnet) ======
    // Uniswap V3 QuoterV2
    address private constant UNISWAP_QUOTER = 0x61fFE014bA17989E743c5F6cB21bF9697530B21e;
    // Pancake V3 QuoterV2 (Same deployment address as Base)
    address private constant PANCAKE_QUOTER = 0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997;

    address public algebraQuoter = address(0);

    // ====== REGISTRY / STATE ======
    mapping(address => PoolRegistry.PoolInfo) public poolRegistry;
    mapping(address => bool) private activeSwaps;

    bool public useLimitedAllowances = true;
    mapping(address => mapping(address => bool)) private hasInfiniteAllowance;

    // ====== EVENTS ======
    event ArbitrageExecuted(
        address[3] pools,
        uint256 inAmt,
        uint256 outAmt,
        int256 profit,
        uint256 gasUsed
    );
    event EmergencyWithdrawal(address token, uint256 amount);
    event UseLimitedAllowancesSet(bool enabled);
    event AlgebraQuoterSet(address quoter);

    modifier onlyOwner() {
        require(msg.sender == OWNER_ADDRESS, "Only owner");
        _;
    }

    constructor() {
        PoolRegistry.initializeAllPools(poolRegistry);
    }

    // ====== ADMIN ======
    function pause() external onlyOwner {
        _pause();
    }
    function unpause() external onlyOwner {
        _unpause();
    }

    function setUseLimitedAllowances(bool _useLimited) external onlyOwner {
        useLimitedAllowances = _useLimited;
        emit UseLimitedAllowancesSet(_useLimited);
    }

    function setAlgebraQuoter(address q) external onlyOwner {
        algebraQuoter = q;
        emit AlgebraQuoterSet(q);
    }

    function sweep(address token) external onlyOwner nonReentrant {
        uint256 bal = IERC20(token).balanceOf(address(this));
        if (bal > 0) IERC20(token).safeTransfer(OWNER_ADDRESS, bal);
        emit EmergencyWithdrawal(token, bal);
    }

    function withdrawAll() external onlyOwner nonReentrant {
        uint256 u = IERC20(USDC).balanceOf(address(this));
        if (u > 0) IERC20(USDC).safeTransfer(OWNER_ADDRESS, u);
        uint256 w = IERC20(WETH).balanceOf(address(this));
        if (w > 0) IERC20(WETH).safeTransfer(OWNER_ADDRESS, w);
        if (u > 0) emit EmergencyWithdrawal(USDC, u);
        if (w > 0) emit EmergencyWithdrawal(WETH, w);
    }

    function addPool(address pool, uint8 dex) external onlyOwner {
        require(pool != address(0), "zero");
        require(dex <= uint8(PoolRegistry.Dex.Algebra), "bad dex");
        PoolRegistry._set(poolRegistry, pool, PoolRegistry.Dex(dex));
    }

    // ====== PREVIEW ======
    function preview(address[3] calldata pools, uint256 usdcAmount)
        external
        whenNotPaused
        returns (uint256 expectedOut, int256 profit)
    {
        require(usdcAmount > 0, "Invalid amount");
        _validatePools(pools);

        uint256 outAmt = _simulatePath(pools, usdcAmount);
        return (outAmt, int256(outAmt) - int256(usdcAmount));
    }

    // ====== EXECUTE ======
    function execute(
        address[3] calldata pools,
        uint256 usdcAmount,
        uint256 minProfit,
        uint256 maxSlippageBps
    ) external nonReentrant whenNotPaused returns (int256 profit) {
        require(usdcAmount > 0, "Invalid amount");
        _validatePools(pools);

        // SAFETY MODE
        if (minProfit > 0) {
            uint256 expected = _simulatePath(pools, usdcAmount);
            require(expected >= usdcAmount + minProfit, "Not profitable");
        }

        uint256 gasStart = gasleft();
        uint256 outAmt;

        if (pools[2] == address(0)) {
            outAmt = _execute2Hop(
                pools[0],
                pools[1],
                usdcAmount,
                maxSlippageBps
            );
        } else {
            outAmt = _execute3Hop(
                pools[0],
                pools[1],
                pools[2],
                usdcAmount,
                maxSlippageBps
            );
        }

        profit = int256(outAmt) - int256(usdcAmount);
        emit ArbitrageExecuted(
            [pools[0], pools[1], pools[2]],
            usdcAmount,
            outAmt,
            profit,
            gasStart - gasleft()
        );
    }

    // ====== INTERNAL: SIMULATION ======
    function _validatePools(address[3] calldata pools) internal view {
        require(poolRegistry[pools[0]].exists, "Pool1 !exists");
        require(poolRegistry[pools[1]].exists, "Pool2 !exists");
        if (pools[2] != address(0))
            require(poolRegistry[pools[2]].exists, "Pool3 !exists");
    }

    function _simulatePath(address[3] calldata pools, uint256 amountIn)
        internal
        returns (uint256)
    {
        if (pools[2] == address(0)) {
            return _simulate2Hop(pools[0], pools[1], amountIn);
        } else {
            return _simulate3Hop(pools[0], pools[1], pools[2], amountIn);
        }
    }

    function _simulate2Hop(
        address pool0,
        address pool1,
        uint256 amountIn
    ) internal returns (uint256) {
        address mid = _midToken(pool0, poolRegistry[pool0].dex);
        uint256 amt = _quoteExactInputSingle(
            pool0,
            poolRegistry[pool0].dex,
            USDC,
            mid,
            amountIn
        );
        return
            _quoteExactInputSingle(
                pool1,
                poolRegistry[pool1].dex,
                mid,
                USDC,
                amt
            );
    }

    function _simulate3Hop(
        address pool0,
        address pool1,
        address pool2,
        uint256 amountIn
    ) internal returns (uint256) {
        address token1 = _midToken(pool0, poolRegistry[pool0].dex);
        uint256 amt = _quoteExactInputSingle(
            pool0,
            poolRegistry[pool0].dex,
            USDC,
            token1,
            amountIn
        );
        address token2 = _nextToken(pool1, poolRegistry[pool1].dex, token1);
        amt = _quoteExactInputSingle(
            pool1,
            poolRegistry[pool1].dex,
            token1,
            token2,
            amt
        );
        _assertEndsInUSDC(pool2, poolRegistry[pool2].dex, token2);
        return
            _quoteExactInputSingle(
                pool2,
                poolRegistry[pool2].dex,
                token2,
                USDC,
                amt
            );
    }

    function _quoteExactInputSingle(
        address pool,
        PoolRegistry.Dex dex,
        address tokenIn,
        address tokenOut,
        uint256 amountIn
    ) internal returns (uint256 out) {
        (address t0, address t1) = _tokens(pool, dex);
        require(
            (tokenIn == t0 && tokenOut == t1) ||
                (tokenIn == t1 && tokenOut == t0),
            "quote: token pair not in pool"
        );

        if (
            dex == PoolRegistry.Dex.UniswapV3 ||
            dex == PoolRegistry.Dex.PancakeV3
        ) {
            uint24 fee = IUniswapV3Pool(pool).fee();
            bytes memory path = _encodeV3Path(tokenIn, tokenOut, fee);
            address quoter = dex == PoolRegistry.Dex.UniswapV3
                ? UNISWAP_QUOTER
                : PANCAKE_QUOTER;

            try
                IV3QuoterV2Bytes(quoter).quoteExactInput(path, amountIn)
            returns (uint256 amountOut, uint160, uint32, uint256) {
                out = amountOut;
            } catch {
                out = 0;
            }
        } else {
            require(algebraQuoter != address(0), "Algebra quoter not set");
            IAlgebraQuoterV2.QuoteExactInputSingleParams
                memory p = IAlgebraQuoterV2.QuoteExactInputSingleParams({
                    tokenIn: tokenIn,
                    tokenOut: tokenOut,
                    amountIn: amountIn,
                    limitSqrtPrice: 0
                });
            try
                IAlgebraQuoterV2(algebraQuoter).quoteExactInputSingle(p)
            returns (uint256 amountOut, uint160, uint32, uint256) {
                out = amountOut;
            } catch {
                out = 0;
            }
        }
    }

    // ====== INTERNAL: REAL EXECUTION ======
    function _execute2Hop(
        address pool0,
        address pool1,
        uint256 amountInUSDC,
        uint256 maxSlippageBps
    ) internal returns (uint256) {
        address mid = _midToken(pool0, poolRegistry[pool0].dex);
        uint256 amt = _executeSwap(
            pool0,
            poolRegistry[pool0].dex,
            USDC,
            mid,
            amountInUSDC,
            maxSlippageBps
        );
        return
            _executeSwap(
                pool1,
                poolRegistry[pool1].dex,
                mid,
                USDC,
                amt,
                maxSlippageBps
            );
    }

    function _execute3Hop(
        address pool0,
        address pool1,
        address pool2,
        uint256 amountInUSDC,
        uint256 maxSlippageBps
    ) internal returns (uint256) {
        address token1 = _midToken(pool0, poolRegistry[pool0].dex);
        uint256 amt = _executeSwap(
            pool0,
            poolRegistry[pool0].dex,
            USDC,
            token1,
            amountInUSDC,
            maxSlippageBps
        );
        address token2 = _nextToken(pool1, poolRegistry[pool1].dex, token1);
        amt = _executeSwap(
            pool1,
            poolRegistry[pool1].dex,
            token1,
            token2,
            amt,
            maxSlippageBps
        );
        _assertEndsInUSDC(pool2, poolRegistry[pool2].dex, token2);
        return
            _executeSwap(
                pool2,
                poolRegistry[pool2].dex,
                token2,
                USDC,
                amt,
                maxSlippageBps
            );
    }

    function _executeSwap(
        address pool,
        PoolRegistry.Dex dex,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 maxSlippageBps
    ) internal returns (uint256 amountOut) {
        activeSwaps[pool] = true;

        if (useLimitedAllowances) {
            uint256 cur = IERC20(tokenIn).allowance(address(this), pool);
            if (cur < amountIn) {
                if (cur > 0) IERC20(tokenIn).approve(pool, 0);
                IERC20(tokenIn).approve(pool, amountIn);
            }
        } else {
            if (!hasInfiniteAllowance[tokenIn][pool]) {
                IERC20(tokenIn).approve(pool, type(uint256).max);
                hasInfiniteAllowance[tokenIn][pool] = true;
            }
        }

        bool zeroForOne = tokenIn < tokenOut;
        uint160 sqrtLimit = _computeSqrtPriceLimitX96(
            pool,
            dex,
            maxSlippageBps,
            zeroForOne
        );

        int256 amount0;
        int256 amount1;

        if (
            dex == PoolRegistry.Dex.UniswapV3 ||
            dex == PoolRegistry.Dex.PancakeV3
        ) {
            (amount0, amount1) = IUniswapV3Pool(pool).swap(
                address(this),
                zeroForOne,
                int256(amountIn),
                sqrtLimit,
                abi.encode(tokenIn)
            );
        } else {
            (amount0, amount1) = IAlgebraPool(pool).swap(
                address(this),
                zeroForOne,
                int256(amountIn),
                sqrtLimit,
                abi.encode(tokenIn)
            );
        }

        if (useLimitedAllowances) IERC20(tokenIn).approve(pool, 0);
        activeSwaps[pool] = false;

        if (zeroForOne) {
            amountOut = uint256(-amount1);
        } else {
            amountOut = uint256(-amount0);
        }
    }

    function _computeSqrtPriceLimitX96(
        address pool,
        PoolRegistry.Dex dex,
        uint256 maxSlippageBps,
        bool zeroForOne
    ) internal view returns (uint160) {
        if (maxSlippageBps == 0) {
            return zeroForOne ? (MIN_SQRT_RATIO + 1) : (MAX_SQRT_RATIO - 1);
        }

        uint160 sqrtP;
        if (
            dex == PoolRegistry.Dex.UniswapV3 ||
            dex == PoolRegistry.Dex.PancakeV3
        ) {
            (sqrtP, , , , , , ) = IUniswapV3Pool(pool).slot0();
        } else {
            (sqrtP, , , , ) = IAlgebraPool(pool).globalState();
        }

        if (zeroForOne) {
            uint256 limit = (uint256(sqrtP) * (10_000 - maxSlippageBps)) /
                10_000;
            if (limit < MIN_SQRT_RATIO) return MIN_SQRT_RATIO + 1;
            return uint160(limit);
        } else {
            uint256 limit = (uint256(sqrtP) * (10_000 + maxSlippageBps)) /
                10_000;
            if (limit > MAX_SQRT_RATIO) return MAX_SQRT_RATIO - 1;
            return uint160(limit);
        }
    }

    // ====== CALLBACKS ======
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external {
        _payCallback(msg.sender, amount0Delta, amount1Delta, data);
    }
    function pancakeV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external {
        _payCallback(msg.sender, amount0Delta, amount1Delta, data);
    }
    function algebraSwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external {
        _payCallback(msg.sender, amount0Delta, amount1Delta, data);
    }

    function _payCallback(
        address pool,
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) internal {
        require(activeSwaps[pool], "callback-invalid");
        address tokenIn = abi.decode(data, (address));
        if (amount0Delta > 0)
            IERC20(tokenIn).safeTransfer(pool, uint256(amount0Delta));
        if (amount1Delta > 0)
            IERC20(tokenIn).safeTransfer(pool, uint256(amount1Delta));
    }

    // ====== HELPERS ======
    function _tokens(address pool, PoolRegistry.Dex dex)
        internal
        view
        returns (address t0, address t1)
    {
        if (
            dex == PoolRegistry.Dex.UniswapV3 ||
            dex == PoolRegistry.Dex.PancakeV3
        ) {
            t0 = IUniswapV3Pool(pool).token0();
            t1 = IUniswapV3Pool(pool).token1();
        } else {
            t0 = IAlgebraPool(pool).token0();
            t1 = IAlgebraPool(pool).token1();
        }
    }

    function _midToken(address pool, PoolRegistry.Dex dex)
        internal
        view
        returns (address)
    {
        (address t0, address t1) = _tokens(pool, dex);
        return (t0 == USDC) ? t1 : t0;
    }

    function _nextToken(address pool, PoolRegistry.Dex dex, address prev)
        internal
        view
        returns (address)
    {
        (address t0, address t1) = _tokens(pool, dex);
        return (t0 == prev) ? t1 : t0;
    }

    function _assertEndsInUSDC(
        address pool,
        PoolRegistry.Dex dex,
        address token2
    ) internal view {
        (address t0, address t1) = _tokens(pool, dex);
        require(
            (t0 == token2 && t1 == USDC) || (t1 == token2 && t0 == USDC),
            "Invalid 3-hop path"
        );
    }

    function _encodeV3Path(
        address tokenIn,
        address tokenOut,
        uint24 fee
    ) internal pure returns (bytes memory) {
        return abi.encodePacked(tokenIn, fee, tokenOut);
    }
}
EthPoolRegistry.sol 23 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

library PoolRegistry {
    enum Dex { UniswapV3, PancakeV3, Algebra }

    struct PoolInfo {
        Dex dex;
        bool exists;
    }

    function _set(
        mapping(address => PoolInfo) storage reg,
        address pool,
        Dex dex
    ) internal {
        reg[pool] = PoolInfo({ dex: dex, exists: true });
    }

    function initializeAllPools(mapping(address => PoolInfo) storage reg) external {
        _set(reg, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640, Dex.UniswapV3);
    }
}
ethInterfaces.sol 85 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// ---------- UniswapV3 / PancakeV3 Pool ----------
interface IUniswapV3Pool {
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);

    function fee() external view returns (uint24);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint8 feeProtocol,
            bool unlocked
        );
}

/// ---------- Uniswap/Pancake QuoterV2 Interfaces ----------
// Consolidated for brevity as they share signatures
interface IV3QuoterV2Bytes {
    function quoteExactInput(bytes memory path, uint256 amountIn)
        external
        returns (
            uint256 amountOut,
            uint160 sqrtPriceX96After,
            uint32 initializedTicksCrossed,
            uint256 gasEstimate
        );
}

/// ---------- Algebra (Slipstream/QuickSwap) Interfaces ----------
// Note: Algebra is less common on Mainnet than Base (Aerodrome).
// Ensure you are targeting valid Algebra pools if using this Dex ID.
interface IAlgebraPool {
    function swap(
        address recipient,
        bool zeroToOne,
        int256 amountSpecified,
        uint160 limitSqrtPrice,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);

    function token0() external view returns (address);
    function token1() external view returns (address);
    function globalState()
        external
        view
        returns (
            uint160 price,
            int24 tick,
            uint16 lastFee,
            uint8 pluginConfig,
            uint8 communityFee
        );
}

interface IAlgebraQuoterV2 {
    struct QuoteExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint256 amountIn;
        uint160 limitSqrtPrice;
    }
    function quoteExactInputSingle(QuoteExactInputSingleParams memory params)
        external
        returns (
            uint256 amountOut,
            uint160 sqrtPriceX96After,
            uint32 initializedTicksCrossed,
            uint256 gasEstimate
        );
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(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);
    }
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @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);
}
Pausable.sol 105 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}
ReentrancyGuard.sol 77 lines
// SPDX-License-Identifier: MIT
// 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;
    }
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @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);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @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);
}

Read Contract

algebraQuoter 0xe9d0788f → address
paused 0x5c975abb → bool
poolRegistry 0xedf7ae21 → uint8, bool
useLimitedAllowances 0x3dacc241 → bool

Write Contract 12 functions

These functions modify contract state and require a wallet transaction to execute.

addPool 0xa76f8ff3
address pool
uint8 dex
algebraSwapCallback 0x2c8958f6
int256 amount0Delta
int256 amount1Delta
bytes data
execute 0xbd54a1d6
address[3] pools
uint256 usdcAmount
uint256 minProfit
uint256 maxSlippageBps
returns: int256
pancakeV3SwapCallback 0x23a69e75
int256 amount0Delta
int256 amount1Delta
bytes data
pause 0x8456cb59
No parameters
preview 0x0074fe1c
address[3] pools
uint256 usdcAmount
returns: uint256, int256
setAlgebraQuoter 0x4fa0c169
address q
setUseLimitedAllowances 0xd109c09a
bool _useLimited
sweep 0x01681a62
address token
uniswapV3SwapCallback 0xfa461e33
int256 amount0Delta
int256 amount1Delta
bytes data
unpause 0x3f4ba83a
No parameters
withdrawAll 0x853828b6
No parameters

Recent Transactions

No transactions found for this address