Разработка utility-токена

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка utility-токена
Простая
~2-3 рабочих дня
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка utility-токена

Utility-токен отличается от governance токена или security токена не юридически, а функционально: он нужен для чего-то конкретного внутри протокола. Оплата газа (ETH), оплата вычислений (FIL в Filecoin), доступ к сервису (API credits), скидки на fees (BNB на Binance) — всё это utility. Проблема большинства «utility» токенов: utility искусственная, токен не нужен для работы протокола, его принудительно вставили в tokenomics ради продажи.

Настоящий utility-токен решает проблему, которую нельзя решить без токена: coordinated incentives для участников сети, trustless escrow, programmable условия доступа.

Проектирование utility механики

Token необходимость: тест

Прежде чем проектировать токен, ответьте: можно ли заменить токен на USDC или ETH? Если да — возможно, токен не нужен. Если нет — почему нет?

Убедительные причины иметь собственный токен:

  • Governance: токен = право голоса, ETH не может это заменить без централизации
  • Staking для безопасности: валидаторы стейкают токен, слэшинг при мошенничестве — skin in the game нельзя заменить внешним активом
  • Protocol revenue sharing: токенхолдеры получают часть fees протокола
  • Инфляционные награды: субсидирование bootstrapping через инфляцию нативного токена

Capture механика

Utility-токен должен «захватывать» часть ценности протокола. Популярные паттерны:

Fee switch: протокол берёт X% от операций. Часть идёт в treasury, часть — токенхолдерам или buyback/burn. Uniswap governance голосует за fee switch именно по этой логике.

Staking для доступа: провайдеры услуг должны стейкать токен. Stake = гарантия добросовестности. При нарушении — slashing. Chainlink операторы стейкают LINK.

Token-denominated pricing: услуга стоит N токенов, не N долларов. Спрос на услугу → спрос на токен. Filecoin: хранение стоит FIL.

Реализация: staking utility

Типичный utility-токен со staking для доступа к сервису:

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract UtilityToken is ERC20, ERC20Permit, AccessControl, ReentrancyGuard {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant SERVICE_ROLE = keccak256("SERVICE_ROLE");
    
    uint256 public constant PROVIDER_STAKE_REQUIRED = 10_000 * 10**18; // 10k токенов
    
    struct ProviderStake {
        uint256 amount;
        uint256 stakedAt;
        bool active;
    }
    
    mapping(address => ProviderStake) public providerStakes;
    mapping(address => uint256) public serviceCredits; // оплаченные кредиты
    
    uint256 public constant CREDIT_PRICE = 1 * 10**18; // 1 токен = 1 кредит
    uint256 public burned;
    
    event ProviderRegistered(address indexed provider, uint256 stake);
    event ProviderSlashed(address indexed provider, uint256 amount, string reason);
    event CreditsPurchased(address indexed user, uint256 amount);
    
    constructor(address admin, address treasury, uint256 initialSupply)
        ERC20("Utility Token", "UTL")
        ERC20Permit("Utility Token")
    {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(MINTER_ROLE, admin);
        _mint(treasury, initialSupply);
    }
    
    // Провайдер стейкает токены для регистрации
    function stakeAsProvider() external nonReentrant {
        require(!providerStakes[msg.sender].active, "Already registered");
        require(
            balanceOf(msg.sender) >= PROVIDER_STAKE_REQUIRED,
            "Insufficient balance"
        );
        
        _transfer(msg.sender, address(this), PROVIDER_STAKE_REQUIRED);
        providerStakes[msg.sender] = ProviderStake({
            amount: PROVIDER_STAKE_REQUIRED,
            stakedAt: block.timestamp,
            active: true
        });
        
        _grantRole(SERVICE_ROLE, msg.sender);
        emit ProviderRegistered(msg.sender, PROVIDER_STAKE_REQUIRED);
    }
    
    // Пользователь покупает кредиты
    function purchaseCredits(uint256 creditAmount) external nonReentrant {
        uint256 tokenCost = creditAmount * CREDIT_PRICE;
        require(balanceOf(msg.sender) >= tokenCost, "Insufficient tokens");
        
        // 80% burn, 20% в treasury — дефляционная механика
        uint256 burnAmount = tokenCost * 80 / 100;
        uint256 treasuryAmount = tokenCost - burnAmount;
        
        _burn(msg.sender, burnAmount);
        burned += burnAmount;
        _transfer(msg.sender, treasury, treasuryAmount);
        
        serviceCredits[msg.sender] += creditAmount;
        emit CreditsPurchased(msg.sender, creditAmount);
    }
    
    // Провайдер списывает кредиты за оказанную услугу
    function consumeCredits(address user, uint256 amount) external onlyRole(SERVICE_ROLE) {
        require(serviceCredits[user] >= amount, "Insufficient credits");
        serviceCredits[user] -= amount;
        emit CreditsConsumed(user, msg.sender, amount);
    }
    
    // Slashing при нарушении провайдером
    function slashProvider(
        address provider, 
        uint256 amount, 
        string calldata reason
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        ProviderStake storage stake = providerStakes[provider];
        require(stake.active, "Not active provider");
        require(amount <= stake.amount, "Exceeds stake");
        
        stake.amount -= amount;
        _burn(address(this), amount); // сожгли слэшнутые токены
        burned += amount;
        
        if (stake.amount < PROVIDER_STAKE_REQUIRED / 2) {
            stake.active = false;
            _revokeRole(SERVICE_ROLE, provider);
        }
        
        emit ProviderSlashed(provider, amount, reason);
    }
}

