Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0xbFAe8E87053309fDe07ab3cA5f4B5345f8e3058f
Balance 0 ETH
Nonce 1
Code Size 22949 bytes
Last Active
Indexed Transactions 68 (24,587,63724,587,661)
Gas Used (indexed) 7,150,499
External Etherscan · Sourcify

Contract Bytecode

22949 bytes
0x6080604052600436106101855760003560e01c806398a0fb3c116100d1578063d7b0e0a51161008a578063e9e7941d11610064578063e9e7941d14610528578063f0aff68d14610548578063f242862114610568578063fe411f141461059c57600080fd5b8063d7b0e0a5146104b4578063dcba74f2146104d4578063e2d9d4dc1461050857600080fd5b806398a0fb3c146103e6578063a32b1fcd14610406578063b7e0d4c014610426578063bc641f2714610439578063c31c9c071461044c578063c45a01551461048057600080fd5b80635a47ddc31161013e5780637f64ba03116101185780637f64ba031461034457806383509d0a1461037857806383b9a7d31461039857806397607530146103c657600080fd5b80635a47ddc3146102d65780635e60dab5146103115780636ba165431461033157600080fd5b80630dede6c4146101c9578063204b5c0a146102035780634386e63c14610230578063448725b4146102505780634c1ee03e14610270578063544caa56146102a857600080fd5b366101c457336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101c2576101c2614bd8565b005b600080fd5b3480156101d557600080fd5b506101e96101e4366004614c2a565b6105bc565b604080519283526020830191909152015b60405180910390f35b34801561020f57600080fd5b5061022361021e366004614cf4565b61061e565b6040516101fa9190614d67565b34801561023c57600080fd5b506101e961024b366004614dab565b610a46565b34801561025c57600080fd5b506101e961026b366004614e0d565b610bad565b34801561027c57600080fd5b5061029061028b366004614eb7565b610d3c565b6040516001600160a01b0390911681526020016101fa565b3480156102b457600080fd5b506102c86102c3366004614f02565b610f0c565b6040516101fa929190614f3b565b3480156102e257600080fd5b506102f66102f1366004614f55565b610f84565b604080519384526020840192909252908201526060016101fa565b34801561031d57600080fd5b506101e961032c366004614eb7565b6110be565b61022361033f366004614fe4565b611176565b34801561035057600080fd5b506102907f0000000000000000000000003d219d5089331f6bf99cb20b9b199ab3b429337a81565b34801561038457600080fd5b506102236103933660046150b6565b611722565b3480156103a457600080fd5b506103b86103b3366004615182565b6118be565b6040519081526020016101fa565b3480156103d257600080fd5b506101c26103e1366004614cf4565b611967565b3480156103f257600080fd5b506102f66104013660046151b9565b611baf565b34801561041257600080fd5b506101e9610421366004615214565b611da6565b6102f66104343660046152d0565b611ef6565b6101c2610447366004614fe4565b612191565b34801561045857600080fd5b506102907f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac81565b34801561048c57600080fd5b506102907f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc3081565b3480156104c057600080fd5b506101e96104cf3660046152d0565b612500565b3480156104e057600080fd5b506102907f000000000000000000000000d8377aea61c4c4d43bf0588956f4e861720803c681565b34801561051457600080fd5b506101e9610523366004614e0d565b612607565b34801561053457600080fd5b506101c2610543366004614cf4565b61276b565b34801561055457600080fd5b50610223610563366004614cf4565b612930565b34801561057457600080fd5b506102907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156105a857600080fd5b506101e96105b73660046152d0565b612d8b565b60008082428110156105e95760405162461bcd60e51b81526004016105e090615342565b60405180910390fd5b6105f1612e61565b6106018b8b8b8b8b8b8b8b612eba565b90935091506106106001600055565b509850989650505050505050565b606081428110156106415760405162461bcd60e51b81526004016105e090615342565b610649612e61565b6001600160a01b0384168686610660600182615375565b81811061066f5761066f61538c565b905060c0020160a001602081019061068791906153a2565b6001600160a01b0316146106ad5760405162461bcd60e51b81526004016105e0906153bf565b60405163161681db60e11b81526001600160a01b037f000000000000000000000000d8377aea61c4c4d43bf0588956f4e861720803c61690632c2d03b6906106fd908b908a908a906004016153db565b6000604051808303816000875af115801561071c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107449190810190615500565b9050508092505086826001845161075b9190615375565b8151811061076b5761076b61538c565b602002602001015110156107915760405162461bcd60e51b81526004016105e090615588565b858560008181106107a4576107a461538c565b905060c0020160800160208101906107bc91906155a5565b61083d57610838868660008181106107d6576107d661538c565b905060c0020160200160208101906107ee91906153a2565b33888860008181106108025761080261538c565b61081892602060c09092020190810191506153a2565b8560008151811061082b5761082b61538c565b60200260200101516130a0565b6109d4565b610880868660008181106108535761085361538c565b905060c00201602001602081019061086b91906153a2565b33308560008151811061082b5761082b61538c565b816000815181106108935761089361538c565b6020026020010151868660008181106108ae576108ae61538c565b905060c0020160200160208101906108c691906153a2565b6001600160a01b031663dd62ed3e307f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac6040518363ffffffff1660e01b8152600401610913929190614f3b565b602060405180830381865afa158015610930573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095491906155c2565b10156109d4576109d47f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac836000815181106109915761099161538c565b6020026020010151888860008181106109ac576109ac61538c565b905060c0020160200160208101906109c491906153a2565b6001600160a01b031691906131e7565b610a31828787808060200260200160405190810160405280939291908181526020016000905b82821015610a2657610a1760c083028601368190038101906155db565b815260200190600101906109fa565b5050505050856132a1565b610a3b6001600055565b509695505050505050565b60008060007f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc306001600160a01b0316636801cc308888886040518463ffffffff1660e01b8152600401610a9b93929190615686565b602060405180830381865afa158015610ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610adc91906156aa565b90506001600160a01b038116610af9576000809250925050610ba4565b600080610b078989896110be565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6f91906155c2565b905080610b7c84896156c7565b610b8691906156e6565b955080610b9383896156c7565b610b9d91906156e6565b9450505050505b94509492505050565b600080610bb8612e61565b6000610be58e7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28f610d3c565b9050806001600160a01b031663d505accf33308a610c03578f610c07565b6000195b8c8b8b8b6040518863ffffffff1660e01b8152600401610c2d9796959493929190615708565b600060405180830381600087803b158015610c4757600080fd5b505af1925050508015610c58575060015b610ceb57604051636eb1769f60e11b81528c906001600160a01b0383169063dd62ed3e90610c8c9033903090600401614f3b565b602060405180830381865afa158015610ca9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccd91906155c2565b1015610ceb5760405162461bcd60e51b81526004016105e090615749565b610d1b8e7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28f8f8f8f8f8f612eba565b9093509150610d2c90506001600055565b9b509b9950505050505050505050565b6000806000610d4b8686610f0c565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015286151560f81b6048820152919350915060009060490160405160208183030381529060405280519060200120905060007f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc306001600160a01b0316639aab92486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2391906155c2565b905060007f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc306001600160a01b031663f65bd0b76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea991906156aa565b6040516001600160f81b031960208201526bffffffffffffffffffffffff19606083901b166021820152603581018590526055810184905290915060750160408051601f1981840301815291905280516020909101209998505050505050505050565b600080826001600160a01b0316846001600160a01b031610610f2f578284610f32565b83835b90925090506001600160a01b03821615801590610f615750806001600160a01b0316826001600160a01b031614155b610f7d5760405162461bcd60e51b81526004016105e090615749565b9250929050565b60008060008342811015610faa5760405162461bcd60e51b81526004016105e090615342565b610fb2612e61565b610fc18d8d8d8d8d8d8d613a4f565b90945092506000610fd38e8e8e610d3c565b9050610fe18e3383886130a0565b610fed8d3383876130a0565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af1158015611035573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105991906155c2565b9250600083116110a35760405162461bcd60e51b815260206004820152601560248201527416995c9bc81b1a5c5d5a591a5d1e481b5a5b9d1959605a1b60448201526064016105e0565b506110ae6001600055565b5099509950999650505050505050565b60008060006110cd8686610f0c565b5090506000806110de888888610d3c565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561111b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113f9190615765565b5091509150826001600160a01b0316886001600160a01b031614611164578082611167565b81815b90999098509650505050505050565b606081428110156111995760405162461bcd60e51b81526004016105e090615342565b6111a1612e61565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316868660008181106111de576111de61538c565b905060c0020160200160208101906111f691906153a2565b6001600160a01b03161461121c5760405162461bcd60e51b81526004016105e090615793565b6001600160a01b0384168686611233600182615375565b8181106112425761124261538c565b905060c0020160a001602081019061125a91906153a2565b6001600160a01b0316146112805760405162461bcd60e51b81526004016105e0906153bf565b60405163161681db60e11b81526001600160a01b037f000000000000000000000000d8377aea61c4c4d43bf0588956f4e861720803c61690632c2d03b6906112d09034908a908a906004016153db565b6000604051808303816000875af11580156112ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113179190810190615500565b9050508092505086826001845161132e9190615375565b8151811061133e5761133e61538c565b602002602001015110156113645760405162461bcd60e51b81526004016105e090615588565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0836000815181106113a6576113a661538c565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156113d957600080fd5b505af11580156113ed573d6000803e3d6000fd5b5050505050858560008181106114055761140561538c565b905060c00201608001602081019061141d91906155a5565b611574577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663a9059cbb6114d4888860008181106114665761146661538c565b905060c00201602001602081019061147e91906153a2565b898960008181106114915761149161538c565b905060c0020160400160208101906114a991906153a2565b8a8a60008181106114bc576114bc61538c565b905060c00201606001602081019061028b91906155a5565b846000815181106114e7576114e761538c565b60200260200101516040518363ffffffff1660e01b81526004016115209291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af115801561153f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156391906157b0565b61156f5761156f614bd8565b6116bc565b816000815181106115875761158761538c565b60200260200101517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663dd62ed3e307f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac6040518363ffffffff1660e01b81526004016115fd929190614f3b565b602060405180830381865afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e91906155c2565b10156116bc576116bc7f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac8360008151811061167b5761167b61538c565b60200260200101517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166131e79092919063ffffffff16565b61170e828787808060200260200160405190810160405280939291908181526020016000905b82821015610a26576116ff60c083028601368190038101906155db565b815260200190600101906116e2565b6117186001600055565b5095945050505050565b606081428110156117455760405162461bcd60e51b81526004016105e090615342565b61174d612e61565b6001600160a01b0384168686611764600182615375565b8181106117735761177361538c565b905060c0020160a001602081019061178b91906153a2565b6001600160a01b0316146117b15760405162461bcd60e51b81526004016105e0906153bf565b61185f868660008181106117c7576117c761538c565b905060c0020160200160208101906117df91906153a2565b3361184c898960008181106117f6576117f661538c565b905060c00201602001602081019061180e91906153a2565b8a8a60008181106118215761182161538c565b905060c00201604001602081019061183991906153a2565b8b8b60008181106114bc576114bc61538c565b8a60008151811061082b5761082b61538c565b6118b1878787808060200260200160405190810160405280939291908181526020016000905b82821015610a26576118a260c083028601368190038101906155db565b81526020019060010190611885565b8691506117186001600055565b6040516378a051ad60e11b8152600481018490526001600160a01b038381166024830152600091829184169063f140a35a90604401602060405180830381865afa92505050801561192c575060408051601f3d908101601f19168201909252611929918101906155c2565b60015b6119385750600061193b565b90505b600061194986868685613cf6565b9050801561195957509050611960565b6000925050505b9392505050565b80428110156119885760405162461bcd60e51b81526004016105e090615342565b611990612e61565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21685856119c7600182615375565b8181106119d6576119d661538c565b905060c0020160400160208101906119ee91906153a2565b6001600160a01b031614611a145760405162461bcd60e51b81526004016105e090615793565b611a5f85856000818110611a2a57611a2a61538c565b905060c002016020016020810190611a4291906153a2565b33611a59888860008181106114665761146661538c565b8a6130a0565b611a6a858530614104565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015611ad1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af591906155c2565b905086811015611b175760405162461bcd60e51b81526004016105e090615588565b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611b7957600080fd5b505af1158015611b8d573d6000803e3d6000fd5b50505050611b9b848261457c565b50611ba66001600055565b50505050505050565b6000806000807f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc306001600160a01b0316636801cc308a8a8a6040518463ffffffff1660e01b8152600401611c0593929190615686565b602060405180830381865afa158015611c22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4691906156aa565b9050600080806001600160a01b03841615611cd057836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cbd91906155c2565b9050611cca8c8c8c6110be565b90935091505b80600003611d04578896508795506103e8611cf3611cee888a6156c7565b614624565b611cfd9190615375565b9450611d97565b6000611d118a8585614694565b9050888111611d5957899750955085611d5284611d2e848b6156c7565b611d3891906156e6565b84611d43858b6156c7565b611d4d91906156e6565b6146f8565b9550611d95565b6000611d668a8587614694565b9850899750889050611d9185611d7c85846156c7565b611d8691906156e6565b85611d43868c6156c7565b9650505b505b50505050955095509592505050565b600080611db1612e61565b6000611dbe8f8f8f610d3c565b9050806001600160a01b031663d505accf33308a611ddc578f611de0565b6000195b8c8b8b8b6040518863ffffffff1660e01b8152600401611e069796959493929190615708565b600060405180830381600087803b158015611e2057600080fd5b505af1925050508015611e31575060015b611ec457604051636eb1769f60e11b81528c906001600160a01b0383169063dd62ed3e90611e659033903090600401614f3b565b602060405180830381865afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea691906155c2565b1015611ec45760405162461bcd60e51b81526004016105e090615749565b611ed48f8f8f8f8f8f8f8f612eba565b9093509150611ee590506001600055565b9c509c9a5050505050505050505050565b60008060008342811015611f1c5760405162461bcd60e51b81526004016105e090615342565b611f24612e61565b611f538b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28c8c348d8d613a4f565b90945092506000611f858c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28d610d3c565b9050611f938c3383886130a0565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015611fee57600080fd5b505af1158015612002573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063a9059cbb925060440190506020604051808303816000875af1158015612077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209b91906157b0565b6120a7576120a7614bd8565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af11580156120ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211391906155c2565b92506000831161215d5760405162461bcd60e51b815260206004820152601560248201527416995c9bc81b1a5c5d5a591a5d1e481b5a5b9d1959605a1b60448201526064016105e0565b8334111561217857612178336121738634615375565b61457c565b506121836001600055565b509750975097945050505050565b80428110156121b25760405162461bcd60e51b81526004016105e090615342565b6121ba612e61565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316858560008181106121f7576121f761538c565b905060c00201602001602081019061220f91906153a2565b6001600160a01b0316146122355760405162461bcd60e51b81526004016105e090615793565b60003490507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561229557600080fd5b505af11580156122a9573d6000803e3d6000fd5b50889350506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216915063a9059cbb90506122f589846000816117f6576117f661538c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018590526044016020604051808303816000875af1158015612342573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236691906157b0565b61237257612372614bd8565b60008787612381600185615375565b8181106123905761239061538c565b905060c0020160400160208101906123a891906153a2565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa1580156123f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241491906155c2565b9050612421888888614104565b88818989612430600187615375565b81811061243f5761243f61538c565b905060c00201604001602081019061245791906153a2565b6040516370a0823160e01b81526001600160a01b038a8116600483015291909116906370a0823190602401602060405180830381865afa15801561249f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c391906155c2565b6124cd9190615375565b10156124eb5760405162461bcd60e51b81526004016105e090615588565b5050506124f86001600055565b505050505050565b60008082428110156125245760405162461bcd60e51b81526004016105e090615342565b61252c612e61565b61255c8a7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28b8b8b8b308b612eba565b909350915061256c8a868561470e565b604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156125ce57600080fd5b505af11580156125e2573d6000803e3d6000fd5b505050506125f0858361457c565b6125fa6001600055565b5097509795505050505050565b600080612612612e61565b600061263f8e7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28f610d3c565b905060008761264e578c612652565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf9061268d903390309086908f908e908e908e90600401615708565b600060405180830381600087803b1580156126a757600080fd5b505af19250505080156126b8575060015b61274b57604051636eb1769f60e11b81528d906001600160a01b0384169063dd62ed3e906126ec9033903090600401614f3b565b602060405180830381865afa158015612709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272d91906155c2565b101561274b5760405162461bcd60e51b81526004016105e090615749565b61275a8f8f8f8f8f8f8f612d8b565b9094509250610d2c91506130999050565b804281101561278c5760405162461bcd60e51b81526004016105e090615342565b612794612e61565b6127aa85856000818110611a2a57611a2a61538c565b83600086826127ba600182615375565b8181106127c9576127c961538c565b905060c0020160400160208101906127e191906153a2565b6040516370a0823160e01b81526001600160a01b03878116600483015291909116906370a0823190602401602060405180830381865afa158015612829573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284d91906155c2565b905061285a878787614104565b87818888612869600187615375565b8181106128785761287861538c565b905060c00201604001602081019061289091906153a2565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401602060405180830381865afa1580156128d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fc91906155c2565b6129069190615375565b10156129245760405162461bcd60e51b81526004016105e090615588565b5050611ba66001600055565b606081428110156129535760405162461bcd60e51b81526004016105e090615342565b61295b612e61565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168686612992600182615375565b8181106129a1576129a161538c565b905060c0020160400160208101906129b991906153a2565b6001600160a01b0316146129df5760405162461bcd60e51b81526004016105e090615793565b60405163161681db60e11b81526001600160a01b037f000000000000000000000000d8377aea61c4c4d43bf0588956f4e861720803c61690632c2d03b690612a2f908b908a908a906004016153db565b6000604051808303816000875af1158015612a4e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a769190810190615500565b90505080925050868260018451612a8d9190615375565b81518110612a9d57612a9d61538c565b60200260200101511015612ac35760405162461bcd60e51b81526004016105e090615588565b85856000818110612ad657612ad661538c565b905060c002016080016020810190612aee91906155a5565b612b3c57612b3786866000818110612b0857612b0861538c565b905060c002016020016020810190612b2091906153a2565b33610818898960008181106117f6576117f661538c565b612c63565b612b52868660008181106108535761085361538c565b81600081518110612b6557612b6561538c565b602002602001015186866000818110612b8057612b8061538c565b905060c002016020016020810190612b9891906153a2565b6001600160a01b031663dd62ed3e307f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac6040518363ffffffff1660e01b8152600401612be5929190614f3b565b602060405180830381865afa158015612c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2691906155c2565b1015612c6357612c637f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac836000815181106109915761099161538c565b612cb5828787808060200260200160405190810160405280939291908181526020016000905b82821015610a2657612ca660c083028601368190038101906155db565b81526020019060010190612c89565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d8360018551612cf39190615375565b81518110612d0357612d0361538c565b60200260200101516040518263ffffffff1660e01b8152600401612d2991815260200190565b600060405180830381600087803b158015612d4357600080fd5b505af1158015612d57573d6000803e3d6000fd5b50505050610a31848360018551612d6e9190615375565b81518110612d7e57612d7e61538c565b602002602001015161457c565b6000808242811015612daf5760405162461bcd60e51b81526004016105e090615342565b612db7612e61565b612de78a7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28b8b8b8b308b612eba565b6040516370a0823160e01b8152306004820152919450925061256c908b9087906001600160a01b038316906370a0823190602401602060405180830381865afa158015612e38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5c91906155c2565b61470e565b600260005403612eb35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105e0565b6002600055565b6000808242811015612ede5760405162461bcd60e51b81526004016105e090615342565b6000612eeb8c8c8c610d3c565b6040516323b872dd60e01b81523360048201526001600160a01b03821660248201819052604482018c90529192506323b872dd906064016020604051808303816000875af1158015612f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f6591906157b0565b612f9a5760405162461bcd60e51b81526004016105e0906020808252600490820152634954464d60e01b604082015260600190565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015612fe6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300a91906157cd565b91509150600061301a8f8f610f0c565b509050806001600160a01b03168f6001600160a01b03161461303d578183613040565b82825b90975095508a87108015906130555750898610155b6130875760405162461bcd60e51b815260206004820152600360248201526249414160e81b60448201526064016105e0565b50505050509850989650505050505050565b6001600055565b6000846001600160a01b03163b116130e45760405162461bcd60e51b815260206004820152600760248201526621a7a222a622a760c91b60448201526064016105e0565b6040516001600160a01b038481166024830152838116604483015260648201839052600091829187169060840160408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b17905251613146919061581d565b6000604051808303816000865af19150503d8060008114613183576040519150601f19603f3d011682016040523d82523d6000602084013e613188565b606091505b50915091508180156131b25750805115806131b25750808060200190518101906131b291906157b0565b6124f85760405162461bcd60e51b81526004016105e09060208082526004908201526324a9aa2360e11b604082015260600190565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613238848261484a565b61329b57604080516001600160a01b038516602482015260006044808301919091528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526132919085906148f1565b61329b84826148f1565b50505050565b815160005b81811015613a485760006001600160a01b03168482815181106132cb576132cb61538c565b602002602001015160a001516001600160a01b0316036133125760405162461bcd60e51b81526020600482015260026024820152615a4160f01b60448201526064016105e0565b8381815181106133245761332461538c565b6020026020010151608001511561374a578481815181106133475761334761538c565b60200260200101518482815181106133615761336161538c565b6020026020010151602001516001600160a01b031663dd62ed3e307f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac6040518363ffffffff1660e01b81526004016133ba929190614f3b565b602060405180830381865afa1580156133d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fb91906155c2565b1015613475576134757f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac8683815181106134375761343761538c565b60200260200101518684815181106134515761345161538c565b6020026020010151602001516001600160a01b03166131e79092919063ffffffff16565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091526040518061010001604052808684815181106134d4576134d461538c565b6020026020010151602001516001600160a01b031681526020018684815181106135005761350061538c565b6020026020010151604001516001600160a01b031681526020017f0000000000000000000000003d219d5089331f6bf99cb20b9b199ab3b429337a6001600160a01b0316638992848788868151811061355b5761355b61538c565b6020908102919091010151516040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf91906156aa565b6001600160a01b031681526020018684815181106135ef576135ef61538c565b602002602001015160a001516001600160a01b031681526020018581526020018784815181106136215761362161538c565b602090810291909101810151825260008282018190526040928301528151630b3ce3c960e11b815283516001600160a01b039081166004830152918401518216602482015291830151811660448301526060830151811660648301526080830151608483015260a083015160a483015260c083015160c483015260e0830151811660e48301529192507f00000000000000000000000072d63a5b080e1b89cc93f9b9f50cbfa5e291c8ac90911690631679c79290610104016020604051808303816000875af11580156136f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061371c91906155c2565b86613728846001615839565b815181106137385761373861538c565b6020026020010181815250505061392f565b60006137908583815181106137615761376161538c565b60200260200101516020015186848151811061377f5761377f61538c565b602002602001015160400151610f0c565b5090506000866137a1846001615839565b815181106137b1576137b161538c565b60200260200101519050600080836001600160a01b03168886815181106137da576137da61538c565b6020026020010151602001516001600160a01b0316146137fc57826000613800565b6000835b915091506138668886815181106138195761381961538c565b6020026020010151602001518987815181106138375761383761538c565b6020026020010151604001518a88815181106138555761385561538c565b602002602001015160600151610d3c565b6001600160a01b031663022c0d9f83838b89815181106138885761388861538c565b602002602001015160a00151600067ffffffffffffffff8111156138ae576138ae61504b565b6040519080825280601f01601f1916602001820160405280156138d8576020820181803683370190505b506040518563ffffffff1660e01b81526004016138f8949392919061587d565b600060405180830381600087803b15801561391257600080fd5b505af1158015613926573d6000803e3d6000fd5b50505050505050505b8381815181106139415761394161538c565b602002602001015160a001516001600160a01b0316336001600160a01b03167fe7857fba7d66e2e29213fda7a0394efbaa80d435dfc7b4c1f147d78c2f9caa628784815181106139935761399361538c565b6020026020010151888560016139a99190615839565b815181106139b9576139b961538c565b60200260200101518886815181106139d3576139d361538c565b6020026020010151602001518987815181106139f1576139f161538c565b602002602001015160600151604051613a2e949392919093845260208401929092526001600160a01b031660408301521515606082015260800190565b60405180910390a380613a40816158aa565b9150506132a6565b5050505050565b600080838610158015613a625750828510155b613a975760405162461bcd60e51b81526004016105e090602080825260049082015263444c4d4160e01b604082015260600190565b6040516306801cc360e41b81526000906001600160a01b037f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc301690636801cc3090613aea908d908d908d90600401615686565b602060405180830381865afa158015613b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b2b91906156aa565b90506001600160a01b038116613bd1576040516320b7f73960e21b81526001600160a01b037f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc3016906382dfdce490613b8b908d908d908d90600401615686565b6020604051808303816000875af1158015613baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bce91906156aa565b90505b600080613bdf8c8c8c6110be565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4791906155c2565b905080600003613c5c57899550889450613ca4565b6000613c698b8585614694565b9050898111613c7d578a9650945084613ca2565b6000613c8a8b8587614694565b90508b811115613c9c57613c9c614bd8565b96508995505b505b878610158015613cb45750868510155b613ce65760405162461bcd60e51b815260206004820152600360248201526249414160e81b60448201526064016105e0565b5050505097509795505050505050565b6000613d77604051806101a001604052806000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b836001600160a01b031663392f37e96040518163ffffffff1660e01b815260040160e060405180830381865afa158015613db5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dd991906158c3565b6001600160a01b0390811660c089015290811660a08801819052911515608088015260608701929092526040808701939093526020860193909352928452516370a0823160e01b815291861660048301526000916370a0823190602401602060405180830381865afa158015613e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e7791906155c2565b60c08301516040516370a0823160e01b81526001600160a01b038881166004830152929350600092909116906370a0823190602401602060405180830381865afa158015613ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613eed91906155c2565b90508260a001516001600160a01b0316876001600160a01b031614613f13578082613f16565b81815b61010085015260e084015260a08301516001600160a01b03888116911614613f475782606001518360400151613f52565b826040015183606001515b61014085015261012084015260a08301516001600160a01b03888116911614613f815760208301518351613f89565b825160208401515b61018085015261016084015261012083015160e0840151600091613fac91615375565b613fb6908a615839565b608085015160405163cc56b2c560e01b81526001600160a01b038a811660048301529115156024820152919250600091612710917f0000000000000000000000005aef44edfc5a7edd30826c724ea12d7be15bdc30169063cc56b2c590604401602060405180830381865afa158015614033573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061405791906155c2565b61406190846156c7565b61406b91906156e6565b9050808a8660e0015161407e9190615839565b6140889190615375565b60e0860152610100850180518891906140a2908390615375565b915081815250506140ce85610120015186610140015187610160015188610180015189608001516149c6565b6140f28660e001518761010001518861016001518961018001518a608001516149c6565b1015955050505050505b949350505050565b60005b8281101561329b576000808585848181106141245761412461538c565b905060c00201602001602081019061413c91906153a2565b86868581811061414e5761414e61538c565b905060c00201604001602081019061416691906153a2565b9150915060006141768383610f0c565b50905060006141e48888878181106141905761419061538c565b905060c0020160200160208101906141a891906153a2565b8989888181106141ba576141ba61538c565b905060c0020160400160208101906141d291906153a2565b8a8a898181106114bc576114bc61538c565b9050600080600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561422a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424e9190615765565b50915091506000866001600160a01b0316896001600160a01b031614614275578183614278565b82825b506040516370a0823160e01b81526001600160a01b03888116600483015291925082918b16906370a0823190602401602060405180830381865afa1580156142c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142e891906155c2565b6142f29190615375565b604051631aa6a63f60e01b8152600481018290526001600160a01b038b811660248301528a811660448301529196507f000000000000000000000000d8377aea61c4c4d43bf0588956f4e861720803c690911690631aa6a63f906064016040805180830381865afa15801561436b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438f9190615937565b5080945050505050600080856001600160a01b0316886001600160a01b0316146143bb578260006143bf565b6000835b909250905060006143d160018d615375565b8a106143dd578a614464565b6144648d8d6143ed8d6001615839565b8181106143fc576143fc61538c565b905060c00201602001602081019061441491906153a2565b8e8e6144218e6001615839565b8181106144305761443061538c565b905060c00201604001602081019061444891906153a2565b8f8f6144558f6001615839565b8181106114bc576114bc61538c565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f906144a6908690869086906024810161587d565b600060405180830381600087803b1580156144c057600080fd5b505af11580156144d4573d6000803e3d6000fd5b5050505060008d8d8c8181106144ec576144ec61538c565b905060c00201606001602081019061450491906155a5565b60408051888152602081018890526001600160a01b038d81168284015283151560608301529151929350908e169133917fe7857fba7d66e2e29213fda7a0394efbaa80d435dfc7b4c1f147d78c2f9caa62919081900360800190a3505050505050505050508080614574906158aa565b915050614107565b604080516000808252602082019092526001600160a01b0384169083906040516145a6919061581d565b60006040518083038185875af1925050503d80600081146145e3576040519150601f19603f3d011682016040523d82523d6000602084013e6145e8565b606091505b505090508061461f5760405162461bcd60e51b815260206004820152600360248201526222aa2360e91b60448201526064016105e0565b505050565b60006003821115614685575080600061463e6002836156e6565b614649906001615839565b90505b8181101561467f5790508060028161466481866156e6565b61466e9190615839565b61467891906156e6565b905061464c565b50919050565b811561468f575060015b919050565b600080841180156146a55750600083115b80156146b15750600082115b6146e35760405162461bcd60e51b815260206004820152600360248201526212539360ea1b60448201526064016105e0565b826146ee83866156c7565b6140fc91906156e6565b60008183106147075781611960565b5090919050565b6000836001600160a01b03163b116147525760405162461bcd60e51b815260206004820152600760248201526621a7a222a622a760c91b60448201526064016105e0565b6040516001600160a01b03838116602483015260448201839052600091829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516147ac919061581d565b6000604051808303816000865af19150503d80600081146147e9576040519150601f19603f3d011682016040523d82523d6000602084013e6147ee565b606091505b509150915081801561481857508051158061481857508080602001905181019061481891906157b0565b613a485760405162461bcd60e51b81526020600482015260036024820152621254d560ea1b60448201526064016105e0565b6000806000846001600160a01b031684604051614867919061581d565b6000604051808303816000865af19150503d80600081146148a4576040519150601f19603f3d011682016040523d82523d6000602084013e6148a9565b606091505b50915091508180156148d35750805115806148d35750808060200190518101906148d391906157b0565b80156148e857506001600160a01b0385163b15155b95945050505050565b6000614946826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614ab59092919063ffffffff16565b905080516000148061496757508080602001905181019061496791906157b0565b61461f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105e0565b60008115614aa1576000846149e388670de0b6b3a76400006156c7565b6149ed91906156e6565b9050600084614a0488670de0b6b3a76400006156c7565b614a0e91906156e6565b90506000670de0b6b3a7640000614a2583856156c7565b614a2f91906156e6565b90506000670de0b6b3a7640000614a4684806156c7565b614a5091906156e6565b670de0b6b3a7640000614a6386806156c7565b614a6d91906156e6565b614a779190615839565b9050670de0b6b3a7640000614a8c82846156c7565b614a9691906156e6565b9450505050506148e8565b614aab85876156c7565b9695505050505050565b60606140fc848460008585600080866001600160a01b03168587604051614adc919061581d565b60006040518083038185875af1925050503d8060008114614b19576040519150601f19603f3d011682016040523d82523d6000602084013e614b1e565b606091505b5091509150614b2f87838387614b3a565b979650505050505050565b60608315614ba9578251600003614ba2576001600160a01b0385163b614ba25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105e0565b50816140fc565b6140fc8383815115614bbe5781518083602001fd5b8060405162461bcd60e51b81526004016105e0919061595c565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0381168114614c0357600080fd5b50565b803561468f81614bee565b8015158114614c0357600080fd5b803561468f81614c11565b600080600080600080600080610100898b031215614c4757600080fd5b8835614c5281614bee565b97506020890135614c6281614bee565b96506040890135614c7281614c11565b9550606089013594506080890135935060a0890135925060c0890135614c9781614bee565b8092505060e089013590509295985092959890939650565b60008083601f840112614cc157600080fd5b50813567ffffffffffffffff811115614cd957600080fd5b60208301915083602060c083028501011115610f7d57600080fd5b60008060008060008060a08789031215614d0d57600080fd5b8635955060208701359450604087013567ffffffffffffffff811115614d3257600080fd5b614d3e89828a01614caf565b9095509350506060870135614d5281614bee565b80925050608087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b81811015614d9f57835183529284019291840191600101614d83565b50909695505050505050565b60008060008060808587031215614dc157600080fd5b8435614dcc81614bee565b93506020850135614ddc81614bee565b92506040850135614dec81614c11565b9396929550929360600135925050565b803560ff8116811461468f57600080fd5b60008060008060008060008060008060006101608c8e031215614e2f57600080fd5b8b35614e3a81614bee565b9a5060208c0135614e4a81614c11565b995060408c0135985060608c0135975060808c0135965060a08c0135614e6f81614bee565b955060c08c0135945060e08c0135614e8681614c11565b9350614e956101008d01614dfc565b92506101208c013591506101408c013590509295989b509295989b9093969950565b600080600060608486031215614ecc57600080fd5b8335614ed781614bee565b92506020840135614ee781614bee565b91506040840135614ef781614c11565b809150509250925092565b60008060408385031215614f1557600080fd5b8235614f2081614bee565b91506020830135614f3081614bee565b809150509250929050565b6001600160a01b0392831681529116602082015260400190565b60008060008060008060008060006101208a8c031215614f7457600080fd5b8935614f7f81614bee565b985060208a0135614f8f81614bee565b975060408a0135614f9f81614c11565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a0135614fcb81614bee565b809250506101008a013590509295985092959850929598565b600080600080600060808688031215614ffc57600080fd5b85359450602086013567ffffffffffffffff81111561501a57600080fd5b61502688828901614caf565b909550935050604086013561503a81614bee565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561508a5761508a61504b565b604052919050565b600067ffffffffffffffff8211156150ac576150ac61504b565b5060051b60200190565b6000806000806000608086880312156150ce57600080fd5b853567ffffffffffffffff808211156150e657600080fd5b818801915088601f8301126150fa57600080fd5b8135602061510f61510a83615092565b615061565b82815260059290921b8401810191818101908c84111561512e57600080fd5b948201945b8386101561514c57853582529482019490820190615133565b9950508901359250508082111561516257600080fd5b5061516f88828901614caf565b909550935061503a905060408701614c06565b60008060006060848603121561519757600080fd5b8335925060208401356151a981614bee565b91506040840135614ef781614bee565b600080600080600060a086880312156151d157600080fd5b85356151dc81614bee565b945060208601356151ec81614bee565b935060408601356151fc81614c11565b94979396509394606081013594506080013592915050565b6000806000806000806000806000806000806101808d8f03121561523757600080fd5b8c3561524281614bee565b9b5060208d013561525281614bee565b9a5060408d013561526281614c11565b995060608d0135985060808d0135975060a08d0135965060c08d013561528781614bee565b955060e08d013594506101008d013561529f81614c11565b93506152ae6101208e01614dfc565b92506101408d013591506101608d013590509295989b509295989b509295989b565b600080600080600080600060e0888a0312156152eb57600080fd5b87356152f681614bee565b9650602088013561530681614c11565b955060408801359450606088013593506080880135925060a088013561532b81614bee565b8092505060c0880135905092959891949750929550565b60208082526003908201526204558560ec1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156153875761538761535f565b500390565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156153b457600080fd5b813561196081614bee565b60208082526002908201526124a960f11b604082015260600190565b838152604060208083018290528282018490526000919060609081850187855b8881101561549657813561540e81614bee565b6001600160a01b039081168452828501359061542982614bee565b90811684860152828701359061543e82614bee565b16838701528185013561545081614c11565b1515838601526080615463838201614c1f565b15159084015260a0615476838201614c06565b6001600160a01b03169084015260c09283019291909101906001016153fb565b50909998505050505050505050565b600082601f8301126154b657600080fd5b815160206154c661510a83615092565b82815260059290921b840181019181810190868411156154e557600080fd5b8286015b84811015610a3b57805183529183019183016154e9565b60008060006060848603121561551557600080fd5b835167ffffffffffffffff8082111561552d57600080fd5b615539878388016154a5565b9450602086015191508082111561554f57600080fd5b61555b878388016154a5565b9350604086015191508082111561557157600080fd5b5061557e868287016154a5565b9150509250925092565b602080825260039082015262494f4160e81b604082015260600190565b6000602082840312156155b757600080fd5b813561196081614c11565b6000602082840312156155d457600080fd5b5051919050565b600060c082840312156155ed57600080fd5b60405160c0810181811067ffffffffffffffff821117156156105761561061504b565b604052823561561e81614bee565b8152602083013561562e81614bee565b6020820152604083013561564181614bee565b6040820152606083013561565481614c11565b6060820152608083013561566781614c11565b608082015260a083013561567a81614bee565b60a08201529392505050565b6001600160a01b039384168152919092166020820152901515604082015260600190565b6000602082840312156156bc57600080fd5b815161196081614bee565b60008160001904831182151516156156e1576156e161535f565b500290565b60008261570357634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b602080825260029082015261494160f01b604082015260600190565b60008060006060848603121561577a57600080fd5b8351925060208401519150604084015190509250925092565b6020808252600390820152620494e560ec1b604082015260600190565b6000602082840312156157c257600080fd5b815161196081614c11565b600080604083850312156157e057600080fd5b505080516020909101519092909150565b60005b8381101561580c5781810151838201526020016157f4565b8381111561329b5750506000910152565b6000825161582f8184602087016157f1565b9190910192915050565b6000821982111561584c5761584c61535f565b500190565b600081518084526158698160208601602086016157f1565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b0383166040820152608060608201526000614aab6080830184615851565b6000600182016158bc576158bc61535f565b5060010190565b600080600080600080600060e0888a0312156158de57600080fd5b87519650602088015195506040880151945060608801519350608088015161590581614c11565b60a089015190935061591681614bee565b60c089015190925061592781614bee565b8091505092959891949750929550565b6000806040838503121561594a57600080fd5b825191506020830151614f3081614c11565b602081526000611960602083018461585156fea26469706673582212203868d4230ffe741b4a7033e2723ee023591770045c558090f62aedf165dfb57264736f6c634300080d0033

