Address Contract Verified
Address
0xA6A239809018Eb268b6E043F32fF31516D7B6D08
Balance
0 ETH
Nonce
1
Code Size
18443 bytes
Creator
0x680D92E2...36fC at tx 0x46c37a15...dabc67
Indexed Transactions
0
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
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address