Unstaking cooldown

Провайдер не должен мгновенно выводить stake. Cooldown период — защита от slash evasion (обнаружил проблему → быстро вывел stake → нет slashing):

uint256 public constant UNSTAKE_COOLDOWN = 14 days;

mapping(address => uint256) public unstakeRequestedAt;

function requestUnstake() external {
    require(providerStakes[msg.sender].active, "Not active");
    unstakeRequestedAt[msg.sender] = block.timestamp;
    providerStakes[msg.sender].active = false;
    _revokeRole(SERVICE_ROLE, msg.sender);
}

function finalizeUnstake() external nonReentrant {
    require(unstakeRequestedAt[msg.sender] > 0, "No unstake request");
    require(
        block.timestamp >= unstakeRequestedAt[msg.sender] + UNSTAKE_COOLDOWN,
        "Cooldown not elapsed"
    );
    
    uint256 amount = providerStakes[msg.sender].amount;
    providerStakes[msg.sender].amount = 0;
    unstakeRequestedAt[msg.sender] = 0;
    
    _transfer(address(this), msg.sender, amount);
}

Распределение supply

Типичное распределение для utility-токена протокола:

Аллокация % Vesting
Команда и советники 15–20% 4 года, cliff 1 год
Инвесторы 15–25% 2–3 года, cliff 6 мес
Экосистема/гранты 20–30% Линейно 3–5 лет
Liquidity/DEX 5–10% TGE или по необходимости
Treasury 20–30% Governance решает
Public sale / IDO 5–15% Частично TGE

Общая сумма TGE (Token Generation Event) — желательно не более 15–20% supply. Слишком большой TGE float создаёт давление продаж.

Избегаемые антипаттерны

Бесполезный buyback: buyback токена из treasury и сжигание — это перемещение ценности от treasury к токенхолдерам. Само по себе не создаёт ценности. Имеет смысл только если у протокола есть реальный revenue.

Circular dependency: токен нужен для использования протокола, протокол нужен для получения токена. Без внешней ценности — это замкнутый круг.

Governance без power: governance токен, у которого нет реального права менять параметры протокола — декоративный. Пользователи это понимают.

Срок разработки utility-токена с базовой staking механикой и credits системой: 1–2 недели включая тесты. Сложный tokenomics с несколькими механиками — 3–4 недели.