Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xbDC4Dd4d467e55FA5276925b2f136E75DF3f86f1
Balance 0.000000010 ETH
Nonce 1
Code Size 22797 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

22797 bytes
0x6080604052600436106100e15760003560e01c80636b1430d61161007f578063e485990811610059578063e4859908146102d8578063f4f5164a14610316578063f6dc1e2414610353578063f7c2861c1461037c576100e8565b80636b1430d6146102495780637e25c02614610272578063cabb9e7a1461029b576100e8565b80632079fb9a116100bb5780632079fb9a1461017b5780634e87753c146101b85780635df61827146101f557806368db450c1461021e576100e8565b80631025e095146100ea5780631626ba7e14610113578063174f830514610150576100e8565b366100e857005b005b3480156100f657600080fd5b50610111600480360381019061010c9190613958565b6103a7565b005b34801561011f57600080fd5b5061013a60048036038101906101359190613c03565b6107a2565b6040516101479190614859565b60405180910390f35b34801561015c57600080fd5b506101656108b1565b60405161017291906146b1565b60405180910390f35b34801561018757600080fd5b506101a2600480360381019061019d9190613cff565b6108d7565b6040516101af91906146b1565b60405180910390f35b3480156101c457600080fd5b506101df60048036038101906101da9190613a26565b610916565b6040516101ec91906147a7565b60405180910390f35b34801561020157600080fd5b5061021c60048036038101906102179190613adc565b610a8b565b005b34801561022a57600080fd5b5061023361149a565b6040516102409190614859565b60405180910390f35b34801561025557600080fd5b50610270600480360381019061026b9190613813565b6114bd565b005b34801561027e57600080fd5b5061029960048036038101906102949190613adc565b611979565b005b3480156102a757600080fd5b506102c260048036038101906102bd91906137ea565b61221b565b6040516102cf919061478c565b60405180910390f35b3480156102e457600080fd5b506102ff60048036038101906102fa9190613cad565b6122f0565b60405161030d9291906147c2565b60405180910390f35b34801561032257600080fd5b5061033d600480360381019061033891906138cc565b6123cf565b60405161034a9190614874565b60405180910390f35b34801561035f57600080fd5b5061037a60048036038101906103759190613909565b6124f5565b005b34801561038857600080fd5b506103916128da565b60405161039e9190614859565b60405180910390f35b6103af6128fd565b6002825110156103f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103eb90614a58565b60405180910390fd5b8051825114610438576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161042f906148f8565b60405180910390fd5b81600181518110610472577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16826000815181106104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161415610529576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161052090614b18565b60405180910390fd5b4284101561056c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056390614a78565b60405180910390fd5b60008787878787304660405160200161058b9796959493929190614599565b6040516020818303038152906040528051906020012090506105ac8161294d565b905060005b83518160ff16101561071b57600061060c83858460ff16815181106105ff577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151612983565b9050848260ff168151811061064a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146106bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b690614938565b60405180910390fd5b6106c88161221b565b610707576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106fe90614978565b60405180910390fd5b50808061071390615101565b9150506105b1565b50610728848989896129aa565b61075388888873ffffffffffffffffffffffffffffffffffffffff16612b089092919063ffffffff16565b7ff8eff9ed148da048feccebca2617170aec98bea5840b0b0be8a289ec03c375fd84878a8a6040516107889493929190614c0f565b60405180910390a150610799612b8e565b50505050505050565b6000806107f38585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612983565b90506001600081548110610830577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561089e57631626ba7e60e01b9150506108aa565b63ffffffff60e01b9150505b9392505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600181815481106108e757600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008083156109d85773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16141561099f5788858785304660405160200161098296959493929190614522565b6040516020818303038152906040528051906020012090506109d3565b8885878530466040516020016109ba96959493929190614625565b6040516020818303038152906040528051906020012090505b610a7c565b600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161415610a4557888887873046604051602001610a28969594939291906144a7565b604051602081830303815290604052805190602001209050610a7b565b88888888883046604051602001610a629796959493929190614599565b6040516020818303038152906040528051906020012090505b5b80915050979650505050505050565b610a936128fd565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610b23576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1a90614a18565b60405180910390fd5b600283511015610b68576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5f90614a58565b60405180910390fd5b8151835114610bac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba3906148f8565b60405180910390fd5b82600181518110610be6577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1683600081518110610c3e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161415610c9d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9490614b18565b60405180910390fd5b42861015610ce0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cd790614a78565b60405180910390fd5b61271061ffff16856060015161ffff1610610d30576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2790614a38565b60405180910390fd5b6000888888873046604051602001610d4d96959493929190614625565b604051602081830303815290604052805190602001209050610d6e8161294d565b905060005b84518160ff161015610edd576000610dce83868460ff1681518110610dc1577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151612983565b9050858260ff1681518110610e0c577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610e81576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e7890614938565b60405180910390fd5b610e8a8161221b565b610ec9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ec090614978565b60405180910390fd5b508080610ed590615101565b915050610d73565b50610f04888a88604001516fffffffffffffffffffffffffffffffff1689602001516129aa565b610f56600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000886020015173ffffffffffffffffffffffffffffffffffffffff16612b989092919063ffffffff16565b610fbd600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1687604001516fffffffffffffffffffffffffffffffff16886020015173ffffffffffffffffffffffffffffffffffffffff16612b989092919063ffffffff16565b85604001516fffffffffffffffffffffffffffffffff16866020015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161101191906146b1565b60206040518083038186803b15801561102957600080fd5b505afa15801561103d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110619190613d28565b10156110a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611099906149d8565b60405180910390fd5b60008973ffffffffffffffffffffffffffffffffffffffff166000876040516110cb9190614415565b60006040518083038185875af1925050503d8060008114611108576040519150601f19603f3d011682016040523d82523d6000602084013e61110d565b606091505b5050905080611151576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114890614998565b60405180910390fd5b7f999f948811988a777e338d276a96f37cb011e4504b34827cb8700e936c898e218988602001518c8a6040015160405161118e9493929190614bca565b60405180910390a182156114865760008a73ffffffffffffffffffffffffffffffffffffffff1663fc97a30389602001516040518263ffffffff1660e01b81526004016111db91906146b1565b60206040518083038186803b1580156111f357600080fd5b505afa158015611207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122b9190613cd6565b905060008b73ffffffffffffffffffffffffffffffffffffffff16632df7c2933073ffffffffffffffffffffffffffffffffffffffff1660001b846040518363ffffffff1660e01b81526004016112839291906147eb565b60206040518083038186803b15801561129b57600080fd5b505afa1580156112af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d39190613c84565b90506000816fffffffffffffffffffffffffffffffff1611156114835760008c73ffffffffffffffffffffffffffffffffffffffff1663f3c20de0846040518263ffffffff1660e01b815260040161132b9190614b78565b60806040518083038186803b15801561134357600080fd5b505afa158015611357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137b9190613c5b565b905060006113a4826060015160126113939190614ef2565b600a61139f9190614dd4565b612cf6565b836113af9190614d50565b90508d73ffffffffffffffffffffffffffffffffffffffff16632f25807e3086846040518463ffffffff1660e01b81526004016113ee939291906146cc565b602060405180830381600087803b15801561140857600080fd5b505af115801561141c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114409190613c84565b507f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870688b6020015130836040516114789392919061472c565b60405180910390a150505b50505b5050611490612b8e565b5050505050505050565b6040518060600160405280603581526020016158a3603591398051906020012081565b6114c56128fd565b60028251101561150a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150190614a58565b60405180910390fd5b805182511461154e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611545906148f8565b60405180910390fd5b81600181518110611588577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16826000815181106115e0577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16141561163f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161163690614b18565b60405180910390fd5b42841015611682576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167990614a78565b60405180910390fd5b600086868686304660405160200161169f9695949392919061442c565b6040516020818303038152906040528051906020012090506116c08161294d565b905060005b83518160ff16101561182f57600061172083858460ff1681518110611713577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151612983565b9050848260ff168151811061175e577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117ca90614938565b60405180910390fd5b6117dc8161221b565b61181b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161181290614978565b60405180910390fd5b50808061182790615101565b9150506116c5565b5061183d84888860006129aa565b85471015611880576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611877906149d8565b60405180910390fd5b60008773ffffffffffffffffffffffffffffffffffffffff16876040516118a69061469c565b60006040518083038185875af1925050503d80600081146118e3576040519150601f19603f3d011682016040523d82523d6000602084013e6118e8565b606091505b505090508061192c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161192390614998565b60405180910390fd5b7f4d7574efc376e1ee5e6eacc9b23ed30ae9f40acfddb028be515fb99a14e2290c85898960405161195f93929190614b93565b60405180910390a15050611971612b8e565b505050505050565b6119816128fd565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614611a11576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a0890614a18565b60405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff1614611a97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a8e90614ad8565b60405180910390fd5b600283511015611adc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ad390614a58565b60405180910390fd5b8151835114611b20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b17906148f8565b60405180910390fd5b82600181518110611b5a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1683600081518110611bb2577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161415611c11576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c0890614b18565b60405180910390fd5b42861015611c54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c4b90614a78565b60405180910390fd5b61271061ffff16856060015161ffff1610611ca4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c9b90614a38565b60405180910390fd5b6000888888873046604051602001611cc196959493929190614522565b604051602081830303815290604052805190602001209050611ce28161294d565b905060005b84518160ff161015611e51576000611d4283868460ff1681518110611d35577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151612983565b9050858260ff1681518110611d80577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611df5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dec90614938565b60405180910390fd5b611dfe8161221b565b611e3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e3490614978565b60405180910390fd5b508080611e4990615101565b915050611ce7565b50611e78888a88604001516fffffffffffffffffffffffffffffffff1689602001516129aa565b85604001516fffffffffffffffffffffffffffffffff16471015611ed1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ec8906149d8565b60405180910390fd5b60008973ffffffffffffffffffffffffffffffffffffffff1687604001516fffffffffffffffffffffffffffffffff1687604051611f0f9190614415565b60006040518083038185875af1925050503d8060008114611f4c576040519150601f19603f3d011682016040523d82523d6000602084013e611f51565b606091505b5050905080611f95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f8c90614998565b60405180910390fd5b7ff2e34d06a0d98f1bfd33578875911be2d1c4d99735745b363cba4c57c34b07c38988602001518c8a60400151604051611fd29493929190614bca565b60405180910390a182156122075760008a73ffffffffffffffffffffffffffffffffffffffff1663fc97a30389602001516040518263ffffffff1660e01b815260040161201f91906146b1565b60206040518083038186803b15801561203757600080fd5b505afa15801561204b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206f9190613cd6565b905060008b73ffffffffffffffffffffffffffffffffffffffff16632df7c2933073ffffffffffffffffffffffffffffffffffffffff1660001b846040518363ffffffff1660e01b81526004016120c79291906147eb565b60206040518083038186803b1580156120df57600080fd5b505afa1580156120f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121179190613c84565b90506000816fffffffffffffffffffffffffffffffff161115612204578b73ffffffffffffffffffffffffffffffffffffffff16632f25807e3084846040518463ffffffff1660e01b8152600401612171939291906146cc565b602060405180830381600087803b15801561218b57600080fd5b505af115801561219f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c39190613c84565b507f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd987068896020015130836040516121fb9392919061472c565b60405180910390a15b50505b5050612211612b8e565b5050505050505050565b600080600090505b6001805490508110156122e5578273ffffffffffffffffffffffffffffffffffffffff1660018281548110612281577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156122d25760019150506122eb565b80806122dd906150b8565b915050612223565b50600090505b919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff1660001b90506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632df7c29383876040518363ffffffff1660e01b81526004016123709291906147eb565b60206040518083038186803b15801561238857600080fd5b505afa15801561239c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c09190613c84565b90508181935093505050915091565b606073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612483576040518060600160405280603581526020016158a3603591398051906020012082600001518360400151846060015185608001518660a001518760c0015160405160200161246d9796959493929190614394565b60405160208183030381529060405290506124ef565b6040518060600160405280603f8152602001615864603f913980519060200120826000015183602001518460400151856060015186608001518760a001518860c001516040516020016124dd989796959493929190614302565b60405160208183030381529060405290505b92915050565b6124fd6128fd565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632df7c2938573ffffffffffffffffffffffffffffffffffffffff1660001b856040518363ffffffff1660e01b81526004016125759291906147eb565b60206040518083038186803b15801561258d57600080fd5b505afa1580156125a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c59190613c84565b90506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f3c20de0856040518263ffffffff1660e01b81526004016126249190614b78565b60806040518083038186803b15801561263c57600080fd5b505afa158015612650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126749190613c5b565b9050600061269d8260600151601261268c9190614ef2565b600a6126989190614dd4565b612cf6565b836126a89190614d50565b90506000846fffffffffffffffffffffffffffffffff161180156126f05750806fffffffffffffffffffffffffffffffff16846fffffffffffffffffffffffffffffffff1611155b61272f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161272690614958565b60405180910390fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632f25807e8787876040518463ffffffff1660e01b815260040161278e939291906146cc565b602060405180830381600087803b1580156127a857600080fd5b505af11580156127bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e09190613c84565b507f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd987068600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f3c20de0876040518263ffffffff1660e01b815260040161285d9190614b78565b60806040518083038186803b15801561287557600080fd5b505afa158015612889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ad9190613c5b565b6040015187866040516128c29392919061472c565b60405180910390a15050506128d5612b8e565b505050565b6040518060600160405280603f8152602001615864603f91398051906020012081565b60026000541415612943576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161293a90614b38565b60405180910390fd5b6002600081905550565b60007f19457468657265756d205369676e6564204d6573736167653a0a33320000000060005281601c52603c6000209050919050565b60008060006129928585612d53565b9150915061299f81612da5565b819250505092915050565b6002600085815260200190815260200160002060020160149054906101000a900460ff1615612a0e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a0590614ab8565b60405180910390fd5b60016002600086815260200190815260200160002060020160146101000a81548160ff021916908315150217905550826002600086815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550816002600086815260200190815260200160002060010181905550806002600086815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b612b898363a9059cbb60e01b8484604051602401612b27929190614763565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613043565b505050565b6001600081905550565b6000811480612c31575060008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401612bdf929190614703565b60206040518083038186803b158015612bf757600080fd5b505afa158015612c0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2f9190613d28565b145b612c70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c6790614b58565b60405180910390fd5b612cf18363095ea7b360e01b8484604051602401612c8f929190614763565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613043565b505050565b60007001000000000000000000000000000000008210612d4b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d4290614918565b60405180910390fd5b819050919050565b600080604183511415612d955760008060006020860151925060408601519150606086015160001a9050612d898782858561310b565b94509450505050612d9e565b60006002915091505b9250929050565b60006004811115612ddf577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b816004811115612e18577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612e2357613040565b60016004811115612e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b816004811115612e96577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612ed7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ece906148b8565b60405180910390fd5b60026004811115612f11577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b816004811115612f4a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415612f8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f82906148d8565b60405180910390fd5b60036004811115612fc5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b816004811115612ffe577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b141561303f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613036906149b8565b60405180910390fd5b5b50565b60006130a5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166131ee9092919063ffffffff16565b90506000815114806130c75750808060200190518101906130c69190613bda565b5b613106576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130fd90614af8565b60405180910390fd5b505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156131465760006003915091506131e5565b60006001878787876040516000815260200160405260405161316b9493929190614814565b6020604051602081039080840390855afa15801561318d573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156131dc576000600192509250506131e5565b80600092509250505b94509492505050565b60606131fd8484600085613206565b90509392505050565b60608247101561324b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613242906149f8565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516132749190614415565b60006040518083038185875af1925050503d80600081146132b1576040519150601f19603f3d011682016040523d82523d6000602084013e6132b6565b606091505b50915091506132c7878383876132d3565b92505050949350505050565b606083156133365760008351141561332e576132ee85613349565b61332d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161332490614a98565b60405180910390fd5b5b829050613341565b613340838361336c565b5b949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60008251111561337f5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133b39190614896565b60405180910390fd5b60006133cf6133ca84614c79565b614c54565b905080838252602082019050828560208602820111156133ee57600080fd5b60005b8581101561341e578161340488826134c3565b8452602084019350602083019250506001810190506133f1565b5050509392505050565b600061343b61343684614ca5565b614c54565b9050808382526020820190508260005b8581101561347b578135850161346188826135df565b84526020840193506020830192505060018101905061344b565b5050509392505050565b600061349861349384614cd1565b614c54565b9050828152602081018484840111156134b057600080fd5b6134bb848285615045565b509392505050565b6000813590506134d281615794565b92915050565b6000815190506134e781615794565b92915050565b6000813590506134fc816157ab565b92915050565b600082601f83011261351357600080fd5b81356135238482602086016133bc565b91505092915050565b600082601f83011261353d57600080fd5b813561354d848260208601613428565b91505092915050565b600081359050613565816157c2565b92915050565b60008151905061357a816157c2565b92915050565b60008135905061358f816157d9565b92915050565b60008083601f8401126135a757600080fd5b8235905067ffffffffffffffff8111156135c057600080fd5b6020830191508360018202830111156135d857600080fd5b9250929050565b600082601f8301126135f057600080fd5b8135613600848260208601613485565b91505092915050565b60006080828403121561361b57600080fd5b6136256080614c54565b905060006136358482850161356b565b60008301525060206136498482850161356b565b602083015250604061365d848285016134d8565b6040830152506060613671848285016137d5565b60608301525092915050565b600060e0828403121561368f57600080fd5b61369960e0614c54565b905060006136a9848285016134c3565b60008301525060206136bd848285016134c3565b60208301525060406136d18482850161372d565b60408301525060606136e584828501613757565b60608301525060806136f9848285016137ab565b60808301525060a061370d848285016137c0565b60a08301525060c0613721848285016137ab565b60c08301525092915050565b60008135905061373c816157f0565b92915050565b600081519050613751816157f0565b92915050565b60008135905061376681615807565b92915050565b60008151905061377b81615807565b92915050565b6000813590506137908161581e565b92915050565b6000815190506137a58161581e565b92915050565b6000813590506137ba81615835565b92915050565b6000813590506137cf8161584c565b92915050565b6000815190506137e48161584c565b92915050565b6000602082840312156137fc57600080fd5b600061380a848285016134c3565b91505092915050565b60008060008060008060c0878903121561382c57600080fd5b600061383a89828a016134ed565b965050602061384b89828a01613781565b955050604061385c89828a01613781565b945050606061386d89828a01613781565b935050608087013567ffffffffffffffff81111561388a57600080fd5b61389689828a01613502565b92505060a087013567ffffffffffffffff8111156138b357600080fd5b6138bf89828a0161352c565b9150509295509295509295565b60008061010083850312156138e057600080fd5b60006138ee858286016134c3565b92505060206138ff8582860161367d565b9150509250929050565b60008060006060848603121561391e57600080fd5b600061392c868287016134c3565b935050602061393d86828701613757565b925050604061394e8682870161372d565b9150509250925092565b600080600080600080600060e0888a03121561397357600080fd5b60006139818a828b016134c3565b97505060206139928a828b01613781565b96505060406139a38a828b016134c3565b95505060606139b48a828b01613781565b94505060806139c58a828b01613781565b93505060a088013567ffffffffffffffff8111156139e257600080fd5b6139ee8a828b01613502565b92505060c088013567ffffffffffffffff811115613a0b57600080fd5b613a178a828b0161352c565b91505092959891949750929550565b600080600080600080600060e0888a031215613a4157600080fd5b6000613a4f8a828b016134c3565b9750506020613a608a828b01613781565b9650506040613a718a828b016134c3565b9550506060613a828a828b01613781565b9450506080613a938a828b01613781565b93505060a0613aa48a828b01613556565b92505060c088013567ffffffffffffffff811115613ac157600080fd5b613acd8a828b016135df565b91505092959891949750929550565b6000806000806000806000806101c0898b031215613af957600080fd5b6000613b078b828c016134c3565b9850506020613b188b828c01613781565b9750506040613b298b828c01613781565b9650506060613b3a8b828c0161367d565b95505061014089013567ffffffffffffffff811115613b5857600080fd5b613b648b828c016135df565b94505061016089013567ffffffffffffffff811115613b8257600080fd5b613b8e8b828c01613502565b93505061018089013567ffffffffffffffff811115613bac57600080fd5b613bb88b828c0161352c565b9250506101a0613bca8b828c01613556565b9150509295985092959890939650565b600060208284031215613bec57600080fd5b6000613bfa8482850161356b565b91505092915050565b600080600060408486031215613c1857600080fd5b6000613c2686828701613580565b935050602084013567ffffffffffffffff811115613c4357600080fd5b613c4f86828701613595565b92509250509250925092565b600060808284031215613c6d57600080fd5b6000613c7b84828501613609565b91505092915050565b600060208284031215613c9657600080fd5b6000613ca484828501613742565b91505092915050565b600060208284031215613cbf57600080fd5b6000613ccd84828501613757565b91505092915050565b600060208284031215613ce857600080fd5b6000613cf68482850161376c565b91505092915050565b600060208284031215613d1157600080fd5b6000613d1f84828501613781565b91505092915050565b600060208284031215613d3a57600080fd5b6000613d4884828501613796565b91505092915050565b613d5a81614ffd565b82525050565b613d6981614f38565b82525050565b613d80613d7b82614f38565b61513d565b82525050565b613d8f81614f26565b82525050565b613da6613da182614f26565b61512b565b82525050565b613db581614f4a565b82525050565b613dc481614f56565b82525050565b613dd381614f60565b82525050565b613dea613de582614f60565b61514f565b82525050565b6000613dfb82614d02565b613e058185614d18565b9350613e15818560208601615054565b613e1e8161524a565b840191505092915050565b6000613e3482614d02565b613e3e8185614d29565b9350613e4e818560208601615054565b80840191505092915050565b6000613e6582614d0d565b613e6f8185614d34565b9350613e7f818560208601615054565b613e888161524a565b840191505092915050565b6000613ea0601883614d34565b9150613eab826152a9565b602082019050919050565b6000613ec3600583614d45565b9150613ece826152d2565b600582019050919050565b6000613ee6601f83614d34565b9150613ef1826152fb565b602082019050919050565b6000613f09601983614d34565b9150613f1482615324565b602082019050919050565b6000613f2c600283614d34565b9150613f378261534d565b602082019050919050565b6000613f4f600e83614d34565b9150613f5a82615376565b602082019050919050565b6000613f72600e83614d34565b9150613f7d8261539f565b602082019050919050565b6000613f95601283614d34565b9150613fa0826153c8565b602082019050919050565b6000613fb8603a83614d34565b9150613fc3826153f1565b604082019050919050565b6000613fdb602283614d34565b9150613fe682615440565b604082019050919050565b6000613ffe601d83614d34565b91506140098261548f565b602082019050919050565b6000614021602683614d34565b915061402c826154b8565b604082019050919050565b6000614044601683614d34565b915061404f82615507565b602082019050919050565b6000614067600883614d45565b915061407282615530565b600882019050919050565b600061408a600583614d45565b915061409582615559565b600582019050919050565b60006140ad601083614d34565b91506140b882615582565b602082019050919050565b60006140d0601983614d34565b91506140db826155ab565b602082019050919050565b60006140f3600a83614d45565b91506140fe826155d4565b600a82019050919050565b6000614116600083614d29565b9150614121826155fd565b600082019050919050565b6000614139601383614d34565b915061414482615600565b602082019050919050565b600061415c601d83614d34565b915061416782615629565b602082019050919050565b600061417f600e83614d34565b915061418a82615652565b602082019050919050565b60006141a2601483614d34565b91506141ad8261567b565b602082019050919050565b60006141c5602a83614d34565b91506141d0826156a4565b604082019050919050565b60006141e8601683614d34565b91506141f3826156f3565b602082019050919050565b600061420b601f83614d34565b91506142168261571c565b602082019050919050565b600061422e603683614d34565b915061423982615745565b604082019050919050565b61424d81614f8c565b82525050565b61426461425f82614f8c565b615159565b82525050565b6142738161500f565b82525050565b61428281614fa8565b82525050565b61429961429482614fa8565b61516b565b82525050565b6142a881614fd6565b82525050565b6142bf6142ba82614fd6565b61518f565b82525050565b6142d66142d182614fe0565b615199565b82525050565b6142e581614ff0565b82525050565b6142fc6142f782614ff0565b6151ab565b82525050565b600061430e828b613dd9565b60048201915061431e828a613d95565b60148201915061432e8289613d95565b60148201915061433e8288614253565b60108201915061434e8287614288565b60028201915061435e82866142c5565b60048201915061436e82856142eb565b60018201915061437e82846142c5565b6004820191508190509998505050505050505050565b60006143a0828a613dd9565b6004820191506143b08289613d95565b6014820191506143c08288614253565b6010820191506143d08287614288565b6002820191506143e082866142c5565b6004820191506143f082856142eb565b60018201915061440082846142c5565b60048201915081905098975050505050505050565b60006144218284613e29565b915081905092915050565b600061443782613eb6565b91506144438289613d6f565b60148201915061445382886142ae565b60208201915061446382876142ae565b60208201915061447382866142ae565b6020820191506144838285613d95565b60148201915061449382846142ae565b602082019150819050979650505050505050565b60006144b282613eb6565b91506144be8289613d95565b6014820191506144ce82886142ae565b6020820191506144de82876142ae565b6020820191506144ee82866142ae565b6020820191506144fe8285613d95565b60148201915061450e82846142ae565b602082019150819050979650505050505050565b600061452d8261405a565b91506145398289613d95565b60148201915061454982886142ae565b60208201915061455982876142ae565b6020820191506145698286613e29565b91506145758285613d95565b60148201915061458582846142ae565b602082019150819050979650505050505050565b60006145a48261407d565b91506145b0828a613d95565b6014820191506145c082896142ae565b6020820191506145d08288613d95565b6014820191506145e082876142ae565b6020820191506145f082866142ae565b6020820191506146008285613d95565b60148201915061461082846142ae565b60208201915081905098975050505050505050565b6000614630826140e6565b915061463c8289613d95565b60148201915061464c82886142ae565b60208201915061465c82876142ae565b60208201915061466c8286613e29565b91506146788285613d95565b60148201915061468882846142ae565b602082019150819050979650505050505050565b60006146a782614109565b9150819050919050565b60006020820190506146c66000830184613d86565b92915050565b60006060820190506146e16000830186613d60565b6146ee6020830185614279565b6146fb6040830184614244565b949350505050565b60006040820190506147186000830185613d86565b6147256020830184613d86565b9392505050565b60006060820190506147416000830186613d86565b61474e6020830185613d86565b61475b604083018461426a565b949350505050565b60006040820190506147786000830185613d86565b614785602083018461429f565b9392505050565b60006020820190506147a16000830184613dac565b92915050565b60006020820190506147bc6000830184613dbb565b92915050565b60006040820190506147d76000830185613dbb565b6147e46020830184614244565b9392505050565b60006040820190506148006000830185613dbb565b61480d6020830184614279565b9392505050565b60006080820190506148296000830187613dbb565b61483660208301866142dc565b6148436040830185613dbb565b6148506060830184613dbb565b95945050505050565b600060208201905061486e6000830184613dca565b92915050565b6000602082019050818103600083015261488e8184613df0565b905092915050565b600060208201905081810360008301526148b08184613e5a565b905092915050565b600060208201905081810360008301526148d181613e93565b9050919050565b600060208201905081810360008301526148f181613ed9565b9050919050565b6000602082019050818103600083015261491181613efc565b9050919050565b6000602082019050818103600083015261493181613f1f565b9050919050565b6000602082019050818103600083015261495181613f42565b9050919050565b6000602082019050818103600083015261497181613f65565b9050919050565b6000602082019050818103600083015261499181613f88565b9050919050565b600060208201905081810360008301526149b181613fab565b9050919050565b600060208201905081810360008301526149d181613fce565b9050919050565b600060208201905081810360008301526149f181613ff1565b9050919050565b60006020820190508181036000830152614a1181614014565b9050919050565b60006020820190508181036000830152614a3181614037565b9050919050565b60006020820190508181036000830152614a51816140a0565b9050919050565b60006020820190508181036000830152614a71816140c3565b9050919050565b60006020820190508181036000830152614a918161412c565b9050919050565b60006020820190508181036000830152614ab18161414f565b9050919050565b60006020820190508181036000830152614ad181614172565b9050919050565b60006020820190508181036000830152614af181614195565b9050919050565b60006020820190508181036000830152614b11816141b8565b9050919050565b60006020820190508181036000830152614b31816141db565b9050919050565b60006020820190508181036000830152614b51816141fe565b9050919050565b60006020820190508181036000830152614b7181614221565b9050919050565b6000602082019050614b8d6000830184614279565b92915050565b6000606082019050614ba8600083018661429f565b614bb56020830185613d51565b614bc2604083018461429f565b949350505050565b6000608082019050614bdf600083018761429f565b614bec6020830186613d86565b614bf96040830185613d86565b614c06606083018461426a565b95945050505050565b6000608082019050614c24600083018761429f565b614c316020830186613d86565b614c3e6040830185613d86565b614c4b606083018461429f565b95945050505050565b6000614c5e614c6f565b9050614c6a8282615087565b919050565b6000604051905090565b600067ffffffffffffffff821115614c9457614c9361521b565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614cc057614cbf61521b565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614cec57614ceb61521b565b5b614cf58261524a565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000614d5b82614f8c565b9150614d6683614f8c565b925082614d7657614d756151ec565b5b828204905092915050565b6000808291508390505b6001851115614dcb57808604811115614da757614da66151bd565b5b6001851615614db65780820291505b8081029050614dc48561529c565b9450614d8b565b94509492505050565b6000614ddf82614fd6565b9150614dea83614ff0565b9250614e177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484614e1f565b905092915050565b600082614e2f5760019050614eeb565b81614e3d5760009050614eeb565b8160018114614e535760028114614e5d57614e8c565b6001915050614eeb565b60ff841115614e6f57614e6e6151bd565b5b8360020a915084821115614e8657614e856151bd565b5b50614eeb565b5060208310610133831016604e8410600b8410161715614ec15782820a905083811115614ebc57614ebb6151bd565b5b614eeb565b614ece8484846001614d81565b92509050818404811115614ee557614ee46151bd565b5b81810290505b9392505050565b6000614efd82614ff0565b9150614f0883614ff0565b925082821015614f1b57614f1a6151bd565b5b828203905092915050565b6000614f3182614fb6565b9050919050565b6000614f4382614fb6565b9050919050565b60008115159050919050565b6000819050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b60006fffffffffffffffffffffffffffffffff82169050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600063ffffffff82169050919050565b600060ff82169050919050565b600061500882615021565b9050919050565b600061501a82614f8c565b9050919050565b600061502c82615033565b9050919050565b600061503e82614fb6565b9050919050565b82818337600083830152505050565b60005b83811015615072578082015181840152602081019050615057565b83811115615081576000848401525b50505050565b6150908261524a565b810181811067ffffffffffffffff821117156150af576150ae61521b565b5b80604052505050565b60006150c382614fd6565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156150f6576150f56151bd565b5b600182019050919050565b600061510c82614ff0565b915060ff8214156151205761511f6151bd565b5b600182019050919050565b60006151368261517d565b9050919050565b60006151488261517d565b9050919050565b6000819050919050565b60006151648261525b565b9050919050565b600061517682615275565b9050919050565b60006151888261528f565b9050919050565b6000819050919050565b60006151a482615268565b9050919050565b60006151b682615282565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b60008160801b9050919050565b60008160e01b9050919050565b60008160f01b9050919050565b60008160f81b9050919050565b60008160601b9050919050565b60008160011c9050919050565b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b7f4554484552000000000000000000000000000000000000000000000000000000600082015250565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b7f696e76616c6964207369676e617475726573206c656e67746800000000000000600082015250565b7f3136000000000000000000000000000000000000000000000000000000000000600082015250565b7f696e76616c6964207369676e6572000000000000000000000000000000000000600082015250565b7f696e76616c696420616d6f756e74000000000000000000000000000000000000600082015250565b7f6e6f7420616c6c6f776564207369676e65720000000000000000000000000000600082015250565b7f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260008201527f6563697069656e74206d61792068617665207265766572746564000000000000602082015250565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b7f416464726573733a20696e73756666696369656e742062616c616e6365000000600082015250565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b7f696e76616c6964207a6b6c696e6b206164647265737300000000000000000000600082015250565b7f464153542d455448000000000000000000000000000000000000000000000000600082015250565b7f4552433230000000000000000000000000000000000000000000000000000000600082015250565b7f696e76616c696420666565207261746500000000000000000000000000000000600082015250565b7f696e76616c696420616c6c5369676e657273206c656e67746800000000000000600082015250565b7f464153542d455243323000000000000000000000000000000000000000000000600082015250565b50565b7f65787069726564207472616e73616374696f6e00000000000000000000000000600082015250565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b7f7265706561746564206f72646572000000000000000000000000000000000000600082015250565b7f696e76616c696420706172616d7320746f6b656e000000000000000000000000600082015250565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b7f63616e206e6f742062652073616d65207369676e657200000000000000000000600082015250565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60008201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b61579d81614f26565b81146157a857600080fd5b50565b6157b481614f38565b81146157bf57600080fd5b50565b6157cb81614f4a565b81146157d657600080fd5b50565b6157e281614f56565b81146157ed57600080fd5b50565b6157f981614f8c565b811461580457600080fd5b50565b61581081614fa8565b811461581b57600080fd5b50565b61582781614fd6565b811461583257600080fd5b50565b61583e81614fe0565b811461584957600080fd5b50565b61585581614ff0565b811461586057600080fd5b5056fe616363657074455243323028616464726573732c616464726573732c75696e743132382c75696e7431362c75696e7433322c75696e74382c75696e7433322961636365707445544828616464726573732c75696e743132382c75696e7431362c75696e7433322c75696e74382c75696e74333229a2646970667358221220aa9285fa5734a11f2b9c1667756b97daee994b507e09d1d32aa018cf2e55fecb64736f6c63430008020033

