🎓 A1Learner
🔍
0 of 45 lessons completed

Solidity Vesting Schedules

A vesting schedule is a plan that releases tokens slowly over time instead of all at once. A cliff is the early period during which nothing is released.

Nothing is claimable before the cliff

The claimable function returns zero while the clock is before the cliff. At the cliff the first small share unlocks.

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

contract VestingSchedule {
    uint256 public start;
    uint256 public cliff;
    uint256 public duration;
    uint256 public total;
    uint256 public released;

    constructor(uint256 amount) {
        start = 1000;
        cliff = 1100;
        duration = 1000;
        total = amount;
    }

    function claimable() public view returns (uint256) {
        if (block.timestamp < cliff) {
            return 0;
        }
        if (block.timestamp >= start + duration) {
            return total - released;
        }
        return (total * (block.timestamp - start)) / duration - released;
    }
}

Half the schedule unlocks half the total

Halfway through the schedule the unlocked share is half the total. Claiming it leaves nothing claimable until more time passes.

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

contract VestingClaim {
    uint256 public start;
    uint256 public cliff;
    uint256 public duration;
    uint256 public total;
    uint256 public released;

    constructor(uint256 amount) {
        start = 1000;
        cliff = 1100;
        duration = 1000;
        total = amount;
    }

    function claimable() public view returns (uint256) {
        if (block.timestamp < cliff) {
            return 0;
        }
        if (block.timestamp >= start + duration) {
            return total - released;
        }
        return (total * (block.timestamp - start)) / duration - released;
    }

    function claim() public returns (uint256 amount) {
        amount = claimable();
        require(amount > 0, "nothing to claim");
        released += amount;
    }
}

The full total is claimable at the end

At the end of the schedule the remaining share is the whole total minus what was claimed. A further claim then reverts.

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

contract VestingFull {
    uint256 public start;
    uint256 public cliff;
    uint256 public duration;
    uint256 public total;
    uint256 public released;

    constructor(uint256 amount) {
        start = 1000;
        cliff = 1100;
        duration = 1000;
        total = amount;
    }

    function claimable() public view returns (uint256) {
        if (block.timestamp < cliff) {
            return 0;
        }
        if (block.timestamp >= start + duration) {
            return total - released;
        }
        return (total * (block.timestamp - start)) / duration - released;
    }

    function claim() public returns (uint256 amount) {
        amount = claimable();
        require(amount > 0, "nothing to claim");
        released += amount;
    }
}

Example

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

contract VestingWallet {
    uint256 public start;
    uint256 public cliff;
    uint256 public duration;
    uint256 public total;
    uint256 public released;

    constructor(uint256 amount) {
        start = 1000;
        cliff = 1100;
        duration = 1000;
        total = amount;
    }

    function claimable() public view returns (uint256) {
        if (block.timestamp < cliff) {
            return 0;
        }
        if (block.timestamp >= start + duration) {
            return total - released;
        }
        return (total * (block.timestamp - start)) / duration - released;
    }

    function claim() public returns (uint256 amount) {
        amount = claimable();
        require(amount > 0, "nothing to claim");
        released += amount;
    }
}

Key points

  • Vesting: Vesting is the slow release of tokens over a set schedule.
  • Cliff: A cliff is the opening period of a schedule during which nothing can be claimed.
  • Linear release: A linear release unlocks the same share of tokens for each unit of time after the cliff.
  • Claimable: A claimable amount is the unlocked share minus what has already been claimed.
  • Released: A released amount is the total a holder has already claimed from the schedule.
  • Restatement: Vesting spreads token release across time so a holder gains access gradually rather than at once.

In this example, VestingWallet checks zero before the cliff, claims half at the midpoint, and claims the remaining half at the end so the released total equals the full schedule amount.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Remix IDE

Exercise

A schedule totals 1000 tokens with a cliff at time 1100. How much is claimable at time 1050?