Verified Source Code Full Match

Compiler: v0.8.13+commit.abaa5c0e EVM: london Optimization: Yes (200 runs)
IAlgebraSwapCallback.sol 19 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Callback for IAlgebraPoolActions#swap
/// @notice Any contract that calls IAlgebraPoolActions#swap must implement this interface
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraSwapCallback {
  /// @notice Called to `msg.sender` after executing a swap via IAlgebraPool#swap.
  /// @dev In the implementation you must pay the pool tokens owed for the swap.
  /// The caller of this method _must_ be checked to be a AlgebraPool deployed by the canonical AlgebraFactory.
  /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
  /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
  /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
  /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
  /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
  /// @param data Any data passed through by the caller via the IAlgebraPoolActions#swap call
  function algebraSwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
IAlgebraFactory.sol 199 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import './plugin/IAlgebraPluginFactory.sol';
import './vault/IAlgebraVaultFactory.sol';

/// @title The interface for the Algebra Factory
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraFactory {
  /// @notice Emitted when a process of ownership renounce is started
  /// @param timestamp The timestamp of event
  /// @param finishTimestamp The timestamp when ownership renounce will be possible to finish
  event RenounceOwnershipStart(uint256 timestamp, uint256 finishTimestamp);

  /// @notice Emitted when a process of ownership renounce cancelled
  /// @param timestamp The timestamp of event
  event RenounceOwnershipStop(uint256 timestamp);

  /// @notice Emitted when a process of ownership renounce finished
  /// @param timestamp The timestamp of ownership renouncement
  event RenounceOwnershipFinish(uint256 timestamp);

  /// @notice Emitted when a pool is created
  /// @param token0 The first token of the pool by address sort order
  /// @param token1 The second token of the pool by address sort order
  /// @param pool The address of the created pool
  event Pool(address indexed token0, address indexed token1, address pool);

  /// @notice Emitted when a pool is created
  /// @param deployer The corresponding custom deployer contract
  /// @param token0 The first token of the pool by address sort order
  /// @param token1 The second token of the pool by address sort order
  /// @param pool The address of the created pool
  event CustomPool(address indexed deployer, address indexed token0, address indexed token1, address pool);

  /// @notice Emitted when the default community fee is changed
  /// @param newDefaultCommunityFee The new default community fee value
  event DefaultCommunityFee(uint16 newDefaultCommunityFee);

  /// @notice Emitted when the default tickspacing is changed
  /// @param newDefaultTickspacing The new default tickspacing value
  event DefaultTickspacing(int24 newDefaultTickspacing);

  /// @notice Emitted when the default fee is changed
  /// @param newDefaultFee The new default fee value
  event DefaultFee(uint16 newDefaultFee);

  /// @notice Emitted when the defaultPluginFactory address is changed
  /// @param defaultPluginFactoryAddress The new defaultPluginFactory address
  event DefaultPluginFactory(address defaultPluginFactoryAddress);

  /// @notice Emitted when the vaultFactory address is changed
  /// @param newVaultFactory The new vaultFactory address
  event VaultFactory(address newVaultFactory);

  /// @notice role that can change communityFee and tickspacing in pools
  /// @return The hash corresponding to this role
  function POOLS_ADMINISTRATOR_ROLE() external view returns (bytes32);

  /// @notice role that can call `createCustomPool` function
  /// @return The hash corresponding to this role
  function CUSTOM_POOL_DEPLOYER() external view returns (bytes32);

  /// @notice Returns `true` if `account` has been granted `role` or `account` is owner.
  /// @param role The hash corresponding to the role
  /// @param account The address for which the role is checked
  /// @return bool Whether the address has this role or the owner role or not
  function hasRoleOrOwner(bytes32 role, address account) external view returns (bool);

  /// @notice Returns the current owner of the factory
  /// @dev Can be changed by the current owner via transferOwnership(address newOwner)
  /// @return The address of the factory owner
  function owner() external view returns (address);

  /// @notice Returns the current poolDeployerAddress
  /// @return The address of the poolDeployer
  function poolDeployer() external view returns (address);

  /// @notice Returns the default community fee
  /// @return Fee which will be set at the creation of the pool
  function defaultCommunityFee() external view returns (uint16);

  /// @notice Returns the default fee
  /// @return Fee which will be set at the creation of the pool
  function defaultFee() external view returns (uint16);

  /// @notice Returns the default tickspacing
  /// @return Tickspacing which will be set at the creation of the pool
  function defaultTickspacing() external view returns (int24);

  /// @notice Return the current pluginFactory address
  /// @dev This contract is used to automatically set a plugin address in new liquidity pools
  /// @return Algebra plugin factory
  function defaultPluginFactory() external view returns (IAlgebraPluginFactory);

  /// @notice Return the current vaultFactory address
  /// @dev This contract is used to automatically set a vault address in new liquidity pools
  /// @return Algebra vault factory
  function vaultFactory() external view returns (IAlgebraVaultFactory);

  /// @notice Returns the default communityFee, tickspacing, fee and communityFeeVault for pool
  /// @return communityFee which will be set at the creation of the pool
  /// @return tickSpacing which will be set at the creation of the pool
  /// @return fee which will be set at the creation of the pool
  function defaultConfigurationForPool() external view returns (uint16 communityFee, int24 tickSpacing, uint16 fee);

  /// @notice Deterministically computes the pool address given the token0 and token1
  /// @dev The method does not check if such a pool has been created
  /// @param token0 first token
  /// @param token1 second token
  /// @return pool The contract address of the Algebra pool
  function computePoolAddress(address token0, address token1) external view returns (address pool);

  /// @notice Deterministically computes the custom pool address given the customDeployer, token0 and token1
  /// @dev The method does not check if such a pool has been created
  /// @param customDeployer the address of custom plugin deployer
  /// @param token0 first token
  /// @param token1 second token
  /// @return customPool The contract address of the Algebra pool
  function computeCustomPoolAddress(address customDeployer, address token0, address token1) external view returns (address customPool);

  /// @notice Returns the pool address for a given pair of tokens, or address 0 if it does not exist
  /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
  /// @param tokenA The contract address of either token0 or token1
  /// @param tokenB The contract address of the other token
  /// @return pool The pool address
  function poolByPair(address tokenA, address tokenB) external view returns (address pool);

  /// @notice Returns the custom pool address for a customDeployer and a given pair of tokens, or address 0 if it does not exist
  /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
  /// @param customDeployer The address of custom plugin deployer
  /// @param tokenA The contract address of either token0 or token1
  /// @param tokenB The contract address of the other token
  /// @return customPool The pool address
  function customPoolByPair(address customDeployer, address tokenA, address tokenB) external view returns (address customPool);

  /// @notice returns keccak256 of AlgebraPool init bytecode.
  /// @dev the hash value changes with any change in the pool bytecode
  /// @return Keccak256 hash of AlgebraPool contract init bytecode
  function POOL_INIT_CODE_HASH() external view returns (bytes32);

  /// @return timestamp The timestamp of the beginning of the renounceOwnership process
  function renounceOwnershipStartTimestamp() external view returns (uint256 timestamp);

  /// @notice Creates a pool for the given two tokens
  /// @param tokenA One of the two tokens in the desired pool
  /// @param tokenB The other of the two tokens in the desired pool
  /// @param data Data for plugin creation
  /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0.
  /// The call will revert if the pool already exists or the token arguments are invalid.
  /// @return pool The address of the newly created pool
  function createPool(address tokenA, address tokenB, bytes calldata data) external returns (address pool);

  /// @notice Creates a custom pool for the given two tokens using `deployer` contract
  /// @param deployer The address of plugin deployer, also used for custom pool address calculation
  /// @param creator The initiator of custom pool creation
  /// @param tokenA One of the two tokens in the desired pool
  /// @param tokenB The other of the two tokens in the desired pool
  /// @param data The additional data bytes
  /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0.
  /// The call will revert if the pool already exists or the token arguments are invalid.
  /// @return customPool The address of the newly created custom pool
  function createCustomPool(
    address deployer,
    address creator,
    address tokenA,
    address tokenB,
    bytes calldata data
  ) external returns (address customPool);

  /// @dev updates default community fee for new pools
  /// @param newDefaultCommunityFee The new community fee, _must_ be <= MAX_COMMUNITY_FEE
  function setDefaultCommunityFee(uint16 newDefaultCommunityFee) external;

  /// @dev updates default fee for new pools
  /// @param newDefaultFee The new  fee, _must_ be <= MAX_DEFAULT_FEE
  function setDefaultFee(uint16 newDefaultFee) external;

  /// @dev updates default tickspacing for new pools
  /// @param newDefaultTickspacing The new tickspacing, _must_ be <= MAX_TICK_SPACING and >= MIN_TICK_SPACING
  function setDefaultTickspacing(int24 newDefaultTickspacing) external;

  /// @dev updates pluginFactory address
  /// @param newDefaultPluginFactory address of new plugin factory
  function setDefaultPluginFactory(address newDefaultPluginFactory) external;

  /// @dev updates vaultFactory address
  /// @param newVaultFactory address of new vault factory
  function setVaultFactory(address newVaultFactory) external;

  /// @notice Starts process of renounceOwnership. After that, a certain period
  /// of time must pass before the ownership renounce can be completed.
  function startRenounceOwnership() external;

  /// @notice Stops process of renounceOwnership and removes timer.
  function stopRenounceOwnership() external;
}
IAlgebraPluginFactory.sol 29 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title An interface for a contract that is capable of deploying Algebra plugins
/// @dev Such a factory can be used for automatic plugin creation for new pools.
/// Also a factory be used as an entry point for custom (additional) pools creation
interface IAlgebraPluginFactory {
  /// @notice Deploys new plugin contract for pool
  /// @param pool The address of the new pool
  /// @param creator The address that initiated the pool creation
  /// @param deployer The address of new plugin deployer contract (0 if not used)
  /// @param token0 First token of the pool
  /// @param token1 Second token of the pool
  /// @return New plugin address
  function beforeCreatePoolHook(
    address pool,
    address creator,
    address deployer,
    address token0,
    address token1,
    bytes calldata data
  ) external returns (address);

  /// @notice Called after the pool is created
  /// @param plugin The plugin address
  /// @param pool The address of the new pool
  /// @param deployer The address of new plugin deployer contract (0 if not used)
  function afterCreatePoolHook(address plugin, address pool, address deployer) external;
}
IAlgebraVaultFactory.sol 23 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the Algebra Vault Factory
/// @notice This contract can be used for automatic vaults creation
/// @dev Version: Algebra Integral
interface IAlgebraVaultFactory {
  /// @notice returns address of the community fee vault for the pool
  /// @param pool the address of Algebra Integral pool
  /// @return communityFeeVault the address of community fee vault
  function getVaultForPool(address pool) external view returns (address communityFeeVault);

  /// @notice creates the community fee vault for the pool if needed
  /// @param pool the address of Algebra Integral pool
  /// @return communityFeeVault the address of community fee vault
  function createVaultForPool(
    address pool,
    address creator,
    address deployer,
    address token0,
    address token1
  ) external returns (address communityFeeVault);
}
ISwapRouter.sol 79 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import '@cryptoalgebra/integral-core/contracts/interfaces/callback/IAlgebraSwapCallback.sol';

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Algebra
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-periphery
interface ISwapRouter is IAlgebraSwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        address deployer;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 limitSqrtPrice;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        address deployer;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 limitSqrtPrice;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @dev If native token is used as input, this function should be accompanied by a `refundNativeToken` in multicall to avoid potential loss of native tokens
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @dev If native token is used as input, this function should be accompanied by a `refundNativeToken` in multicall to avoid potential loss of native tokens
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @dev Unlike standard swaps, handles transferring from user before the actual swap.
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingleSupportingFeeOnTransferTokens(
        ExactInputSingleParams calldata params
    ) external payable returns (uint256 amountOut);
}
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;
    }
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount) external returns (bool);
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 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 {
    using Address for address;

    /**
     * @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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @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.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @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).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @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 silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
IAlgebraCLFactory.sol 11 lines
// SPDX-License-Identifier: GPL-3.0-or-later
// BlackHole Foundation 2025

pragma solidity 0.8.13;

import { IAlgebraFactory } from '@cryptoalgebra/integral-core/contracts/interfaces/IAlgebraFactory.sol';

interface IAlgebraCLFactory is IAlgebraFactory{
    function allPairsLength() external view returns (uint);
    function allPairs(uint256 index) external view returns (address);
}
IAlgebraPoolAPIStorage.sol 9 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

interface IAlgebraPoolAPIStorage {
    function pairToDeployer(address) external view returns (address);
    function setDeployerForPair(address _pair) external;
    function customDeployers(uint256 i) external view returns(address);
    function setDeployerForPair(address _pair, address _deployer) external;
}
IPair.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

interface IPair {
    function metadata() external view returns (uint dec0, uint dec1, uint r0, uint r1, bool st, address t0, address t1);
    function claimFees() external returns (uint, uint);
    function tokens() external view returns (address, address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function transferFrom(address src, address dst, uint amount) external returns (bool);
    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function burn(address to) external returns (uint amount0, uint amount1);
    function mint(address to) external returns (uint liquidity);
    function getReserves() external view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast);
    function getAmountOut(uint, address) external view returns (uint);

    function name() external view returns(string memory);
    function symbol() external view returns(string memory);
    function totalSupply() external view returns (uint);
    function decimals() external view returns (uint8);

    function claimable0(address _user) external view returns (uint);
    function claimable1(address _user) external view returns (uint);

    function isStable() external view returns(bool);
    function allowance(address owner, address spender) external view returns (uint);
}
IPairFactory.sol 16 lines
// SPDX-License-Identifier: MIT OR GPL-3.0-or-later
pragma solidity 0.8.13;

interface IPairFactory {
    function allPairsLength() external view returns (uint);
    function isPair(address pair) external view returns (bool);
    function allPairs(uint index) external view returns (address);
    function pairCodeHash() external view returns (bytes32);
    function pairGenerator() external view returns (address);
    function getPair(address tokenA, address token, bool stable) external view returns (address);
    function createPair(address tokenA, address tokenB, bool stable) external returns (address pair);
    function getFee(address _pairAddress, bool _stable) external view returns(uint256);
    function dibs() external view returns (address);
    function getReferralFee(address _pairAddress) external view returns (uint256);
    function isPaused() external view returns (bool);
}
IRouter.sol 18 lines
// SPDX-License-Identifier: MIT OR GPL-3.0-or-later
pragma solidity 0.8.13;

interface IRouter {
    struct route {
        address pair;
        address from;
        address to;
        bool stable;
        bool concentrated;
        address receiver;
    }
    function pairFor(address tokenA, address tokenB, bool stable) external view returns (address pair);
    function swapExactTokensForTokens(uint amountIn,uint amountOutMin,route[] calldata routes,address to,uint deadline) external returns (uint[] memory amounts);
    function addLiquidity(address tokenA,address tokenB,bool stable,uint amountADesired,uint amountBDesired,uint amountAMin,uint amountBMin,address to,uint deadline) external returns (uint amountA, uint amountB, uint liquidity);
    function getReserves(address tokenA, address tokenB, bool stable) external view returns (uint reserveA, uint reserveB);
    function getPoolAmountOut(uint amountIn, address tokenIn, address pair) external view returns (uint amount);
}
IRouterHelper.sol 10 lines
// SPDX-License-Identifier: MIT OR GPL-3.0-or-later
pragma solidity 0.8.13;

import "./IRouter.sol";

interface IRouterHelper {
    function getAmountsOut(uint amountIn, IRouter.route[] memory routes) external returns (uint[] memory amounts, uint[] memory priceBeforeSwap, uint[] memory priceAfterSwap);
    function getAmountOut(uint amountIn, address tokenIn, address tokenOut) external view returns (uint amount, bool stable);
    function getAmountOutForFeeOnTransfer(uint amountIn, address tokenIn, address tokenOut) external view returns (uint amount, bool stable);
}
IWETH.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

interface IWETH {
    function deposit() external payable;
    function transfer(address to, uint256 value) external returns (bool);
    function withdraw(uint256) external;
}
Math.sol 35 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

library Math {
    function max(uint a, uint b) internal pure returns (uint) {
        return a >= b ? a : b;
    }
    function min(uint a, uint b) internal pure returns (uint) {
        return a < b ? a : b;
    }
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
    function cbrt(uint256 n) internal pure returns (uint256) { unchecked {
        uint256 x = 0;
        for (uint256 y = 1 << 255; y > 0; y >>= 3) {
            x <<= 1;
            uint256 z = 3 * x * (x + 1) + 1;
            if (n / y >= z) {
                n -= y * z;
                x += 1;
            }
        }
        return x;
    }}
}
RouterV2.sol 758 lines
// SPDX-License-Identifier: MIT OR GPL-3.0-or-later
pragma solidity 0.8.13;

import './interfaces/IAlgebraCLFactory.sol';
import './interfaces/IAlgebraPoolAPIStorage.sol';

import '@cryptoalgebra/integral-periphery/contracts/interfaces/ISwapRouter.sol';
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import './interfaces/IPair.sol';
import './interfaces/IRouterHelper.sol';
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IRouter.sol";
import "./interfaces/IPairFactory.sol";
import "./libraries/Math.sol";
import "./interfaces/IWETH.sol";

contract RouterV2 is ReentrancyGuard {

	using SafeERC20 for IERC20;

    struct PairSwapMetadata {
        uint decimals0;
        uint decimals1;
        uint reserve0;
        uint reserve1;
        bool stable;
        address token0;
        address token1;
        uint balanceA;
        uint balanceB;
        uint reserveA;
        uint reserveB;
        uint decimalsA;
        uint decimalsB;
    }

    struct PermitParams {
        uint value;
        uint deadline;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct LiquidityParams {
        address tokenA;
        address tokenB;
        bool stable;
        uint liquidity;
        uint amountAMin;
        uint amountBMin;
        address to;
        uint deadline;
    }

    address public immutable factory;
    IWETH public immutable wETH;
    uint internal constant MINIMUM_LIQUIDITY = 10**3;

    address public immutable swapRouter;
    IAlgebraPoolAPIStorage public immutable algebraPoolAPIStorage;
    address public immutable routerHelper;

    // swap event for the rebate system
    event Swap(address indexed sender,uint amount0In, uint amount0Out,address _tokenIn, address indexed to, bool stable);

    modifier ensure(uint deadline) {
        require(deadline >= block.timestamp, 'EXP');
        _;
    }

    constructor(address _factory, address _wETH, address _swapRouter, address _algebraPoolAPIStorage, address _routerHelper) {
        factory = _factory;
        wETH = IWETH(_wETH);
        swapRouter = _swapRouter;
        algebraPoolAPIStorage = IAlgebraPoolAPIStorage(_algebraPoolAPIStorage);
        routerHelper = _routerHelper;
    }

    receive() external payable {
        assert(msg.sender == address(wETH)); // only accept ETH via fallback from the WETH contract
    }

    function _k(uint x, uint y, uint decimals0, uint decimals1, bool stable) internal pure returns (uint) {
        if (stable) {
            uint _x = x * 1e18 / decimals0;
            uint _y = y * 1e18 / decimals1;
            uint _a = (_x * _y) / 1e18;
            uint _b = ((_x * _x) / 1e18 + (_y * _y) / 1e18);
            return _a * _b / 1e18;  // x3y+y3x >= k
        } else {
            return x * y; // xy >= k
        }
    }

    function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) {
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0) && token0 != token1, 'IA');
    }

    // calculates the CREATE2 address for a pair without making any external calls
    function pairFor(address tokenA, address tokenB, bool stable) public view returns (address pair) {
        (address token0, address token1) = sortTokens(tokenA, tokenB);
        bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable));
        bytes32 initCodeHash = IPairFactory(factory).pairCodeHash();
        address pairGenerator = IPairFactory(factory).pairGenerator();
        pair = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            pairGenerator,
                            salt,
                            initCodeHash
                        )
                    )
                )
            )
        );
    }

    // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
    function quoteLiquidity(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
        require(amountA > 0 && reserveA > 0 && reserveB > 0, 'INL');
        amountB = amountA * reserveB / reserveA;
    }

    // fetches and sorts the reserves for a pair
    function getReserves(address tokenA, address tokenB, bool stable) public view returns (uint reserveA, uint reserveB) {
        (address token0,) = sortTokens(tokenA, tokenB);
        (uint reserve0, uint reserve1,) = IPair(pairFor(tokenA, tokenB, stable)).getReserves();
        (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    function getPoolAmountOut(uint amountIn, address tokenIn, address pair) public view returns (uint amount) {
        
        uint amountOut = 0;

        try IPair(pair).getAmountOut(amountIn, tokenIn) returns (uint outAmt) {
            amountOut = outAmt;
        } catch {
            amountOut = 0;
        }
        
        bool swapPossible = _swapRatio(amountIn, tokenIn, pair, amountOut);

        if(swapPossible){
            return amountOut;
        }

        return 0;
    }

    function _swapRatio(uint amountIn, address tokenIn, address pair, uint amountOut) internal view returns (bool){

        PairSwapMetadata memory pairSwapMetaData;
    
        (pairSwapMetaData.decimals0, pairSwapMetaData.decimals1, pairSwapMetaData.reserve0, 
        pairSwapMetaData.reserve1, pairSwapMetaData.stable, pairSwapMetaData.token0, pairSwapMetaData.token1)
         = IPair(pair).metadata();
        uint _balance0 = IERC20(pairSwapMetaData.token0).balanceOf(address(pair));
        uint _balance1 = IERC20(pairSwapMetaData.token1).balanceOf(address(pair));

        (pairSwapMetaData.balanceA, pairSwapMetaData.balanceB) = tokenIn == pairSwapMetaData.token0 ? (_balance0, _balance1) : (_balance1, _balance0);
        (pairSwapMetaData.reserveA, pairSwapMetaData.reserveB) = tokenIn == pairSwapMetaData.token0 ? (pairSwapMetaData.reserve0, pairSwapMetaData.reserve1) : (pairSwapMetaData.reserve1, pairSwapMetaData.reserve0);
        (pairSwapMetaData.decimalsA, pairSwapMetaData.decimalsB) = tokenIn == pairSwapMetaData.token0 ? (pairSwapMetaData.decimals0, pairSwapMetaData.decimals1) : (pairSwapMetaData.decimals1, pairSwapMetaData.decimals0);

        uint actualAmountIn = amountIn + (pairSwapMetaData.balanceA - pairSwapMetaData.reserveA);
        uint feeAmount = actualAmountIn * IPairFactory(factory).getFee(pair, pairSwapMetaData.stable) / 10000;
        pairSwapMetaData.balanceA = pairSwapMetaData.balanceA + amountIn - feeAmount;
        pairSwapMetaData.balanceB -= amountOut;

        return _k(pairSwapMetaData.balanceA, pairSwapMetaData.balanceB, pairSwapMetaData.decimalsA, pairSwapMetaData.decimalsB, pairSwapMetaData.stable) >= _k(pairSwapMetaData.reserveA, pairSwapMetaData.reserveB, pairSwapMetaData.decimalsA, pairSwapMetaData.decimalsB, pairSwapMetaData.stable);
    }

    
    function quoteAddLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint amountADesired,
        uint amountBDesired
    ) external view returns (uint amountA, uint amountB, uint liquidity) {
        address _pair = IPairFactory(factory).getPair(tokenA, tokenB, stable);
        (uint reserveA, uint reserveB) = (0,0);
        uint _totalSupply = 0;
        if (_pair != address(0)) {
            _totalSupply = IERC20(_pair).totalSupply();
            (reserveA, reserveB) = getReserves(tokenA, tokenB, stable);
        }
        if (_totalSupply == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
            liquidity = Math.sqrt(amountA * amountB) - MINIMUM_LIQUIDITY;
        } else {

            uint amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                (amountA, amountB) = (amountADesired, amountBOptimal);
                liquidity = Math.min(amountA * _totalSupply / reserveA, amountB * _totalSupply / reserveB);
            } else {
                uint amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                (amountA, amountB) = (amountAOptimal, amountBDesired);
                liquidity = Math.min(amountA * _totalSupply / reserveA, amountB * _totalSupply / reserveB);
            }
        }
    }

    function quoteRemoveLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint liquidity
    ) external view returns (uint amountA, uint amountB) {
        address _pair = IPairFactory(factory).getPair(tokenA, tokenB, stable);

        if (_pair == address(0)) {
            return (0,0);
        }

        (uint reserveA, uint reserveB) = getReserves(tokenA, tokenB, stable);
        uint _totalSupply = IERC20(_pair).totalSupply();

        amountA = liquidity * reserveA / _totalSupply; // using balances ensures pro-rata distribution
        amountB = liquidity * reserveB / _totalSupply; // using balances ensures pro-rata distribution

    }

    function _addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin
    ) internal returns (uint amountA, uint amountB) {
        require(amountADesired >= amountAMin && amountBDesired >= amountBMin, "DLMA");
        // create the pair if it doesn't exist yet
        address _pair = IPairFactory(factory).getPair(tokenA, tokenB, stable);
        if (_pair == address(0)) {
            _pair = IPairFactory(factory).createPair(tokenA, tokenB, stable);
        }
        (uint reserveA, uint reserveB) = getReserves(tokenA, tokenB, stable);
        uint _totalSupply = IERC20(_pair).totalSupply();
        if (_totalSupply == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
        require(amountA >= amountAMin && amountB >= amountBMin, "IAA");
    }

    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external ensure(deadline) nonReentrant returns (uint amountA, uint amountB, uint liquidity) {
        (amountA, amountB) = _addLiquidity(tokenA, tokenB, stable, amountADesired, amountBDesired, amountAMin, amountBMin);
        address pair = pairFor(tokenA, tokenB, stable);
        _safeTransferFrom(tokenA, msg.sender, pair, amountA);
        _safeTransferFrom(tokenB, msg.sender, pair, amountB);
        liquidity = IPair(pair).mint(to);

        // Additional check: ensure we received liquidity tokens
        require(liquidity > 0, 'Zero liquidity minted');
    }

    function addLiquidityETH(
        address token,
        bool stable,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable ensure(deadline) nonReentrant returns (uint amountToken, uint amountETH, uint liquidity) {
        (amountToken, amountETH) = _addLiquidity(
            token,
            address(wETH),
            stable,
            amountTokenDesired,
            msg.value,
            amountTokenMin,
            amountETHMin
        );
        address pair = pairFor(token, address(wETH), stable);
        _safeTransferFrom(token, msg.sender, pair, amountToken);
        wETH.deposit{value: amountETH}();
        assert(wETH.transfer(pair, amountETH));
        liquidity = IPair(pair).mint(to);

        // Additional check: ensure we received liquidity tokens
        require(liquidity > 0, 'Zero liquidity minted');

        // refund dust ETH, if any
        if (msg.value > amountETH) _safeTransferETH(msg.sender, msg.value - amountETH);
    }

    // **** REMOVE LIQUIDITY ****
    /// @dev Internal helper, no reentrancy guard. Public/externals must be `nonReentrant`
    ///      and delegate to this to avoid nested `nonReentrant` calls.
    function _removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) internal ensure(deadline) returns (uint amountA, uint amountB) {
        address pair = pairFor(tokenA, tokenB, stable);
        require(IPair(pair).transferFrom(msg.sender, pair, liquidity), "ITFM"); // send liquidity to pair
        (uint amount0, uint amount1) = IPair(pair).burn(to);
        (address token0,) = sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        require(amountA >= amountAMin && amountB >= amountBMin, 'IAA');
    }

    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) public ensure(deadline) nonReentrant returns (uint amountA, uint amountB) {
        (amountA, amountB) = _removeLiquidity(
            tokenA,
            tokenB,
            stable,
            liquidity,
            amountAMin,
            amountBMin,
            to,
            deadline
        );
    }

    function removeLiquidityETH(
        address token,
        bool stable,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) public ensure(deadline) nonReentrant returns (uint amountToken, uint amountETH) {
        (amountToken, amountETH) = _removeLiquidity(
            token,
            address(wETH),
            stable,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        _safeTransfer(token, to, amountToken);
        wETH.withdraw(amountETH);
        _safeTransferETH(to, amountETH);
    }

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        bool stable,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external nonReentrant returns (uint amountA, uint amountB) {
        address pair = pairFor(tokenA, tokenB, stable);
        
        try IPair(pair).permit(
            msg.sender, 
            address(this), 
            approveMax ? type(uint).max : liquidity, 
            deadline, 
            v, 
            r, 
            s
        ) {
            // Permit succeeded
        } catch {
            // Permit failed, check if we have sufficient allowance
            require(
                IPair(pair).allowance(msg.sender, address(this)) >= liquidity,
                "IA"
            );
        }

        (amountA, amountB) = _removeLiquidity(
            tokenA,
            tokenB,
            stable,
            liquidity,
            amountAMin,
            amountBMin,
            to,
            deadline
        );
    }

    function removeLiquidityETHWithPermit(
        address token,
        bool stable,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external nonReentrant returns (uint amountToken, uint amountETH) {
        address pair = pairFor(token, address(wETH), stable);
        
        try IPair(pair).permit(
            msg.sender, 
            address(this), 
            approveMax ? type(uint).max : liquidity, 
            deadline, 
            v, 
            r, 
            s
        ) {
            // Permit succeeded
        } catch {
            // Permit failed, check if we have sufficient allowance
            require(
                IPair(pair).allowance(msg.sender, address(this)) >= liquidity,
                "IA"
            );
        }

        (amountToken, amountETH) = _removeLiquidity(
            token,
            address(wETH),
            stable,
            liquidity,
            amountTokenMin,
            amountETHMin,
            to,
            deadline
        );
    }

    // **** SWAP ****
    // requires the initial amount to have already been sent to the first pair
    function _swap(uint[] memory amounts, IRouter.route[] memory routes, uint deadline) internal virtual {
        uint256 routesLen = routes.length;
        for (uint i = 0; i < routesLen; i++) {
            require(routes[i].receiver != address(0), "ZA");
            if(routes[i].concentrated){
                if (IERC20(routes[i].from).allowance(address(this), swapRouter) < amounts[i]) {
                    IERC20(routes[i].from).forceApprove(swapRouter, amounts[i]);
                }
                ISwapRouter.ExactInputSingleParams memory inputParams;
                inputParams = ISwapRouter.ExactInputSingleParams ({
                    tokenIn: routes[i].from,
                    tokenOut: routes[i].to,
                    deployer: IAlgebraPoolAPIStorage(algebraPoolAPIStorage).pairToDeployer(routes[i].pair),
                    recipient: routes[i].receiver,
                    deadline: deadline,
                    amountIn: amounts[i],
                    amountOutMinimum: 0,
                    limitSqrtPrice: 0
                });

                amounts[i+1] = ISwapRouter(swapRouter).exactInputSingle(inputParams);
            }
            else{
                (address token0,) = sortTokens(routes[i].from, routes[i].to);
                uint amountOut = amounts[i + 1];
                (uint amount0Out, uint amount1Out) = routes[i].from == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
                IPair(pairFor(routes[i].from, routes[i].to, routes[i].stable)).swap(
                    amount0Out, amount1Out, routes[i].receiver, new bytes(0)
                );
            }

            emit Swap(msg.sender, amounts[i], amounts[i+1], routes[i].from, routes[i].receiver, routes[i].stable); 
        }
    }

    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        IRouter.route[] calldata routes,
        address to,
        uint deadline
    ) external ensure(deadline) nonReentrant returns (uint[] memory amounts) {
        require(routes[routes.length - 1].receiver == to, 'IR'); // Invalid recipient
        (amounts,,) = IRouterHelper(routerHelper).getAmountsOut(amountIn, routes);
        require(amounts[amounts.length - 1] >= amountOutMin, 'IOA');
        if(!routes[0].concentrated)
        {
            _safeTransferFrom(
                routes[0].from, msg.sender, routes[0].pair, amounts[0]
            );
        }
        else{
             _safeTransferFrom(
                routes[0].from, msg.sender, address(this), amounts[0]
            );
            if (IERC20(routes[0].from).allowance(address(this), swapRouter) < amounts[0]) {
                IERC20(routes[0].from).forceApprove(swapRouter, amounts[0]);
            }
        }
        _swap(amounts, routes, deadline);
    }

    function swapExactETHForTokens(uint amountOutMin, IRouter.route[] calldata routes, address to, uint deadline) external payable ensure(deadline) nonReentrant returns (uint[] memory amounts) {
        require(routes[0].from == address(wETH), 'INP');
        require(routes[routes.length - 1].receiver == to, 'IR'); // Invalid recipient
        (amounts,,) = IRouterHelper(routerHelper).getAmountsOut(msg.value, routes);
        require(amounts[amounts.length - 1] >= amountOutMin, 'IOA');
        wETH.deposit{value: amounts[0]}();

        if (!routes[0].concentrated) {
            assert(wETH.transfer(pairFor(routes[0].from, routes[0].to, routes[0].stable),amounts[0]));
        } else {
            if (IERC20(address(wETH)).allowance(address(this), swapRouter) < amounts[0]) {
                IERC20(address(wETH)).forceApprove(swapRouter, amounts[0]);
            }
        }
        _swap(amounts, routes, deadline);
    }

    function swapExactTokensForETH(uint amountIn, uint amountOutMin, IRouter.route[] calldata routes, address to, uint deadline)
    external
    ensure(deadline)
    nonReentrant
    returns (uint[] memory amounts)
    {
        require(routes[routes.length - 1].to == address(wETH), 'INP');
        (amounts,,) = IRouterHelper(routerHelper).getAmountsOut(amountIn, routes);
        require(amounts[amounts.length - 1] >= amountOutMin, 'IOA');

        if(!routes[0].concentrated)
        {
            _safeTransferFrom(
                routes[0].from, msg.sender, pairFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]
            );
        }
        else{
             _safeTransferFrom(
                routes[0].from, msg.sender, address(this), amounts[0]
            );
            if (IERC20(routes[0].from).allowance(address(this), swapRouter) < amounts[0]) {
                IERC20(routes[0].from).forceApprove(swapRouter, amounts[0]);
            }
        }
        _swap(amounts, routes, deadline);
        wETH.withdraw(amounts[amounts.length - 1]);
        _safeTransferETH(to, amounts[amounts.length - 1]);
    }

    function UNSAFE_swapExactTokensForTokens(
        uint[] memory amounts,
        IRouter.route[] calldata routes,
        address to,
        uint deadline
    ) external ensure(deadline) nonReentrant returns (uint[] memory) {
        require(routes[routes.length - 1].receiver == to, 'IR'); // Invalid recipient
        _safeTransferFrom(routes[0].from, msg.sender, pairFor(routes[0].from, routes[0].to, routes[0].stable), amounts[0]);
        _swap(amounts, routes, deadline);
        return amounts;
    }

    function _safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'ETF');
    }

    function _safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0, "CODELEN");
        (bool success, bytes memory data) =
        token.call(abi.encodeCall(IERC20.transfer, (to, value)));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "IST");
    }

    function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0, "CODELEN");
        (bool success, bytes memory data) =
        token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "ISTF");
    }

    // Experimental Extension [ETH.guru/solidly/BaseV1Router02]

    // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens)****
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        bool stable,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) public ensure(deadline) nonReentrant returns (uint amountToken, uint amountETH) {
        (amountToken, amountETH) = _removeLiquidity(
            token,
            address(wETH),
            stable,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        _safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
        wETH.withdraw(amountETH);
        _safeTransferETH(to, amountETH);
    }
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        bool stable,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external nonReentrant returns (uint amountToken, uint amountETH) {
        address pair = pairFor(token, address(wETH), stable);
        uint value = approveMax ? type(uint).max : liquidity;
        try IPair(pair).permit(
            msg.sender, 
            address(this), 
            value, 
            deadline, 
            v, 
            r, 
            s
        ) {
            // Permit succeeded
        } catch {
            // Permit failed, check if we have sufficient allowance
            require(
                IPair(pair).allowance(msg.sender, address(this)) >= liquidity,
                "IA"
            );
        }
        (amountToken, amountETH) = removeLiquidityETHSupportingFeeOnTransferTokens(
            token, stable, liquidity, amountTokenMin, amountETHMin, to, deadline
        );
    }
    
    // **** SWAP (supporting fee-on-transfer tokens) ****
    // requires the initial amount to have already been sent to the first pair
    function _swapSupportingFeeOnTransferTokens(IRouter.route[] calldata routes, address _to) internal virtual {
        for (uint i; i < routes.length; i++) {
        	(address input, address output) = (routes[i].from, routes[i].to);
            (address token0,) = sortTokens(input, output);
            IPair pair = IPair(pairFor(routes[i].from, routes[i].to, routes[i].stable));
            uint amountInput;
            uint amountOutput;
            { // scope to avoid stack too deep errors
            (uint reserve0, uint reserve1,) = pair.getReserves();
            (uint reserveInput,) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
            amountInput = IERC20(input).balanceOf(address(pair)) - reserveInput;
            (amountOutput,) = IRouterHelper(routerHelper).getAmountOutForFeeOnTransfer(amountInput, input, output);
            }
            (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
            address to = i < routes.length - 1 ? pairFor(routes[i+1].from, routes[i+1].to, routes[i+1].stable) : _to;
            pair.swap(amount0Out, amount1Out, to, new bytes(0));

            bool _stable = routes[i].stable;
            emit Swap(msg.sender,amountInput,amountOutput,input,_to,_stable);  
        }
    }

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        IRouter.route[] calldata routes,
        address to,
        uint deadline
    ) external ensure(deadline) nonReentrant {
        _safeTransferFrom(
        	routes[0].from,
        	msg.sender,
        	pairFor(routes[0].from, routes[0].to, routes[0].stable),
        	amountIn
        );
        uint routesLen = routes.length;
        uint balanceBefore = IERC20(routes[routesLen - 1].to).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(routes, to);
        require(
            IERC20(routes[routesLen - 1].to).balanceOf(to) - balanceBefore >= amountOutMin,
            'IOA'
        );
    }

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        IRouter.route[] calldata routes,
        address to,
        uint deadline
    )
        external
        payable
        ensure(deadline)
        nonReentrant
    {
        require(routes[0].from == address(wETH), 'INP');
        uint amountIn = msg.value;
        wETH.deposit{value: amountIn}();
        uint routesLen = routes.length;
        assert(wETH.transfer(pairFor(routes[0].from, routes[0].to, routes[0].stable), amountIn));
        uint balanceBefore = IERC20(routes[routesLen - 1].to).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(routes, to);
        require(
            IERC20(routes[routesLen - 1].to).balanceOf(to) - balanceBefore >= amountOutMin,
            'IOA'
        );
    }

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        IRouter.route[] calldata routes,
        address to,
        uint deadline
    )
        external
        ensure(deadline)
        nonReentrant
    {
        require(routes[routes.length - 1].to == address(wETH), 'INP');
        _safeTransferFrom(
            routes[0].from, msg.sender, pairFor(routes[0].from, routes[0].to, routes[0].stable), amountIn
        );
        _swapSupportingFeeOnTransferTokens(routes, address(this));
        uint amountOut = IERC20(address(wETH)).balanceOf(address(this));
        require(amountOut >= amountOutMin, 'IOA');
        wETH.withdraw(amountOut);
        _safeTransferETH(to, amountOut);
    }
}

Read Contract

algebraPoolAPIStorage 0x7f64ba03 → address
factory 0xc45a0155 → address
getPoolAmountOut 0x83b9a7d3 → uint256
getReserves 0x5e60dab5 → uint256, uint256
pairFor 0x4c1ee03e → address
quoteAddLiquidity 0x98a0fb3c → uint256, uint256, uint256
quoteRemoveLiquidity 0x4386e63c → uint256, uint256
routerHelper 0xdcba74f2 → address
sortTokens 0x544caa56 → address, address
swapRouter 0xc31c9c07 → address
wETH 0xf2428621 → address

Write Contract 15 functions

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

UNSAFE_swapExactTokensForTokens 0x98e74dc6
uint256[] amounts
tuple[] routes
address to
uint256 deadline
returns: uint256[]
addLiquidity 0x5a47ddc3
address tokenA
address tokenB
bool stable
uint256 amountADesired
uint256 amountBDesired
uint256 amountAMin
uint256 amountBMin
address to
uint256 deadline
returns: uint256, uint256, uint256
addLiquidityETH 0xb7e0d4c0
address token
bool stable
uint256 amountTokenDesired
uint256 amountTokenMin
uint256 amountETHMin
address to
uint256 deadline
returns: uint256, uint256, uint256
removeLiquidity 0x0dede6c4
address tokenA
address tokenB
bool stable
uint256 liquidity
uint256 amountAMin
uint256 amountBMin
address to
uint256 deadline
returns: uint256, uint256
removeLiquidityETH 0xd7b0e0a5
address token
bool stable
uint256 liquidity
uint256 amountTokenMin
uint256 amountETHMin
address to
uint256 deadline
returns: uint256, uint256
removeLiquidityETHSupportingFeeOnTransferTokens 0xfe411f14
address token
bool stable
uint256 liquidity
uint256 amountTokenMin
uint256 amountETHMin
address to
uint256 deadline
returns: uint256, uint256
removeLiquidityETHWithPermit 0x448725b4
address token
bool stable
uint256 liquidity
uint256 amountTokenMin
uint256 amountETHMin
address to
uint256 deadline
bool approveMax
uint8 v
bytes32 r
bytes32 s
returns: uint256, uint256
removeLiquidityETHWithPermitSupportingFeeOnTransferTokens 0xe2d9d4dc
address token
bool stable
uint256 liquidity
uint256 amountTokenMin
uint256 amountETHMin
address to
uint256 deadline
bool approveMax
uint8 v
bytes32 r
bytes32 s
returns: uint256, uint256
removeLiquidityWithPermit 0xa32b1fcd
address tokenA
address tokenB
bool stable
uint256 liquidity
uint256 amountAMin
uint256 amountBMin
address to
uint256 deadline
bool approveMax
uint8 v
bytes32 r
bytes32 s
returns: uint256, uint256
swapExactETHForTokens 0x8db441f3
uint256 amountOutMin
tuple[] routes
address to
uint256 deadline
returns: uint256[]
swapExactETHForTokensSupportingFeeOnTransferTokens 0x4401dbe7
uint256 amountOutMin
tuple[] routes
address to
uint256 deadline
swapExactTokensForETH 0xfec8ae02
uint256 amountIn
uint256 amountOutMin
tuple[] routes
address to
uint256 deadline
returns: uint256[]
swapExactTokensForETHSupportingFeeOnTransferTokens 0xe48a5dbe
uint256 amountIn
uint256 amountOutMin
tuple[] routes
address to
uint256 deadline
swapExactTokensForTokens 0x9fe3709a
uint256 amountIn
uint256 amountOutMin
tuple[] routes
address to
uint256 deadline
returns: uint256[]
swapExactTokensForTokensSupportingFeeOnTransferTokens 0x1527cd07
uint256 amountIn
uint256 amountOutMin
tuple[] routes
address to
uint256 deadline

Recent Transactions

|
Hash Method Block Age From/To Value Txn Fee Type
0xba6d4418...88ad6f 0x204b5c0a 24,587,661 IN 0x3DD9B720...1c17 0 ETH 0.000040489139 ETH EIP-1559
0x884fa02e...64e40a 0x204b5c0a 24,587,656 IN 0xFA1afeCA...f39e 0 ETH 0.000089531002 ETH EIP-1559
0xabcda758...6a0cc9 0xf0aff68d 24,587,655 IN 0xeac9bf64...224D 0 ETH 0.000021796527 ETH EIP-1559
0x4fc4baa0...daacdd 0x204b5c0a 24,587,652 IN 0x761BA636...D4B5 0 ETH 0.000120174259 ETH EIP-1559
0x766ab8b7...781998 0x204b5c0a 24,587,647 IN 0x761BA636...D4B5 0 ETH 0.000041777160 ETH EIP-1559
0xef73c89f...7a9f29 0x204b5c0a 24,587,642 IN 0x65FF65FE...3E07 0 ETH 0.00120244 ETH EIP-1559
0xd4a00990...dc2882 0x204b5c0a 24,587,640 IN 0x761BA636...D4B5 0 ETH 0.000043018477 ETH EIP-1559
0x6123afa1...f284d5 0x204b5c0a 24,587,639 IN 0xb3357F46...a462 0 ETH 0.000957943751 ETH EIP-1559
0x152ba6c1...f44441 0x204b5c0a 24,587,637 IN 0xb3357F46...a462 0 ETH 0.000969055603 ETH EIP-1559
0x63cf4f70...b9c3a2 0x204b5c0a 24,587,637 IN 0x09378463...eDA0 0 ETH 0.000031572956 ETH EIP-1559