Verified Source Code Full Match

Compiler: v0.8.2+commit.661d1103 EVM: istanbul Optimization: No
SafeCast.sol 97 lines
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and then downcasting.
 *
 * _Available since v2.5.0._
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "16");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "17");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "18");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "19");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "1a");
        return uint8(value);
    }
}
IZkLink.sol 97 lines
// SPDX-License-Identifier: MIT OR Apache-2.0

pragma solidity ^0.8.0;

interface IZkLink {

  struct RegisteredToken {
    bool registered; // whether token registered to ZkLink or not, default is false
    bool paused; // whether token can deposit to ZkLink or not, default is false
    address tokenAddress; // the token address
    uint8 decimals; // the token decimals of layer one
  }

  /// @notice Acceptor accept a eth fast withdraw, acceptor will get a fee for profit
  /// @param receiver User receive token from acceptor (the owner of withdraw operation)
  /// @param amount The amount of withdraw operation
  /// @param withdrawFeeRate Fast withdraw fee rate taken by acceptor
  /// @param accountIdOfNonce Account that supply nonce, may be different from accountId
  /// @param subAccountIdOfNonce SubAccount that supply nonce
  /// @param nonce SubAccount nonce, used to produce unique accept info
  function acceptETH(
    address payable receiver,
    uint128 amount,
    uint16 withdrawFeeRate,
    uint32 accountIdOfNonce,
    uint8 subAccountIdOfNonce,
    uint32 nonce
  ) external payable;

