# Emission
GNS token emission and distribution system.
## Overview
The emission system controls creation and distribution of new GNS tokens with a deflationary model featuring periodic halvings, ensuring predictable and decreasing supply growth over 12 years. For more details, check out [docs](https://docs.gnoswap.io/gnoswap-token/emission).
## Token Economics
- **Total Supply Cap**: 1,000,000,000 GNS
- **Initial Minted**: 100,000,000 GNS, pre-minted to the configured `ADMIN`
role address during GNS realm initialization
- **To Be Minted**: 900,000,000 GNS over 12 years
- **Halving Period**: Every 2 years (63,072,000 seconds)
- **Halving Reduction**: 50% decrease in emission rate
- **Distribution**: Automatic during protocol activity
## Configuration
- **Distribution Ratios** (modifiable by admin or governance):
- Liquidity Staker: 75% (default)
- DevOps: 20% (default)
- Community Pool: 5% (default)
- Governance Staker: 0% (default)
- **Start Time**: Unix timestamp. It may be changed while the configured timestamp is still in the future; once active, it cannot be changed.
## Core Features
### Emission Schedule
Implements Bitcoin-style halving model:
- Year 1-2: 100% emission rate
- Year 3-4: 50% emission rate
- Year 5-6: 25% emission rate
- Year 7-8: 12.5% emission rate
- Year 9-12: 6.25% emission rate
### Distribution Mechanism
When triggered by protocol activity:
1. Calculates elapsed time since last distribution
2. Mints GNS based on the current timestamp range and halving-year rates
3. Distributes to targets per configured ratios
4. Carries forward any undistributed amounts
If emission is halted, `MintAndDistributeGns` returns `(0, false)` without
panicking. A caller that requires emission must explicitly handle that result.
## Key Functions
### `MintAndDistributeGns`
Mints and distributes GNS tokens automatically.
### `SetDistributionStartTime`
Sets or reschedules the emission start timestamp before distribution is active.
The timestamp must be positive and in the future; after the configured start
time has been reached, the timestamp is immutable.
### `ChangeDistributionPct`
Updates distribution percentages (admin or governance only).
### `GetDistributionBpsPct`
Returns current distribution percentage in basis points for a target, or an error if the target is invalid.
## Gnoweb
`Render("")` shows distribution dates in UTC, GNS amounts with six decimal places,
allocation percentages, and cumulative distributions for the four recipients.
Staker and governance-staker counters since their last accounting clear are shown
separately: these allocations have already been transferred and are not wallet
balances or user-claimable rewards. Unsupported paths return `404`.
## Technical Details
### Timestamp-Based Emission
The following is a conceptual view of the schedule:
```
emissionPerSecond = baseEmission / (2^halvingCount)
amountToMint = emissionPerSecond * elapsedSeconds
```
The implementation uses integer, piecewise rates. For each halving year
intersecting the inclusive mint range `[fromTimestamp, toTimestamp]`, it
initializes `yearAmountPerSecond` as
`floor(yearDistributionAmount / SECONDS_IN_YEAR)` and multiplies that rate by
the inclusive number of seconds. The mint range is clamped to the 12-year
schedule end. When a range reaches a year end, the remaining integer amount
(including division dust) is added so that the year's allocation is exhausted.
### Halving Calculation
Halving years are determined by the schedule's year boundaries; the conceptual
form is:
```
halvingCount = floor(timeSinceStart / halvingPeriod)
```
### Distribution Targets
1. **Liquidity Staker**: Rewards for LP providers
2. **DevOps**: Development and operations fund
3. **Community Pool**: Community-governed treasury
4. **Governance Staker**: GNS staking rewards (currently 0%)
## Usage
```go
// Set emission start (admin/governance; timestamp must be in the future)
SetDistributionStartTime(cross(cur), futureStartTimestamp)
// Trigger emission (called automatically by protocol flows)
amount, ok := MintAndDistributeGns(cross(cur))
// Update distribution ratios
ChangeDistributionPct(
cross(cur),
7000, // 70% to liquidity stakers
2000, // 20% to devops
1000, // 10% to community pool
0, // 0% to governance stakers
)
// Query distribution info
stakerPct, err := GetDistributionBpsPct(LIQUIDITY_STAKER)
if err != nil {
panic(err)
}
accumulated := GetAccuDistributedToStaker()
rate, err := GetStakerEmissionAmountPerSecond()
if err != nil {
panic(err)
}
```
## Security
- Start time may be rescheduled while still in the future and is immutable once active
- Distribution percentages must sum to 10000 (100%)
- A halted `MintAndDistributeGns` call returns `false`; no automatic cross-module cascade occurs
- If staker cache invalidation is required, keep the optional distribution-change callback registered
- Leftover tracking carries undistributed amounts forward
- Halving is enforced at protocol level
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.