Skip to main content

Supply Mechanics

The GHOST token has a hard-capped supply with zero inflation. All minting and burning is exclusively controlled through the ghostmint precompile, and the supply invariant is checked every block at the consensus level. This page documents the supply parameters, enforcement mechanisms, and tracking infrastructure.

Supply Parameters

ParameterValueLocation
Maximum supply1,000,000,000 GHOST (10^27 aghost)x/ghostmint/types/keys.go (MaxMintSupply)
Inflation rate0%x/mint module configuration
Denominationaghost (18 decimals)Native denom across Cosmos and EVM
Smallest unit1 aghost10^-18 GHOST

The maximum supply is hard-coded as a Go variable in the ghostmint module:

// MaxMintSupply is the hard cap on total tokens mintable via ghostmint.
// 1 billion GHOST = 1e27 aghost (18 decimals).
MaxMintSupply = math.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(27), nil))

This value is a compile-time constant. Changing it requires a chain upgrade with validator consensus -- it cannot be modified by governance proposals, contract calls, or any runtime mechanism.

Zero Inflation

The Cosmos SDK x/mint module is configured with a 0% inflation rate. No new GHOST tokens are created through block rewards or staking inflation. The only mechanism that creates GHOST tokens is the ghostmint precompile, and it is constrained by the MaxMintSupply cap and the net supply tracking.

Net Supply Tracking

The ghostmint module tracks cumulative minting and burning in its KVStore:

netSupply = totalMinted - totalBurned

Every mint operation checks:

netSupply + mintAmount <= MaxMintSupply

This formula accounts for burns. If 500 million GHOST are minted and 200 million are burned (through privacy commits), the net supply is 300 million. The protocol can still mint up to 700 million more GHOST before hitting the cap. Burns "free up" supply capacity.

KVStore Keys

KeyPurpose
TotalMintedCumulative aghost minted via ghostmint precompile since genesis
TotalBurnedCumulative aghost burned via ghostmint precompile since genesis
LastTotalSupplyPrevious block's total aghost supply (for invariant checking)

These values are persisted in the module's KVStore and updated atomically with each mint or burn operation.

Ghostmint Precompile

All GHOST minting and burning flows through the ghostmint precompile at address 0x0808. This is the only code path that can create or destroy GHOST tokens (outside of genesis allocation).

MethodGas CostDescription
mintNativeTo(address, uint256)50,000Mint aghost to recipient via x/bank
burnNativeFrom(address, uint256)50,000Burn aghost from sender via x/bank
totalMinted()200Read cumulative minted amount
totalBurned()200Read cumulative burned amount

Authorization

The precompile maintains an authorized callers map. Only contracts in this map can call mintNativeTo or burnNativeFrom. Currently, the sole authorized caller is the NativeAssetHandler contract:

Authorized CallerAddressRole
NativeAssetHandler0x35cdaE691037fcBb3ff9D0518725F1ae98d502b7Bridges CommitRevealVault burn/mint calls to the precompile

If the authorized callers map is empty (misconfiguration), the precompile rejects all calls -- it does not default to permissive behavior. Additional authorized callers can be added through governance-controlled chain upgrades.

Mint Flow

When mintNativeTo is called:

  1. Validate the caller is authorized
  2. Validate amount is positive
  3. Check netSupply + amount <= MaxMintSupply
  4. Call x/bank.MintCoins() to create tokens in the ghostmint module account
  5. Call x/bank.SendCoinsFromModuleToAccount() to transfer tokens to the recipient
  6. Update totalMinted in KVStore
  7. Record the balance change in the EVM StateDB journal

Burn Flow

When burnNativeFrom is called:

  1. Validate the caller is authorized
  2. Validate amount is positive
  3. Call x/bank.SendCoinsFromAccountToModule() to transfer tokens from the precompile address to the ghostmint module account
  4. Call x/bank.BurnCoins() to destroy the tokens
  5. Update totalBurned in KVStore
  6. Record the balance change in the EVM StateDB journal

Supply Invariant

The ghostmint module runs a per-block supply invariant check in the EndBlocker. Every block, the module:

  1. Reads the current total supply of aghost from x/bank
  2. Compares it with the LastTotalSupply stored from the previous block
  3. If the current supply exceeds the previous supply unexpectedly, logs an error:
SUPPLY INVARIANT: unexpected supply increase
previous: <last block supply>
current: <this block supply>
delta: <unexpected increase>
denom: aghost
  1. Updates LastTotalSupply to the current value for the next block's check

This invariant catches any unexpected supply creation -- whether from a bug in the ghostmint module, a compromised precompile, or any other source. Because the Cosmos SDK's x/bank module tracks total supply independently of the ghostmint module, the invariant provides a cross-check between two independent accounting systems.

Note: The invariant currently logs an error rather than halting the chain. This is a deliberate design choice: halting on an invariant violation would require manual intervention to restart, which could be worse than the violation itself in some scenarios. Future versions may escalate to a chain halt for critical violations.

Solvency Tracking

At the smart contract level, the CommitRevealVault and BatchCommitRevealVault independently track total committed and total revealed amounts per token:

totalRevealed[token] <= totalCommitted[token]

This invariant ensures that the vault never mints more tokens than were burned. It operates at the EVM level and is independent of the consensus-level supply invariant -- providing defense in depth.

Supply Summary

LayerInvariantEnforcement
Consensus (Go)netSupply <= MaxMintSupplyMint rejected if cap exceeded
Consensus (Go)Supply does not increase unexpectedly between blocksEndBlocker check, error logged
EVM (Solidity)totalRevealed[token] <= totalCommitted[token]Reveal rejected if solvency violated
EVM (Solidity)Only authorized callers can invoke precompileUnauthorized calls rejected