Can I increase the number of locked address in TokenTimelock contract?

Hi everyone,

I would like to create smart contract where I can lock the erc20 token. I found that TokenTimeLock contract can do this. However it can only lock one address. (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/TokenTimelock.sol)
I want to lock several addresses in different amounts and different release time.
So I change the storage in TokenTimelock contract.

address private immutable _beneficiary;
uint256 private immutable _releaseTime;

And replace with two mappings.

Mapping (lockedAddress => lockedAmount)
Mappint (lockedAddress => lockedTime)

I wonder if this is an appropriate way and if there are any security issues.
I would appreciate every answer as I'm worrying with that for days.
Thank You.

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/utils/TokenTimelock.sol)

pragma solidity ^0.8.0;

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

contract Tokenlock is Ownable {
    using SafeERC20 for IERC20;
    IERC20 private immutable _token;

    mapping (address => uint256) private _releaseTime ;
    mapping (address => uint256) private _releaseAmount;

    constructor(
        IERC20 token_
    ) {
        _token = token_;
    }

    function token() public view returns (IERC20) {
        return _token;
    }

    function setTimeMapping(address[] memory _beneficiaryList, uint256[] memory _time) external onlyOwner {
        require(_beneficiaryList.length == _time.length, "length not equal");
        for(uint i = 0; i < _time.length; i++){
            _releaseTime[_beneficiaryList[i]] = _time[i];
        }
    }

    function setAmountMapping(address[] memory _beneficiaryList, uint256[] memory _amount) external onlyOwner {
        require(_beneficiaryList.length == _amount.length, "length not equal");
        for(uint i = 0; i < _amount.length; i++){
            _releaseAmount[_beneficiaryList[i]] = _amount[i];
        }
    }

    function release() public {
        address releaseAddress = msg.sender;
        require(block.timestamp >= _releaseTime[releaseAddress], "TokenTimelock: current time is before release time");

        uint256 amount = _releaseAmount[releaseAddress];
        require(token().balanceOf(address(this)) > amount, "TokenTimelock: no tokens to release");

        token().safeTransfer(releaseAddress, amount);
    }
}

Hey @roy105703007 we've built an open-source ERC20Lockable extension for Flair, the source-code is here: https://github.com/0xflair/evm-contracts/blob/main/contracts/tokens/extensions/ERC20RoleBasedLockingExtension.sol

It uses AccessControl and "Roles" to control the lock, basically you can lock for any address your want, or you can lock/unlock for all addresses by giving the role to address(0).

You can actually use our dashboard to deploy this contract yourself quickly and playaround with it :slight_smile: https://app.flair.finance/tokens

Also if you like to have the "vesting & time-based release" we do have "Streams" contracts that helps you do that (also open-source), you'll basically give your wallets special NFTs that allows them to "claim" these ERC20 tokens.

This allows you to top-up the stream anytime with ERC20 and also the claimer wallets can transfer those NFTs to any wallet they want, because the released tokens are assigned to NFT instead of only their wallet address, more convenience for the claimer :slight_smile:

Let me know if this was helpful.

Hi Aram,

It was very helpful!
I need time to understand the contract you wrote.
But this helped me a lot.
Thank you very much for your reply!

1 Like