How to check vesting statements in Smart Contracts ?

René Füchtenkordt
TrustedDapps
Published in
9 min readApr 18, 2018

Vesting is an important tool to keep founders from running away with your money. A vesting contract is set between the founders and their investors and ensures that the money they receive is paid out over time. The payout is split in parts called tranches.

A simple vesting statement could look like this:

Company x receives an investment of $10M. 10% are reserved as a bonus for the team vested over 4 years.

Usually tranches are paid out yearly, so in this case $1M / 4 Years = $ 250K per year goes to the team. Often there will also be a so called “cliff” which is a delay before the vesting period starts.

Normally the contracts are written by lawyers and there needs to be a seperate vesting statement for every investment received. In a situation where hundreds of people invest small amounts of money — as it is often the case in ICOs — this approach is not feasible.

Luckily, with the emergence of smart contracts, vesting statements can be enforced automatically. The amount of individual investors and money received doesn’t matter. Instead of lawyers and lots of paperwork, we just need a few lines of code — beautiful.

Vesting is a tool to make a project more attractive to investors, and I’ve seen this on any good whitepaper so far. But the problem with whitepapers is, that they are just papers and won’t enforce anything. So the vesting statements need to be encoded in a smart contract on the blockchain.

In this guide you will learn how to check vesting statements in smart contracts for yourself.

1. Gather data

I picked Nucleus Vision as an example for this tutorial.

In the whitepaper on page 52 it states that:

“25% of the tokens will be allocated to the founding Nucleus Vision team […]. The team tokens will be locked in a smart contract with a 24-months vesting period and six-months cliff.”

The token supply is 10 billion nCash, so 2.5 billion nCash goes to the team over 2 years. So we have two tranches of 1.25 billion nCash with a cliff of 6 months.

From the whitepaper:

Vesting length = 24 monthsCliff length = 6 months

The private sale started in November 2017, the vesting period should start somewhere around this date

Start date = November 2017

2. Transform the dates

Before we can check the blockchain, we need to transform our dates into timestamps suitable for programming:

💡Human readable dates are impractical to use in code, so dates are transformed into either seconds or milliseconds passed since the so called unix epoch. The epoch is defined as 1st of January 1970 midnight GMT. A unix timestamp is expressed by milliseconds passed since the epoch (1st of January 1970).

Timestamps on the solidity documentation: [link]

block.timestamp (uint): current block timestamp as seconds since unix epoch

So can expect the vesting duration and cliff to be measured in seconds on the Ethereum blockchain.

➡️ Transform months to seconds: [Link]

Vesting length = 24 months = 63.070.000 secondsCliff length = 6 months = 15.770.000 seconds

➡️ Transform date to Unix Timestamp: [Link]

Start date = 1st of November 2017 = 1509494400

now that we have the times we are looking for, we should now …

3. Check the event log

We need to look for a reference for our dates in the nCash Smart Contract. nCash is an ERC20 Token so it lives on the Ethereum blockchain.

Be careful: It’s important that we check what is written on the blockchain, so GitHub is not valid.

➡️ Go to https://etherscan.io/

Tools like etherscan.io are so called block explorers, so basically google for the Ethereum blockchain.

➡️ Search for Nucleus (The first result with the green checkmark is the right one) [Link]

This is the contract that is responsible for creating and managing the tokens. The contract holds all information about which addresses own the tokens and how many.

The token holders tab shows us a list of all token owners. Note the two addresses on top, each owning 25% of the total token supply. It’s safe to assume that these are the team and company reserve tokens stated in the Nucleus whitepaper with 25% each.

Now we need to find out if this supply is locked by any kind of vesting mechanism. Every smart contract has an owner that controls it. The owner can either be a wallet controlled by an individual or a smart contract itself. In our case the owner needs to be a smart contract that enforces the vesting policy. So let’s check that.

➡️ Under TokenTracker Summary click on ERC20 Contract [Link]

➡️ Go to Misc > Contract Creator and klick the first [Link]

Now we see the owner contract. Instead of auditing the whole code, we can simply check the internal transactions that appeared in the contract first.

➡️ Klick on the Events tab [Link]

Here we can see all internal transactions within the smart contract. We are looking for a method that says something about vesting.

The first event in the log says:

NucleusVisionTimeVestingTokensMinted (address beneficiary, uint256 tokens, uint256 start, uint256 cliff, uint256 duration)

Bingo! Looks promising. What we see here is that a function named

NucleusVisionTimeVestingTokensMinted 

was called, and that it received five parameters:

address beneficiaryuint256 tokensuint256 startuint256 cliffuint256 duration

That is the data we are looking for.

The values are stored as hexadecimal, but etherscan can translate them for us.

➡️ Set correct variable type in the dropdown next to the parameter.

The right ones are:

AddressNumberNumberNumberNumber

Now we know what the variables contain

mintTokensWithTimeBasedVesting(address beneficiary, uint256 tokens, uint256 start, uint256 cliff, uint256 duration)address beneficiary = 0x356df211c92d53a4e0ccfdd3125e87e8e570ef14uint256 tokens = 2,5e+27uint256 start = 1511481600uint256 cliff = 15552000uint256 duration = 63072000

To get the token value we have to deduct the decimals defined in the ERC20 contract:

➡️ Calculate the correct token amount [link]

uint256 tokens = 2,5e + (27 — 18) = 2,5e+9 = 2.500.000.000

Bingo! The token supply matches the 25% proposed as team supply in the whitepaper.

Why “-18” ?

💡 Note that an ERC20 contract defines decimals for the token supply, in case of nCash it is 18. So we have to deduct this from the value stored in the variable to get the correct number. From Stackexchange:

