// SPDX-License-Identifier: CC0-1.0
pragmasolidity^0.8.0;import"@openzeppelin/contracts/token/ERC20/ERC20.sol";contractLockedERC20ExampleContractimplementsERC-7444{ERC20publicimmutabletoken;uint256publictotalLocked;//Timelock struct
structTimeLock{addressowner;uint256amount;uint256maturity;bytes32lockId;}//maps lockId to balance of the lock
mapping(bytes32=>TimeLock)publicidToLock;functionconstructor(address_token,)public{token=ERC20(_token);}//Maturity is not appropriate
errorLockPeriodOngoing();errorInvalidReceiver();errorTransferFailed();/// @dev Deposit tokens to be locked in the requested locking period
/// @param amount The amount of tokens to deposit
/// @param lockingPeriod length of locking period for the tokens to be locked
functiondeposit(uint256amount,uint256lockingPeriod)externalreturns(bytes32lockId){uint256maturity=block.timestamp+lockingPeriod;lockId=keccack256(abi.encode(msg.sender,amount,maturity));require(idToLock[lockId].maturity==0,"lock already exists");if(!token.transferFrom(msg.sender,address(this),amount)){revertTransferFailed();}TimeLockmemorynewLock=TimeLock(msg.sender,amount,maturity,lockedId);totalLocked+=amount;idToLock[lockId]=newLock;}/// @dev Withdraw tokens in the lock after the end of the locking period
/// @param lockId id of the lock that user have deposited in
functionwithdraw(bytes32lockId)external{TimeLockmemorylock=idToLock[lockId];if(msg.sender!=lock.owner){revertInvalidReceiver();}if(block.timestamp>lock.maturity){revertLockPeriodOngoing();}totalLocked-=lock.amount;//State cleanup
deleteidToLock[lockId];if(!token.transfer(msg.sender,lock.amount)){revertTransferFailed();}}functiongetMaturity(bytes32id)externalviewreturns(uint256maturity){returnidToLock[id].maturity;}}