Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xA5dB3faB53eCB34387A180217937b3C772aeCB0F
Balance 0 ETH
Nonce 1
Code Size 10365 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

10365 bytes
0x608060405234801561001057600080fd5b50600436106101165760003560e01c80637a1ac61e116100a2578063bbe4491711610071578063bbe4491714610233578063bc197c811461023c578063f23a6e611461024f578063f2fde38b14610262578063fb930e721461027557600080fd5b80637a1ac61e146101f45780638456cb59146102075780638da5cb5b1461020f578063acd2ebf21461022057600080fd5b80631f7678ce116100e95780631f7678ce1461018c578063238ac933146101a35780635c975abb146101ce5780635f3e098a146101d9578063715018a6146101ec57600080fd5b806301ffc9a71461011b578063046f7da214610143578063150b7a021461014d5780631742057314610179575b600080fd5b61012e610129366004612059565b6102b6565b60405190151581526020015b60405180910390f35b61014b6102ed565b005b61016061015b3660046120e8565b6102ff565b6040516001600160e01b0319909116815260200161013a565b61014b61018736600461219c565b61033b565b61019560fe5481565b60405190815260200161013a565b60fd546101b6906001600160a01b031681565b6040516001600160a01b03909116815260200161013a565b60975460ff1661012e565b61014b6101e7366004612205565b610e91565b61014b6110a4565b61014b610202366004612251565b6110b6565b61014b61122e565b6033546001600160a01b03166101b6565b61014b61022e366004612251565b61123e565b61019560ff5481565b61016061024a366004612284565b611299565b61016061025d36600461233f565b6112d8565b61014b6102703660046123b7565b611315565b6101956102833660046123d2565b6001600160a01b039283166000908152610101602090815260408083209490951682529283528381209181529152205490565b60006001600160e01b03198216630a85bd0160e11b14806102e757506001600160e01b03198216630271189760e51b145b92915050565b6102f561138e565b6102fd6113e8565b565b6101005460009060ff16600214610329576040516356fdbe7d60e11b815260040160405180910390fd5b50630a85bd0160e11b95945050505050565b61034361143a565b61034b611493565b6103598333878786866114d9565b158061037157504360ff548461036f9190612424565b105b1561038e5760405162127a7b60eb1b815260040160405180910390fd5b60005b84811015610e3c5760008686838181106103ad576103ad612437565b90506020028101906103bf919061244d565b6103cd9060208101906123b7565b90508686838181106103e1576103e1612437565b90506020028101906103f3919061244d565b61040190604081019061246d565b90506000036106465760005b87878481811061041f5761041f612437565b9050602002810190610431919061244d565b61043f90602081019061246d565b905081101561064057336000908152610101602090815260408083206001600160a01b038616845290915281209089898681811061047f5761047f612437565b9050602002810190610491919061244d565b61049f90602081019061246d565b848181106104af576104af612437565b905060200201358152602001908152602001600020546000036104e5576040516360bea25160e11b815260040160405180910390fd5b336000908152610101602090815260408083206001600160a01b03861684529091528120818a8a8781811061051c5761051c612437565b905060200281019061052e919061244d565b61053c90602081019061246d565b8581811061054c5761054c612437565b90506020020135815260200190815260200160002081905550816001600160a01b03166342842e0e3061057c3390565b8b8b8881811061058e5761058e612437565b90506020028101906105a0919061244d565b6105ae90602081019061246d565b868181106105be576105be612437565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561061557600080fd5b505af1158015610629573d6000803e3d6000fd5b505050508080610638906124b7565b91505061040d565b50610e29565b600287878481811061065a5761065a612437565b905060200281019061066c919061244d565b61067a90602081019061246d565b905010156109f65786868381811061069457610694612437565b90506020028101906106a6919061244d565b6106b490604081019061246d565b60008181106106c5576106c5612437565b9050602002013561010160006106d83390565b6001600160a01b039081168252602080830193909352604091820160009081209186168152925281209089898681811061071457610714612437565b9050602002810190610726919061244d565b61073490602081019061246d565b600081811061074557610745612437565b90506020020135815260200190815260200160002054101561077a576040516360bea25160e11b815260040160405180910390fd5b600087878481811061078e5761078e612437565b90506020028101906107a0919061244d565b6107ae90604081019061246d565b60008181106107bf576107bf612437565b9050602002013561010160006107d23390565b6001600160a01b03908116825260208083019390935260409182016000908120918716815292528120908a8a8781811061080e5761080e612437565b9050602002810190610820919061244d565b61082e90602081019061246d565b600081811061083f5761083f612437565b9050602002013581526020019081526020016000205461085f91906124d0565b905087878481811061087357610873612437565b9050602002810190610885919061244d565b61089390604081019061246d565b60008181106108a4576108a4612437565b9050602002013561010160006108b73390565b6001600160a01b03908116825260208083019390935260409182016000908120918716815292528120908a8a878181106108f3576108f3612437565b9050602002810190610905919061244d565b61091390602081019061246d565b600081811061092457610924612437565b90506020020135815260200190815260200160002081905550816001600160a01b031663f242432a306109543390565b8b8b8881811061096657610966612437565b9050602002810190610978919061244d565b61098690602081019061246d565b600081811061099757610997612437565b90506020020135856040518563ffffffff1660e01b81526004016109be94939291906124e3565b600060405180830381600087803b1580156109d857600080fd5b505af11580156109ec573d6000803e3d6000fd5b5050505050610e29565b6000878784818110610a0a57610a0a612437565b9050602002810190610a1c919061244d565b610a2a90602081019061246d565b905067ffffffffffffffff811115610a4457610a4461251b565b604051908082528060200260200182016040528015610a6d578160200160208202803683370190505b50905060005b888885818110610a8557610a85612437565b9050602002810190610a97919061244d565b610aa590602081019061246d565b9050811015610d9057888885818110610ac057610ac0612437565b9050602002810190610ad2919061244d565b610ae090604081019061246d565b82818110610af057610af0612437565b905060200201356101016000610b033390565b6001600160a01b03908116825260208083019390935260409182016000908120918816815292528120908b8b88818110610b3f57610b3f612437565b9050602002810190610b51919061244d565b610b5f90602081019061246d565b85818110610b6f57610b6f612437565b905060200201358152602001908152602001600020541015610ba4576040516360bea25160e11b815260040160405180910390fd5b888885818110610bb657610bb6612437565b9050602002810190610bc8919061244d565b610bd690604081019061246d565b82818110610be657610be6612437565b905060200201356101016000610bf93390565b6001600160a01b03908116825260208083019390935260409182016000908120918816815292528120908b8b88818110610c3557610c35612437565b9050602002810190610c47919061244d565b610c5590602081019061246d565b85818110610c6557610c65612437565b90506020020135815260200190815260200160002054610c8591906124d0565b828281518110610c9757610c97612437565b602002602001018181525050888885818110610cb557610cb5612437565b9050602002810190610cc7919061244d565b610cd590604081019061246d565b82818110610ce557610ce5612437565b905060200201356101016000610cf83390565b6001600160a01b03908116825260208083019390935260409182016000908120918816815292528120908b8b88818110610d3457610d34612437565b9050602002810190610d46919061244d565b610d5490602081019061246d565b85818110610d6457610d64612437565b905060200201358152602001908152602001600020819055508080610d88906124b7565b915050610a73565b506001600160a01b038216632eb2c2d630338b8b88818110610db457610db4612437565b9050602002810190610dc6919061244d565b610dd490602081019061246d565b866040518663ffffffff1660e01b8152600401610df5959493929190612563565b600060405180830381600087803b158015610e0f57600080fd5b505af1158015610e23573d6000803e3d6000fd5b50505050505b5080610e34816124b7565b915050610391565b50336001600160a01b03167f011673439234c6c4ab1bbaf0bb213c849faa0badecf357e8257819c9a3d68e138686604051610e789291906126e8565b60405180910390a2610e8a6001606555565b5050505050565b610e9961143a565b610ea1611493565b60fe54811015610ec4576040516311453d1560e11b815260040160405180910390fd5b816000819003610ee75760405163de9fe3cd60e01b815260040160405180910390fd5b60005b8181101561104e57848482818110610f0457610f04612437565b9050602002810190610f16919061244d565b610f2490604081019061246d565b9050600003610f9e57610f99858583818110610f4257610f42612437565b9050602002810190610f54919061244d565b610f629060208101906123b7565b868684818110610f7457610f74612437565b9050602002810190610f86919061244d565b610f9490602081019061246d565b6117ab565b61103c565b61103c858583818110610fb357610fb3612437565b9050602002810190610fc5919061244d565b610fd39060208101906123b7565b868684818110610fe557610fe5612437565b9050602002810190610ff7919061244d565b61100590602081019061246d565b88888681811061101757611017612437565b9050602002810190611029919061244d565b61103790604081019061246d565b6118e4565b80611046816124b7565b915050610eea565b50336001600160a01b03167f32e0a216c38657fb69ac38b36348bcab9651e43af587bf706ba5e7f0c7f712d185858560405161108c93929190612704565b60405180910390a25061109f6001606555565b505050565b6110ac61138e565b6102fd6000611b71565b600054610100900460ff16158080156110d65750600054600160ff909116105b806110f05750303b1580156110f0575060005460ff166001145b6111585760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561117b576000805461ff0019166101001790555b611183611bc3565b61118b611bf3565b611193611c1a565b6111d7604051806040016040528060058152602001640908a9892b60db1b81525060405180604001604052806005815260200164302e302e3160d81b815250611c4d565b6111e284848461123e565b8015611228576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b61123661138e565b6102fd611c8e565b61124661138e565b81158015611252575080155b156112705760405163209d6cb160e21b815260040160405180910390fd5b60fd80546001600160a01b0319166001600160a01b03949094169390931790925560fe5560ff55565b6101005460009060ff166002146112c3576040516356fdbe7d60e11b815260040160405180910390fd5b5063bc197c8160e01b98975050505050505050565b6101005460009060ff16600214611302576040516356fdbe7d60e11b815260040160405180910390fd5b5063f23a6e6160e01b9695505050505050565b61131d61138e565b6001600160a01b0381166113825760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161114f565b61138b81611b71565b50565b6033546001600160a01b031633146102fd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161114f565b6113f0611ccb565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60026065540361148c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161114f565b6002606555565b60975460ff16156102fd5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161114f565b6000808467ffffffffffffffff8111156114f5576114f561251b565b60405190808252806020026020018201604052801561151e578160200160208202803683370190505b50905060005b858110156116a8577fdf26e40bc1f135d6b80b651a07ad65f2a160452b59b747f03bc854090bc5266087878381811061155f5761155f612437565b9050602002810190611571919061244d565b61157f9060208101906123b7565b88888481811061159157611591612437565b90506020028101906115a3919061244d565b6115b190602081019061246d565b6040516020016115c2929190612728565b604051602081830303815290604052805190602001208989858181106115ea576115ea612437565b90506020028101906115fc919061244d565b61160a90604081019061246d565b60405160200161161b929190612728565b6040516020818303038152906040528051906020012060405160200161166394939291909384526001600160a01b039290921660208401526040830152606082015260800190565b6040516020818303038152906040528051906020012082828151811061168b5761168b612437565b6020908102919091010152806116a0816124b7565b915050611524565b5060007f2c85c132c8952239fa3c963700331973245f24d77971c4d8473ceaff6f3c22588989846040516020016116df9190612751565b60408051601f198184030181528282528051602091820120908301959095528101929092526001600160a01b03166060820152608081019190915260a001604051602081830303815290604052805190602001209050600061174082611d14565b905060006117848288888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d6292505050565b60fd546001600160a01b039081169116149b9a5050505050505050505050565b6001606555565b8260005b82811015610e8a57610100805460ff191660021790556001600160a01b0382166342842e0e6117db3390565b308787868181106117ee576117ee612437565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561184557600080fd5b505af1158015611859573d6000803e3d6000fd5b5050610100805460ff1916600190811790915591506101019050600061187c3390565b6001600160a01b03908116825260208083019390935260409182016000908120918a16815292528120908686858181106118b8576118b8612437565b9050602002013581526020019081526020016000208190555080806118dc906124b7565b9150506117af565b846002841015611a3457610100805460ff191660021790556001600160a01b03811663f242432a6119123390565b308888600081811061192657611926612437565b905060200201358787600081811061194057611940612437565b905060200201356040518563ffffffff1660e01b815260040161196694939291906124e3565b600060405180830381600087803b15801561198057600080fd5b505af1158015611994573d6000803e3d6000fd5b5050610100805460ff1916600117905550839050826000816119b8576119b8612437565b9050602002013561010160006119cb3390565b6001600160a01b03908116825260208083019390935260409182016000908120918b168152925281209087878281611a0557611a05612437565b9050602002013581526020019081526020016000206000828254611a299190612424565b90915550611b699050565b610100805460ff191660021790556001600160a01b038116632eb2c2d6611a583390565b30888888886040518763ffffffff1660e01b8152600401611a7e96959493929190612787565b600060405180830381600087803b158015611a9857600080fd5b505af1158015611aac573d6000803e3d6000fd5b5050610100805460ff1916600117905550600090505b84811015611b6757838382818110611adc57611adc612437565b905060200201356101016000611aef3390565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252812090888885818110611b2b57611b2b612437565b9050602002013581526020019081526020016000206000828254611b4f9190612424565b90915550819050611b5f816124b7565b915050611ac2565b505b505050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16611bea5760405162461bcd60e51b815260040161114f906127e6565b6102fd33611b71565b600054610100900460ff166117a45760405162461bcd60e51b815260040161114f906127e6565b600054610100900460ff16611c415760405162461bcd60e51b815260040161114f906127e6565b6097805460ff19169055565b600054610100900460ff16611c745760405162461bcd60e51b815260040161114f906127e6565b81516020928301208151919092012060c99190915560ca55565b611c96611493565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861141d3390565b60975460ff166102fd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161114f565b60006102e7611d21611d86565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000806000611d718585611e06565b91509150611d7e81611e4b565b509392505050565b6000611e017f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611db560c95490565b60ca546040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b905090565b6000808251604103611e3c5760208301516040840151606085015160001a611e3087828585611f95565b94509450505050611e44565b506000905060025b9250929050565b6000816004811115611e5f57611e5f612831565b03611e675750565b6001816004811115611e7b57611e7b612831565b03611ec85760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161114f565b6002816004811115611edc57611edc612831565b03611f295760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161114f565b6003816004811115611f3d57611f3d612831565b0361138b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161114f565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611fcc5750600090506003612050565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612020573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661204957600060019250925050612050565b9150600090505b94509492505050565b60006020828403121561206b57600080fd5b81356001600160e01b03198116811461208357600080fd5b9392505050565b80356001600160a01b03811681146120a157600080fd5b919050565b60008083601f8401126120b857600080fd5b50813567ffffffffffffffff8111156120d057600080fd5b602083019150836020828501011115611e4457600080fd5b60008060008060006080868803121561210057600080fd5b6121098661208a565b94506121176020870161208a565b935060408601359250606086013567ffffffffffffffff81111561213a57600080fd5b612146888289016120a6565b969995985093965092949392505050565b60008083601f84011261216957600080fd5b50813567ffffffffffffffff81111561218157600080fd5b6020830191508360208260051b8501011115611e4457600080fd5b6000806000806000606086880312156121b457600080fd5b853567ffffffffffffffff808211156121cc57600080fd5b6121d889838a01612157565b90975095506020880135945060408801359150808211156121f857600080fd5b50612146888289016120a6565b60008060006040848603121561221a57600080fd5b833567ffffffffffffffff81111561223157600080fd5b61223d86828701612157565b909790965060209590950135949350505050565b60008060006060848603121561226657600080fd5b61226f8461208a565b95602085013595506040909401359392505050565b60008060008060008060008060a0898b0312156122a057600080fd5b6122a98961208a565b97506122b760208a0161208a565b9650604089013567ffffffffffffffff808211156122d457600080fd5b6122e08c838d01612157565b909850965060608b01359150808211156122f957600080fd5b6123058c838d01612157565b909650945060808b013591508082111561231e57600080fd5b5061232b8b828c016120a6565b999c989b5096995094979396929594505050565b60008060008060008060a0878903121561235857600080fd5b6123618761208a565b955061236f6020880161208a565b94506040870135935060608701359250608087013567ffffffffffffffff81111561239957600080fd5b6123a589828a016120a6565b979a9699509497509295939492505050565b6000602082840312156123c957600080fd5b6120838261208a565b6000806000606084860312156123e757600080fd5b6123f08461208a565b92506123fe6020850161208a565b9150604084013590509250925092565b634e487b7160e01b600052601160045260246000fd5b808201808211156102e7576102e761240e565b634e487b7160e01b600052603260045260246000fd5b60008235605e1983360301811261246357600080fd5b9190910192915050565b6000808335601e1984360301811261248457600080fd5b83018035915067ffffffffffffffff82111561249f57600080fd5b6020019150600581901b3603821315611e4457600080fd5b6000600182016124c9576124c961240e565b5060010190565b818103818111156102e7576102e761240e565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052604160045260246000fd5b81835260006001600160fb1b0383111561254a57600080fd5b8260051b80836020870137939093016020019392505050565b600060018060a01b03808816835260208188168185015260a0604085015261258f60a085018789612531565b8481036060860152855180825282870193509082019060005b818110156125c4578451835293830193918301916001016125a8565b505084810360808601526000815281810193505050509695505050505050565b6000808335601e198436030181126125fb57600080fd5b830160208101925035905067ffffffffffffffff81111561261b57600080fd5b8060051b3603821315611e4457600080fd5b81835260006020808501808196508560051b81019150846000805b888110156126da578385038a528235605e19893603018112612668578283fd5b880160606001600160a01b0361267d8361208a565b16875261268c888301836125e4565b828a8a015261269e838a018284612531565b9250505060406126b0818401846125e4565b9350888303828a01526126c4838583612531565b9d8a019d98505050938701935050600101612648565b509298975050505050505050565b6020815260006126fc60208301848661262d565b949350505050565b60408152600061271860408301858761262d565b9050826020830152949350505050565b60006001600160fb1b0383111561273e57600080fd5b8260051b80858437919091019392505050565b815160009082906020808601845b8381101561277b5781518552938201939082019060010161275f565b50929695505050505050565b6001600160a01b0387811682528616602082015260a0604082018190526000906127b49083018688612531565b82810360608401526127c7818587612531565b8381036080909401939093525050600081526020019695505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052602160045260246000fdfea26469706673582212208819677719cdb3ccb0ea8f05c481560744b193112b4f28b685f172001de56e0564736f6c63430008130033

