How to use TokenTimelock.sol to lock up tokens?

Hello wonderful people!

I am not a developer but I managed to use openzeppelin to create my first erc20 token for my game project! it’s working wonderfully.

This is a wonderful project! Many thanks for all contributors :blush:

I want to use TokenTimelock.sol to create a new contract so that I can send some tokens to it to lock them up for a specific time

here’s my tokenlockup.sol file:

pragma solidity ^0.5.2;

import "openzeppelin-solidity/contracts/token/ERC20/TokenTimelock.sol";


contract lockupMyTokens {
  string public constant token = "0xmytokenaddress";
  string public constant beneficiary = "0xmyBeneficiaryAddress";
  // Test May 28th 8:30 pm GNT
  uint256 public constant releaseTime = 1559075400;
}

I deployed it to testnet but I cannot interact with the contract. I think I need to add some function or constructor.

Can anyone help me to add this missing piece?

I looked at all github issues / PRs and couldn’t find an example that I can copy paste and use because I don’t have much dev experience, I couldn’t figure this out and it’s been 2 days now.

Any help would be appreciated!

3 Likes

Hi @manipulator01
Welcome to the forum. It would be great if you could take a moment and Introduce yourself here! including a bit more about the game you are working on.

A TokenTimelock contract could look as follows:
What you didn’t have was inheriting from TokenTimelock (is TokenTimelock) and calling the TokenTimelock constructor with your desired values.

Once deployed, as you said, you would need to transfer the tokens to the timelock contract.

pragma solidity ^0.5.2;

import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/TokenTimelock.sol";


contract SimpleTokenTimelock is TokenTimelock {
    constructor () public TokenTimelock(
        IERC20(0xCfEB869F69431e42cdB54A4F4f105C19C080A601), // token
        0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b, // beneficiary
        1559075400) {
    }
}

If there isn’t an example, the tests can be good to look at to work out how a contract works. Though please ask all the questions that you need.

3 Likes

Note that it’s not necessary to use inheritance to define the constructor arguments.

If you’re using a Truffle/web3.js contract, for example you can pass arguments as TokenTimelock.new(token, beneficiary, release). If you’re using Truffle migrations, I think you can do deployer.deploy(TokenTimelock, token, beneficiary, release).

2 Likes

Thank you so much @abcoathup! It worked like a charm. :heart_eyes:
@frangio thanks for the advice. I didn’t know I can do that.

You guys are awesome. :slightly_smiling_face:

3 Likes

Hi @manipulator01 when you have a moment it would be awesome if you could Introduce yourself here! and/or let us know What are you working on?

1 Like

Hi @frangio, please how is the amount to be locked indicated?

You deploy a TokenTimelock instance, then you transfer ERC20 tokens to it. All of the ERC20 balance in the timelock will be locked until the specified release date. So the amount is defined by how much you transfer into it.

I get an error as seen in ss :confused:

Hi, welcome! :wave:

Just like the error message: Release time is before current time, so just set a delayed time.

1 Like

Hello, thanks a lot for your help :slight_smile:

I set a forward time to lock, send the request. As a result, the success returns, but it happens when you make any withdrawals.
As a result of my tests, it does not work stable :confused:
my goal is to generate a new token and integrate tokentimelock
example i want to do and can i do this example
Ex: tokenTimeLock request "withdrawal" : [
{"toAddress":0xaaaaa , "amount": 123455667, "locktime": 1639837380 },
{"toAddress":0xaaaaa , "amount": 347, "locktime": 1639847380 },
{"toAddress":0xaaaaa , "amount": 33242434, "locktime": 1639897380 }
] or
{"toAddress":0xaaaaa , "amount": 123455667, "locktime": 1639837380 }

sample scenario

Wallet1 will send 3 times tokens to Wallet2,

1 st transfer
wallet1 will send 10 tokens to wallet2 and wallet2 will be able to use 10 tokens after 4 days

2 nd transfer
wallet1 will send 7 tokens to wallet2 and wallet2 will be able to use 7 tokens sent at any time

