Address Contract Verified
Address
0xe8a01D8Dac4Af19eC7a22cf87f3d141ce6e7e9Fb
Balance
0 ETH
Nonce
2
Code Size
9389 bytes
Creator
0x739A8F9c...3d18 at tx 0x9817984a...382c85
Indexed Transactions
0
Contract Bytecode
9389 bytes
0x608060405234801561001057600080fd5b50600436106101725760003560e01c80637856a353116100de578063a743d8c011610097578063d250496c11610071578063d250496c14610340578063e2bbb15814610360578063fc0c546a14610373578063fd0a0b151461038657600080fd5b8063a743d8c0146102fc578063c4bef1671461030f578063c5db1dde1461033757600080fd5b80637856a3531461028a5780637cbc23731461029d5780638870455f146102b0578063983d95ce146102c35780639bc62245146102d6578063a7076b36146102e957600080fd5b806325f63b541161013057806325f63b54146101fe578063375b74c31461021e5780633e0a5d0914610249578063510c82b3146102515780635fcbd2851461026457806370c489ef1461027757600080fd5b8062350e7f1461017757806305436d15146101a0578063089cdd0c146101b85780631764f236146101c157806322637940146101d657806322e07352146101f6575b600080fd5b61018a6101853660046120d7565b610390565b6040516101979190612114565b60405180910390f35b6101aa6202a30081565b604051908152602001610197565b6101aa60065481565b6101d46101cf366004612176565b6104b0565b005b6101e96101e43660046120d7565b6104c9565b60405161019791906121c6565b600d546101aa565b6101aa61020c366004612245565b60096020526000908152604090205481565b600454610231906001600160a01b031681565b6040516001600160a01b039091168152602001610197565b600b546101aa565b6101d461025f366004612245565b610607565b600254610231906001600160a01b031681565b6101d46102853660046120d7565b6107d3565b6101d4610298366004612245565b610817565b6101d46102ab366004612262565b610969565b600154610231906001600160a01b031681565b6101d46102d13660046120d7565b610974565b6101d46102e4366004612245565b6109b4565b6101aa6102f7366004612284565b610b01565b6101d461030a366004612245565b610bc4565b61032261031d366004612284565b610dbc565b60408051928352602083019190915201610197565b6101aa60005481565b6101aa61034e366004612245565b60086020526000908152604090205481565b6101d461036e366004612262565b610e94565b600354610231906001600160a01b031681565b6101aa624f1a0081565b60606000825167ffffffffffffffff8111156103ae576103ae612026565b60405190808252806020026020018201604052801561040c57816020015b6103f9604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b8152602001906001900390816103cc5790505b50905060005b83518110156104a957600a6000858381518110610431576104316122d4565b6020908102919091018101518252818101929092526040908101600020815160608101835281546001600160a01b031681526001820154938101939093526002015490820152825183908390811061048b5761048b6122d4565b602002602001018190525080806104a190612300565b915050610412565b5092915050565b6104b9816107d3565b6104c4338484610e9f565b505050565b60606000825167ffffffffffffffff8111156104e7576104e7612026565b60405190808252806020026020018201604052801561055357816020015b6105406040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816105055790505b50905060005b83518110156104a957600c6000858381518110610578576105786122d4565b6020908102919091018101518252818101929092526040908101600020815160a08101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260040154608082015282518390839081106105e9576105e96122d4565b602002602001018190525080806105ff90612300565b915050610559565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106749190612319565b6001600160a01b0316146106a35760405162461bcd60e51b815260040161069a90612336565b60405180910390fd5b6005546001600160a01b038281169116146107005760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420437573746f6469616e204164647265737300000000000000604482015260640161069a565b426202a3006000546107129190612363565b11156107605760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e742057616974696e672054696d6500000000000000604482015260640161069a565b6004546005546040517fd0db98814986e26fb56ed4ba7bd4cdb4bc68f5471c86e4fb372aef6c43be1703926107a69233926001600160a01b039283169290911690612376565b60405180910390a150600554600480546001600160a01b0319166001600160a01b03909216919091179055565b60005b8151811015610813576108018282815181106107f4576107f46122d4565b6020026020010151611327565b8061080b81612300565b9150506107d6565b5050565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108849190612319565b6001600160a01b0316146108aa5760405162461bcd60e51b815260040161069a90612336565b60075460ff16156108f35760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e48125b9a5d1a585b1a5e9959606a1b604482015260640161069a565b6007805460ff191660011790556004546040517fd0db98814986e26fb56ed4ba7bd4cdb4bc68f5471c86e4fb372aef6c43be17039161093f9133916001600160a01b0316908590612376565b60405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b610813338383610e9f565b60005b8151811015610813576109a2828281518110610995576109956122d4565b6020026020010151611517565b806109ac81612300565b915050610977565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa1580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a219190612319565b6001600160a01b031614610a475760405162461bcd60e51b815260040161069a90612336565b6001600160a01b038116610a945760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964205a65726f204164647265737360601b604482015260640161069a565b6005546040517ffdf466e06a1186bd2e3fbcbfba4810e434e9e196de25e5e29d7bcc38bea4b07891610ad39133916001600160a01b0316908590612376565b60405180910390a1600580546001600160a01b0319166001600160a01b039290921691909117905542600055565b6001600160a01b038216600090815260096020526040812054815b8351811015610bba576000600a6000868481518110610b3d57610b3d6122d4565b6020908102919091018101518252818101929092526040908101600020815160608101835281546001600160a01b0390811680835260018401549583019590955260029092015492810192909252909250871603610ba7576020810151610ba49084612363565b92505b5080610bb281612300565b915050610b1c565b5090505b92915050565b60015460408051638da5cb5b60e01b8152905133926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015610c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c319190612319565b6001600160a01b031614610c575760405162461bcd60e51b815260040161069a90612336565b6001600160a01b038116610ca45760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964205a65726f204164647265737360601b604482015260640161069a565b6001546040517ff1237c4484b1216b734487b31c22619eabadf16f655c110b807119b914fff22691610ce39133916001600160a01b0316908590612376565b60405180910390a1600180546001600160a01b0319166001600160a01b03831690811790915560408051638da5cb5b60e01b8152905160009291638da5cb5b9160048083019260209291908290030181865afa158015610d47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6b9190612319565b6001600160a01b031603610db95760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964204f776e6572204164647265737360581b604482015260640161069a565b50565b60008060008060005b8551811015610e88576000600c6000888481518110610de657610de66122d4565b6020908102919091018101518252818101929092526040908101600020815160a08101835281546001600160a01b039081168083526001840154958301959095526002830154938201939093526003820154606082015260049091015460808201529250891603610e75576040810151610e609084612363565b9250806020015184610e729190612363565b93505b5080610e8081612300565b915050610dc5565b50909590945092505050565b610813338383611853565b610ea7611d66565b6001600160a01b038316600090815260096020526040902054821115610f0f5760405162461bcd60e51b815260206004820152601c60248201527f417661696c61626c652062616c616e6365206e6f7420656e6f75676800000000604482015260640161069a565b6002546040516303d1689d60e11b8152600481018490526000916001600160a01b0316906307a2d13a90602401602060405180830381865afa158015610f59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7d9190612399565b905081811015610fc45760405162461bcd60e51b815260206004820152601260248201527120b9b9b2ba1030b6b7bab73a1032b93937b960711b604482015260640161069a565b6001600160a01b03841660009081526009602052604081208054859290610fec9084906123b2565b909155505060025460405163b390c0ab60e01b815260048101859052600060248201526001600160a01b039091169063b390c0ab90604401600060405180830381600087803b15801561103e57600080fd5b505af1158015611052573d6000803e3d6000fd5b5050505061105e611d9e565b7ffb0aec119cd63b2a545926384480162cb277b4ed052310c39da3b670d2ab408e858386600260009054906101000a90046001600160a01b03166001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f99190612399565b600d54600160009054906101000a90046001600160a01b03166001600160a01b0316636e6cc20d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111739190612399565b600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ea9190612399565b426040516111ff9897969594939291906123c5565b60405180910390a26040518060a00160405280856001600160a01b03168152602001828152602001848152602001600260009054906101000a90046001600160a01b03166001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190612399565b815260200142815250600c60006112b9611db8565b81526020808201929092526040908101600020835181546001600160a01b0319166001600160a01b03909116178155918301516001830155820151600282015560608201516003820155608090910151600490910155506104c4600160008051602061245883398151915255565b61132f611d66565b6000818152600a6020908152604091829020825160608101845281546001600160a01b03908116825260018084015483860152600290930154828601529154845163f0dfeab760e01b8152945191944294919093169263f0dfeab792600480830193928290030181865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190612399565b82604001516113de9190612363565b11156114235760405162461bcd60e51b8152602060048201526014602482015273098dec6d640e8d2daca40dcdee840cadcdeeaced60631b604482015260640161069a565b80602001516000036114355750611500565b8051602080830151604080516001600160a01b03909416845291830152429082015282907f6620c2a607a07fb3d5b7449d56a4140f5bfe8bf551b92c45af5faf395e260d6b9060600160405180910390a260208082015182516001600160a01b031660009081526009909252604082208054919290916114b6908490612363565b909155505060006020828101828152848352600a909152604091829020835181546001600160a01b0319166001600160a01b03909116178155905160018201559101516002909101555b610db9600160008051602061245883398151915255565b61151f611d66565b6000818152600c60209081526040808320815160a08101835281546001600160a01b03908116825260018084015483870152600284015483860152600384015460608401526004938401546080840152548451636e6cc20d60e01b81529451929695911693636e6cc20d9381810193918290030181865afa1580156115a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cc9190612399565b9050624f1a008111156115df5750624f1a005b428183608001516115f09190612363565b11156116355760405162461bcd60e51b8152602060048201526014602482015273098dec6d640e8d2daca40dcdee840cadcdeeaced60631b604482015260640161069a565b8160400151600003611648575050611500565b81516020830151600354611667926001600160a01b0390911691611ddd565b61166f611d9e565b7ff041d18460e8444b78f944ad4de3c6cf13f1912a1eb46f4c8de656fb627b47338360000151846020015185604001518660600151600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171b9190612399565b604080516001600160a01b039096168652602086019490945292840191909152606083015260808201524260a082015260c00160405180910390a2815160408084015181516001600160a01b0390931683526020830152429082015283907f2723d816727813c693c68fadd143360e52698101b43f5b167544b88dd58f7da29060600160405180910390a260408083015183516001600160a01b0316600090815260086020529182208054919290916117d59084906123b2565b9091555050600060408381018281526020808601848152878552600c90915291909220845181546001600160a01b0319166001600160a01b0390911617815590516001820155905160028201556060830151600382015560809092015160049092019190915550610db9600160008051602061245883398151915255565b61185b611d66565b60015460405163ef1e1bed60e01b81523060048201526001600160a01b039091169063ef1e1bed90602401602060405180830381865afa1580156118a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c79190612399565b8210156119165760405162461bcd60e51b815260206004820152601860248201527f4465706f73697420616d6f756e7420746f6f20736d616c6c0000000000000000604482015260640161069a565b6004546001600160a01b031661196e5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420637573746f6469616e204164647265737300000000000000604482015260640161069a565b600354600480546040516370a0823160e01b81526001600160a01b039182169281019290925260009216906370a0823190602401602060405180830381865afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e39190612399565b600454600354919250611a05916001600160a01b039081169187911686611e3c565b600354600480546040516370a0823160e01b81526001600160a01b039182169281019290925260009216906370a0823190602401602060405180830381865afa158015611a56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7a9190612399565b9050611a8682826123b2565b600254604051630d9778e560e11b815260048101839052602481018690529195506000916001600160a01b0390911690631b2ef1ca906044016020604051808303816000875af1158015611ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b029190612399565b6001600160a01b038716600090815260086020526040812080549293508392909190611b2f908490612363565b90915550611b3d9050611d9e565b7f71763977f5ea6af2ea4e5ba0bcf8dfba8fad9773fe36cd941d09dc757ce8df15878784600260009054906101000a90046001600160a01b03166001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd89190612399565b600b54600160009054906101000a90046001600160a01b03166001600160a01b031663f0dfeab76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c529190612399565b600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc99190612399565b42604051611cde9897969594939291906123c5565b60405180910390a26040518060600160405280876001600160a01b0316815260200182815260200142815250600a6000611d16611e7b565b81526020808201929092526040908101600020835181546001600160a01b0319166001600160a01b039091161781559183015160018301559190910151600290910155506104c49150611dc99050565b600080516020612458833981519152805460011901611d9857604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6006805460009182611daf83612300565b91905055905090565b600d805460009182611daf83612300565b600160008051602061245883398151915255565b6040516001600160a01b038381166024830152604482018390526104c491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611e8c565b6040516001600160a01b038481166024830152838116604483015260648201839052611e759186918216906323b872dd90608401611e0a565b50505050565b600b805460009182611daf83612300565b6000611ea16001600160a01b03841683611eef565b90508051600014158015611ec6575080806020019051810190611ec49190612406565b155b156104c457604051635274afe760e01b81526001600160a01b038416600482015260240161069a565b6060611efd83836000611f04565b9392505050565b606081471015611f295760405163cd78605960e01b815230600482015260240161069a565b600080856001600160a01b03168486604051611f459190612428565b60006040518083038185875af1925050503d8060008114611f82576040519150601f19603f3d011682016040523d82523d6000602084013e611f87565b606091505b5091509150611f97868383611fa1565b9695505050505050565b606082611fb657611fb182611ffd565b611efd565b8151158015611fcd57506001600160a01b0384163b155b15611ff657604051639996b31560e01b81526001600160a01b038516600482015260240161069a565b5080611efd565b80511561200d5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261204d57600080fd5b8135602067ffffffffffffffff8083111561206a5761206a612026565b8260051b604051601f19603f8301168101818110848211171561208f5761208f612026565b6040529384528581018301938381019250878511156120ad57600080fd5b83870191505b848210156120cc578135835291830191908301906120b3565b979650505050505050565b6000602082840312156120e957600080fd5b813567ffffffffffffffff81111561210057600080fd5b61210c8482850161203c565b949350505050565b602080825282518282018190526000919060409081850190868401855b8281101561216957815180516001600160a01b0316855286810151878601528501518585015260609093019290850190600101612131565b5091979650505050505050565b60008060006060848603121561218b57600080fd5b8335925060208401359150604084013567ffffffffffffffff8111156121b057600080fd5b6121bc8682870161203c565b9150509250925092565b602080825282518282018190526000919060409081850190868401855b8281101561216957815180516001600160a01b0316855286810151878601528581015186860152606080820151908601526080908101519085015260a090930192908501906001016121e3565b6001600160a01b0381168114610db957600080fd5b60006020828403121561225757600080fd5b8135611efd81612230565b6000806040838503121561227557600080fd5b50508035926020909101359150565b6000806040838503121561229757600080fd5b82356122a281612230565b9150602083013567ffffffffffffffff8111156122be57600080fd5b6122ca8582860161203c565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612312576123126122ea565b5060010190565b60006020828403121561232b57600080fd5b8151611efd81612230565b60208082526013908201527221b0b63632b91034b9903737ba1037bbb732b960691b604082015260600190565b80820180821115610bbe57610bbe6122ea565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6000602082840312156123ab57600080fd5b5051919050565b81810381811115610bbe57610bbe6122ea565b6001600160a01b03989098168852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60006020828403121561241857600080fd5b81518015158114611efd57600080fd5b6000825160005b81811015612449576020818601810151858301520161242f565b50600092019182525091905056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212206193b4672e07940fd1258b29059bd009d55f919ad21d0d44f2a15f5608bdab1f64736f6c63430008140033
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");
_;
}
}
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");
_;
}
}
Read Contract
MAX_REDEEM_LOCK_TIME 0xfd0a0b15 → uint256
UPDATE_CUSTODIAN_WAITING_TIME 0x05436d15 → uint256
availableShare 0x25f63b54 → uint256
balanceMap 0xd250496c → uint256
custodian 0x375b74c3 → address
dataStorage 0x8870455f → address
eventId 0x089cdd0c → uint256
getAvailableAmount 0xa7076b36 → uint256
getDepositLockInfo 0x00350e7f → tuple[]
getDepositLockLength 0x3e0a5d09 → uint256
getRedeemLockInfo 0x22637940 → tuple[]
getRedeemLockLength 0x22e07352 → uint256
getWithdrawAmount 0xc4bef167 → uint256, uint256
lpToken 0x5fcbd285 → address
token 0xfc0c546a → address
updatePreCustodianTime 0xc5db1dde → uint256
Write Contract 9 functions
These functions modify contract state and require a wallet transaction to execute.
deposit 0xe2bbb158
uint256 amount
uint256 minShare
initialCustodian 0x7856a353
address account
redeem 0x7cbc2373
uint256 share
uint256 minAssetAmount
redeemAndUnLockDeposit 0x1764f236
uint256 amount
uint256 minAssetAmount
uint256[] ids
unLockDeposit 0x70c489ef
uint256[] ids
updateCustodian 0x510c82b3
address account
updateDataStorageContract 0xa743d8c0
address storageContract
updatePreCustodian 0x9bc62245
address account
withdraw 0x983d95ce
uint256[] ids
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address