Purpose and Scope
StableNet implements a two-layer governance system for minting and burning of the native stablecoin.This architecture clearly separates authorization (who is allowed to be a minter) from execution (who can actually perform mint/burn operations):
- GovMasterMinter: Approves and manages minter entities
- GovMinter: Executes mint and burn operations through collective voting
For the operational protocol followed by minters when performing mint/burn operations, see Mint and Burn Protocol.
For how minted tokens are represented on-chain, see NativeCoinAdapter Contract.
For an overview of all system contracts, see System Contracts Overview.
Two-Layer Minting Architecture
Minting governance uses a hierarchical authorization model to balance flexibility and security.This architecture is implemented through two fixed-address system contracts and storage slots in
NativeCoinAdapter.
Key design principles:
| Layer | Contract Address | Members | Operations |
|---|---|---|---|
| Authorization | 0x0000...1002 | Master minter members | configureMinter(), removeMinter() |
| Execution | 0x0000...1003 | Minter members | mint(), burn() (quorum approval required) |
NativeCoinAdapter contract:
onlyMasterMinter: checksmsg.sender == masterMinter(slot 0x0)onlyMinters: checks_minters[msg.sender] == true(slot 0x1)- Allowance check:
_minterAllowed[msg.sender] >= amount(slot 0x2)
GovMasterMinter Contract
Contract Identification and Deployment
GovMasterMinter is deployed as a system contract at genesis:- Address:
0x0000000000000000000000000000000000001002 - Deployment method: Direct injection into the genesis block (no owner)
- Upgrade mechanism: Replacement only via hard fork
- Version: Specified in the genesis configuration (e.g.
"v1")
Responsibilities
GovMasterMinter acts as the authorization layer for minting operations:- Minter registration: Approves specific addresses as minters
- Minter removal: Revokes existing minter permissions
- Allowance management: Sets per-minter mint/burn limits
- Extensibility: Enables approval of various minter types such as bridge-based or system minters
masterMinter concept used in Circle’s FiatToken contracts into an on-chain governance model.
Genesis Parameters
GovMasterMinter is initialized at genesis viaparams.ChainConfig.Anzeon.SystemContracts.GovMasterMinter:
| Parameter | Type | Purpose | Example Value | Genesis Location |
|---|---|---|---|---|
members | address list | Master minter governance members | "0xaa5f...4697" | params.GovMasterMinter.Params["members"] |
quorum | uint | Minimum approvals required | "1" | params.GovMasterMinter.Params["quorum"] |
expiry | uint | Proposal expiration time (seconds) | "604800" | params.GovMasterMinter.Params["expiry"] |
memberVersion | uint | Membership version | "1" | params.GovMasterMinter.Params["memberVersion"] |
fiatToken | address | NativeCoinAdapter address | "0x0000...1000" | params.GovMasterMinter.Params["fiatToken"] |
minters | address list | Initially approved minters | "0x0000...1003" | params.GovMasterMinter.Params["minters"] |
maxMinterAllowance | uint256 | Maximum allowance per minter | "10000000000000000000000000000" | params.GovMasterMinter.Params["maxMinterAllowance"] |
maxProposals | uint | Maximum concurrent proposals | "3" | params.GovMasterMinter.Params["maxProposals"] |
Initialization Sequence
core.SetupGenesisBlock()callscore.InjectContracts()InjectContracts()callssystemcontracts.InjectGovMasterMinter()InjectGovMasterMinter()directly initializesNativeCoinAdapterstorage:- Slot 0x0:
masterMinter = 0x0000...1002 - Slot 0x1:
_minters[address] = truefor each approved minter - Slot 0x2:
_minterAllowed[address] = maxMinterAllowancefor each minter
- Slot 0x0:
Storage Layout
GovMasterMinter does not maintain its own storage.Instead, it manages state via storage slots in
NativeCoinAdapter, defined as constants in systemcontracts/coin_adapter.go:
| Operation | Slot | Key Derivation | Value Type | ||
|---|---|---|---|---|---|
| Read master minter | 0x0 | Direct slot access | address | ||
| Check minter | 0x1 | `keccak256(address | slot)` | bool | |
| Read allowance | 0x2 | `keccak256(address | slot)` | uint256 |
Interaction with NativeCoinAdapter
GovMasterMinter can only call permission management functions onNativeCoinAdapter, protected by the onlyMasterMinter modifier.
Function signatures:
configureMinter(address minter, uint256 minterAllowedAmount) external onlyMasterMinterremoveMinter(address minter) external onlyMasterMinter
- A governance proposal reaches quorum and enters execution
- The transaction is sent from the GovMasterMinter contract
NativeCoinAdaptercomparesmsg.senderwithmasterMinterin slot 0x0- On match, slots 0x1 and 0x2 are updated and events are emitted
GovMinter Contract
Contract Identification and Deployment
GovMinter is deployed as a system contract at genesis:- Address:
0x0000000000000000000000000000000000001003 - Deployment method: Direct injection into the genesis block
- Upgrade mechanism: Hard fork only
- Version: Specified in the genesis configuration
Responsibilities
GovMinter acts as the execution layer for minting operations:- Mint execution: Issues native stablecoins
- Burn execution: Burns native stablecoins
- Oracle role: Verifies off-chain fiat deposits and withdrawals
- Member governance: Manages its own member set
- Multi-approval coordination: Collects quorum approvals for mint/burn proposals
Genesis Parameters
GovMinter is configured at genesis viaparams.ChainConfig.Anzeon.SystemContracts.GovMinter:
| Parameter | Type | Purpose | Example Value | Genesis Location |
|---|---|---|---|---|
members | address list | Minter operator members | "0xaa5f...4697" | params.GovMinter.Params["members"] |
quorum | uint | Minimum approvals for mint/burn | "1" | params.GovMinter.Params["quorum"] |
expiry | uint | Proposal expiration time | "604800" | params.GovMinter.Params["expiry"] |
memberVersion | uint | Member version | "1" | params.GovMinter.Params["memberVersion"] |
fiatToken | address | NativeCoinAdapter address | "0x0000...1000" | params.GovMinter.Params["fiatToken"] |
maxProposals | uint | Maximum concurrent proposals | "3" | params.GovMinter.Params["maxProposals"] |
Initialization Prerequisites
GovMinter must be approved as a minter before it can operate:- GovMinter address must be included in GovMasterMinter’s
minterslist - GovMasterMinter must assign an allowance to GovMinter
- During genesis,
InjectGovMasterMinter()writes this into NativeCoinAdapter slots 0x1 and 0x2
mint() / burn() calls will be rejected at the onlyMinters check.
Mint and Burn Workflow
Before any balance change, mint and burn operations must pass the following validation chain: Access control validation chain:- Minter approval check:
_minters[msg.sender] == true - Allowance check:
_minterAllowed[msg.sender] >= amount - Balance update: Direct native balance modification via StateDB
- Allowance deduction:
_minterAllowed[msg.sender] -= amount
mint(address to, uint256 amount) external onlyMintersburn(uint256 amount) external onlyMinters
Self-Governance of Members
GovMinter can manage its own membership.However, if GovMasterMinter revokes GovMinter’s minter approval, GovMinter’s entire execution authority is immediately disabled.
Governance Mechanism
GovMasterMinter and GovMinter share a common GovBase pattern.Voting Process
Proposal lifecycle:- Creation: A member creates a proposal
- Voting: Members vote to approve or reject
- Quorum reached: Approvals meet or exceed
quorum - Execution: Executed before expiry
- Expiration: Automatically discarded if quorum is not reached
Quorum Requirements
| Network Size | Recommended Quorum | Rationale |
|---|---|---|
| 1 member | 1 | Development and testing |
| 2–4 members | 2 | Simple majority |
| 5+ members | ⌈(n/2) + 1⌉ | BFT-oriented safety |
Member Versioning
memberVersion is incremented on membership changes and prevents execution of proposals created under older versions, mitigating replay attacks.
Proposal Limits
maxProposals limits the number of concurrent proposals to prevent governance-level DoS attacks.
Integration with System Contracts
| Relationship | Storage/Code Location | Purpose |
|---|---|---|
| GovMasterMinter → Slot 0x0 | statedb.GetState(nca, 0x0) | Master minter verification |
| GovMinter → Slot 0x1 | _minters[address] | Minter approval check |
| GovMinter → Slot 0x2 | _minterAllowed[address] | Allowance check |
| NativeCoinAdapter → Precompile | Native balance update | Balance modification |
| Genesis → Storage | InjectGovMasterMinter() | Initial state setup |
Summary
The two-layer minting governance architecture guarantees:| Feature | Benefit |
|---|---|
| Separation of authorization and execution | Prevents concentration of power |
| Multi-approval | Blocks unilateral abuse |
| Extensibility | Supports diverse minter types |
| Transparency | All actions recorded on-chain |
| Security | Allowance-based issuance limits |

