ERC-20 is an interface, not an implementation. Six mandatory functions (totalSupply, balanceOf, transfer, transferFrom, approve, allowance) and two events (Transfer, Approval). Everything else is implementation details that matter. Our experience — over 50 ERC-20 tokens launched into production — shows that these details determine whether the token will be compatible with DeFi protocols or will require a rewrite.
Which approach to ERC-20 token development to choose?
The first dilemma — upgradeable (Proxy + Implementation) or immutable. Proxy provides flexibility for changes, but each transaction via delegatecall costs about 150,000 gas compared to 45,000 for a regular contract. Immutable contracts are three times cheaper for users and simpler to audit. Recommendation: for utility tokens and governance — immutable; for DeFi vaults and complex protocols — upgradeable with caution.
The second issue — minting control. If the minter is an EOA, this is a centralization risk: the key might leak or the owner could mint an unlimited amount. Solution — use a multisig or a smart contract with the MINTER role. Our projects always use AccessControl for distributed governance.
The third — gas optimization. Not using ERC20Permit (EIP-2612) forces the user to spend two transactions instead of one for the first interaction with DeFi.
Why use OpenZeppelin instead of writing from scratch?
OpenZeppelin is the industry standard. Their code has undergone hundreds of audits, used in millions of contracts. Do not write ERC-20 from scratch — it increases the risk of errors and reduces integrator trust. Our solutions are based on OpenZeppelin with additional custom modules.
Basic Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
contract MyToken is ERC20, ERC20Burnable, ERC20Permit, Ownable2Step {
uint256 public constant MAX_SUPPLY = 100_000_000 * 10**18; // 100M tokens
constructor(
address initialOwner,
address treasury
)
ERC20("My Token", "MTK")
ERC20Permit("My Token")
Ownable2Step()
{
_transferOwnership(initialOwner);
_mint(treasury, MAX_SUPPLY); // entire supply at deploy
}
}
ERC20Permit is an important extension: it allows approval via off-chain signatures. This improves UX (one transaction instead of two) and reduces gas for the user. Ownable2Step instead of Ownable protects against accidentally transferring control to an incorrect address.
Mintable Token with Access Control
If the token needs to be minted after deployment, use AccessControl:
import "@openzeppelin/contracts/access/AccessControl.sol";
contract MintableToken is ERC20, ERC20Burnable, ERC20Permit, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
uint256 public immutable maxSupply;
constructor(
string memory name,
string memory symbol,
uint256 _maxSupply,
address admin
) ERC20(name, symbol) ERC20Permit(name) {
maxSupply = _maxSupply;
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(MINTER_ROLE, admin);
}
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
require(totalSupply() + amount <= maxSupply, "Exceeds max supply");
_mint(to, amount);
}
}
MINTER_ROLE should be assigned to a smart contract (staking reward, vesting), not an EOA.
Comparison of Approaches
| Criterion |
Immutable Contract |
Upgradeable Proxy |
| Gas (per transaction) |
~45,000 gas |
~150,000 gas (due to delegatecall) |
| Flexibility |
No changes |
Upgradeable logic |
| Risk |
Only logical errors |
Proxy errors, storage collisions |
| Audit |
Simpler |
More complex (two contracts) |
| Recommendation |
Utility, governance |
DeFi vaults, complex protocols |
Why decimals Should Be 18 (Usually)
By default, decimals = 18 (like ETH). Exception: USDC/USDT use 6. If creating a stablecoin or wrap — check the original's decimals. Never use 0 decimals for tokens that will trade on a DEX — AMM works poorly with integers. We've encountered projects where incorrect decimals caused incompatibility issues with protocols.
Common Mistakes
Transfer tax: every transfer takes a percentage — breaks DeFi protocols. If still needed, use a whitelist for Uniswap, Aave, Compound contracts. Centralized blacklist without timelock: bad for community tokens. Reentrancy in transfer hooks: if adding _beforeTokenTransfer or _afterTokenTransfer, ensure you don't call external code.
Work Stages
| Stage |
Duration |
Result |
| Analytics |
1-2 days |
Token specification, architecture selection |
| Implementation |
2-5 days |
Smart contract, tests, deployment scripts |
| Audit |
1-3 weeks |
Vulnerability report, fixes |
| Deployment and verification |
1 day |
Contract on chain, verified on Etherscan |
| Support |
1 month |
Free fixes after launch |
Verification and Deployment
# Tests
forge test -vvv
# Deploy with verification
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--etherscan-api-key $ETHERSCAN_KEY
After deployment — verify the contract on Etherscan/Polygonscan. An unverified token raises legitimate suspicion from exchanges and users.
What's Included in Turnkey ERC-20 Token Development
- Smart contract in Solidity with custom functions (mint, burn, permit, pause, blacklist)
- Unit tests (Foundry/Hardhat) with coverage >90%
- Deployment scripts configured for your network (Ethereum, Polygon, Arbitrum, BNB Chain)
- Verification on blockchain explorer (Etherscan, Polygonscan)
- Developer and user documentation
- Consultation on DeFi protocol integration
- Guarantee — 1 month free fixes after launch
We will assess your project within 1 business day. We are a team of senior blockchain developers: 5+ years on the market, 50+ tokens delivered. Contact us to discuss details and order turnkey ERC-20 token development.
Token Development: ERC-20, Tokenomics, Vesting
We’ve seen more rekt tokens than we can count — not because the code was broken, but because the economic assumptions were naive. A token that doesn’t collapse from inflation in six months, where governance actually works, and vesting can’t be bypassed through delegation tricks — that’s real engineering. We build under that standard.
How We Avoid Common ERC-20 Pitfalls
ERC-20 standard has nine functions. Complexity starts with extensions:
ERC-20Permit (EIP-2612) — gasless approve via signature. User signs permit(owner, spender, value, deadline, v, r, s) off-chain, spender calls permit() + transferFrom() in one transaction. Removes separate approve step. Risk: signature can be intercepted — need deadline and nonce checking. We always implement EIP-712 typed structured data to prevent signature malleability.
ERC-20Votes (EIP-5805) — snapshot balances for governance. Checkpoint system stores balance history by block number. getPastVotes(address, blockNumber) returns balance at proposal creation, not current. Prevents flash loan governance: can't borrow tokens and vote in one transaction.
Rebasing tokens (stETH, Ampleforth) — balanceOf changes automatically through internal shares ratio. High integration complexity: most DeFi protocols don't work correctly with rebasing without non-rebasing wrapper. We've deployed wrappers that decouple balance from share price for Uniswap compatibility.
Fee-on-transfer tokens — percentage cut on every transfer. Breaks AMM calculations: pool receives less than expected. Uniswap v2/v3 don't support natively — needs special pair/router. We’ve built custom routers that handle fee-on-transfer tokens without reverting.
Why Tokenomics Sustainability Matters More Than Excel
Tokenomics isn't Excel table summing to 100%. It's incentive model that either works long-term or creates selling pressure killing the project.
Emission Schedule and Inflation — Fixed supply (Bitcoin model) works for store-of-value, but for utility tokens you need controlled inflation. Inflationary model (like Ethereum post-Merge) generates new tokens to incentivize participants. Key balance: emission should be <= value captured by protocol. If protocol earns $100k/month but emission is $500k/month in market value — constant selling pressure inevitable. We model these scenarios using Python simulations with cadCAD for complex systems.
Supply Distribution — No universal formula. Principle: no single entity >33% voting power at launch. Otherwise governance is fiction.
| Category |
Typical Range |
Risk |
| Team + advisors |
15–20% |
Dumping on unlock |
| Investors (seed, private) |
15–25% |
Coordinated exit |
| Treasury / DAO |
20–35% |
Governance capture |
| Ecosystem / grants |
10–20% |
Inefficient allocation |
| Public sale / LBP |
5–15% |
Undervaluation → whale capture |
| Liquidity provision |
5–10% |
Mercenary capital |
What Are the Most Critical Vesting Contract Mistakes?
Linear vesting with cliff is standard for team and investors. cliff is the period after TGE with zero availability. After cliff: linear unlock until duration. Typical implementation errors we catch in audit:
- Revocable vesting without timelock — owner can revoke immediately. Solution: revocation through multisig + governance vote with 7-day delay.
- Cliff doesn't block governance rights — with ERC-20Votes, recipient can delegate voting power from day one even if tokens aren't unlocked. We explicitly separate voting power from claim logic.
- No emergency pause — if vesting contract vulnerability discovered, need ability to pause claims. Pausable + timelock on unpause.
We’ve seen a project where the cliff was set to 0 by mistake — team could dump immediately. Our fuzz tests catch such edge cases before deployment.
Vesting contract implementation details
Pausable and Ownable2Step from OpenZeppelin are standard. We add a 7-day timelock on revocation functions. All withdraw functions emit events for off-chain tracking. Fuzz tests verify that cumulative released amount never exceeds total allocation, even after multiple revocations or partial claims.
Why Is Liquidity Bootstrapping Crucial for Token Launch?
Launch mechanics are critical. Three main approaches:
-
Balancer LBP — temporary pool with high initial token weight (90/10 project-token/USDC) that automatically decreases to 50/50 over days. Creates downward price pressure preventing bot buys at one price. After LBP liquidity moves to permanent pool.
-
Fjord Foundry — specialized platform for LBP and fair launches. Less operational overhead than direct Balancer integration.
-
Uniswap v3 with limited range — add liquidity in narrow range around initial price. High capital efficiency but requires active range management.
-
TWAMM — mechanics for gradual large-order sales without slippage. Implemented in FraxSwap.
LBP is 3-5x better than standard AMM listing for price discovery; we’ve seen fair launches with 50% less initial dump compared to direct Uniswap listings.
Governance Tokens and Voting Mechanics
OpenZeppelin Governor is the standard. Modular: GovernorVotes for counting, GovernorTimelockControl for timelock execution, GovernorSettings for adjustable parameters. Quorum is minimum percentage of supply for voting validity. Compound set quorum at 400k COMP (4% supply). We set quorum dynamically based on historical participation to avoid apathy or whale capture.
Flash loan governance attack — attacker borrows tokens via flash loan, delegates to self, creates proposal or votes, returns tokens. ERC-20Votes with block-based snapshot completely blocks this: must have tokens at snapshot creation moment, not voting moment.
Delegation — small holders often don't vote. Liquid delegation (like Optimism) lets delegate voting power to addresses without transfer. Critical for protocols with many passive holders.
| Token Type |
Use Case |
Our Stack |
| ERC-20 utility |
Payments, rewards, gas |
Solidity 0.8.x, OpenZeppelin 5.x |
| ERC-20Permit |
Gasless approvals |
EIP-2612, EIP-712 |
| ERC-20Votes |
On-chain governance |
Governor, TimelockController |
| ERC-1155 |
Multi-token (NFT + fungible) |
Solidity, OpenZeppelin |
| Vesting contracts |
Team/investor lockup |
LinearVesting, CliffVesting |
Token Development Stack
Contracts: Solidity 0.8.x, OpenZeppelin Contracts 5.x (ERC20, ERC20Permit, ERC20Votes, Governor, TimelockController, TokenVesting).
Tokenomics audit: Python models with emission/demand simulation, cadCAD for complex systems modeling.
Deployment and management: Foundry scripts, Gnosis Safe for treasury, OpenZeppelin Defender for automation.
Analytics: Dune Analytics for on-chain metrics, Token Terminal for protocol revenue.
What’s Included in the Work (Deliverables)
- Tokenomics model with stress tests (bear market, whale exit, governance capture)
- Contract development with Foundry fuzz tests (gas optimization, reentrancy tests, overflow checks)
- Audit summary and list of edge cases covered
- Deployment scripts with Gnosis Safe admin keys
- Documentation for future upgrades and maintenance
- 30-day post-launch monitoring support
Process
-
Tokenomics design — supply model, allocation, emission schedule, vesting. Stress-test scenarios.
-
Contract development — ERC-20 + extensions, vesting, governance. Foundry fuzz tests on vesting calculations, governance thresholds.
-
Audit — special attention on governance attack vectors, vesting bypass, permit replay attacks. We use Slither and Echidna for formal verification.
-
LBP / launch — choose mechanics, set parameters, monitor first 24 hours.
-
Post-launch — monitor supply distribution via Dune, governance participation metrics, treasury management.
Timelines
- ERC-20 with permit and basic governance: 2–3 weeks
- Vesting contract with revocation and cliff: 2–4 weeks
- Full governance (Governor + Timelock + Token): 4–7 weeks
- Token + LBP + governance + vesting: 8–14 weeks
We can estimate your project within 24 hours after discussing requirements. Contact us to start the conversation — no obligation, just a technical chat about your token model. Get a detailed proposal tailored to your tokenomics and compliance needs.