How is TokenVesting contract working in Reality?

Hi, I’m curious how TokenVesting contract and this function in particular will work in reality:

This would mean, that the funds on a ERC20-Token for the executer are already present in order to make this transfer happen, isn’t it?

Because _transfer is defined as follows:

function _transfer(address from, address to, uint256 value) internal {
    require(to != address(0));

    _balances[from] = _balances[from].sub(value);
    _balances[to] = _balances[to].add(value);
    emit Transfer(from, to, value);
}

The release-Method of TokenVesting-Contract is defined like this:

token.safeTransfer(_beneficiary, unreleased);

At the end, safeTransfer transfers token from msg.sender to _beneficiary, which means that msg.sender needs to hold the required funds in order to make this transfer really happen. But how is this contract avoiding a double spent? It can not control the original funds and freeze them.

Is it my mistake in thinking ?
How is it meant this way to work with VestingContract?

(I know that it is just a draft)

1 Like

Hi @itinance

Good places to start are the documentation and the tests

Tokens to be vested need to be transferred to the TokenVesting contract. The process is:

  1. Create the TokenVesting instance
  2. Transfer token(s) to vest

From https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/test/drafts/TokenVesting.test.js

    beforeEach(async function () {
      this.vesting = await TokenVesting.new(
        beneficiary, this.start, this.cliffDuration, this.duration, true, { from: owner });

      this.token = await ERC20Mintable.new({ from: owner });
      await this.token.mint(this.vesting.address, amount, { from: owner });
    });

Yes. Tokens need to be transferred to the TokenVesting contract.

msg.sender is actually the TokenVesting contract holding the tokens to vest. The tokens can only be transferred out of the TokenVesting contract via either release or revoke


There is also a simple holding contract, TokenTimelock:

2 Likes

Is there any chance to combine TokenVesting with TokenTimelock? I have already asked here for a similar situation.

In my clients use case is as follows:

  • at every last day of a month all tokens, that was sold so far, where duplicated into a TokenTimelock for 12 month (every month a new instance of TokenTimelock is created)
  • But after the 12 months only 10% of total token can be released per month, until all token was released.

It would be easy if we could pass the TokenVesting contract (with little changes) as beneficiary into the TokenTimelock. But it is not possible to release these tokens any more because we don’t habe the private key of the TokenVesting contract.

1 Like

Seems to work. I was confused who is allowed to call the release-method in this case.

1 Like

But how is the permissions-model handled in TokenTimelock-contract? In my tests everybody is able to call the release method and thus be able to release tokens into beneficiaries account. Shall it be allowed this way?

1 Like

There is no need to restrict who can call release, as release transfers tokens only to the beneficiary. This means that the beneficiary, the token project or any third party could release the tokens. It gives flexibility for how this can be used.

    /**
     * @notice Transfers tokens held by timelock to beneficiary.
     */
    function release() public {
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp >= _releaseTime, "TokenTimelock: current time is before release time");

        uint256 amount = _token.balanceOf(address(this));
        require(amount > 0, "TokenTimelock: no tokens to release");

        _token.safeTransfer(_beneficiary, amount);
    }

Alright, thanks @abcoathup for your confirmation! It is indeed a very convinient method to release those tokens.

1 Like