Building a Token Vesting Contract

Enabling long-term relationships with members of a token ecosystem

In a token ecosystem, how do you guarantee that tokens will be issued at a future point in time to long-term members of your community?

The answer is token vesting, and it’s one of the more interesting features of the Cardstack token contract we’re building. This will be an important way to incentivize users to join Cardstack’s ecosystem—and remain committed.

I’d like to share with you how our token vesting is implemented in our Solidity codebase. Our strategy borrows heavily from the approach used by Open Zeppelin, which is a generic vesting contract that can manage vesting for any ERC20 token.

The primary difference: token vesting is built directly into our token contract and allow the Cardstack Foundation to grant tokens that vest to any participant of the Cardstack ecosystem. It’s also the mechanism by which the Cardstack Foundation itself receives Cardstack tokens.

A typical vesting schedule.

How it Works

The Cardstack Foundation grants vested tokens to users — we’ll call them beneficiaries. This is done by invoking a privileged function with the vesting schedule defined as parameters to the function grantVestedTokens().

The grantVestedTokens() function uses the following parameters:

  • Beneficiary token address
  • Fully vested amount
  • Vesting start date (as Unix time). If not specified, vesting begins as soon as the transaction is mined.
  • Vesting duration (as seconds)
  • Vesting cliff (as seconds from vesting start)
  • Vesting revocation

The current vesting status can be monitored by calling the view function (non-blockchain altering)getVestingSchedule(address beneficiary) on the token contract. This function returns:

  • The vesting start date (as unix time)
  • The vesting cliff date (as unix time)
  • The duration of vesting (as seconds)
  • The fully vested amount
  • The currently vested amount as of date-timestamp of the most recently mined block
  • The currently vested available amount as of the date-timestamp of the most recently mined block, where vested tokens are not available before the cliff date
  • The amount of tokens that are releasable
  • Vesting revocation
  • The revoke date (if the vesting has been revoked)

After a vested token grant is issued, a releaseVestedTokens() function can be called (in the same manner as the Open Zeppelin vested contract), to release any tokens that have vested after the cliff date into the beneficiary’s address that have not yet been “collected”. The smart contract uses the date-timestamp of the block that the releaseVestedTokens() function call was mined within to calculate the amount of tokens that have vested since the vesting start date.

Once the tokens have been released into the beneficiary’s address, the beneficiary is free to use the tokens as they wish. As more tokens vest, the beneficiary can continue to release the tokens into their account as often as they wish, using the vestingSchedule(address beneficiary) function to monitor the amount of tokens that are releasable.

After the beneficiary’s tokens have fully vested, and the beneficiary has collected all their tokens by calling releaseVestedTokens() a final time, then the vesting will be complete and no more tokens may be collected by calling releaseVestedTokens(). At this point the Cardstack Foundation has the option to granting a new vested token grant to the same beneficiary. Note that we currently observe a limit of one active token vesting schedule per beneficiary address.

Vesting Revocation

There are instances in which a vesting schedule should be revoked. For example: an employee who receives vested tokens as a condition of their employment — and whose tokens would stop vesting on their last day of employment. We call this “Vesting Revocation”. When a vesting schedule is revoked, the beneficiary can claim all the tokens that have vested between the vesting start date and the vesting revoke date — but not any new vested tokens after that date.

A revocable vesting schedule.

When a vesting schedule is established a flag is specified to indicate if the vesting is revokable. A non-revokable vesting schedule will always reach the fully vested amount after the vesting duration has elapsed. A revokable vesting schedule may be revoked by the Cardstack Foundation before the fully vested amount has been reached by calling the revokeVesting() function, in which case the vested and unreleased tokens at the date of the revocation are immediately released into the beneficiary’s address. After the revocation, Cardstack Foundation can create a new vesting schedule for the beneficiary which will vest normally based on the new vesting schedule’s parameters.

Vesting and Circulation Cap

There are two limits that govern the amount of Cardstack tokens that exist and can be used.

The first limit is the amount of Cardstack tokens that have been minted. The second limit is a self-imposed limit that Cardstack places on the amount of tokens that are able to be in circulation at any moment. The circulation limit prevents Cardstack tokens from being granted or purchased beyond the stated limit. The circulation limit is gradually increased each year in a logarithmic fashion. (You can view our complete token details here.)

In order to provide vested tokens enough headroom to fully vest without breaching the circulation limit, and without exceeding the amount of tokens that have been minted, the Cardstack token contract only permits vested token grants to be issued when the fully vested amount of the grant does not exceed the circulation limit, nor the amount of minted tokens.

When a vested token grant is issued, at the time of issuance the fully vested token amount is considered as tokens “in circulation”. This permits the vested token grant to vest in a manner that is unencumbered by the circulation cap, thus ensuring the beneficiaries have guaranteed access to their vested tokens at all points in time.

Wrapping It Up

All of us at Cardstack are excited about the vesting mechanism built into our ERC20 token. As we’ve shown above, we’ve built it in such a manner that ensures beneficiaries have guaranteed access to vested tokens. We’ve created tools to make it really easy to see the status of vested token grants and to start using vested tokens immediately within the Cardstack platform.

This will be a powerful way for us to pique interest, build relationships with our community, and reward those who stay for the long haul.

Join our community

To learn more about Cardstack, visit https://cardstack.com.

Join the Cardstack community channel on Telegram at https://t.me/cardstack


Hassan (@habdelra) has been designing and building a system for digital scarcity and digital rights on the bitcoin blockchain since 2014. He has been working on open-source Cardstack codebase since 2015 focusing on bringing external data sources into the Cardstack framework. Hassan is leading the design and architecture efforts in Solidity for Cardstack, and is an expert on the trade-offs of on-chain and off-chain computation and storage. Hassan has a Bachelor’s degree in Computer Science and Mathematics from the Colorado School of Mines.