Withdraw functionality in solidity of locker smartcontract

i am developing a locker smartcontract where user can send erc20 token and set time for locking period.for withdraw function i want to implement:

the locking time should passed
the address( wallet) lock the token can only withdraw

i am having difficulty to build the logic for withdraw function.

here is the code

    pragma solidity ^0.8.7;
// SPDX-License-Identifier: MIT

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract lock  {
    address public owner;
    
   struct Lock{
       address token;
       uint amount;
       uint endtime;

    }

    constructor() {
     owner= msg.sender;
     
    }

    mapping(address => Lock) public tokenLock;

    function locker( address _token, uint256 _amount, uint _time) public{
        
        tokenLock[msg.sender]= Lock(_token, _amount, _time);
        IERC20(_token).transferFrom(msg.sender, address(this),_amount);
       }
    
   function chkBalance(address _token) public view returns (uint){
     return  IERC20(_token).balanceOf(address(this));
   }

   

   >  function claim(address _token) public { 
>          require(block.timestamp >time);
> 
>        }

}

I think you need to update your struct to add some type of identification, so you can refer to the correct locked token. I have added Id in my below example code.

       struct Lock{
       address token;
       uint amount;
       uint endtime;
       uint256 id;
    }

Lock[] public locker;

function claim(uint256 _Id, address _token) public { 
Lock storage claimRequest = locker[_Id];
require(claimRequest.endtime <= block.timestamp);
// continue your function here
}

but how would user know what id to add? and how to implement this part…* the address (wallet)lock the token can only withdraw.

you need to create it inside the contract, like a counter.
Every time the locker function is called the counter should increment by 1, so there wont be any duplicates in Id.

You need to check if the Id is owned by the owner. This will require adding one more mapping to map Id’s to a wallet addresses, so you can add a require function to check if the wallet owns the Locked tokens of that particular Id

mapping (uint256 => address) public lockerOwner; //you need to add "lockerOwner[Id] = msg.sender;" inside your locker function.

function claim(uint256 _Id, address _token) public { 
Lock storage claimRequest = locker[_Id];
require(lockerOwner[Id] == msg.sender);
require(claimRequest.endtime <= block.timestamp);
// continue your function here
}

> you need to create it inside the contract, like a counter.
> Every time the `locker` function is called the counter should increment by 1, so there wont be any duplicates in Id.

can u show me?

Simple way to do it is by defining a counter

int counter;

// add initial value of you counter in constructor so it starts with zero.
constructor() {
       counter = 0;
    }

// add this inside your `locker` function
Id = counter;
tokenLock[msg.sender]= Lock(_token, _amount, _time, Id);

// add this at the end of the function.
counter += 1;

Edit: make sure the data types of id and counter are same

1 Like

how about this implementation of claim function:

/ SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract lock  {
    address public owner;
    
    struct Lock {
        address token;
        uint amount;
        uint endtime;
    }

    constructor() {
        owner = msg.sender;
    }

    mapping(address => Lock) public tokenLock;

    function locker( address _token, uint256 _amount, uint _time) public{
        // NOTE: Add 'block.timestamp' plus time for manage lock time  
        tokenLock[msg.sender] = Lock(_token, _amount, block.timestamp + _time);
        IERC20(_token).transferFrom(msg.sender, address(this),_amount);
    }
    
    function chkBalance(address _token) public view returns (uint){
        return IERC20(_token).balanceOf(address(this));
    }

   >  function claim(address _token) public { 
>         // NOTE: Retrieve the end time from Lock struct
>         uint time = tokenLock[msg.sender].endtime;
>         require(block.timestamp > time, "You must to attend your locktime!");
>         address _to = msg.sender;
>         uint amountTokenInSmartContract = IERC20(_token).balanceOf(address(this));
>         // NOTE: Use 'transfer' method for send '_to' address the amount of token locked inside smart contract  
>         IERC20(_token).transfer(_to, amountTokenInSmartContract);
>     }
> 
> }
> ```

This is ok, but my concern is what if one user runs the locker function multiple times?
The old Lock data of the user will be replaced with new data.

If there won’t be any such instances, then your logic works fine.