Tokenomics
Configure and manage the native token supply of your Avalanche L1 blockchain.
Overview
The tokenomics of your Avalanche L1 blockchain is a crucial aspect that determines how value flows through your network. The Subnet-EVM provides powerful tools to manage your token economy:
- Initial token allocation in genesis
- Dynamic token minting through the Native Minter precompile
- Fee burning or redistribution mechanisms (via Transaction Fees & Gas)
Initial Token Supply
When creating your Avalanche L1, you can configure the initial token distribution in the genesis file:
{
"alloc": {
"0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC": {
"balance": "0x3635C9ADC5DEA00000" // 1000 tokens (in wei)
},
"0x1234567890123456789012345678901234567890": {
"balance": "0x21E19E0C9BAB2400000" // 10000 tokens (in wei)
}
}
}
Consider the following when planning initial allocation:
- Reserve tokens for validator rewards
- Allocate tokens for development and ecosystem growth
- Set aside tokens for future community initiatives
- Consider vesting schedules for team allocations
Native Minter
Purpose
The Native Minter precompile allows authorized addresses to mint additional tokens after network launch. This is useful for:
- Implementing programmatic token emission schedules
- Providing validator rewards
- Supporting ecosystem growth initiatives
- Implementing monetary policy
Configuration
Located at address 0x0200000000000000000000000000000000000001
, you can activate this precompile in your genesis file:
{
"config": {
"contractNativeMinterConfig": {
"blockTimestamp": 0,
"adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"]
}
}
}
Interface
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface INativeMinter {
event NativeCoinMinted(address indexed sender, address indexed recipient, uint256 amount);
// Mint [amount] number of native coins and send to [addr]
function mintNativeCoin(address addr, uint256 amount) external;
// IAllowList
event RoleSet(uint256 indexed role, address indexed account, address indexed sender, uint256 oldRole);
// Set [addr] to have the admin role over the precompile contract.
function setAdmin(address addr) external;
// Set [addr] to be enabled on the precompile contract.
function setEnabled(address addr) external;
// Set [addr] to have the manager role over the precompile contract.
function setManager(address addr) external;
// Set [addr] to have no role for the precompile contract.
function setNone(address addr) external;
// Read the status of [addr].
function readAllowList(address addr) external view returns (uint256 role);
}
The Native Minter precompile uses the AllowList interface to restrict access to its functionality with the following roles.
Tokenomics Best Practices
-
Initial Distribution:
- Ensure fair distribution among stakeholders
- Reserve sufficient tokens for network operation
- Consider long-term sustainability
- Document allocation rationale
-
Minting Policy:
- Define clear minting guidelines
- Use multi-sig for admin control
- Implement transparent emission schedules
- Monitor total supply changes
-
Supply Management:
- Balance minting with burning mechanisms
- Consider implementing supply caps
- Monitor token velocity and distribution
- Plan for long-term sustainability
-
Security Considerations:
- Use multi-sig wallets for admin addresses
- Implement time-locks for large mints
- Regular audits of minting activity
- Monitor for unusual minting patterns
-
Validator Incentives:
- Design sustainable reward mechanisms
- Balance inflation with network security
- Consider validator stake requirements
- Plan for long-term validator participation
Example Implementations
Fixed Supply with Emergency Minting
{
"config": {
"contractNativeMinterConfig": {
"blockTimestamp": 0,
"adminAddresses": ["MULTISIG_ADDRESS"],
"enabledAddresses": []
}
},
"alloc": {
"TREASURY": {"balance": "TOTAL_SUPPLY"},
"VALIDATOR_REWARDS": {"balance": "VALIDATOR_ALLOCATION"},
"ECOSYSTEM_FUND": {"balance": "ECOSYSTEM_ALLOCATION"}
}
}
Programmatic Emission Schedule
contract EmissionSchedule {
INativeMinter public constant NATIVE_MINTER = INativeMinter(0x0200000000000000000000000000000000000001);
uint256 public constant EMISSION_RATE = 1000 * 1e18; // 1000 tokens per day
uint256 public constant EMISSION_DURATION = 365 days;
uint256 public immutable startTime;
constructor() {
startTime = block.timestamp;
}
function mintDailyEmission() external {
require(block.timestamp < startTime + EMISSION_DURATION, "Emission ended");
NATIVE_MINTER.mintNativeCoin(address(this), EMISSION_RATE);
// Distribution logic here
}
}
Validator Reward Contract
contract ValidatorRewards {
INativeMinter public constant NATIVE_MINTER = INativeMinter(0x0200000000000000000000000000000000000001);
uint256 public constant REWARD_RATE = 10 * 1e18; // 10 tokens per block
function distributeRewards(address[] calldata validators) external {
uint256 reward = REWARD_RATE / validators.length;
for (uint i = 0; i < validators.length; i++) {
NATIVE_MINTER.mintNativeCoin(validators[i], reward);
}
}
}
You can find the Native Minter implementation in the subnet-evm repository.
Is this guide helpful?