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.







