Address Contract Verified
Address
0xbFAe8E87053309fDe07ab3cA5f4B5345f8e3058f
Balance
0 ETH
Nonce
1
Code Size
22949 bytes
Creator
0xe2d2F783...BCa2 at tx 0x33f98b54...3b66ba
Last Active
Indexed Transactions
68 (24,587,637 → 24,587,661)
Gas Used (indexed)
7,150,499
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
Top Interactions
| Address | Txns | Sent | Received |
|---|---|---|---|
| 0x761BA636...D4B5 | 3 | 3 | |
| 0xb3357F46...a462 | 2 | 2 | |
| 0xFA1afeCA...f39e | 1 | 1 | |
| 0x65FF65FE...3E07 | 1 | 1 | |
| 0x09378463...eDA0 | 1 | 1 | |
| 0xeac9bf64...224D | 1 | 1 | |
| 0x3DD9B720...1c17 | 1 | 1 |
Token Balances (2)
View Transfers →Recent Transactions
|
| Hash | Block | Age | From/To | Value | |
|---|---|---|---|---|---|
| 0xba6d4418...88ad6f | 24,587,661 | IN | 0x3DD9B720...1c17 | 0 ETH | |
| 0x884fa02e...64e40a | 24,587,656 | IN | 0xFA1afeCA...f39e | 0 ETH | |
| 0xabcda758...6a0cc9 | 24,587,655 | IN | 0xeac9bf64...224D | 0 ETH | |
| 0x4fc4baa0...daacdd | 24,587,652 | IN | 0x761BA636...D4B5 | 0 ETH | |
| 0x766ab8b7...781998 | 24,587,647 | IN | 0x761BA636...D4B5 | 0 ETH | |
| 0xef73c89f...7a9f29 | 24,587,642 | IN | 0x65FF65FE...3E07 | 0 ETH | |
| 0xd4a00990...dc2882 | 24,587,640 | IN | 0x761BA636...D4B5 | 0 ETH | |
| 0x6123afa1...f284d5 | 24,587,639 | IN | 0xb3357F46...a462 | 0 ETH | |
| 0x152ba6c1...f44441 | 24,587,637 | IN | 0xb3357F46...a462 | 0 ETH | |
| 0x63cf4f70...b9c3a2 | 24,587,637 | IN | 0x09378463...eDA0 | 0 ETH |