Verified Source Code Full Match

Compiler: v0.8.19+commit.7dd6d404 EVM: paris Optimization: Yes (200 runs)
HelixStake.sol 393 lines
// SPDX-License-Identifier: PRIVATE
pragma solidity ^0.8.19;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";

import "@openzeppelin/contracts-upgradeable/interfaces/IERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol";

// TOKEN
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";

error HelixStake__ConfigError();
error HelixStake__NoDirectTransfer();
error HelixStake__StakeNotExists();
error HelixStake__NotValidRequest();
error HelixStake__StackNoToken();
error HelixStake__PeriodTooShort();

// error HelixStake__NoPermission();

contract HelixStake is
    Initializable,
    OwnableUpgradeable,
    ReentrancyGuardUpgradeable,
    PausableUpgradeable,
    EIP712Upgradeable,
    IERC165Upgradeable,
    IERC721ReceiverUpgradeable,
    IERC1155ReceiverUpgradeable
{
    /*
        HELIX Legal Terms
        1. HELIX Terms of Service [https://helixmetaverse.com/tos/]
        2. HELIX Privacy Policy [https://helixmetaverse.com/privacy/]
    */

    /// @dev Emitted when tokens are staked.
    event TokensStaked(
        address indexed staker,
        StakeRequest[] requests,
        uint256 timePeriod
    );

    /// @dev Emitted when a set of staked token are withdrawn.
    event TokensWithdrawn(address indexed staker, StakeRequest[] requests);

    /// @dev WITHDRAW HASH
    bytes32 private constant WITHDRAW_HASH =
        keccak256(
            "withdraw(uint256 blockNum,address user,StakeRequest[] reqs)StakeRequest(address tokenAddress,uint256[] tokenIds,uint256[] amounts)"
        );

    /// @dev Request HASH
    bytes32 private constant REQ_HASH =
        keccak256(
            "StakeRequest(address tokenAddress,uint256[] tokenIds,uint256[] amounts)"
        );

    /// @dev signer
    address public signer;

    /// @dev The minimal stack time
    uint256 public minStakeTime;

    /// @dev the valid time for request
    uint256 public validTime;

    /// @dev Flag to check direct transfers of staking tokens.
    uint8 internal isStaking = 1;

    /// @dev Stacking Request
    struct StakeRequest {
        address tokenAddress;
        uint256[] tokenIds;
        // 0 length it is a ERC721, ERC1155 otherwise
        uint256[] amounts;
    }

    /// @dev staking data
    mapping(address => mapping(address => mapping(uint256 => uint256)))
        private _stake;

    /// @dev Initiliazes the contract, like a constructor.
    function initialize(
        address _signer,
        uint256 _minStakeTime,
        uint256 _validTime
    ) public initializer {
        __Ownable_init_unchained();
        __ReentrancyGuard_init_unchained();
        __Pausable_init_unchained();
        __EIP712_init_unchained("HELIX", "0.0.1");

        setConfig(_signer, _minStakeTime, _validTime);
    }

    /// @dev update stacking configuration
    function setConfig(
        address _signer,
        uint256 _minStakeTime,
        uint256 _validTime
    ) public onlyOwner {
        if (_minStakeTime <= 0 && _validTime <= 0) {
            revert HelixStake__ConfigError();
        }
        signer = _signer;
        minStakeTime = _minStakeTime;
        validTime = _validTime;
    }

    function pause() external onlyOwner {
        _pause();
    }

    function resume() external onlyOwner {
        _unpause();
    }

    /// @dev stake
    function stake(
        StakeRequest[] calldata _requests,
        uint256 _timePeriod
    ) external nonReentrant whenNotPaused {
        if (_timePeriod < minStakeTime) revert HelixStake__PeriodTooShort();
        uint256 len = _requests.length;
        if (len == 0) revert HelixStake__StackNoToken();

        // check period
        // block.number + _timePeriod;

        // stack
        for (uint256 i = 0; i < len; i++) {
            if (_requests[i].amounts.length == 0) {
                _stakeERC721(_requests[i].tokenAddress, _requests[i].tokenIds);
            } else {
                _stakeERC1155(
                    _requests[i].tokenAddress,
                    _requests[i].tokenIds,
                    _requests[i].amounts
                );
            }
        }
        emit TokensStaked(_stakeSender(), _requests, _timePeriod);
    }

    /// @dev withdraw
    function withdraw(
        StakeRequest[] calldata _req,
        uint256 blockNum,
        bytes calldata _sign
    ) external nonReentrant whenNotPaused {
        if (
            !_checkSignature(blockNum, _stakeSender(), _req, _sign) ||
            blockNum + validTime < block.number
        ) revert HelixStake__NotValidRequest();

        for (uint256 i = 0; i < _req.length; i++) {
            address tokenAddress = _req[i].tokenAddress;
            if (_req[i].amounts.length == 0) {
                // ERC721
                for (uint256 j = 0; j < _req[i].tokenIds.length; j++) {
                    // check if user staked token
                    if (
                        _stake[_stakeSender()][tokenAddress][
                            _req[i].tokenIds[j]
                        ] == 0
                    ) revert HelixStake__StakeNotExists();
                    // clear if user staked
                    _stake[_stakeSender()][tokenAddress][
                        _req[i].tokenIds[j]
                    ] = 0;
                    // transfer token
                    IERC721(tokenAddress).safeTransferFrom(
                        address(this),
                        _stakeSender(),
                        _req[i].tokenIds[j]
                    );
                }
            } else {
                // ERC1155
                if (_req[i].tokenIds.length < 2) {
                    // check if user staked token
                    if (
                        _stake[_stakeSender()][tokenAddress][
                            _req[i].tokenIds[0]
                        ] < _req[i].amounts[0]
                    ) revert HelixStake__StakeNotExists();
                    // clear if user staked
                    uint256 amount = _stake[_stakeSender()][tokenAddress][
                        _req[i].tokenIds[0]
                    ] - _req[i].amounts[0];
                    _stake[_stakeSender()][tokenAddress][
                        _req[i].tokenIds[0]
                    ] = _req[i].amounts[0];
                    IERC1155(tokenAddress).safeTransferFrom(
                        address(this),
                        _stakeSender(),
                        _req[i].tokenIds[0],
                        amount,
                        ""
                    );
                } else {
                    uint256[] memory amounts = new uint256[](
                        _req[i].tokenIds.length
                    );
                    for (uint256 j = 0; j < _req[i].tokenIds.length; j++) {
                        // check if user staked token
                        if (
                            _stake[_stakeSender()][tokenAddress][
                                _req[i].tokenIds[j]
                            ] < _req[i].amounts[j]
                        ) revert HelixStake__StakeNotExists();
                        // clear if user staked
                        amounts[j] =
                            _stake[_stakeSender()][tokenAddress][
                                _req[i].tokenIds[j]
                            ] -
                            _req[i].amounts[j];
                        _stake[_stakeSender()][tokenAddress][
                            _req[i].tokenIds[j]
                        ] = _req[i].amounts[j];
                    }
                    IERC1155(tokenAddress).safeBatchTransferFrom(
                        address(this),
                        _stakeSender(),
                        _req[i].tokenIds,
                        amounts,
                        ""
                    );
                }
            }
        }
        emit TokensWithdrawn(_stakeSender(), _req);
    }

    function getStaked(
        address _addr,
        address _tokenAddr,
        uint256 tokenId
    ) external view returns (uint256) {
        return _stake[_addr][_tokenAddr][tokenId];
    }

    /*///////////////////////////////////////////////////////////////
                        ERC 165 / 721 / 1155 logic
    //////////////////////////////////////////////////////////////*/
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external view returns (bytes4) {
        if (isStaking != 2) revert HelixStake__NoDirectTransfer();
        return this.onERC721Received.selector;
    }

    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) external view returns (bytes4) {
        if (isStaking != 2) revert HelixStake__NoDirectTransfer();
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external view returns (bytes4) {
        if (isStaking != 2) revert HelixStake__NoDirectTransfer();
        return this.onERC1155BatchReceived.selector;
    }

    function supportsInterface(
        bytes4 interfaceId
    ) external pure returns (bool) {
        return
            interfaceId == type(IERC721ReceiverUpgradeable).interfaceId ||
            interfaceId == type(IERC1155ReceiverUpgradeable).interfaceId;
    }

    /*///////////////////////////////////////////////////////////////
                        Internal function
    //////////////////////////////////////////////////////////////*/

    function _stakeERC721(
        address _tokenAddr,
        uint256[] calldata _tokenIds
    ) internal {
        IERC721 token = IERC721(_tokenAddr);
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            // if (
            //     token.ownerOf(_tokenIds[i]) != _stakeSender() ||
            //     (token.getApproved(_tokenIds[i]) != address(this) &&
            //         !token.isApprovedForAll(_stakeSender(), address(this)))
            // ) revert HelixStake__NoPermission();

            isStaking = 2;
            token.safeTransferFrom(_stakeSender(), address(this), _tokenIds[i]);
            isStaking = 1;

            _stake[_stakeSender()][_tokenAddr][_tokenIds[i]] = 1;
        }
    }

    function _stakeERC1155(
        address _tokenAddr,
        uint256[] calldata _tokenIds,
        uint256[] calldata _amounts
    ) internal {
        IERC1155 token = IERC1155(_tokenAddr);
        if (_tokenIds.length < 2) {
            // if (
            //     token.balanceOf(_stakeSender(), _tokenIds[0]) < _amounts[0] ||
            //     !token.isApprovedForAll(_stakeSender(), address(this))
            // ) revert HelixStake__NoPermission();
            isStaking = 2;
            token.safeTransferFrom(
                _stakeSender(),
                address(this),
                _tokenIds[0],
                _amounts[0],
                ""
            );
            isStaking = 1;

            _stake[_stakeSender()][_tokenAddr][_tokenIds[0]] += _amounts[0];
        } else {
            isStaking = 2;
            token.safeBatchTransferFrom(
                _stakeSender(),
                address(this),
                _tokenIds,
                _amounts,
                ""
            );
            isStaking = 1;

            for (uint256 i = 0; i < _tokenIds.length; i++) {
                _stake[_stakeSender()][_tokenAddr][_tokenIds[i]] += _amounts[i];
            }
        }
    }

    /// @dev check signature
    function _checkSignature(
        uint256 blockNum,
        address _sender,
        StakeRequest[] calldata _reqs,
        bytes calldata _sign
    ) internal view returns (bool) {
        bytes32[] memory reqHash = new bytes32[](_reqs.length);
        for (uint256 i = 0; i < _reqs.length; i++) {
            reqHash[i] = keccak256(
                abi.encode(
                    REQ_HASH,
                    _reqs[i].tokenAddress,
                    keccak256(abi.encodePacked(_reqs[i].tokenIds)),
                    keccak256(abi.encodePacked(_reqs[i].amounts))
                )
            );
        }
        bytes32 hash = keccak256(
            abi.encode(
                WITHDRAW_HASH,
                blockNum,
                _sender,
                keccak256(abi.encodePacked(reqHash))
            )
        );
        bytes32 digest = _hashTypedDataV4(hash);
        address signer_ = ECDSAUpgradeable.recover(digest, _sign);
        return signer_ == signer;
    }

    /// @dev Exposes the ability to override the msg sender -- support ERC2771.
    function _stakeSender() internal virtual returns (address) {
        return msg.sender;
    }
}
IERC721.sol 145 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
IERC1155.sol 125 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
AddressUpgradeable.sol 219 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
ContextUpgradeable.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
StringsUpgradeable.sol 70 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";

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

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

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

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

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}
OwnableUpgradeable.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
Initializable.sol 165 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @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]
 * ```
 * 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 Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _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 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _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() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @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 {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}
MathUpgradeable.sol 345 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}
PausableUpgradeable.sol 117 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
IERC165Upgradeable.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165Upgradeable.sol";
ReentrancyGuardUpgradeable.sol 81 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import "../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;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}
ECDSAUpgradeable.sol 213 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../StringsUpgradeable.sol";

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

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

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

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

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

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

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

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

        return (signer, RecoverError.NoError);
    }

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

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

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

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}
EIP712Upgradeable.sol 121 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.0;

import "./ECDSAUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 *
 * @custom:storage-size 52
 */
abstract contract EIP712Upgradeable is Initializable {
    /* solhint-disable var-name-mixedcase */
    bytes32 private _HASHED_NAME;
    bytes32 private _HASHED_VERSION;
    bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
        __EIP712_init_unchained(name, version);
    }

    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev The hash of the name parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712NameHash() internal virtual view returns (bytes32) {
        return _HASHED_NAME;
    }

    /**
     * @dev The hash of the version parameter for the EIP712 domain.
     *
     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
     * are a concern.
     */
    function _EIP712VersionHash() internal virtual view returns (bytes32) {
        return _HASHED_VERSION;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}
IERC165Upgradeable.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
IERC721ReceiverUpgradeable.sol 27 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721ReceiverUpgradeable {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}
IERC1155ReceiverUpgradeable.sol 58 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155ReceiverUpgradeable is IERC165Upgradeable {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

Read Contract

getStaked 0xfb930e72 → uint256
minStakeTime 0x1f7678ce → uint256
onERC1155BatchReceived 0xbc197c81 → bytes4
onERC1155Received 0xf23a6e61 → bytes4
onERC721Received 0x150b7a02 → bytes4
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
signer 0x238ac933 → address
supportsInterface 0x01ffc9a7 → bool
validTime 0xbbe44917 → uint256

Write Contract 8 functions

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

initialize 0x7a1ac61e
address _signer
uint256 _minStakeTime
uint256 _validTime
pause 0x8456cb59
No parameters
renounceOwnership 0x715018a6
No parameters
resume 0x046f7da2
No parameters
setConfig 0xacd2ebf2
address _signer
uint256 _minStakeTime
uint256 _validTime
stake 0xdb27d23a
tuple[] _requests
uint256 _timePeriod
transferOwnership 0xf2fde38b
address newOwner
withdraw 0xd03dc306
tuple[] _req
uint256 blockNum
bytes _sign

Recent Transactions

No transactions found for this address