Address Contract Verified
Address
0xbDC4Dd4d467e55FA5276925b2f136E75DF3f86f1
Balance
0.000000010 ETH
Nonce
1
Code Size
22797 bytes
Creator
0x1304D7cB...1E9B at tx 0xda76c7e1...e0fef8
Indexed Transactions
0
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
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address