Address Contract Verified
Address
0x739A8F9cB6Ec2B79006554dbc3a42fbF75303d18
Balance
0 ETH
Nonce
4
Code Size
24361 bytes
Creator
0x53B84Cb2...e82f at tx 0x2883f0fd...7e09c8
Indexed Transactions
0
Contract Bytecode
24361 bytes
0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063b156c0b714610046578063efe9ca8514610075578063f63e17c11461008a575b600080fd5b600054610059906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b61008861008336600461022b565b61009d565b005b61008861009836600461024d565b610140565b600080546040516001600160a01b039091169083906100bb906101f5565b6001600160a01b03928316815291166020820152604001604051809103906000f0801580156100ee573d6000803e3d6000fd5b50604080516001600160a01b03838116825285166020820152428183015290519192507febfd4a4c376936a8c8644a47eb647339ee696b4d5d0e6bb12d1fb585a13258e9919081900360600190a15050565b600080546040516001600160a01b039091169085908590859061016290610202565b6001600160a01b03948516815293909216602084015260408301526060820152608001604051809103906000f0801580156101a1573d6000803e3d6000fd5b50604080516001600160a01b03838116825287166020820152428183015290519192507f888f92d3aa24b7e4b3ee63a0e9cf8a5f4a5aa97b3e11610b6c113bfc674defeb919081900360600190a150505050565b61422c8061028183390190565b611a47806144ad83390190565b80356001600160a01b038116811461022657600080fd5b919050565b60006020828403121561023d57600080fd5b6102468261020f565b9392505050565b60008060006060848603121561026257600080fd5b61026b8461020f565b9560208501359550604090940135939250505056fe60806040523480156200001157600080fd5b506040516200422c3803806200422c83398101604081905262000034916200030c565b6001600160a01b038216158015906200005557506001600160a01b03811615155b620000a65760405162461bcd60e51b815260206004820152601460248201527f496e76616c6964205a65726f2041646472657373000000000000000000000000604482015260640160405180910390fd5b600380546001600160a01b038084166001600160a01b031992831681179093556001805491861691909216179055604080516306fdde0360e01b815290518392916306fdde039160048083019260009291908290030181865afa15801562000112573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200013c919081019062000380565b6040516020016200014e919062000438565b604051602081830303815290604052826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200019c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001c6919081019062000380565b604051602001620001d891906200046a565b604051602081830303815290604052836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000226573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200024c919062000497565b6040516200025a90620002e1565b620002699493929190620004f1565b604051809103906000f08015801562000286573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b039290921691821790556040519081527f89108c0f3fc085cbf58988ad77d3a1fd3edd62890facb64482f5b6db31ea995f9060200160405180910390a1505062000540565b61182f80620029fd83390190565b80516001600160a01b03811681146200030757600080fd5b919050565b600080604083850312156200032057600080fd5b6200032b83620002ef565b91506200033b60208401620002ef565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620003775781810151838201526020016200035d565b50506000910152565b6000602082840312156200039357600080fd5b81516001600160401b0380821115620003ab57600080fd5b818401915084601f830112620003c057600080fd5b815181811115620003d557620003d562000344565b604051601f8201601f19908116603f0116810190838211818310171562000400576200040062000344565b816040528281528760208487010111156200041a57600080fd5b6200042d8360208301602088016200035a565b979650505050505050565b674c70546f6b656e2d60c01b8152600082516200045d8160088501602087016200035a565b9190910160080192915050565b624c502d60e81b8152600082516200048a8160038501602087016200035a565b9190910160030192915050565b600060208284031215620004aa57600080fd5b815160ff81168114620004bc57600080fd5b9392505050565b60008151808452620004dd8160208601602086016200035a565b601f01601f19169290920160200192915050565b6001600160a01b03851681526080602082018190526000906200051790830186620004c3565b82810360408401526200052b8186620004c3565b91505060ff8316606083015295945050505050565b6124ad80620005506000396000f3fe608060405234801561001057600080fd5b50600436106101725760003560e01c80637856a353116100de578063a743d8c011610097578063d250496c11610071578063d250496c14610340578063e2bbb15814610360578063fc0c546a14610373578063fd0a0b151461038657600080fd5b8063a743d8c0146102fc578063c4bef1671461030f578063c5db1dde1461033757600080fd5b80637856a3531461028a5780637cbc23731461029d5780638870455f146102b0578063983d95ce146102c35780639bc62245146102d6578063a7076b36146102e957600080fd5b806325f63b541161013057806325f63b54146101fe578063375b74c31461021e5780633e0a5d0914610249578063510c82b3146102515780635fcbd2851461026457806370c489ef1461027757600080fd5b8062350e7f1461017757806305436d15146101a0578063089cdd0c146101b85780631764f236146101c157806322637940146101d657806322e07352146101f6575b600080fd5b61018a6101853660046120d7565b610390565b6040516101979190612114565b60405180910390f35b6101aa6202a30081565b604051908152602001610197565b6101aa60065481565b6101d46101cf366004612176565b6104b0565b005b6101e96101e43660046120d7565b6104c9565b60405161019791906121c6565b600d546101aa565b6101aa61020c366004612245565b60096020526000908152604090205481565b600454610231906001600160a01b031681565b6040516001600160a01b039091168152602001610197565b600b546101aa565b6101d461025f366004612245565b610607565b600254610231906001600160a01b031681565b6101d46102853660046120d7565b6107d3565b6101d4610298366004612245565b610817565b6101d46102ab366004612262565b610969565b600154610231906001600160a01b031681565b6101d46102d13660046120d7565b610974565b6101d46102e4366004612245565b6109b4565b6101aa6102f7366004612284565b610b01565b6101d461030a366004612245565b610bc4565b61032261031d366004612284565b610dbc565b60408051928352602083019190915201610197565b6101aa60005481565b6101aa61034e366004612245565b60086020526000908152604090205481565b6101d461036e366004612262565b610e94565b600354610231906001600160a01b031681565b6101aa624f1a0081565b60606000825167ffffffffffffffff8111156103ae576103ae612026565b60405190808252806020026020018201604052801561040c57816020015b6103f9604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b8152602001906001900390816103cc5790505b50905060005b83518110156104a957600a6000858381518110610431576104316122d4565b6020908102919091018101518252818101929092526040908101600020815160608101835281546001600160a01b031681526001820154938101939093526002015490820152825183908390811061048b5761048b6122d4565b602002602001018190525080806104a190612300565b915050610412565b5092915050565b6104b9816107d3565b6104c4338484610e9f565b505050565b60606000825167ffffffffffffffff8111156104e7576104e7612026565b60405190808252806020026020018201604052801561055357816020015b6105406040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816105055790505b50905060005b83518110156104a957600c6000858381518110610578576105786122d4565b6020908102919091018101518252818101929092526040908101600020815160a08101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260040154608082015282518390839081106105e9576105e96122d4565b602002602001018190525080806105ff90612300565b915050610559565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106749190612319565b6001600160a01b0316146106a35760405162461bcd60e51b815260040161069a90612336565b60405180910390fd5b6005546001600160a01b038281169116146107005760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420437573746f6469616e204164647265737300000000000000604482015260640161069a565b426202a3006000546107129190612363565b11156107605760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e742057616974696e672054696d6500000000000000604482015260640161069a565b6004546005546040517fd0db98814986e26fb56ed4ba7bd4cdb4bc68f5471c86e4fb372aef6c43be1703926107a69233926001600160a01b039283169290911690612376565b60405180910390a150600554600480546001600160a01b0319166001600160a01b03909216919091179055565b60005b8151811015610813576108018282815181106107f4576107f46122d4565b6020026020010151611327565b8061080b81612300565b9150506107d6565b5050565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108849190612319565b6001600160a01b0316146108aa5760405162461bcd60e51b815260040161069a90612336565b60075460ff16156108f35760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e48125b9a5d1a585b1a5e9959606a1b604482015260640161069a565b6007805460ff191660011790556004546040517fd0db98814986e26fb56ed4ba7bd4cdb4bc68f5471c86e4fb372aef6c43be17039161093f9133916001600160a01b0316908590612376565b60405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b610813338383610e9f565b60005b8151811015610813576109a2828281518110610995576109956122d4565b6020026020010151611517565b806109ac81612300565b915050610977565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa1580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a219190612319565b6001600160a01b031614610a475760405162461bcd60e51b815260040161069a90612336565b6001600160a01b038116610a945760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964205a65726f204164647265737360601b604482015260640161069a565b6005546040517ffdf466e06a1186bd2e3fbcbfba4810e434e9e196de25e5e29d7bcc38bea4b07891610ad39133916001600160a01b0316908590612376565b60405180910390a1600580546001600160a01b0319166001600160a01b039290921691909117905542600055565b6001600160a01b038216600090815260096020526040812054815b8351811015610bba576000600a6000868481518110610b3d57610b3d6122d4565b6020908102919091018101518252818101929092526040908101600020815160608101835281546001600160a01b0390811680835260018401549583019590955260029092015492810192909252909250871603610ba7576020810151610ba49084612363565b92505b5080610bb281612300565b915050610b1c565b5090505b92915050565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c319190612319565b6001600160a01b031614610c575760405162461bcd60e51b815260040161069a90612336565b6001600160a01b038116610ca45760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964205a65726f204164647265737360601b604482015260640161069a565b6001546040517ff1237c4484b1216b734487b31c22619eabadf16f655c110b807119b914fff22691610ce39133916001600160a01b0316908590612376565b60405180910390a1600180546001600160a01b0319166001600160a01b03831690811790915560408051638da5cb5b60e01b8152905160009291638da5cb5b9160048083019260209291908290030181865afa158015610d47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6b9190612319565b6001600160a01b031603610db95760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964204f776e6572204164647265737360581b604482015260640161069a565b50565b60008060008060005b8551811015610e88576000600c6000888481518110610de657610de66122d4565b6020908102919091018101518252818101929092526040908101600020815160a08101835281546001600160a01b039081168083526001840154958301959095526002830154938201939093526003820154606082015260049091015460808201529250891603610e75576040810151610e609084612363565b9250806020015184610e729190612363565b93505b5080610e8081612300565b915050610dc5565b50909590945092505050565b610813338383611853565b610ea7611d66565b6001600160a01b038316600090815260096020526040902054821115610f0f5760405162461bcd60e51b815260206004820152601c60248201527f417661696c61626c652062616c616e6365206e6f7420656e6f75676800000000604482015260640161069a565b6002546040516303d1689d60e11b8152600481018490526000916001600160a01b0316906307a2d13a90602401602060405180830381865afa158015610f59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7d9190612399565b905081811015610fc45760405162461bcd60e51b815260206004820152601260248201527120b9b9b2ba1030b6b7bab73a1032b93937b960711b604482015260640161069a565b6001600160a01b03841660009081526009602052604081208054859290610fec9084906123b2565b909155505060025460405163b390c0ab60e01b815260048101859052600060248201526001600160a01b039091169063b390c0ab90604401600060405180830381600087803b15801561103e57600080fd5b505af1158015611052573d6000803e3d6000fd5b5050505061105e611d9e565b7ffb0aec119cd63b2a545926384480162cb277b4ed052310c39da3b670d2ab408e858386600260009054906101000a90046001600160a01b03166001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f99190612399565b600d54600160009054906101000a90046001600160a01b03166001600160a01b0316636e6cc20d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111739190612399565b600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ea9190612399565b426040516111ff9897969594939291906123c5565b60405180910390a26040518060a00160405280856001600160a01b03168152602001828152602001848152602001600260009054906101000a90046001600160a01b03166001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190612399565b815260200142815250600c60006112b9611db8565b81526020808201929092526040908101600020835181546001600160a01b0319166001600160a01b03909116178155918301516001830155820151600282015560608201516003820155608090910151600490910155506104c4600160008051602061245883398151915255565b61132f611d66565b6000818152600a6020908152604091829020825160608101845281546001600160a01b03908116825260018084015483860152600290930154828601529154845163f0dfeab760e01b8152945191944294919093169263f0dfeab792600480830193928290030181865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190612399565b82604001516113de9190612363565b11156114235760405162461bcd60e51b8152602060048201526014602482015273098dec6d640e8d2daca40dcdee840cadcdeeaced60631b604482015260640161069a565b80602001516000036114355750611500565b8051602080830151604080516001600160a01b03909416845291830152429082015282907f6620c2a607a07fb3d5b7449d56a4140f5bfe8bf551b92c45af5faf395e260d6b9060600160405180910390a260208082015182516001600160a01b031660009081526009909252604082208054919290916114b6908490612363565b909155505060006020828101828152848352600a909152604091829020835181546001600160a01b0319166001600160a01b03909116178155905160018201559101516002909101555b610db9600160008051602061245883398151915255565b61151f611d66565b6000818152600c60209081526040808320815160a08101835281546001600160a01b03908116825260018084015483870152600284015483860152600384015460608401526004938401546080840152548451636e6cc20d60e01b81529451929695911693636e6cc20d9381810193918290030181865afa1580156115a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cc9190612399565b9050624f1a008111156115df5750624f1a005b428183608001516115f09190612363565b11156116355760405162461bcd60e51b8152602060048201526014602482015273098dec6d640e8d2daca40dcdee840cadcdeeaced60631b604482015260640161069a565b8160400151600003611648575050611500565b81516020830151600354611667926001600160a01b0390911691611ddd565b61166f611d9e565b7ff041d18460e8444b78f944ad4de3c6cf13f1912a1eb46f4c8de656fb627b47338360000151846020015185604001518660600151600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171b9190612399565b604080516001600160a01b039096168652602086019490945292840191909152606083015260808201524260a082015260c00160405180910390a2815160408084015181516001600160a01b0390931683526020830152429082015283907f2723d816727813c693c68fadd143360e52698101b43f5b167544b88dd58f7da29060600160405180910390a260408083015183516001600160a01b0316600090815260086020529182208054919290916117d59084906123b2565b9091555050600060408381018281526020808601848152878552600c90915291909220845181546001600160a01b0319166001600160a01b0390911617815590516001820155905160028201556060830151600382015560809092015160049092019190915550610db9600160008051602061245883398151915255565b61185b611d66565b60015460405163ef1e1bed60e01b81523060048201526001600160a01b039091169063ef1e1bed90602401602060405180830381865afa1580156118a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c79190612399565b8210156119165760405162461bcd60e51b815260206004820152601860248201527f4465706f73697420616d6f756e7420746f6f20736d616c6c0000000000000000604482015260640161069a565b6004546001600160a01b031661196e5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420637573746f6469616e204164647265737300000000000000604482015260640161069a565b600354600480546040516370a0823160e01b81526001600160a01b039182169281019290925260009216906370a0823190602401602060405180830381865afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e39190612399565b600454600354919250611a05916001600160a01b039081169187911686611e3c565b600354600480546040516370a0823160e01b81526001600160a01b039182169281019290925260009216906370a0823190602401602060405180830381865afa158015611a56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7a9190612399565b9050611a8682826123b2565b600254604051630d9778e560e11b815260048101839052602481018690529195506000916001600160a01b0390911690631b2ef1ca906044016020604051808303816000875af1158015611ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b029190612399565b6001600160a01b038716600090815260086020526040812080549293508392909190611b2f908490612363565b90915550611b3d9050611d9e565b7f71763977f5ea6af2ea4e5ba0bcf8dfba8fad9773fe36cd941d09dc757ce8df15878784600260009054906101000a90046001600160a01b03166001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd89190612399565b600b54600160009054906101000a90046001600160a01b03166001600160a01b031663f0dfeab76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c529190612399565b600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc99190612399565b42604051611cde9897969594939291906123c5565b60405180910390a26040518060600160405280876001600160a01b0316815260200182815260200142815250600a6000611d16611e7b565b81526020808201929092526040908101600020835181546001600160a01b0319166001600160a01b039091161781559183015160018301559190910151600290910155506104c49150611dc99050565b600080516020612458833981519152805460011901611d9857604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6006805460009182611daf83612300565b91905055905090565b600d805460009182611daf83612300565b600160008051602061245883398151915255565b6040516001600160a01b038381166024830152604482018390526104c491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611e8c565b6040516001600160a01b038481166024830152838116604483015260648201839052611e759186918216906323b872dd90608401611e0a565b50505050565b600b805460009182611daf83612300565b6000611ea16001600160a01b03841683611eef565b90508051600014158015611ec6575080806020019051810190611ec49190612406565b155b156104c457604051635274afe760e01b81526001600160a01b038416600482015260240161069a565b6060611efd83836000611f04565b9392505050565b606081471015611f295760405163cd78605960e01b815230600482015260240161069a565b600080856001600160a01b03168486604051611f459190612428565b60006040518083038185875af1925050503d8060008114611f82576040519150601f19603f3d011682016040523d82523d6000602084013e611f87565b606091505b5091509150611f97868383611fa1565b9695505050505050565b606082611fb657611fb182611ffd565b611efd565b8151158015611fcd57506001600160a01b0384163b155b15611ff657604051639996b31560e01b81526001600160a01b038516600482015260240161069a565b5080611efd565b80511561200d5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261204d57600080fd5b8135602067ffffffffffffffff8083111561206a5761206a612026565b8260051b604051601f19603f8301168101818110848211171561208f5761208f612026565b6040529384528581018301938381019250878511156120ad57600080fd5b83870191505b848210156120cc578135835291830191908301906120b3565b979650505050505050565b6000602082840312156120e957600080fd5b813567ffffffffffffffff81111561210057600080fd5b61210c8482850161203c565b949350505050565b602080825282518282018190526000919060409081850190868401855b8281101561216957815180516001600160a01b0316855286810151878601528501518585015260609093019290850190600101612131565b5091979650505050505050565b60008060006060848603121561218b57600080fd5b8335925060208401359150604084013567ffffffffffffffff8111156121b057600080fd5b6121bc8682870161203c565b9150509250925092565b602080825282518282018190526000919060409081850190868401855b8281101561216957815180516001600160a01b0316855286810151878601528581015186860152606080820151908601526080908101519085015260a090930192908501906001016121e3565b6001600160a01b0381168114610db957600080fd5b60006020828403121561225757600080fd5b8135611efd81612230565b6000806040838503121561227557600080fd5b50508035926020909101359150565b6000806040838503121561229757600080fd5b82356122a281612230565b9150602083013567ffffffffffffffff8111156122be57600080fd5b6122ca8582860161203c565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612312576123126122ea565b5060010190565b60006020828403121561232b57600080fd5b8151611efd81612230565b60208082526013908201527221b0b63632b91034b9903737ba1037bbb732b960691b604082015260600190565b80820180821115610bbe57610bbe6122ea565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6000602082840312156123ab57600080fd5b5051919050565b81810381811115610bbe57610bbe6122ea565b6001600160a01b03989098168852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60006020828403121561241857600080fd5b81518015158114611efd57600080fd5b6000825160005b81811015612449576020818601810151858301520161242f565b50600092019182525091905056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212206193b4672e07940fd1258b29059bd009d55f919ad21d0d44f2a15f5608bdab1f64736f6c6343000814003360a060405260146007553480156200001657600080fd5b506040516200182f3803806200182f83398101604081905262000039916200017f565b82828260036200004a8482620002b2565b506004620000598382620002b2565b50600580546001600160a01b03891660805260ff929092166001600160a81b03199092169190911761010033021790555062000099905081600a62000493565b6006556009805460ff191660ff9290921691909117905550620004ab915050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620000e257600080fd5b81516001600160401b0380821115620000ff57620000ff620000ba565b604051601f8301601f19908116603f011681019082821181831017156200012a576200012a620000ba565b816040528381526020925086838588010111156200014757600080fd5b600091505b838210156200016b57858201830151818301840152908201906200014c565b600093810190920192909252949350505050565b600080600080608085870312156200019657600080fd5b84516001600160a01b0381168114620001ae57600080fd5b60208601519094506001600160401b0380821115620001cc57600080fd5b620001da88838901620000d0565b94506040870151915080821115620001f157600080fd5b506200020087828801620000d0565b925050606085015160ff811681146200021857600080fd5b939692955090935050565b600181811c908216806200023857607f821691505b6020821081036200025957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002ad57600081815260208120601f850160051c81016020861015620002885750805b601f850160051c820191505b81811015620002a95782815560010162000294565b5050505b505050565b81516001600160401b03811115620002ce57620002ce620000ba565b620002e681620002df845462000223565b846200025f565b602080601f8311600181146200031e5760008415620003055750858301515b600019600386901b1c1916600185901b178555620002a9565b600085815260208120601f198616915b828110156200034f578886015182559484019460019091019084016200032e565b50858210156200036e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620003d5578160001904821115620003b957620003b96200037e565b80851615620003c757918102915b93841c939080029062000399565b509250929050565b600082620003ee575060016200048d565b81620003fd575060006200048d565b8160018114620004165760028114620004215762000441565b60019150506200048d565b60ff8411156200043557620004356200037e565b50506001821b6200048d565b5060208310610133831016604e8410600b841016171562000466575081810a6200048d565b62000472838362000394565b80600019048211156200048957620004896200037e565b0290505b92915050565b6000620004a460ff841683620003dd565b9392505050565b608051611368620004c7600039600061021701526113686000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80637ddf9cd1116100c3578063b390c0ab1161007c578063b390c0ab146102e9578063c5849de6146102fc578063c6e6f59214610309578063dc5550901461031c578063dd62ed3e14610325578063fbfa77cf1461035e57600080fd5b80637ddf9cd1146102965780638d6cc56d146102a957806395d89b41146102bc578063a035b1fe146102c4578063a9059cbb146102cd578063b05f233a146102e057600080fd5b80632a1bab73116101155780632a1bab73146101ed578063313ce567146101f657806338d52e0f146102155780634b761cc21461024f578063611fb8441461025857806370a082311461026d57600080fd5b806306fdde031461015d57806307a2d13a1461017b578063095ea7b31461019c57806318160ddd146101bf5780631b2ef1ca146101c757806323b872dd146101da575b600080fd5b610165610376565b6040516101729190611008565b60405180910390f35b61018e610189366004611056565b610408565b604051908152602001610172565b6101af6101aa366004611087565b610439565b6040519015158152602001610172565b60025461018e565b61018e6101d53660046110b3565b610451565b6101af6101e83660046110d5565b610547565b61018e60075481565b6005546102039060ff1681565b60405160ff9091168152602001610172565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610172565b61018e61a8c081565b61026b610266366004611056565b61056b565b005b61018e61027b366004611116565b6001600160a01b031660009081526020819052604090205490565b61026b6102a4366004611056565b61071b565b61026b6102b7366004611056565b61097b565b610165610b33565b61018e60065481565b6101af6102db366004611087565b610b42565b61018e6103e881565b61026b6102f73660046110b3565b610b50565b6009546102039060ff1681565b61018e610317366004611056565b610c42565b61018e60085481565b61018e61033336600461113a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6005546102379061010090046001600160a01b031681565b60606003805461038590611173565b80601f01602080910402602001604051908101604052809291908181526020018280546103b190611173565b80156103fe5780601f106103d3576101008083540402835291602001916103fe565b820191906000526020600020905b8154815290600101906020018083116103e157829003601f168201915b5050505050905090565b60095460009061041c9060ff16600a6112a7565b60065461042990846112b6565b61043391906112cd565b92915050565b600033610447818585610c64565b5060019392505050565b600061045b610c76565b60055461010090046001600160a01b031633146104b55760405162461bcd60e51b815260206004820152601360248201527210d85b1b195c881a5cc81b9bdd081d985d5b1d606a1b60448201526064015b60405180910390fd5b60006104c084610c42565b9050828110156105125760405162461bcd60e51b815260206004820152601a60248201527f496e73756666696369656e74206f75747075742073686172657300000000000060448201526064016104ac565b61051c3082610cc0565b905061043360017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b600033610555858285610cf6565b610560858585610d74565b506001949350505050565b60055460408051638870455f60e01b81529051339261010090046001600160a01b031691638870455f9160048083019260209291908290030181865afa1580156105b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105dd91906112ef565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561061a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063e91906112ef565b6001600160a01b03161461068a5760405162461bcd60e51b815260206004820152601360248201527221b0b63632b91034b9903737ba1037bbb732b960691b60448201526064016104ac565b60008111801561069c57506103e88111155b6106da5760405162461bcd60e51b815260206004820152600f60248201526e2232bb34b0ba34b7b71022b93937b960891b60448201526064016104ac565b60075460408051918252602082018390527f1110b6d249864c75ab19175957f6f191ef83858b7f108cb5430dadda15190cb4910160405180910390a1600755565b60055460408051638870455f60e01b81529051339261010090046001600160a01b031691638870455f9160048083019260209291908290030181865afa158015610769573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078d91906112ef565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ee91906112ef565b6001600160a01b03161461083a5760405162461bcd60e51b815260206004820152601360248201527221b0b63632b91034b9903737ba1037bbb732b960691b60448201526064016104ac565b61a8c06008544261084b919061130c565b1161088b5760405162461bcd60e51b815260206004820152601060248201526f2ab83230ba32aa34b6b29022b93937b960811b60448201526064016104ac565b4260085560006127106108a06103e88261131f565b6006546108ad91906112b6565b6108b791906112cd565b905060006127106108ca6103e88261130c565b6006546108d791906112b6565b6108e191906112cd565b90508083101580156108f35750818311155b6109305760405162461bcd60e51b815260206004820152600e60248201526d141c9a58d948195e18d95959195960921b60448201526064016104ac565b60065460408051338152602081019290925281018490527f7c3bda8adcb9df1edd0059da351d966538bcc99f067c0770872170ac97fb68879060600160405180910390a15050600655565b60055460408051638870455f60e01b81529051339261010090046001600160a01b031691638870455f9160048083019260209291908290030181865afa1580156109c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ed91906112ef565b6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4e91906112ef565b6001600160a01b031614610a9c5760405162461bcd60e51b815260206004820152601560248201527421b0b63632b91034b9903737ba1036b0b730b3b2b960591b60448201526064016104ac565b61a8c060085442610aad919061130c565b11610aed5760405162461bcd60e51b815260206004820152601060248201526f2ab83230ba32aa34b6b29022b93937b960811b60448201526064016104ac565b4260085560075460009061271090610b05908261131f565b600654610b1291906112b6565b610b1c91906112cd565b905060006127106007546127106108ca919061130c565b60606004805461038590611173565b600033610447818585610d74565b610b58610c76565b60055461010090046001600160a01b03163314610bad5760405162461bcd60e51b815260206004820152601360248201527210d85b1b195c881a5cc81b9bdd081d985d5b1d606a1b60448201526064016104ac565b6000610bb883610408565b905081811015610c0a5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e74206f75747075742061737365740000000000000060448201526064016104ac565b610c143084610dd3565b50610c3e60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b60065460095460009190610c5a9060ff16600a6112a7565b61042990846112b6565b610c718383836001610e09565b505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901610cba57604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6001600160a01b038216610cea5760405163ec442f0560e01b8152600060048201526024016104ac565b610c3e60008383610ede565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610d6e5781811015610d5f57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016104ac565b610d6e84848484036000610e09565b50505050565b6001600160a01b038316610d9e57604051634b637e8f60e11b8152600060048201526024016104ac565b6001600160a01b038216610dc85760405163ec442f0560e01b8152600060048201526024016104ac565b610c71838383610ede565b6001600160a01b038216610dfd57604051634b637e8f60e11b8152600060048201526024016104ac565b610c3e82600083610ede565b6001600160a01b038416610e335760405163e602df0560e01b8152600060048201526024016104ac565b6001600160a01b038316610e5d57604051634a1406b160e11b8152600060048201526024016104ac565b6001600160a01b0380851660009081526001602090815260408083209387168352929052208290558015610d6e57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610ed091815260200190565b60405180910390a350505050565b6001600160a01b038316610f09578060026000828254610efe919061131f565b90915550610f7b9050565b6001600160a01b03831660009081526020819052604090205481811015610f5c5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016104ac565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216610f9757600280548290039055610fb6565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610ffb91815260200190565b60405180910390a3505050565b600060208083528351808285015260005b8181101561103557858101830151858201604001528201611019565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561106857600080fd5b5035919050565b6001600160a01b038116811461108457600080fd5b50565b6000806040838503121561109a57600080fd5b82356110a58161106f565b946020939093013593505050565b600080604083850312156110c657600080fd5b50508035926020909101359150565b6000806000606084860312156110ea57600080fd5b83356110f58161106f565b925060208401356111058161106f565b929592945050506040919091013590565b60006020828403121561112857600080fd5b81356111338161106f565b9392505050565b6000806040838503121561114d57600080fd5b82356111588161106f565b915060208301356111688161106f565b809150509250929050565b600181811c9082168061118757607f821691505b6020821081036111a757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156111fe5781600019048211156111e4576111e46111ad565b808516156111f157918102915b93841c93908002906111c8565b509250929050565b60008261121557506001610433565b8161122257506000610433565b816001811461123857600281146112425761125e565b6001915050610433565b60ff841115611253576112536111ad565b50506001821b610433565b5060208310610133831016604e8410600b8410161715611281575081810a610433565b61128b83836111c3565b806000190482111561129f5761129f6111ad565b029392505050565b600061113360ff841683611206565b8082028115828204841417610433576104336111ad565b6000826112ea57634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561130157600080fd5b81516111338161106f565b81810381811115610433576104336111ad565b80820180821115610433576104336111ad56fea2646970667358221220550135780502e17c899dbca0f95c452ce5b7b406ed7b550f17461569255bf23464736f6c6343000814003360806040523480156200001157600080fd5b5060405162001a4738038062001a47833981016040819052620000349162000102565b6001600160a01b038416158015906200005557506001600160a01b03831615155b620000a65760405162461bcd60e51b815260206004820152601460248201527f496e76616c6964205a65726f2041646472657373000000000000000000000000604482015260640160405180910390fd5b600080546001600160a01b039586166001600160a01b03199182161790915560018054949095169316929092179092556004919091556005556200014a565b80516001600160a01b0381168114620000fd57600080fd5b919050565b600080600080608085870312156200011957600080fd5b6200012485620000e5565b93506200013460208601620000e5565b6040860151606090960151949790965092505050565b6118ed806200015a6000396000f3fe608060405234801561001057600080fd5b506004361061012b5760003560e01c806394409a56116100ad578063e5afa56611610071578063e5afa56614610265578063fa78668f14610285578063fb011b3e1461028f578063fbfa4e11146102a2578063fc0c546a146102b557600080fd5b806394409a5614610210578063a7076b3614610219578063a743d8c01461022c578063b6b55f251461023f578063c125e0d61461025257600080fd5b806347cb5c8a116100f457806347cb5c8a14610196578063614200aa1461019f57806370c489ef146101b257806377922249146101c55780638870455f146101e557600080fd5b8062350e7f14610130578063089cdd0c146101595780630d668087146101705780632e1a7d4d146101795780633e0a5d091461018e575b600080fd5b61014361013e3660046115cc565b6102c8565b6040516101509190611609565b60405180910390f35b61016260035481565b604051908152602001610150565b61016260045481565b61018c61018736600461166b565b6103e8565b005b600954610162565b61016260055481565b61018c6101ad366004611684565b6103f5565b61018c6101c03660046115cc565b61040c565b6101626101d33660046116e0565b60076020526000908152604090205481565b6000546101f8906001600160a01b031681565b6040516001600160a01b039091168152602001610150565b61016260025481565b6101626102273660046116fd565b61044c565b61018c61023a3660046116e0565b610506565b61018c61024d36600461166b565b610705565b61018c61026036600461166b565b61070f565b6101626102733660046116e0565b60066020526000908152604090205481565b61016262ed4e0081565b61018c61029d366004611737565b6107e3565b61018c6102b036600461166b565b610a2c565b6001546101f8906001600160a01b031681565b60606000825167ffffffffffffffff8111156102e6576102e661151b565b60405190808252806020026020018201604052801561034457816020015b610331604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b8152602001906001900390816103045790505b50905060005b83518110156103e1576008600085838151811061036957610369611778565b6020908102919091018101518252818101929092526040908101600020815160608101835281546001600160a01b03168152600182015493810193909352600201549082015282518390839081106103c3576103c3611778565b602002602001018190525080806103d9906117a4565b91505061034a565b5092915050565b6103f23382610b47565b50565b6103fe8161040c565b6104083383610b47565b5050565b60005b81518110156104085761043a82828151811061042d5761042d611778565b6020026020010151610d34565b80610444816117a4565b91505061040f565b6001600160a01b038216600090815260076020526040812054815b83518110156104fc5760006008600086848151811061048857610488611778565b6020908102919091018101518252818101929092526040908101600020815160608101835281546001600160a01b0390811680835260018401549583019590955260029092015492810192909252909250871690036104e957806020015192505b50806104f4816117a4565b915050610467565b5090505b92915050565b60005460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa15801561054f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057391906117bd565b6001600160a01b0316146105a25760405162461bcd60e51b8152600401610599906117da565b60405180910390fd5b6001600160a01b0381166105ef5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964205a65726f204164647265737360601b6044820152606401610599565b600054604080513381526001600160a01b03928316602082015291831682820152517ff1237c4484b1216b734487b31c22619eabadf16f655c110b807119b914fff2269181900360600190a1600080546001600160a01b0319166001600160a01b038316908117825560408051638da5cb5b60e01b81529051638da5cb5b916004808201926020929091908290030181865afa158015610693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b791906117bd565b6001600160a01b0316036103f25760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964204f776e6572204164647265737360581b6044820152606401610599565b6103f23382610ed7565b60005460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077c91906117bd565b6001600160a01b0316146107a25760405162461bcd60e51b8152600401610599906117da565b60055460408051918252602082018390527f010ac0d049278e70f6c494bd4d7245f2328893b011594ababa4e1f41eb8a8b14910160405180910390a1600555565b60005460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa15801561082c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085091906117bd565b6001600160a01b0316146108765760405162461bcd60e51b8152600401610599906117da565b6001546001600160a01b0380841691160361094e576002546001546040516370a0823160e01b81523060048201528392916001600160a01b0316906370a0823190602401602060405180830381865afa1580156108d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fb9190611807565b6109059190611820565b10156109495760405162461bcd60e51b81526020600482015260136024820152724e6f7420656e6f7567682061697264726f707360681b6044820152606401610599565b6109c2565b60001981036109c2576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561099b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bf9190611807565b90505b6109d66001600160a01b038316848361127b565b604080516001600160a01b038086168252841660208201529081018290524260608201527f444884a1e39c7f49542f3f9fa846e975edaaa2b5a761178c5652970f1683c4059060800160405180910390a1505050565b60005460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9991906117bd565b6001600160a01b031614610abf5760405162461bcd60e51b8152600401610599906117da565b62ed4e00811115610b065760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964204c6f636b2054696d6560781b6044820152606401610599565b60045460408051918252602082018390527f13bfb77112fbe53e5632336cd9e60b0b6541afa67787cb33b22b85002f21b56f910160405180910390a1600455565b610b4f6112df565b6001600160a01b038216600090815260066020526040902054811115610bae5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610599565b6001600160a01b038216600090815260076020526040902054811115610c165760405162461bcd60e51b815260206004820152601c60248201527f4e6f7420656e6f75676820617661696c61626c652062616c616e6365000000006044820152606401610599565b6001600160a01b03821660009081526006602052604081208054839290610c3e908490611820565b90915550506001600160a01b03821660009081526007602052604081208054839290610c6b908490611820565b9091555050600154610c87906001600160a01b0316838361127b565b8060026000828254610c999190611820565b90915550610ca79050611317565b6001546001600160a01b0384811660008181526006602090815260409182902054600254835194855294909516908301528101859052606081019290925260808201524260a08201527f1fa023e3d13b6bbce31cbc8e2b2a9da6344e8e7a762ca067cb4a9eab0b890cda9060c00160405180910390a2610408600160008051602061189883398151915255565b610d3c6112df565b600081815260086020908152604091829020825160608101845281546001600160a01b031681526001820154928101929092526002015491810182905260045490914291610d8991611833565b1115610de35760405162461bcd60e51b8152602060048201526024808201527f54686520756e6c6f636b2074696d6520686173206e6f74206265656e2072656160448201526318da195960e21b6064820152608401610599565b8060200151600003610df55750610ec0565b8051602080830151604080516001600160a01b03909416845291830152429082015282907f6620c2a607a07fb3d5b7449d56a4140f5bfe8bf551b92c45af5faf395e260d6b9060600160405180910390a260208082015182516001600160a01b03166000908152600790925260408220805491929091610e76908490611833565b9091555050600060208281018281528483526008909152604091829020835181546001600160a01b0319166001600160a01b03909116178155905160018201559101516002909101555b6103f2600160008051602061189883398151915255565b610edf6112df565b60055481600254610ef09190611833565b1115610f4c5760405162461bcd60e51b815260206004820152602560248201527f496e73756666696369656e7420617661696c61626c65207374616b696e6720616044820152641b5bdd5b9d60da1b6064820152608401610599565b60005460405163ef1e1bed60e01b81523060048201526001600160a01b039091169063ef1e1bed90602401602060405180830381865afa158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb89190611807565b8110156110075760405162461bcd60e51b815260206004820152601860248201527f4465706f73697420616d6f756e7420746f6f20736d616c6c00000000000000006044820152606401610599565b6001546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110749190611807565b60015490915061108f906001600160a01b0316843085611331565b6001546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156110d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fc9190611807565b90506111088282611820565b6001600160a01b038516600090815260066020526040812080549295508592909190611135908490611833565b92505081905550826002600082825461114e9190611833565b9091555061115c9050611317565b6001546001600160a01b038087166000908152600660205260409020546002547ff84b221f75085fb5810cfe7d64f501dc6510b35053c9142c5fae6415883468d3938993169188916111ad60095490565b604080516001600160a01b039788168152969095166020870152938501929092526060840152608083015260a08201524260c082015260e00160405180910390a26040518060600160405280856001600160a01b03168152602001848152602001428152506008600061121e611370565b81526020808201929092526040908101600020835181546001600160a01b0319166001600160a01b039091161781559183015160018301559190910151600290910155506104089050600160008051602061189883398151915255565b6040516001600160a01b038381166024830152604482018390526112da91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611381565b505050565b60008051602061189883398151915280546001190161131157604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6003805460009182611328836117a4565b91905055905090565b6040516001600160a01b03848116602483015283811660448301526064820183905261136a9186918216906323b872dd906084016112a8565b50505050565b6009805460009182611328836117a4565b60006113966001600160a01b038416836113e4565b905080516000141580156113bb5750808060200190518101906113b99190611846565b155b156112da57604051635274afe760e01b81526001600160a01b0384166004820152602401610599565b60606113f2838360006113f9565b9392505050565b60608147101561141e5760405163cd78605960e01b8152306004820152602401610599565b600080856001600160a01b0316848660405161143a9190611868565b60006040518083038185875af1925050503d8060008114611477576040519150601f19603f3d011682016040523d82523d6000602084013e61147c565b606091505b509150915061148c868383611496565b9695505050505050565b6060826114ab576114a6826114f2565b6113f2565b81511580156114c257506001600160a01b0384163b155b156114eb57604051639996b31560e01b81526001600160a01b0385166004820152602401610599565b50806113f2565b8051156115025780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261154257600080fd5b8135602067ffffffffffffffff8083111561155f5761155f61151b565b8260051b604051601f19603f830116810181811084821117156115845761158461151b565b6040529384528581018301938381019250878511156115a257600080fd5b83870191505b848210156115c1578135835291830191908301906115a8565b979650505050505050565b6000602082840312156115de57600080fd5b813567ffffffffffffffff8111156115f557600080fd5b61160184828501611531565b949350505050565b602080825282518282018190526000919060409081850190868401855b8281101561165e57815180516001600160a01b0316855286810151878601528501518585015260609093019290850190600101611626565b5091979650505050505050565b60006020828403121561167d57600080fd5b5035919050565b6000806040838503121561169757600080fd5b82359150602083013567ffffffffffffffff8111156116b557600080fd5b6116c185828601611531565b9150509250929050565b6001600160a01b03811681146103f257600080fd5b6000602082840312156116f257600080fd5b81356113f2816116cb565b6000806040838503121561171057600080fd5b823561171b816116cb565b9150602083013567ffffffffffffffff8111156116b557600080fd5b60008060006060848603121561174c57600080fd5b8335611757816116cb565b92506020840135611767816116cb565b929592945050506040919091013590565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016117b6576117b661178e565b5060010190565b6000602082840312156117cf57600080fd5b81516113f2816116cb565b60208082526013908201527221b0b63632b91034b9903737ba1037bbb732b960691b604082015260600190565b60006020828403121561181957600080fd5b5051919050565b818103818111156105005761050061178e565b808201808211156105005761050061178e565b60006020828403121561185857600080fd5b815180151581146113f257600080fd5b6000825160005b81811015611889576020818601810151858301520161186f565b50600092019182525091905056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212209f48f23aff74fe92151e9b3053dfa647e131dfa140b4a6788e92c3b8f7f97f1164736f6c63430008140033a26469706673582212207af70031ad059b749782c9096b8b65e790f898c249ac6b58f4e8e3e750a32ed064736f6c63430008140033
Verified Source Code Full Match
Compiler: v0.8.20+commit.a1b79de6
EVM: paris
Optimization: Yes (200 runs)
Initializable.sol 228 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
ReentrancyGuardUpgradeable.sol 105 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ReentrancyGuardUpgradeable is Initializable {
// 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;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._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 {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// 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) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}
draft-IERC6093.sol 161 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 118 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev 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);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev 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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that 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(token).code.length > 0;
}
}
Address.sol 159 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
ERC20.sol 301 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 public decimals;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_,uint8 decimals_) {
_name = name_;
_symbol = symbol_;
decimals = decimals_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
IDataStorage.sol 21 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
interface IDataStorage{
function owner() external view returns(address);
function manager() external view returns(address);
function depositLockTime() external view returns(uint256);
function redeemLockTime() external view returns(uint256);
function minDepositMap(address) external view returns(uint256);
function updateDepositLockTime(uint256) external;
function updateRedeemLockTime(uint256) external;
function setVaultMinDeposit(address,uint256) external;
}
LpToken.sol 98 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "./ERC20.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "./interfaces/IDataStorage.sol";
import "./USDVault.sol";
contract LpToken is ERC20,ReentrancyGuardUpgradeable{
uint256 public constant MAX_DEVIATION = 1000;
address public vault;
address private immutable _asset;
uint256 public price; // total stake USDT / lpToken totalSupply
uint256 public maxDeviation = 20; // max 10000
uint256 public updateTime;
uint256 public constant INTERVAL_TIME = 12 hours;
uint8 public PRICE_DECIMAL;
event UpdateIntervalTime(uint256 oldIntervalTime,uint256 currentIntervalTime);
event UpdateDeviation(uint256 oldDeviation,uint256 currentDeviation);
event UpdateDataStorage(address user,address oldStorage,address currentStorage);
event UpdatePrice(address account,uint256 oldPrice,uint256 currentPrice);
constructor(address assetToken,string memory name,string memory symbol,uint8 decimals) ERC20(name,symbol,decimals){
_asset = assetToken;
vault = msg.sender;
price = 10 ** decimals;
PRICE_DECIMAL = decimals;
}
function mint(uint256 assetAmount,uint256 minShareAmount) external nonReentrant onlyVault returns(uint256){
uint256 shares = convertToShares(assetAmount);
require(shares >= minShareAmount,"Insufficient output shares");
_mint(address(this),shares);
return shares;
}
function burn(uint256 shares,uint256 minAssetAmount) external nonReentrant onlyVault{
uint256 assetAmount = convertToAssets(shares);
require(assetAmount >= minAssetAmount,"Insufficient output asset");
_burn(address(this),shares);
}
function updatePrice(uint256 currentPrice) external onlyManager{
require(block.timestamp - updateTime > INTERVAL_TIME,"UpdateTime Error");
updateTime = block.timestamp;
uint256 max = price * (10000 + maxDeviation) / 10000;
uint256 min = price * (10000 - maxDeviation) / 10000;
require(currentPrice >= min && currentPrice <= max,"Price exceeded");
emit UpdatePrice(msg.sender,price,currentPrice);
price = currentPrice;
}
function forceUpdatePrice(uint256 currentPrice) external onlyOwner{
require(block.timestamp - updateTime > INTERVAL_TIME,"UpdateTime Error");
updateTime = block.timestamp;
uint256 maxPrice = price * (10000 + MAX_DEVIATION) / 10000;
uint256 minPrice = price * (10000 - MAX_DEVIATION) / 10000;
require(currentPrice >= minPrice && currentPrice <= maxPrice,"Price exceeded");
emit UpdatePrice(msg.sender,price,currentPrice);
price = currentPrice;
}
function updateDeviation(uint256 deviation) external onlyOwner {
require(deviation > 0 && deviation <= MAX_DEVIATION,"Deviation Error");
emit UpdateDeviation(maxDeviation,deviation);
maxDeviation = deviation;
}
function convertToShares(uint256 assets) public view virtual returns (uint256) {
return assets * (10 ** PRICE_DECIMAL) / price;
}
function convertToAssets(uint256 shares) public view virtual returns (uint256) {
return shares * price / (10 ** PRICE_DECIMAL);
}
function asset() public view returns (address) {
return address(_asset);
}
modifier onlyManager() {
require(IDataStorage(USDVault(vault).dataStorage()).manager() == msg.sender,"Caller is not manager");
_;
}
modifier onlyVault() {
require(vault == msg.sender,"Caller is not vault");
_;
}
modifier onlyOwner() {
require(IDataStorage(USDVault(vault).dataStorage()).owner() == msg.sender,"Caller is not owner");
_;
}
}
LRTVault.sol 170 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
// Uncomment this line to use console.log
// import "hardhat/console.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "./interfaces/IDataStorage.sol";
contract LRTVault is ReentrancyGuardUpgradeable{
using SafeERC20 for IERC20;
uint256 public constant MAX_LOCK_TIME = 180 days;
IDataStorage public dataStorage;
address public token; // LRT Token contract address
uint256 public totalStakeAmount;
uint256 public eventId;
uint256 public lockTime;
uint256 public maxLockAmount;
mapping(address => uint256) public stakeAmounts;
mapping(address => uint256) public availableAmounts;
mapping(uint256 => DepositLock) private depositMap;
uint256 private depositLockId;
struct DepositLock{
address account;
uint256 amount;
uint256 createTime;
}
event Deposit(uint256 indexed id,address user,address tokenContract,uint256 depositAmount,uint256 userBalance,uint256 vaultBalance,uint256 lockId,uint256 createTime);
event Withdraw(uint256 indexed id,address user,address tokenContract,uint256 withdrawAmount,uint256 userBalance,uint256 vaultBalance,uint256 createTime);
event MoveToken(address receiver,address tokenContract,uint256 amount,uint256 createTime);
event UpdateDataStorage(address user,address oldStorage,address currentStorage);
event UnLockDeposit(uint256 indexed lockId,address user,uint256 amount,uint256 createTime);
event UpdateLockTime(uint256 oldLockTime,uint256 currentLockTime);
event UpdateMaxLockAmount(uint256 oldLockAmount,uint256 currentLockAmount);
constructor(address storageContract,address tokenContract,uint256 initialLockTime,uint256 initialMaxLockAmount) {
require(storageContract != address(0) && tokenContract != address(0),"Invalid Zero Address");
dataStorage = IDataStorage(storageContract);
token = tokenContract;
lockTime = initialLockTime;
maxLockAmount = initialMaxLockAmount;
}
function deposit(uint256 amount) external{
_deposit(msg.sender,amount);
}
function _deposit(address account,uint256 amount) internal nonReentrant{
require(totalStakeAmount + amount <= maxLockAmount,"Insufficient available staking amount");
require(amount >= dataStorage.minDepositMap(address(this)),"Deposit amount too small");
uint256 beforeBalance = IERC20(token).balanceOf(address(this));
IERC20(token).safeTransferFrom(account, address(this), amount);
uint256 afterBalance = IERC20(token).balanceOf(address(this));
amount = afterBalance - beforeBalance;
stakeAmounts[account] += amount;
totalStakeAmount += amount;
emit Deposit(setEventId(),account,token,amount,stakeAmounts[account],totalStakeAmount,getDepositLockLength(),block.timestamp);
depositMap[setDepositLockId()] = DepositLock(account,amount,block.timestamp);
}
function withdraw(uint256 amount) external{
_withdraw(msg.sender,amount);
}
function withdrawAndUnlockDeposit(uint256 amount,uint256[] memory ids) external {
unLockDeposit(ids);
_withdraw(msg.sender,amount);
}
function _withdraw(address account,uint256 amount) internal nonReentrant{
require(stakeAmounts[account] >= amount,"Insufficient balance");
require(availableAmounts[account] >= amount,"Not enough available balance");
stakeAmounts[account] -= amount;
availableAmounts[account] -= amount;
IERC20(token).safeTransfer(account,amount);
totalStakeAmount -= amount;
emit Withdraw(setEventId(),account, token, amount, stakeAmounts[account], totalStakeAmount, block.timestamp);
}
function unLockDeposit(uint256[] memory ids) public {
for(uint256 i; i<ids.length; i++){
_unLockDeposit(ids[i]);
}
}
function _unLockDeposit(uint256 id) internal nonReentrant{
DepositLock memory depositLock= depositMap[id];
require(depositLock.createTime + lockTime <= block.timestamp,"The unlock time has not been reached");
if(depositLock.amount == 0){
return;
}
emit UnLockDeposit(id,depositLock.account,depositLock.amount,block.timestamp);
availableAmounts[depositLock.account] += depositLock.amount;
depositLock.amount = 0;
depositMap[id] = depositLock;
}
function moveToken(address receiver,address tokenContract,uint256 amount) external onlyOwner{
if(token == tokenContract){
require(IERC20(token).balanceOf(address(this)) - totalStakeAmount >= amount,"Not enough airdrops");
}else{
if(amount == type(uint256).max){
amount = IERC20(tokenContract).balanceOf(address(this));
}
}
IERC20(tokenContract).safeTransfer(receiver,amount);
emit MoveToken(receiver,tokenContract,amount,block.timestamp);
}
function setEventId() internal returns(uint256){
return eventId++;
}
function updateDataStorageContract(address storageContract) external onlyOwner{
require(storageContract != address(0),"Invalid Zero Address");
emit UpdateDataStorage(msg.sender,address(dataStorage),storageContract);
dataStorage = IDataStorage(storageContract);
require(dataStorage.owner() != address(0),"Invalid Owner Address");
}
function updateLockTime(uint256 second) external onlyOwner{
require(second <= MAX_LOCK_TIME,"Invalid Lock Time");
emit UpdateLockTime(lockTime,second);
lockTime = second;
}
function updateMaxLockAmount(uint256 amount) external onlyOwner{
emit UpdateMaxLockAmount(maxLockAmount,amount);
maxLockAmount = amount;
}
function setDepositLockId() internal returns(uint256) {
return depositLockId++;
}
function getDepositLockInfo(uint256[] memory ids) public view returns(DepositLock[] memory) {
DepositLock[] memory list = new DepositLock[](ids.length);
for(uint256 i; i<ids.length; i++){
list[i] = depositMap[ids[i]];
}
return list;
}
function getDepositLockLength() public view returns(uint256) {
return depositLockId;
}
function getAvailableAmount(address account,uint256[] memory ids) public view returns(uint256){
uint256 amount = availableAmounts[account];
for(uint256 i; i<ids.length; i++){
DepositLock memory depositLock = depositMap[ids[i]];
if(depositLock.account == account){
amount = depositLock.amount;
}
}
return amount;
}
modifier onlyOwner() {
require(dataStorage.owner() == msg.sender,"Caller is not owner");
_;
}
}
USDVault.sol 253 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
// Uncomment this line to use console.log
// import "hardhat/console.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "./interfaces/IDataStorage.sol";
import "./LpToken.sol";
contract USDVault is ReentrancyGuardUpgradeable{
using SafeERC20 for IERC20;
uint256 public constant MAX_REDEEM_LOCK_TIME = 60 days;
uint256 public constant UPDATE_CUSTODIAN_WAITING_TIME = 2 days;
uint256 public updatePreCustodianTime;
IDataStorage public dataStorage;
LpToken public lpToken;
address public token; // U Token contract address
address public custodian;
address private preCustodian;
uint256 public eventId;
bool private _initializing;
mapping(address => uint256) public balanceMap; // user total share balance
mapping(address => uint256) public availableShare; // user avalible share balance
mapping(uint256 => DepositLock) private depositMap;
uint256 private depositLockId;
mapping(uint256 => RedeemLock) private redeemMap;
uint256 private redeemLockId;
struct DepositLock{
address account;
uint256 share;
uint256 createTime;
}
struct RedeemLock{
address account;
uint256 assetAmount;
uint256 share; // lp amount
uint256 price; // total USD / total shares
uint256 createTime;
}
event Deposit(uint256 indexed id,address user,uint256 depositAsset,uint256 depositShare,uint256 price,uint256 lockId,uint256 lockTime,uint256 totalShares,uint256 createTime);
event Withdraw(uint256 indexed id,address user,uint256 withdrawAsset,uint256 withdrawShare,uint256 price,uint256 totalShares,uint256 createTime);
event Redeem(uint256 indexed id,address user,uint256 redeemAsset,uint256 redeemShare,uint256 price,uint256 lockId,uint256 lockTime,uint256 totalShares,uint256 createTime);
event UnLockDeposit(uint256 indexed lockId,address user,uint256 share,uint256 createTime);
event UnLockRedeem(uint256 indexed lockId,address user,uint256 share,uint256 createTime);
event UpdateCustodian(address user,address oldCustodian,address currentCustodian);
event UpdatePreCustodian(address user,address oldCustodian,address currentCustodian);
event UpdateDataStorage(address user,address oldStorage,address currentStorage);
event CreateLp(address lp);
constructor(address storageContract,address tokenContract) {
require(storageContract != address(0) && tokenContract != address(0),"Invalid Zero Address");
token = tokenContract;
dataStorage = IDataStorage(storageContract);
lpToken = new LpToken(tokenContract,string.concat('LpToken-',IERC20Metadata(tokenContract).name()),string.concat('LP-',IERC20Metadata(tokenContract).symbol()),IERC20Metadata(tokenContract).decimals());
emit CreateLp(address(lpToken));
}
function deposit(uint256 amount,uint256 minShare) external{
_deposit(msg.sender,amount,minShare);
}
function _deposit(address account,uint256 amount,uint256 minShare) internal nonReentrant{
require(amount >= dataStorage.minDepositMap(address(this)),"Deposit amount too small");
require(custodian != address(0),"Invalid custodian Address");
uint256 beforeBalance = IERC20(token).balanceOf(custodian);
IERC20(token).safeTransferFrom(account, custodian, amount);
uint256 afterBalance = IERC20(token).balanceOf(custodian);
amount = afterBalance - beforeBalance;
uint256 shares = lpToken.mint(amount,minShare);
balanceMap[account] += shares;
emit Deposit(setEventId(),account,amount,shares,lpToken.price(),getDepositLockLength(),dataStorage.depositLockTime(),lpToken.totalSupply(),block.timestamp);
depositMap[setDepositLockId()] = DepositLock(account,shares,block.timestamp);
}
function unLockDeposit(uint256[] memory ids) public{
for(uint256 i; i<ids.length; i++){
_unLockDeposit(ids[i]);
}
}
function _unLockDeposit(uint256 id) internal nonReentrant{
DepositLock memory depositLock= depositMap[id];
require(depositLock.createTime + dataStorage.depositLockTime() <= block.timestamp,"Lock time not enough");
if(depositLock.share == 0){
return;
}
emit UnLockDeposit(id,depositLock.account,depositLock.share,block.timestamp);
availableShare[depositLock.account] += depositLock.share;
depositLock.share = 0;
depositMap[id] = depositLock;
}
function withdraw(uint256[] memory ids) external{
for(uint256 i; i<ids.length; i++){
_withdraw(ids[i]);
}
}
function _withdraw(uint256 id) internal nonReentrant{
RedeemLock memory redeemLock = redeemMap[id];
uint256 lockTime = dataStorage.redeemLockTime();
if(lockTime > MAX_REDEEM_LOCK_TIME){
lockTime = MAX_REDEEM_LOCK_TIME;
}
require(redeemLock.createTime + lockTime <= block.timestamp,"Lock time not enough");
if(redeemLock.share == 0){
return;
}
IERC20(token).safeTransfer(redeemLock.account,redeemLock.assetAmount);
emit Withdraw(setEventId(),redeemLock.account,redeemLock.assetAmount,redeemLock.share,redeemLock.price,lpToken.totalSupply(),block.timestamp);
emit UnLockRedeem(id,redeemLock.account,redeemLock.share,block.timestamp);
balanceMap[redeemLock.account] -= redeemLock.share;
redeemLock.share = 0;
redeemLock.assetAmount = 0;
redeemMap[id] = redeemLock;
}
function redeemAndUnLockDeposit(uint256 amount,uint256 minAssetAmount,uint256[] memory ids) external {
unLockDeposit(ids);
_redeem(msg.sender,amount,minAssetAmount);
}
function redeem(uint256 share,uint256 minAssetAmount) external {
_redeem(msg.sender,share,minAssetAmount);
}
function _redeem(address account,uint256 share,uint256 minAssetAmount) internal nonReentrant{
require(availableShare[account] >= share,"Available balance not enough");
uint256 assetAmount = lpToken.convertToAssets(share);
require(assetAmount >= minAssetAmount,"Asset amount error");
availableShare[account] -= share;
lpToken.burn(share,0);
emit Redeem(setEventId(),account,assetAmount,share,lpToken.price(),getRedeemLockLength(),dataStorage.redeemLockTime(),lpToken.totalSupply(),block.timestamp);
redeemMap[setRedeemLockId()] = RedeemLock(account,assetAmount,share,lpToken.price(),block.timestamp);
}
function setDepositLockId() internal returns(uint256) {
return depositLockId++;
}
function setRedeemLockId() internal returns (uint256) {
return redeemLockId++;
}
function getDepositLockInfo(uint256[] memory ids) public view returns(DepositLock[] memory) {
DepositLock[] memory list = new DepositLock[](ids.length);
for(uint256 i; i<ids.length; i++){
list[i] = depositMap[ids[i]];
}
return list;
}
function getDepositLockLength() public view returns(uint256) {
return depositLockId;
}
function getRedeemLockInfo(uint256[] memory ids) public view returns(RedeemLock[] memory) {
RedeemLock[] memory list = new RedeemLock[](ids.length);
for(uint256 i; i<ids.length; i++){
list[i] = redeemMap[ids[i]];
}
return list;
}
function getRedeemLockLength() public view returns(uint256) {
return redeemLockId;
}
function setEventId() internal returns(uint256){
return eventId++;
}
function updateDataStorageContract(address storageContract) external onlyOwner{
require(storageContract != address(0),"Invalid Zero Address");
emit UpdateDataStorage(msg.sender,address(dataStorage),storageContract);
dataStorage = IDataStorage(storageContract);
require(dataStorage.owner() != address(0),"Invalid Owner Address");
}
function getWithdrawAmount(address account,uint256[] memory ids) external view returns (uint256,uint256) {
uint256 assetAmount;
uint256 share;
for(uint256 i; i<ids.length; i++){
RedeemLock memory redeemLock = redeemMap[ids[i]];
if(account == redeemLock.account){
share += redeemLock.share;
assetAmount += redeemLock.assetAmount;
}
}
return (assetAmount,share);
}
function getAvailableAmount(address account,uint256[] memory ids) external view returns(uint256){
uint256 available = availableShare[account];
for(uint256 i; i<ids.length; i++){
DepositLock memory depositLock = depositMap[ids[i]];
if(account == depositLock.account){
available += depositLock.share;
}
}
return available;
}
function updatePreCustodian(address account) external onlyOwner {
require(account != address(0),"Invalid Zero Address");
emit UpdatePreCustodian(msg.sender,preCustodian,account);
preCustodian = account;
updatePreCustodianTime = block.timestamp;
}
function initialCustodian(address account) external onlyOwner{
require(!_initializing,"Already Initialized");
_initializing = true;
emit UpdateCustodian(msg.sender,custodian,account);
custodian = account;
}
function updateCustodian(address account) external onlyOwner {
require(account == preCustodian,"Invalid Custodian Address");
require(updatePreCustodianTime + UPDATE_CUSTODIAN_WAITING_TIME <= block.timestamp,"Insufficient Waiting Time");
emit UpdateCustodian(msg.sender,custodian,preCustodian);
custodian = preCustodian;
}
modifier onlyOwner() {
require(dataStorage.owner() == msg.sender,"Caller is not owner");
_;
}
}
VaultFactory.sol 30 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
// Uncomment this line to use console.log
// import "hardhat/console.sol";
import "./LRTVault.sol";
import "./USDVault.sol";
contract VaultFactory{
address public dataStorageContract;
event CreateLRTVault(address vault,address token,uint256 createTime);
event CreateUSDVault(address vault,address token,uint256 createTime);
constructor(address storageContract){
require(storageContract != address(0),"Invalid Zero Address");
dataStorageContract = storageContract;
}
function createLRTVault(address token,uint256 initialLockTime,uint256 initialMaxLockAmount) external{
LRTVault vault = new LRTVault(dataStorageContract,token,initialLockTime,initialMaxLockAmount);
emit CreateLRTVault(address(vault), token, block.timestamp);
}
function createUSDVault(address token) external{
USDVault vault = new USDVault(dataStorageContract,token);
emit CreateUSDVault(address(vault), token, block.timestamp);
}
}
Read Contract
dataStorageContract 0xb156c0b7 → address
Write Contract 2 functions
These functions modify contract state and require a wallet transaction to execute.
createLRTVault 0xf63e17c1
address token
uint256 initialLockTime
uint256 initialMaxLockAmount
createUSDVault 0xefe9ca85
address token
Recent Transactions
No transactions found for this address