We build utility tokens that solve real protocol problems — not artificially inserted into tokenomics just for fundraising. A utility token differs from governance or security tokens functionally: it is required for something concrete within the ecosystem. Paying gas (ETH), computation (FIL in Filecoin), service access (API credits), fee discounts (BNB on Binance) — all are examples of genuine utility. The problem with most "utility" tokens: the utility is artificial, the token is not needed for the protocol to operate. A real utility token solves a problem that cannot be solved without a token: coordinated incentives for network participants, trustless escrow, programmable access conditions. Our team has over 7 years of blockchain development experience, more than 30 launched tokens, and deep industry expertise — allowing us to design a working economy from the start.
Designing utility mechanics
How to verify if a token is necessary?
Before designing the token, we analyze: can it be replaced by USDC or ETH? If replacement is possible — a native token is not needed. If not — we identify unique utility. Compelling reasons to have your own token: Governance (voting rights), Staking for security (validators stake tokens, slashing for cheating — skin in the game), Protocol revenue sharing (token holders receive part of fees), inflationary rewards for ecosystem bootstrap. Staking can reduce fees by up to 20% for token holders.
Capture mechanics
A utility token must capture part of the protocol's value. Popular patterns: Fee switch (protocol takes a % of operations, part goes to token holders or buyback/burn), Staking for access (providers lock tokens as guarantee), Token-denominated pricing (service costs N tokens). Demand for the service generates demand for the token.
Implementation: staking utility
A typical utility token with staking for access to a service: We use the OpenZeppelin library for standard contracts.
// 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; uint256 public constant CREDIT_PRICE = 1 * 10**18; 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"); 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); } 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); } } Why staking is the foundation of a utility token?
Staking creates obligations for network participants. Service providers must hold tokens as a guarantee of good behavior. On violation — slashing. This locks token value inside the ecosystem. Compared to buyback: staking for access is 3–5 times more effective in retaining users.
Unstaking cooldown
Providers should not be able to withdraw the stake instantly. Cooldown period — protection against slash evasion:
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); } Comparison of value retention mechanics
| Mechanic | Efficiency | Example |
|---|---|---|
| Staking for access | High | BNB, FIL |
| Buyback and burn | Medium | Fee → buyback |
| Fee switch | High | AMM protocols |
| Inflationary rewards | Low (without utility) | DeFi 2.0 |
Supply distribution
Typical distribution for a protocol utility token:
| Allocation | % | Vesting |
|---|---|---|
| Team & 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% | Partially at TGE |
Total TGE supply should ideally not exceed 15–20% of total supply.
How to avoid utility token antipatterns?
Useless buyback — buying back tokens from treasury without real revenue creates no value. Circular dependency — token needed to use protocol, protocol needed to get token — a closed loop. Governance without power — a token without the right to change protocol parameters is decorative. We design mechanics, each of which brings measurable benefit. Proper tokenomics can increase service provider profitability by 30–50%.
How we work on a utility token project
- Analysis: determine if an ERC20 token is needed and what utility it will provide.
- Design: develop tokenomics and economic models.
- Implementation: write Solidity smart contracts using OpenZeppelin.
- Testing: cover with unit and fuzz tests using Foundry.
- Audit: check code for vulnerabilities (reentrancy, overflow, etc.).
- Deployment and verification on Etherscan.
- Support: one month of technical support after launch.
If you are planning a token launch, contact us — we will help design the economy and implement the contracts.
What is included in utility token development
- Tokenomics: analysis and white paper
- Smart contracts: Solidity (ERC20, staking, burn, permit)
- Testing: Foundry (unit + fuzzing)
- Deployment and verification on Etherscan
- Integration with wallets (MetaMask, WalletConnect)
- Documentation for the team
- Technical support for 1 month after launch
Contact us for a project evaluation. Get a tokenomics consultation.