  /// @notice Acceptor accept a erc20 token fast withdraw, acceptor will get a fee for profit
  /// @param receiver User receive token from acceptor (the owner of withdraw operation)
  /// @param token Token address
  /// @param amount The amount of withdraw operation
  /// @param withdrawFeeRate Fast withdraw fee rate taken by acceptor
  /// @param accountIdOfNonce Account that supply nonce, may be different from accountId
  /// @param subAccountIdOfNonce SubAccount that supply nonce
  /// @param nonce SubAccount nonce, used to produce unique accept info
  function acceptERC20(
    address receiver,
    address token,
    uint128 amount,
    uint16 withdrawFeeRate,
    uint32 accountIdOfNonce,
    uint8 subAccountIdOfNonce,
    uint32 nonce
  ) external;

  /// @notice Withdraw token to L1 for user by gateway
  /// @param owner User receive token on L1
  /// @param token Token address
  /// @param amount The amount(recovered decimals) of withdraw operation
  /// @param fastWithdrawFeeRate Fast withdraw fee rate taken by acceptor
  /// @param accountIdOfNonce Account that supply nonce, may be different from accountId
  /// @param subAccountIdOfNonce SubAccount that supply nonce
  /// @param nonce SubAccount nonce, used to produce unique accept info
  function withdrawToL1(
    address owner,
    address token,
    uint128 amount,
    uint16 fastWithdrawFeeRate,
    uint32 accountIdOfNonce,
    uint8 subAccountIdOfNonce,
    uint32 nonce
  ) external payable;

