DevStation / LaunchKit / Templates / TokenVesting

TokenVesting

Linear token vesting with a configurable cliff and total vesting duration.

Deploy This Template
TokenVesting.sol
solidity
1// SPDX-License-Identifier: MIT
2pragma solidity ^0.8.20;
3 
4interface IERC20 {
5 function transfer(address to, uint256 amount) external returns (bool);
6 function balanceOf(address account) external view returns (uint256);
7}
8 
9contract TokenVesting {
10 IERC20 public immutable token;
11 address public immutable beneficiary;
12 uint256 public immutable start;
13 uint256 public immutable cliff;
14 uint256 public immutable duration;
15 uint256 public released;
16 
17 event Released(uint256 amount);
18 
19 constructor(address token_, address beneficiary_, uint256 cliffDays_, uint256 vestingDays_) {
20 require(beneficiary_ != address(0), "ZERO_BENEFICIARY");
21 require(vestingDays_ > 0, "ZERO_DURATION");
22 token = IERC20(token_);
23 beneficiary = beneficiary_;
24 start = block.timestamp;
25 cliff = block.timestamp + cliffDays_ * 1 days;
26 duration = vestingDays_ * 1 days;
27 }
28 
29 function vestedAmount() public view returns (uint256) {
30 uint256 totalBalance = token.balanceOf(address(this)) + released;
31 if (block.timestamp < cliff) return 0;
32 if (block.timestamp >= start + duration) return totalBalance;
33 return (totalBalance * (block.timestamp - start)) / duration;
34 }
35 
36 function releasable() public view returns (uint256) {
37 return vestedAmount() - released;
38 }
39 
40 function release() external {
41 uint256 amount = releasable();
42 require(amount > 0, "NOTHING_VESTED");
43 released += amount;
44 require(token.transfer(beneficiary, amount), "TRANSFER_FAILED");
45 emit Released(amount);
46 }
47}
DevStation
Loading console…