Skip to content

Tokenomics

This document specifies the economic model of the OpenInfra DePIN platform: what units exist, how value moves, what authority can change what, and the invariants that bound governance proposals so a single bad vote can’t take the network down.

It is the source of truth for the internal/tokenomics package, which enforces the invariants below at proposal-validation time. Edits to the bounds in this document must land in the same commit as the code change.

Status: Pilot Phase 7 (devnet). Mainnet deployment, Squads-multisig mint authority, and inflation/burn mechanics are deferred to a future revision of this document.


The credit is the unit the off-chain ledger denominates every entry in (see internal/db/migrations/009_pilot_ledger.up.sql). Credits are signed int64; the conservation invariant Σ debits + Σ credits + Σ fees = 0 holds per workload (verified in internal/settlement/settlement_test.go).

Credits are computed by pricing.Compute(vcpus, memoryMB, durationSec, ratePerCPUMicro, ratePerMBMicro):

ComponentDefault rateMeaning
RATE_PER_CPU_MICRO1_000_0001 credit per vCPU·second
RATE_PER_MB_MICRO1_0000.001 credit per MB·second

Rates are micro-credits per unit-second (1 credit = 1 000 000 micro-credits) so the math stays integer-only.

Devnet mint: 9Jkq8WdgUUp2AR4FeXwE6q4DRddoHGfcKREMeCE6wphT Decimals: 6 (matches SPL convention) Total supply (devnet): 1 000 000 OINFRA-test (no minting after genesis on devnet — see §3.1 for mainnet policy).

The onchain bridge (internal/settlement.OnchainCron) converts provider-credit ledger rows in the solana: namespace into SPL transfers 1 credit = 1 OINFRA base unit (i.e. 1 micro-OINFRA, since OINFRA has 6 decimals). The pegged 1:1 ratio is intentional for v1 so providers can reason about earnings without a floating exchange rate; later revisions may unpeg via a credit-burn / token-mint mechanism governed by §4.

+--------------------+ pricing.Compute +-------------------+
| workload usage | -----------------> | ledger (credits) |
| (vcpu·s, MB·s) | | |
+--------------------+ +---------+----------+
|
OnchainCron (1:1) v
+-------------------+
| OINFRA (SPL) |
+-------------------+

Ledger writes are synchronous on heartbeat-observed completion (Block B); SPL submission is asynchronous via the executor’s 5-minute ticker (Block C). Until SPL submission succeeds, the ledger entry’s settled_onchain_at is null — onchain mid-flight is idempotent because MarkSettled is gated on WHERE settled_onchain_at IS NULL.


AuthorityTodayControls
Treasury hot wallet<dataDir>/treasury.age (age-encrypted to host key)Mint authority for OINFRA-test, signs all SPL transfers
Admin role (JWT)Database row, manual seedCredit minting (POST /api/v1/admin/credits/mint), invite issuance, host ban/unban
Governance (staked credit holders)internal/governanceCatalog add/remove, parameter changes (within the bounds in §4), host ban/unban (via proposal), treasury spend
Operator (env vars)cmd/api-server/main.goRATE_PER_CPU_MICRO, RATE_PER_MB_MICRO, PLATFORM_FEE_BPS, SOLANA_MINT, OPENINFRA_DATA_DIR, OPENINFRA_HOST_KEY

Phase-7 hardening migrates the treasury hot wallet to a 3-of-5 Squads multisig and moves PLATFORM_FEE_BPS from env-var to governance config (requires a schema migration; tracked in ARCHITECTURE.md pending).


Fixed supply of 1 000 000 OINFRA-test minted at genesis. No further mint operations. The treasury holds the entire supply minus what has been transferred out as provider rewards.

Decisions still open and explicitly not ratified by this document:

  • Initial supply at TGE.
  • Whether supply is fixed, inflationary, or deflationary.
  • If inflationary: emission curve (constant / decaying / halving) and destination of new mint (provider rewards / treasury / staker yield).
  • If deflationary: burn source (fee skim / fixed schedule / governance- triggered).
  • Vesting schedule for any team/treasury/investor allocation.

The Phase-7 revision of this document must specify each before the mainnet mint is created. Until then, all OINFRA references in code are OINFRA-test on Solana devnet.


These are the parameters the DAO can change via a param_change proposal. The bounds and per-proposal step limits below are enforced by internal/tokenomics.Validate at proposal-submit time and again at execute time. A proposal that violates either fails validation and never reaches a vote.