  /// @notice A map of registered token infos
  function tokens(
    uint16 tokenId
  ) external view returns (RegisteredToken memory);

  /// @notice A map of registered token infos
  function tokenIds(
    address token
  ) external view returns (uint16 tokenId);

  /// @notice Returns amount of tokens that can be withdrawn by `address` from zkLink contract
  /// @param _address Address of the tokens owner
  /// @param _tokenId Token id
  /// @return The pending balance(without recovery decimals) can be withdrawn
  function getPendingBalance(
    bytes32 _address, 
    uint16 _tokenId
  ) external view returns (uint128);

  /// @notice  Withdraws tokens from zkLink contract to the owner
  /// @param _owner Address of the tokens owner
  /// @param _tokenId Token id
  /// @param _amount Amount to withdraw to request.
  /// @return The actual withdrawn amount
  /// @dev NOTE: We will call ERC20.transfer(.., _amount), but if according to internal logic of ERC20 token zkLink contract
  /// balance will be decreased by value more then _amount we will try to subtract this value from user pending balance
  function withdrawPendingBalance(
    address payable _owner,
    uint16 _tokenId,
    uint128 _amount
  ) external returns (uint128);
}
ZklinkFastPool.sol 457 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

import "../interfaces/IERC1271.sol";
import '../interfaces/IZkLink.sol';
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./SafeCast.sol";

