Utility Token Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Utility Token Development
Simple
~2-3 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Utility Token Development

Utility token differs from governance token or security token not legally, but functionally: it's needed for something concrete inside protocol. Paying for gas (ETH), computing payment (FIL in Filecoin), service access (API credits), fee discounts (BNB on Binance) — all are utility. Problem with most "utility" tokens: utility is artificial, token isn't needed for protocol to work, forcefully inserted into tokenomics for sale.

Real utility token solves problem that can't be solved without token: coordinated incentives for network participants, trustless escrow, programmable access conditions.

Designing utility mechanics

Token necessity: test

Before designing token, answer: can you replace token with USDC or ETH? If yes — maybe token isn't needed. If no — why not?

Convincing reasons to have own token:

  • Governance: token = voting right, ETH can't replace without centralization
  • Staking for security: validators stake token, slashing on fraud — skin in game can't replace external asset
  • Protocol revenue sharing: tokenholders get part of protocol fees
  • Inflationary rewards: bootstrapping subsidy through native token inflation

Capture mechanics

Utility token should "capture" part of protocol value. Popular patterns:

Fee switch: protocol takes X% of operations. Part to treasury, part to tokenholders or buyback/burn. Uniswap governance votes for fee switch exactly this logic.

Staking for access: service providers must stake token. Stake = guarantee of good faith. On violation — slashing. Chainlink operators stake LINK.

Token-denominated pricing: service costs N tokens, not N dollars. Service demand → token demand. Filecoin: storage costs FIL.

Implementation: staking utility

Typical utility token with staking for service access:

// 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 tokens
    
    struct ProviderStake {
        uint256 amount;
        uint256 stakedAt;
        bool active;
    }
    
    mapping(address => ProviderStake) public providerStakes;
    mapping(address => uint256) public serviceCredits; // paid credits
    
    uint256 public constant CREDIT_PRICE = 1 * 10**18; // 1 token = 1 credit
    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);
    }
    
    // Provider stakes tokens to register
    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);
    }
    
    // User buys credits
    function purchaseCredits(uint256 creditAmount) external nonReentrant {
        uint256 tokenCost = creditAmount * CREDIT_PRICE;
        require(balanceOf(msg.sender) >= tokenCost, "Insufficient tokens");
        
        // 80% burn, 20% to treasury — deflationary mechanic
        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);
    }
    
    // Provider consumes credits for service
    function consumeCredits(address user, uint256 amount) external onlyRole(SERVICE_ROLE) {
        require(serviceCredits[user] >= amount, "Insufficient credits");
        serviceCredits[user] -= amount;
    }
    
    // Slashing on provider violation
    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); // burn slashed tokens
        burned += amount;
        
        if (stake.amount < PROVIDER_STAKE_REQUIRED / 2) {
            stake.active = false;
            _revokeRole(SERVICE_ROLE, provider);
        }
        
        emit ProviderSlashed(provider, amount, reason);
    }
}

Unstaking cooldown

Provider shouldn't withdraw stake instantly. Cooldown period protects from slash evasion (discovered problem → quickly withdrew stake → no 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 distribution

Typical distribution for protocol utility token:

Allocation % Vesting
Team and advisors 15–20% 4 years, cliff 1 year
Investors 15–25% 2–3 years, cliff 6 months
Ecosystem/grants 20–30% Linear 3–5 years
Liquidity/DEX 5–10% TGE or as needed
Treasury 20–30% Governance decides
Public sale / IDO 5–15% Partial TGE

Total TGE (Token Generation Event) — ideally not more than 15–20% supply. Too large TGE float creates selling pressure.

Avoiding anti-patterns

Useless buyback: buyback token from treasury and burn — this is value transfer from treasury to tokenholders. Doesn't create value itself. Makes sense only if protocol has real revenue.

Circular dependency: token needed to use protocol, protocol needed to get token. Without external value — closed loop.

Governance without power: governance token with no real right to change protocol parameters — decorative. Users understand this.

Timeline for utility token with basic staking mechanics and credits system: 1–2 weeks including tests. Complex tokenomics with multiple mechanics — 3–4 weeks.