Example using TokenTimelock

A community member requested an example of using TokenTimelock for an ERC20 token.

1 Like

The following is an example using TokenTimelock.
Contracts are deployed and interacted with using OpenZeppelin CLI 2.8: Release Candidate

:warning: This is sample code that has not been tested.
Any production solution should be appropriately tested and audited.
Care should be taken when calculating the release time.

SimpleToken.sol

ERC20 token

pragma solidity ^0.5.0;

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

/**
 * @title SimpleToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract SimpleToken is ERC20, ERC20Detailed {

    /**
     * @dev Constructor that gives msg.sender all of existing tokens.
     */
    constructor () public ERC20Detailed("SimpleToken", "SIM", 18) {
        _mint(msg.sender, 10000 * (10 ** uint256(decimals())));
    }
}

SimpleTokenTimelock.sol

TokenTimelock

pragma solidity ^0.5.0;

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

contract SimpleTokenTimelock is TokenTimelock {
    constructor(IERC20 token, address beneficiary, uint256 releaseTime)
        public
        TokenTimelock(token, beneficiary, releaseTime)
    {}
}

Deploy and setup

Deploy ERC20 token (using OpenZeppelin CLI 2.8: Release Candidate)

$ npx oz deploy
✓ Compiled contracts with solc 0.5.16 (commit.9c3226ce)
? Choose the kind of deployment regular
? Pick a network development
? Pick a contract to deploy SimpleToken
✓ Deployed instance of SimpleToken
0x0290FB167208Af455bB137780163b7B7a9a10C16

For manual testing I used a package to calculate the timestamp.
Care should be taken when calculating the release time, and appropriately tested.

$ npx epoch-cli "2020/02/26 13:52"
npx: installed 1 in 1.274s
1582685520

Deploy ERC20 token timelock (using OpenZeppelin CLI 2.8: Release Candidate).
Specify the token address (from above), a beneficiary (used npx oz accounts) and a release time.

$ npx oz deploy
Nothing to compile, all contracts are up to date.
? Choose the kind of deployment regular
? Pick a network development
? Pick a contract to deploy SimpleTokenTimelock
? token: address: 0x0290FB167208Af455bB137780163b7B7a9a10C16
? beneficiary: address: 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
? releaseTime: uint256: 1582685520
✓ Deployed instance of SimpleTokenTimelock
0x9b1f7F645351AF3631a656421eD2e40f2802E6c0

Transfer ERC20 tokens to be locked to the token timelock

$ npx oz send-tx
? Pick a network development
? Pick an instance SimpleToken at 0x0290FB167208Af455bB137780163b7B7a9a10C16
? Select which function transfer(recipient: address, amount: uint256)
? recipient: address: 0x9b1f7F645351AF3631a656421eD2e40f2802E6c0
? amount: uint256: 10000000000000000000000
✓ Transaction successful. Transaction hash: 0xb2ed00ddd6b00c8eae8b05dbe85bc3f76937c61c5dfdf401607786317b6ce3da
Events emitted:
 - Transfer(0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1, 0x9b1f7F645351AF3631a656421eD2e40f2802E6c0, 10000000000000000000000)

Attempt to release

Attempt to release the tokens from the timelock prior to the release time.

 npx oz send-tx
? Pick a network development
? Pick an instance SimpleTokenTimelock at 0x9b1f7F645351AF3631a656421eD2e40f2802E6c0
? Select which function release()
✖ Calling: 'release' with no arguments
Error while trying to send transaction to 0x9b1f7F645351AF3631a656421eD2e40f2802E6c0. Error: Returned error: VM Exception while processing transaction: revert TokenTimelock: current time is before release time

Release

After the release time, the tokens can be released

$ npx oz send-tx
? Pick a network development
? Pick an instance SimpleTokenTimelock at 0x9b1f7F645351AF3631a656421eD2e40f2802E6c0
? Select which function release()
✓ Transaction successful. Transaction hash: 0xcd95721503e20f29e4f32c448fca1f486db03a7662ed95267d3509f4f609622e

Check balance

$ npx oz call
? Pick a network development
? Pick an instance SimpleToken at 0x0290FB167208Af455bB137780163b7B7a9a10C16
? Select which function balanceOf(account: address)
? account: address: 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
✓ Method 'balanceOf(address)' returned: 10000000000000000000000
10000000000000000000000