Розробка vesting-schedule для команди та інвесторів

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка vesting-schedule для команди та інвесторів
Простий
~2-3 дні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    919
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1147
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    609
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    884

Розробка vesting-schedule для команди та інвесторів

Vesting без cliff — це поганий vesting. Засновник, який отримує токени лінійно з першого дня, не має фінансового стимулу лишатися в проекті після перших місяців. Стандартна Web3 схема: 1 рік cliff (немає токенів взагалі) + 3 роки лінійного vesting. Інвестори зазвичай отримують коротший цикл: 6 місяців cliff + 18–24 місяці linear.

Смарт-контракт vesting

Промисловий стандарт — OpenZeppelin VestingWallet. Для команди та інвесторів з різними параметрами деплоїмо окремі інстансі:

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

import "@openzeppelin/contracts/finance/VestingWallet.sol";

// Деплой для конкретного бенефіціара
// VestingWallet(beneficiary, startTimestamp, durationSeconds)

// Команда: cliff 1 рік, vesting 4 роки суммарно
// start = TGE + 1 рік (cliff), duration = 3 роки
address teamMemberVesting = address(new VestingWallet(
    teamMemberAddress,
    block.timestamp + 365 days,  // start після cliff
    3 * 365 days                  // 3 роки лінійного vesting
));

// Поповнити токенами
IERC20(tokenAddress).transfer(teamMemberVesting, allocatedAmount);

VestingWallet — простий і аудований контракт. Бенефіціар вызов release(tokenAddress) для отримання розблокованих токенів. Не можна відозвати — якщо потрібна revocability (звільнений співробітник), потрібна кастомна реалізація.

Revocable vesting для команди

Стандартна VestingWallet не підтримує revoke. Для співробітників потрібна можливість зупинити vesting при звільненні:

contract RevocableVesting is Ownable2Step {
    IERC20 public immutable token;
    address public beneficiary;
    uint256 public immutable start;
    uint256 public immutable cliff;
    uint256 public immutable duration;
    uint256 public immutable totalAllocation;
    uint256 public released;
    bool public revoked;
    uint256 public revokedAt;
    
    constructor(
        address _token,
        address _beneficiary,
        address _owner,
        uint256 _start,
        uint256 _cliff,
        uint256 _duration,
        uint256 _totalAllocation
    ) Ownable2Step() {
        token = IERC20(_token);
        beneficiary = _beneficiary;
        start = _start;
        cliff = _cliff;
        duration = _duration;
        totalAllocation = _totalAllocation;
        _transferOwnership(_owner);
    }
    
    function vestedAmount() public view returns (uint256) {
        uint256 endTime = revoked ? revokedAt : block.timestamp;
        
        if (endTime < start + cliff) return 0;
        if (endTime >= start + cliff + duration) return totalAllocation;
        
        uint256 elapsed = endTime - (start + cliff);
        return totalAllocation * elapsed / duration;
    }
    
    function releasable() public view returns (uint256) {
        return vestedAmount() - released;
    }
    
    function release() external {
        require(msg.sender == beneficiary, "Not beneficiary");
        uint256 amount = releasable();
        require(amount > 0, "Nothing to release");
        
        released += amount;
        token.safeTransfer(beneficiary, amount);
        emit TokensReleased(amount);
    }
    
    // Owner (компанія) може відозвати невестед токени
    function revoke() external onlyOwner {
        require(!revoked, "Already revoked");
        revoked = true;
        revokedAt = block.timestamp;
        
        // Вже вестед — відаємо бенефіціару
        uint256 vestedNow = vestedAmount() - released;
        if (vestedNow > 0) {
            released += vestedNow;
            token.safeTransfer(beneficiary, vestedNow);
        }
        
        // Невестед — повертаємо в казну
        uint256 remaining = token.balanceOf(address(this));
        if (remaining > 0) {
            token.safeTransfer(owner(), remaining);
        }
        
        emit VestingRevoked(revokedAt, vestedNow, remaining);
    }
}

Cliff реалізований як перевірка endTime < start + cliff — до цієї дати vestedAmount() повертає 0. Після cliff — лінійне зростання пропорційно часу що пройшов.

Фабрика для деплою кількох контрактів

Деплоїти по одному контракту на кожного отримувача вручну — неудобно. Фабрика:

contract VestingFactory is Ownable2Step {
    address public token;
    address[] public allVestings;
    mapping(address => address) public vestingOf; // beneficiary => vesting contract
    
    event VestingCreated(address indexed beneficiary, address vestingContract, uint256 amount);
    
    struct VestingParams {
        address beneficiary;
        uint256 amount;
        uint256 cliffDays;
        uint256 vestingDays;
    }
    
    function batchCreate(
        VestingParams[] calldata params,
        uint256 tgeTimestamp
    ) external onlyOwner {
        for (uint256 i = 0; i < params.length; i++) {
            VestingParams memory p = params[i];
            require(vestingOf[p.beneficiary] == address(0), "Already has vesting");
            
            RevocableVesting vesting = new RevocableVesting(
                token,
                p.beneficiary,
                owner(),
                tgeTimestamp,
                p.cliffDays * 1 days,
                p.vestingDays * 1 days,
                p.amount
            );
            
            IERC20(token).safeTransferFrom(msg.sender, address(vesting), p.amount);
            
            allVestings.push(address(vesting));
            vestingOf[p.beneficiary] = address(vesting);
            
            emit VestingCreated(p.beneficiary, address(vesting), p.amount);
        }
    }
}

Один вызов batchCreate — деплой всіх контрактів для команди та інвесторів. Апрув токенів на фабрику перед вызовом.

Параметри за типами отримувачів

Тип Cliff Vesting Revocable
Засновники 12 мес 36 мес після cliff Так
Ранні співробітники 12 мес 24–36 мес після cliff Так
Seed інвесторів 6–12 мес 12–24 мес після cliff Ні
Стратегічні партнери 6 мес 12–18 мес Частково
Радники 3–6 мес 12–18 мес Ні

Для інвесторів — контракт часто неотзиваемый (умова інвестиційної угоди). Для співробітників — відзиваемый при звільненні.

Податкові розрахунки

Vesting on-chain — це on-chain подій, які залишають слід. У різних юрисдикціях момент оподаткування різний: при vesting (unlock) або при продажі. Це не технічна, а юридична проблема, але смарт-контракт повинен емітувати правильні подій з timestamps для аудиту.

Термін розробки: 3–5 днів для стандартних vesting контрактів з фабрикою та тестами. Аудит опційний для невеликих аллокацій, обов'язковий при сумах >$500k.