KeyTypeMinMaxMax Δ per proposalRationale
base_reward_rateint6401 000 000 000100 000 000Reward emission per epoch; max-Δ caps a 10×/proposal shock
fee_split_host_pctbps (0-10000)5 0009 5001 000Host’s share of fees; min 50% so providers always get majority, max 95% so platform isn’t insolvent
min_proposal_stakeint6410010 000 000 0000No rate cap — small operators must be able to lower it
voting_period_hoursint32247201681 day floor (snap proposals impossible), 30 day ceiling (no proposal can stall forever); 1 week max change
quorum_bpsbps5007 5001 0005% min so a quiet network can still govern; 75% max so a small offline group can’t block all votes
pass_threshold_bpsbps5 0019 5001 000Strict majority floor (5 001 = just over 50%); 95% max so unanimous-or-die isn’t a valid configuration
veto_threshold_bpsbps1 0005 0001 00010% min so a tiny faction can’t veto; 50% max so veto needs less than majority
max_active_proposalsint3211000Anti-DoS for the voting UI; no rate cap (admins should be able to slash it instantly under attack)
unbonding_period_hoursint32242 1601681 day floor (no instant exit-and-attack), 90 day ceiling (no permanent lock); 1 week max change

ValidateBounds(key, proposed) runs at proposal submit and stops out-of- range values from ever reaching the voting queue. ValidateTransition( key, current, proposed) runs at execute and stops a proposal that was in-range when submitted but is now too aggressive against the (possibly changed) current value. Both stages share the same Invariants map so governance can never paint itself into a corner where a previously-valid proposal becomes unstoppable.

4.2 Why platform_fee_bps isn’t in the list yet

Section titled “4.2 Why platform_fee_bps isn’t in the list yet”

PLATFORM_FEE_BPS is currently an env var, not a governance_config column. Moving it into governance requires a schema migration (Phase 7). Until then it’s documented as operator-set, bounded by settlement.MaxPlatformFeeBps = 5000 (50%) and defaulting to settlement.DefaultPlatformFeeBps = 1000 (10%). The same bounds will apply when it migrates to governance.


Every settled workload writes three ledger entries (debit / credit / fee):

workload_debit customer -> -amount
provider_credit provider -> +amount × (1 - platform_fee_bps/10000)
platform_fee treasury -> +amount × platform_fee_bps/10000

The treasury account is the namespaced address internal:treasury on the ledger. There is no automatic mint or onchain transfer for the treasury portion — it accumulates as off-chain credits.

Only via a treasury_spend governance proposal (Block: governance Phase 2c). A passing proposal transfers from internal:treasury to a named user account. The treasury cannot be spent by admin role or by the operator directly — this is intentional and not negotiable in v1.

Phase 7 must decide whether the treasury portion is:

  • Burned (deflationary pressure)
  • Held in treasury and onchain-mirrored on a cadence
  • Distributed to stakers proportional to stake-time
  • Some mix of the above

6. Invariants enforced by internal/tokenomics

Section titled “6. Invariants enforced by internal/tokenomics”

For each governable key K:

Bound(K).Min <= proposed <= Bound(K).Max [ValidateBounds]
Bound(K).MaxStepDelta == 0 OR |proposed - current| <= delta [ValidateTransition]

A MaxStepDelta == 0 means rate-of-change is not capped (the key is either non-disruptive to change, or has no meaningful “step” notion).


Operations that must remain available even if governance is gridlocked:

OperationAuthorityCode path
Ban a hostile hostAdmin (immediately) or governance proposalhosts.status = 'banned'
Pause SPL submissionOperator: unset SOLANA_MINT and restart api-serverOnchain executor declines to start without it
Pause workload acceptanceAdmin: set all hosts to degradedScheduler skips non-active hosts
Drain treasury (mainnet only)Squads multisig override (Phase 7); v1 has no overriden/a

There is no emergency mint authority in v1. The treasury hot wallet holds the entire supply and the only path to add more is to deploy a new mint (effectively a fork).


Listed here so they are not lost. Each must be answered before the section it belongs to is considered ratified for mainnet:

  1. §3.2 Inflation curve and emission destination
  2. §3.2 Vesting cliff and schedule for any non-public allocation
  3. §5.3 Treasury split policy on mainnet
  4. §4.2 Schema migration to move platform_fee_bps into governance
  5. §2 Squads multisig threshold (3-of-5 vs 4-of-7) and signer set
  6. §1.2 Whether to unpeg credits ↔ OINFRA after mainnet liquidity is established (and if so, the rate mechanism — TWAP, oracle, etc.)