3 rd transfer
wallet1 will send 15 coins to wallet2 and wallet2 will be able to use 15 coins after 9 days

  1. day -> 5.day -> 16.day

7 token unlocked 7 token unlocked 7 token unlocked
10 token locked will open in 4 days 10 token unchecked 10 token unchecked
15 token locked will open in 15 days 15 token locked will open in 11 days 15 token unlocked

total locked token: 25 token total locked token: 15 token total locked token: 0 token
unlocked: 7 unlocked: 17 unlocked: 32

Maybe you should share your contract at here.

I'm trying to create a "Timelock.sol" like structure using the Openzepplin library and add the MyToken contract. this is the build i'm trying to do, How can I create this structure in a healthy way? :confused:

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "./Timelock";

contract MyToken is ERC20, ERC20Burnable, ERC20Snapshot, Ownable, Pausable, Timelock {
    constructor() ERC20("MyToken", "MTK") {
        _mint(msg.sender, 1000000 * 18 ** decimals());
        Timelock(address(0));
    }

    function snapshot() public onlyOwner {
        _snapshot();
    }

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

    function unpause() public onlyOwner {
        _unpause();
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount)
        internal
        whenNotPaused
        override(ERC20, ERC20Snapshot)
    {
        super._beforeTokenTransfer(from, to, amount);
    }

    

}

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

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

 abstract contract Timelock {
  uint public constant duration = 15 minutes;
  uint public immutable end;
  address payable public immutable owner;

  constructor(address payable _owner) {
    end = block.timestamp + duration;
    owner = _owner; 
  }

  function deposit(address token, uint amount) external {
    IERC20(token).transferFrom(msg.sender, address(this), amount);
  }

  receive() external payable {}

  function withdraw(address token, uint amount) external {
    require(msg.sender == owner, 'only owner');
    require(block.timestamp >= end, 'too early');
    if(token == address(0)) { 
      owner.transfer(amount);
    } else {
      IERC20(token).transfer(owner, amount);
    }
  }
}

I am getting such an error when using the contract I wrote.

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

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

contract Timelock {
  uint public constant duration = 13 minutes;
  uint public immutable end;
  address payable public immutable owner;

  constructor(address payable _owner) {
    end = block.timestamp + duration;
    owner = _owner; 
  }

  function deposit(address token, uint amount) external {
    IERC20(token).transferFrom(msg.sender, address(this), amount);
  }

  receive() external payable {}

  function withdraw(address token, uint amount) external {
    require(msg.sender == owner, 'only owner');
    require(block.timestamp >= end, 'too early');
    if(token == address(0)) { 
      owner.transfer(amount);
    } else {
      IERC20(token).transfer(owner, amount);
    }
  }
}


I created a sample token, but got such error from transferfrom

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

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

contract TrialToken is ERC20 {
    constructor() ERC20("TrialToken", "TTK") {
        _mint(msg.sender, 50000000 * 10 ** decimals());
    }
}

Hello friends.

Can you tell me, I think this contract is not suitable for my purpose.

  • There are 10,000 tokens.
  • There are 10 user groups - team, investors, advertisers, ...
  • There are 3 months.

I need to have each group of users, in percentage terms, unlock tokens every day.

If for everyone to create a new contract TokenTimelock.sol, this is probably not very rational.

Are there ready-made solutions for my task?

You should deploy one TokenTimelock (or VestingWallet) per group. Each instance would have the tokens dedicated to the group corresponding.

1 Like

Thank you.

I found another interesting implementation option with a large number of functions.

The contract has been audited.

Perhaps one day it will appear on the openzeppelin list.

FYI; this is also an option: https://github.com/p00ls/contracts/blob/master/contracts/finance/vesting/VestedAirdrops.sol

Note: its not OZ official code, even though I wrote it

@Amxx Could you clarify a bit about the "one vestingwallet per group" statement? I thought that a VestingWallet only managed one beneficiary (address), so that each person would need his own VestingWallet contract. Is this not the case?