If I want 1 token with the ability to subdivide it with a precision of 2 decimal places, I represent that as 100.

tokenSupply = tokensIActuallyWant * (10 ^ decimals)

➡️ Transform Unix Timestamp to date: [Link]

uint256 start = 1511481600 = 24/11/2017

So the vesting started on the November 24th

uint256 cliff = 15552000 (seconds) = 6 monthsuint256 duration = 63072000 (seconds) = 24 months

We can now calculate the exact vesting period

Use https://www.timeanddate.com/date/dateadd.html to add the dates:

Vesting start = 24/11/2017Payout starts = 25/05/2018Payout ends = 25/04/2020

We now know that the vesting function in the owner contract was initialized with the correct values. Now we can check what the function does with our supplied parameters.

4. Check the code

We know from the event logs that we are looking for NucleusVisionTimeVestingTokensMinted in the contract

➡️ Open the code tab: [Link]

💡 The smart contract is what controls the flow of value, and once live cannot simply be stopped or updated. We are looking at a very critical piece of code here, and proper code commenting is a must. That means you should be able to understand what’s going on even without coding knowledge. If the code is not properly commented you have found a red flag.

Fortunately, in our case it is well done.

➡️ Press cmd+f (ctr+f) and search for NucleusVisionTimeVestingTokensMinted

/*** event for time vested token mint logging* @param beneficiary who is receiving the time vested tokens* @param tokens amount of tokens that will be vested to the beneficiary* @param start unix timestamp at which the tokens will start vesting* @param cliff duration in seconds after start time at which vesting will start* @param duration total duration in seconds in which the tokens will be vested*/event NucleusVisionTimeVestingTokensMinted(address beneficiary, uint256 tokens, uint256 start, uint256 cliff, uint256 duration);

This is the event that we saw in the event logs. Events can be triggered by functions:

// member function to mint time based vesting tokens to a beneficiaryfunction mintTokensWithTimeBasedVesting(address beneficiary, uint256 tokens, uint256 start, uint256 cliff, uint256 duration) public onlyOwner {require(beneficiary != 0x0);require(tokens > 0);vesting[beneficiary] = new TokenVesting(beneficiary, start, cliff, duration, false);require(token.mint(address(vesting[beneficiary]), tokens));NucleusVisionTimeVestingTokensMinted(beneficiary, tokens, start, cliff, duration);}

This function checks that:

require(beneficiary != 0x0); 

Beneficiary has an address that is not 0

require(tokens > 0);

Vested token amount is bigger than 0

vesting[beneficiary] = new TokenVesting(beneficiary, start, cliff, duration, false); 

New instance of token vesting contract is created with the beneficiary address

require(token.mint(address(vesting[beneficiary]), tokens)); 

Check if beneficiary is registered

event NucleusVisionTimeVestingTokensMinted(beneficiary, tokens, start, cliff, duration); 

Fire vesting event

That is how the event logs are created. From Stackexchange:

Each transaction has an attached receipt which contains zero or more log entries. Log entries represent the result of events having fired from a smart contract.

Now there is a separate function that checks the saved times against the current time, to determine if and how much should be payed out:

function vestedAmount(ERC20Basic token) public view returns (uint256) {/**
* @dev Calculates the amount that has already vested.
* @param token ERC20 token which is being vested
*/
function vestedAmount(ERC20Basic token) public view returns (uint256) {
uint256 currentBalance = token.balanceOf(this);
uint256 totalBalance = currentBalance.add(released[token]);
if (now < cliff) {
return 0;
} else if (now >= start.add(duration) || revoked[token]) {
return totalBalance;
} else {
return totalBalance.mul(now.sub(start)).div(duration);
}
}
}

Notice that now is an alias for block.timestamp which we discussed earlier

if (now < cliff)

Check if we are still before the cliff period

(now >= start.add(duration) || revoked[token])

Check if we are still before the vesting period

else { return totalBalance.mul(now.sub(start)).div(duration); }

If we are in the vesting period, return the amount of tokens relative to the passed time (e.g 50% after 1 year, 100% after 2 years)

Note that instead of having fixed tranches of say one year, the vested amount is paid out gradually

Since this is not a security audit, let’s ignore the rest of the code for now.

The parts we’ve discussed showed us that the correct data has been written on the blockchain, we also gained an insight into the internal mechanisms of the vesting functions.

⚗️ Conclusion

The blockchain is disrupting the way businesses are raising money.

In this brave new world a few lines of code move millions of dollars. Contracts are written by coders, not lawyers anymore and vesting statements can be enforced by a few lines of code.

Blockchain is an opportunity to democratize early stage investments. Today, this emerging landscape paints an image that resembles a dusty wild west town, which attracts pioneers and bandits alike. For this town to prosper, we as the citizens need to apply the law to keep the villains at bay. This tutorial gave you a guideline how to check vesting statements for yourself, which should be part of any project due diligence.

My key learnings during my research:

  • How vesting works
  • How to transform timestamps
  • How timestamps are handled in solidity
  • How we can read smart contracts on the Ethereum blockchain
  • How to read event logs
  • How vesting is implemented in smart contracts

This tutorial is not a security audit and should rather give you an insight how smart contracts & vesting works. If you want to dig deeper into security audits, I recommend the excellent article by Merunas Grincalaitis

For best practice examples look at the Zeppelin contracts:

Was this guide helpful for you, and for which projects could you apply it? — Leave a comment

🚀 Interested in Tokenized Securities? Check out our newest project: STOCheck.com

--

--