September 29, 2023
Токеномика. Линейный вестинг на Solidity
Вестинг - схема получения токенов в зависимости от времени.
cliff - период времени в котором снятие токенов заблокировано
duration - период времени, за который происходит полное разблокирование токенов для снятия
Ниже приведен код контракта линейного вестинга.
pragma solidity 0.8.20; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract Vesting { event TokenReleased( address indexed account, address indexed token, uint256 amount ); struct Info { uint256 locked; uint256 released; } address public immutable token; uint256 public immutable startTimestamp; uint256 internal cliffDuration; uint256 internal vestingDuration; mapping(address => Info) internal _vesting; constructor( address token_, uint256 cliffMonthDuration, uint256 vestingMonthDuration, address[] memory accounts, uint256[] memory amounts ) { require( vestingMonthDuration >= cliffMonthDuration, "duration less then cliff" ); startTimestamp = uint64(block.timestamp); token = token_; cliffDuration = cliffMonthDuration * 4 weeks; vestingDuration = vestingMonthDuration * 4 weeks; for (uint256 i = 0; i < accounts.length; i++) { _vesting[accounts[i]] = Info({locked: amounts[i], released: 0}); } } function release() external { require( block.timestamp > startTimestamp + cliffDuration, "cliff period has not ended yet." ); address sender = msg.sender; Info storage vestingInfo = _vesting[sender]; uint256 amountByMonth = vestingInfo.locked / ((vestingDuration) / 4 weeks); uint256 releaseAmount = 0; // Проверка, что если юзер клеймит после разлока всех токенов, то ему отправляется предназначающийся ему остаток не заклеймленных токенов. if(block.timestamp >= startTimestamp + vestingDuration){ releaseAmount = vestingInfo.locked - vestingInfo.released; }else{ releaseAmount = (((block.timestamp - startTimestamp) * amountByMonth) / 4 weeks) - vestingInfo.released; } require(releaseAmount > 0, "not enough release amount."); vestingInfo.released += releaseAmount; SafeERC20.safeTransfer(IERC20(token), sender, releaseAmount); } }
В конструктор передается адрес токена, начальный блок, cliff, duration и два массива. Первый массив содержит адреса, которые смогут клеймить токены. Второй массив содержит количества токенов для соответствующего адреса.
Например массив 1: [0х1, 0х2] и массив 2: [100, 200]. Значит с адреса 0x1 может быть заклеймлено 100 токенов, а с адреса 0x2 - 200 токенов