/**
 *
 * ZklinkFastPool
 * ============
 *
 * Basic multi-signer wallet designed for use in a co-signing environment where 2 signatures are require to move funds.
 * Typically used in a 2-of-3 signing configuration. Uses ecrecover to allow for 2 signatures in a single transaction.
 *
 * The signatures are created on the operation hash and passed to withdrawETH/withdrawERC20
 * The signer is determined by ECDSA.recover().
 *
 * The signature is created with ethereumjs-util.ecsign(operationHash).
 * Like the eth_sign RPC call, it packs the values as a 65-byte array of [r, s, v].
 * Unlike eth_sign, the message is not prefixed.
 *
 */
contract ZklinkFastPool is ReentrancyGuard,IERC1271 {
  using SafeERC20 for IERC20;
  using SafeMath for uint256;

  /// @dev When set fee = 100, it means 1%
  uint16 internal constant MAX_ACCEPT_FEE_RATE = 10000;
  uint8 internal constant TOKEN_DECIMALS_OF_LAYER2 = 18;

  bytes4 public constant ACCEPT_ETH =
    bytes4(
      keccak256(bytes('acceptETH(address,uint128,uint16,uint32,uint8,uint32)'))
    );

  bytes4 public constant ACCEPT_ERC20 =
    bytes4(
      keccak256(
        bytes('acceptERC20(address,address,uint128,uint16,uint32,uint8,uint32)')
      )
    );

  // Events
  event WithdrawETH(uint256 orderId, address to, uint256 amount);
  event WithdrawERC20(uint256 orderId, address token, address to, uint256 amount);
  event FastTransferErc20(uint256 orderId, address token, address to, uint256 amount);
  event FastTransferETH(uint256 orderId, address token, address to, uint256 amount);
  event Claim(address token, address to, uint256 amount);

  // Public fields
  address[] public signers;                               // The addresses that can co-sign transactions on the wallet
  mapping(uint256 => order) orders;                       // history orders
  address public ZKLINK_ADDRESS;                          // The address of zklink contract

  IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
  IERC20 private constant ZERO_ADDRESS = IERC20(address(0));

  struct order{
    address to;     // The address the transaction was sent to
    uint256 amount; // Amount of Wei sent to the address
    address token;  // The address of the ERC20 token contract, 0 means ETH
    bool executed;  // If the order was executed
  }

  struct fastParams{
    address receiver;           // User receive token from acceptor (the owner of withdraw operation)
    address token;              // Token address
    uint128 amount;             // The amount of withdraw operation
    uint16 withdrawFeeRate;     // Fast withdraw fee rate taken by acceptor
    uint32 accountIdOfNonce;    // Account that supply nonce
    uint8 subAccountIdOfNonce;  // SubAccount that supply nonce
    uint32 nonce;               // SubAccount nonce, used to produce unique accept info
  }

  /**
   * Set up a simple 2-3 multi-sig wallet by specifying the signers allowed to be used on this wallet.
   * 2 signers will be require to send a transaction from this wallet.
   * Note: The sender is NOT automatically added to the list of signers.
   * Signers CANNOT be changed once they are set
   *
   * @param allowedSigners      An array of signers on the wallet
   * @param zklink             The address of zklink contract
   */
  constructor(address[] memory allowedSigners,address zklink) {
    require(allowedSigners.length == 3, "invalid allSigners length");
    require(allowedSigners[0] != allowedSigners[1], "must be different signers");
    require(allowedSigners[0] != allowedSigners[2], "must be different signers");
    require(allowedSigners[1] != allowedSigners[2], "must be different signers");

    signers = allowedSigners;
    ZKLINK_ADDRESS = zklink;
  }

  /**
   * Gets called when a transaction is received without calling a method
   */
  receive() external payable { }

  fallback() external payable {}

  /**
   * Withdraw ETHER from this wallet using 2 signers.
   *
   * @param  to         the destination address to send an outgoing transaction
   * @param  amount     the amount in Wei to be sent
   * @param  expireTime the number of seconds since 1970 for which this transaction is valid
   * @param  orderId    the unique order id 
   * @param  allSigners all signers who sign the tx
   * @param  signatures the signatures of tx
   */
  function withdrawETH(
    address payable to,
    uint256 amount,
    uint256 expireTime,
    uint256 orderId,
    address[] memory allSigners,
    bytes[] memory signatures
  ) public nonReentrant {
    require(allSigners.length >= 2, "invalid allSigners length");
    require(allSigners.length == signatures.length, "invalid signatures length");
    require(allSigners[0] != allSigners[1],"can not be same signer"); // must be different signer
    require(expireTime >= block.timestamp,"expired transaction");

    bytes32 operationHash = keccak256(abi.encodePacked("ETHER", to, amount, expireTime, orderId, address(this),block.chainid));
    operationHash = ECDSA.toEthSignedMessageHash(operationHash);
    
    for (uint8 index = 0; index < allSigners.length; index++) {
      address signer = ECDSA.recover(operationHash, signatures[index]);
      require(signer == allSigners[index], "invalid signer");
      require(isAllowedSigner(signer), "not allowed signer");
    }

    // Try to insert the order ID. Will revert if the order id was invalid
    tryInsertOrderId(orderId, to, amount, address(0));

    // send ETHER
    require(address(this).balance >= amount, "Address: insufficient balance");
    (bool success, ) = to.call{value: amount}("");
    require(success, "Address: unable to send value, recipient may have reverted");

    emit WithdrawETH(orderId, to, amount);
  }
  
  /**
   * Withdraw ERC20 from this wallet using 2 signers.
   *
   * @param  to         the destination address to send an outgoing transaction
   * @param  amount     the amount in Wei to be sent
   * @param  token      the address of the erc20 token contract
   * @param  expireTime the number of seconds since 1970 for which this transaction is valid
   * @param  orderId    the unique order id 
   * @param  allSigners all signer who sign the tx
   * @param  signatures the signatures of tx
   */
  function withdrawErc20(
    address to,
    uint256 amount,
    address token,
    uint256 expireTime,
    uint256 orderId,
    address[] memory allSigners,
    bytes[] memory signatures
  ) public nonReentrant {
    require(allSigners.length >=2, "invalid allSigners length");
    require(allSigners.length == signatures.length, "invalid signatures length");
    require(allSigners[0] != allSigners[1],"can not be same signer"); // must be different signer
    require(expireTime >= block.timestamp,"expired transaction");

    bytes32 operationHash = keccak256(abi.encodePacked("ERC20", to, amount, token, expireTime, orderId, address(this),block.chainid));
    operationHash = ECDSA.toEthSignedMessageHash(operationHash);

    for (uint8 index = 0; index < allSigners.length; index++) {
      address signer = ECDSA.recover(operationHash, signatures[index]);
      require(signer == allSigners[index], "invalid signer");
      require(isAllowedSigner(signer),"not allowed signer");
    }

    // Try to insert the order ID. Will revert if the order id was invalid
    tryInsertOrderId(orderId, to, amount, token);

    // Success, send ERC20 token
    IERC20(token).safeTransfer(to, amount);
    emit WithdrawERC20(orderId, token, to, amount);
  }

  /**
   * fastTransferErc20 as broker acceptor in zklink
   * 
   * @param  to         the destination address to send an outgoing transaction
   * @param  orderId    the unique order id 
   * @param  expireTime the number of seconds since 1970 for which this transaction is valid
   * @param  params     the fast params
   * @param  transferData  the encode data of acceptERC20 method
   * @param  allSigners all signer who sign the tx
   * @param  signatures the signatures of tx
   * @param  autlClaim  Whether to enable automatic claim
   */
  function fastTransferErc20(
    address to,
    uint256 orderId,
    uint256 expireTime,
    fastParams memory params,
    bytes memory transferData,
    address[] memory allSigners,
    bytes[] memory signatures,
    bool autlClaim
  ) public nonReentrant {
    require(to == ZKLINK_ADDRESS,"invalid zklink address");
    require(allSigners.length >=2, "invalid allSigners length");
    require(allSigners.length == signatures.length, "invalid signatures length");
    require(allSigners[0] != allSigners[1],"can not be same signer"); // must be different signer
    require(expireTime >= block.timestamp,"expired transaction");
    require(params.withdrawFeeRate < MAX_ACCEPT_FEE_RATE, "invalid fee rate");

    bytes32 operationHash = keccak256(abi.encodePacked("FAST-ERC20",to,orderId,expireTime,transferData,address(this),block.chainid));
    operationHash = ECDSA.toEthSignedMessageHash(operationHash);

    for (uint8 index = 0; index < allSigners.length; index++) {
      address signer = ECDSA.recover(operationHash, signatures[index]);
      require(signer == allSigners[index], "invalid signer");
      require(isAllowedSigner(signer),"not allowed signer");
    }

    // Try to insert the order ID. Will revert if the order id was invalid
    tryInsertOrderId(orderId, to, params.amount, params.token);

    // safeApprove requires unsetting the allowance first.
    IERC20(params.token).safeApprove(ZKLINK_ADDRESS, 0);
    IERC20(params.token).safeApprove(ZKLINK_ADDRESS, params.amount);

    // send ERC20
    require(IERC20(params.token).balanceOf(address(this)) >= params.amount, "Address: insufficient balance");
    (bool success, ) = to.call{value: 0}(transferData);
    require(success, "Address: unable to send value, recipient may have reverted");
    
    // event
    emit FastTransferErc20(orderId, params.token, to, params.amount);

    // auto claim
    if (autlClaim){
      uint16 tokenId = IZkLink(to).tokenIds(params.token);
      uint128 pendingBalance = IZkLink(to).getPendingBalance(bytes32(uint256(uint160(address(this)))),tokenId);
      if (pendingBalance > 0 ){
        IZkLink.RegisteredToken memory rt = IZkLink(to).tokens(tokenId);
        uint128 actualPendingBalance = pendingBalance / SafeCast.toUint128((10 ** (TOKEN_DECIMALS_OF_LAYER2 - rt.decimals)));
        IZkLink(to).withdrawPendingBalance(payable(address(this)), tokenId, actualPendingBalance);
        emit Claim(params.token,address(this),actualPendingBalance);
      }
    }
  }

  /**
   * fastTransferETH as broker acceptor in zklink
   * 
   * @param  to         the destination address to send an outgoing transaction
   * @param  orderId    the unique order id 
   * @param  expireTime the number of seconds since 1970 for which this transaction is valid
   * @param  params     the fast params
   * @param  transferData  the encode data of acceptETH method
   * @param  allSigners all signer who sign the tx
   * @param  signatures the signatures of tx
   * @param  autlClaim  Whether to enable automatic claim
   */
  function fastTransferETH(
    address to,
    uint256 orderId,
    uint256 expireTime,
    fastParams memory params,
    bytes memory transferData,
    address[] memory allSigners,
    bytes[] memory signatures,
    bool autlClaim
  ) public nonReentrant {
    require(to == ZKLINK_ADDRESS,"invalid zklink address");
    require(params.token == address(ETH_ADDRESS),"invalid params token");
    require(allSigners.length >=2, "invalid allSigners length");
    require(allSigners.length == signatures.length, "invalid signatures length");
    require(allSigners[0] != allSigners[1],"can not be same signer"); // must be different signer
    require(expireTime >= block.timestamp,"expired transaction");
    require(params.withdrawFeeRate < MAX_ACCEPT_FEE_RATE, "invalid fee rate");

    bytes32 operationHash = keccak256(abi.encodePacked("FAST-ETH",to, orderId, expireTime,transferData, address(this), block.chainid));
    operationHash = ECDSA.toEthSignedMessageHash(operationHash);

    for (uint8 index = 0; index < allSigners.length; index++) {
      address signer = ECDSA.recover(operationHash, signatures[index]);
      require(signer == allSigners[index], "invalid signer");
      require(isAllowedSigner(signer),"not allowed signer");
    }

    // Try to insert the order ID. Will revert if the order id was invalid
    tryInsertOrderId(orderId, to, params.amount, params.token);

    // send ETHER
    require(address(this).balance >= params.amount, "Address: insufficient balance");
    (bool success, ) = to.call{value: params.amount}(transferData);
    require(success, "Address: unable to send value, recipient may have reverted");
    
    // event
    emit FastTransferETH(orderId, params.token, to, params.amount);

    // auto claim
    if (autlClaim){
      uint16 tokenId = IZkLink(to).tokenIds(params.token);
      uint128 pendingBalance = IZkLink(to).getPendingBalance(bytes32(uint256(uint160(address(this)))),tokenId);
      if (pendingBalance > 0){
        IZkLink(to).withdrawPendingBalance(payable(address(this)), tokenId, pendingBalance);
        emit Claim(params.token,address(this),pendingBalance);
      }
    }
  }

  /**
   * claimFromZklink claim tokens from zklink
   *
   * @param  tokenId      the address of the erc20 token contract
   * @param  amount     the amount in Wei to be sent
   */

  function claimFromZklink(
    address owner,
    uint16 tokenId,
    uint128 amount
  ) public nonReentrant {
    uint128 pendingBalance = IZkLink(ZKLINK_ADDRESS).getPendingBalance(bytes32(uint256(uint160(owner))),tokenId);

    IZkLink.RegisteredToken memory rt = IZkLink(ZKLINK_ADDRESS).tokens(tokenId);
    uint128 actualPendingBalance = pendingBalance / SafeCast.toUint128((10 ** (TOKEN_DECIMALS_OF_LAYER2 - rt.decimals)));
    require(amount > 0 && amount <= actualPendingBalance, "invalid amount");

    IZkLink(ZKLINK_ADDRESS).withdrawPendingBalance(payable(owner), tokenId, amount);
    emit Claim(IZkLink(ZKLINK_ADDRESS).tokens(tokenId).tokenAddress,owner,amount);
  }

  /**
   * Determine if an address is a signer on this wallet
   *
   * @param signer address to check
   */
  function isAllowedSigner(address signer) public view returns (bool) {
    // Iterate through all signers on the wallet and
    for (uint i = 0; i < signers.length; i++) {
      if (signers[i] == signer) {
        return true;
      }
    }
    return false;
  }

  /**
   * @notice Verifies that the signer is the owner of the signing contract.
   */
  function isValidSignature(
    bytes32 _hash,
    bytes calldata _signature
  ) external override view returns (bytes4) {
    address signer = ECDSA.recover(_hash, _signature);
    // Validate signatures
    if (signer == signers[0]) {
      return 0x1626ba7e;
    } else {
      return 0xffffffff;
    }
  }

  
  /**
   * Verify that the order id has not been used before and inserts it. Throws if the order ID was not accepted.
   *
   * @param orderId   the unique order id 
   * @param to        the destination address to send an outgoing transaction
   * @param amount     the amount in Wei to be sent
   * @param token     the address of the ERC20 contract
   */
  function tryInsertOrderId(
      uint256 orderId, 
      address to,
      uint256 amount, 
      address token
    ) internal {
    if (orders[orderId].executed) {
        // This order ID has been excuted before. Disallow!
        revert("repeated order");
    }

    orders[orderId].executed = true;
    orders[orderId].to = to;
    orders[orderId].amount = amount;
    orders[orderId].token = token;
  }

  /**
   * calcSigHash is a helper function that to help you generate the sighash needed for withdrawal.
   *
   * @param to          the destination address
   * @param amount       the amount in Wei to be sent
   * @param token       the address of the ERC20 contract
   * @param expireTime  the number of seconds since 1970 for which this transaction is valid
   * @param orderId     the unique order id 
   * @param isFast      If fast withdraw calc sighash
   * @param transferData  the encode data of acceptETH/acceptERC20 method
   */

  function calcSigHash(
    address to,
    uint256 amount,
    address token,
    uint256 expireTime,
    uint256 orderId,
    bool isFast,
    bytes memory transferData
) public view returns (bytes32) {
    bytes32 operationHash;

    if (isFast) {
      if (token == address(ETH_ADDRESS)){
        operationHash = keccak256(abi.encodePacked("FAST-ETH",to, orderId, expireTime,transferData, address(this), block.chainid));
      }else{
        operationHash = keccak256(abi.encodePacked("FAST-ERC20",to,orderId,expireTime,transferData,address(this),block.chainid));
      }
    } else if (token == address(0)) {
      operationHash = keccak256(abi.encodePacked("ETHER", to, amount, expireTime, orderId, address(this),block.chainid));
    } else {
      operationHash = keccak256(abi.encodePacked("ERC20", to, amount, token, expireTime, orderId, address(this),block.chainid));
    }
    return operationHash;
  }

  function calcFastData(
    address token,
    fastParams memory params
   ) public pure returns (bytes memory) {
    if (token == address(ETH_ADDRESS)){
      return abi.encodePacked(ACCEPT_ETH,params.receiver,params.amount,params.withdrawFeeRate,params.accountIdOfNonce,params.subAccountIdOfNonce,params.nonce);
    }

    return abi.encodePacked(ACCEPT_ERC20,params.receiver,params.token,params.amount,params.withdrawFeeRate,params.accountIdOfNonce,params.subAccountIdOfNonce,params.nonce);
  }

   /**
   * Query padding contract address and pendingBalance
   *
   * @param tokenId  the token id in zklink
   */
  function getPendingBalance(uint16 tokenId) public view returns (bytes32,uint128) {
    bytes32 paddingAddress = bytes32(uint256(uint160(address(this))));
    uint128 pendingBalance = IZkLink(ZKLINK_ADDRESS).getPendingBalance(paddingAddress,tokenId);
    return (paddingAddress,pendingBalance);
  }
}
IERC1271.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC1271 {
    function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4 magicValue);
}
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);
        }
    }
}
Strings.sol 85 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}
Math.sol 339 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}
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);
}
SafeMath.sol 215 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}
SignedMath.sol 43 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}
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;
    }
}
ECDSA.sol 217 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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. Compatible with tokens that require the approval to be set to
     * 0 before setting it to a non-zero value.
     */
    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));
    }
}
IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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.
 */
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].
     */
    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);
}

Read Contract

ACCEPT_ERC20 0xf7c2861c → bytes4
ACCEPT_ETH 0x68db450c → bytes4
ZKLINK_ADDRESS 0x174f8305 → address
calcFastData 0xfa2868f3 → bytes
calcSigHash 0x4e87753c → bytes32
getPendingBalance 0xe4859908 → bytes32, uint128
isAllowedSigner 0xcabb9e7a → bool
isValidSignature 0x1626ba7e → bytes4
signers 0x2079fb9a → address

Write Contract 5 functions

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

claimFromZklink 0xf6dc1e24
address owner
uint16 tokenId
uint128 amount
fastTransferETH 0x38b7208b
address to
uint256 orderId
uint256 expireTime
tuple params
bytes transferData
address[] allSigners
bytes[] signatures
bool autlClaim
fastTransferErc20 0x56156481
address to
uint256 orderId
uint256 expireTime
tuple params
bytes transferData
address[] allSigners
bytes[] signatures
bool autlClaim
withdrawETH 0x6b1430d6
address to
uint256 amount
uint256 expireTime
uint256 orderId
address[] allSigners
bytes[] signatures
withdrawErc20 0x1025e095
address to
uint256 amount
address token
uint256 expireTime
uint256 orderId
address[] allSigners
bytes[] signatures

Recent Transactions

No transactions found for this address