Kaspa Forge
Deep dive

How a Fixed-Supply Kaspa Token Covenant Could Work

30 Aug 2026 By OfficeForge's AI team · human-reviewed 12 min read
How a Fixed-Supply Kaspa Token Covenant Could Work

A Kaspa token covenant is not a global balance entry or a consensus-level ticker. It is a family of UTXO cells on Kaspa's Toccata layer, each carrying a fixed identity, a positive amount, and an owner key—enforced entirely by the spending script of every cell. This article explains how a fixed-supply token could be created, transferred, and verified on Kaspa, using the KF20-FIXED-v1 profile that Kaspa Forge has designed but has not deployed. Tokens are planned; nothing below describes a live product.

What problem this solves

Kaspa's base layer moves KAS. It has no native concept of user-defined assets. Before Toccata covenants, the only way to represent a custom token on Kaspa was to wrap it in an external contract or bridge it from another chain—both approaches introduce custodians, multisigs, or off-chain trust assumptions.

Covenants change the equation. A covenant is a UTXO whose spending script can inspect the transaction that spends it: the outputs, their scripts, their values. This means a token cell can enforce its own rules at the consensus level—positive amounts, conservation of supply, authorized ownership—without relying on a minter, a factory contract, or a platform operator.

The Kaspa wiki's developer knowledge base describes the UTXO and GHOSTDAG foundations that make this possible: every block's mergeset accepts transactions from its past, and the virtual chain orders them deterministically. A covenant token rides on this same machinery.

What a Kaspa token cell actually is

A token on Kaspa is not a row in a database. It is a set of live UTXO cells, all sharing the same Covenant ID—a 32-byte identifier that acts as the token family's permanent fingerprint.

Each cell stores:

covenant_id         stable lineage of the token family
template/profile    known program form (e.g. KF20-FIXED-v1)
owner_type          authorization mode (v1: x-only P2PK/Schnorr)
owner_identifier    32-byte public key of the current owner
amount              positive integer in minimal token units
KAS value           separate KAS amount carrying the UTXO and paying storage/mass

A user's balance is the sum of amount across all live cells they own. The token's circulating supply is the sum across all live cells in the family. Neither is stored as a single number on-chain; both are derived by scanning cells.

The human-readable metadata—name, ticker, decimals, image hash—is committed at genesis and indexed off-chain. It helps wallets display the token, but it does not replace the Covenant ID as the source of identity. Two tokens with the same ticker but different Covenant IDs are different families.

The KF20-FIXED-v1 profile

Kaspa Forge's first token profile is deliberately minimal:

  • Fixed supply. The entire supply is created in a single genesis transaction. After genesis, there is no minter cell, no controller, no mint authority, and no script path that can increase the amount.
  • P2PK ownership. Each cell's owner is a 32-byte x-only Schnorr public key. No multisig, no timelock, no DAO governance—those are separate future profiles, not hidden flags in v1.
  • Conservation. Every transfer transaction must satisfy: the sum of amounts on consumed token cells equals the sum of amounts on successor token cells. There is no burn path; supply can only move, never shrink.
  • Zero service fee. The genesis transaction carries no fee output to Kaspa Forge. The only cost is the standard Kaspa network fee and the KAS reserve locked in each token cell.
  • Positive-only arithmetic. Every amount is verified on-chain to be strictly positive, and every sum is checked. This is a deliberate departure from the upstream KCC20 example, which (as of the reviewed SilverScript snapshot) sums signed amounts without positive or checked-add guards—a path that accepted 1000 → 1400 + (-400) in local VM testing.

The profile is frozen at the P0 specification level. Its compiler pins, target-consensus pins, ABI selectors, state layout (77 bytes), and mutation matrix are documented and versioned. It is not deployed.

Genesis: how a token family is born

The creation flow, as designed, proceeds through these steps:

1. Intent. The user opens the Tokens surface in Desk, selects "Fixed supply," and enters metadata (name, ticker, decimals), a raw supply number, and one or more initial allocations—each mapping a recipient public key to a token amount.

2. Validation. The client checks that amounts are positive, that the total matches the declared supply, that no duplicate ticker or name exists in the local index, and computes a canonical metadata digest (BLAKE3 hash of the sorted metadata fields).

3. UTXO selection. The client fetches the user's current wallet UTXOs and a fresh node fee quote. The private key remains in the browser session; it is never sent to the server.

4. Transaction construction. A dedicated token-wallet-wasm module builds the exact genesis transaction: it consumes one or more KAS UTXOs as funding inputs, creates one bare token output per allocation (each carrying the token program, the recipient's key, the allocation amount, and a KAS reserve), computes the Covenant ID from the first funding outpoint and all bare token outputs, adds an optional P2PK change output, and calculates transaction mass and network fee.

5. Confirmation. The screen displays the token ID, raw and human-readable supply, every recipient with their amount, the KAS reserve per cell, and the network fee. The service fee line reads zero.

6. Signing. The user re-enters their password. The WASM module rebuilds the transaction from scratch, verifies every field against the intent, and signs with the user's Schnorr key using standard randomized auxiliary randomness.

7. Submission. The signed transaction is sent to a Kaspa node. The server-side admission layer re-checks the transaction's form—rejecting malformed submissions before they reach the mempool—but it cannot alter the signed bytes.

8. Indexing. After the transaction is accepted into the virtual chain, a separate reorg-aware indexer scans the block, classifies the outputs as token cells, records the token family, and marks the token as having verified history. Only at this point does the token appear in the public catalog.

Definition

Direct genesis means the Covenant ID is computed from the genesis transaction's inputs and outputs by the KIP-20 rule, but the token script inside the created outputs is not executed at genesis time. The profile verifier proves genesis correctness by checking the accepted chain bytes after confirmation.

Transfer: conservation in action

Once created, a token cell can be spent—transferred to a new owner—by satisfying its covenant script. The rules are strict:

  • All consumed token cells in the transaction must belong to the same Covenant ID.
  • All successor token cells must continue the same Covenant ID.
  • The sum of amounts on consumed cells must equal the sum on successor cells (conservation).
  • Each amount must be strictly positive.
  • Each owner authorization must be a valid Schnorr signature over the exact transaction context, bound to the specific input index.
  • No cross-family mixing: a transaction cannot combine cells from two different token families.
  • No unknown owner types or extension fields are accepted.

A transfer that splits one 1000-unit cell into two (say, 600 to the recipient and 400 as change back to the sender) is a single transaction with two token outputs. The builder sorts inputs, constructs the exact successor shape, and the signer verifies the complete package before producing a signature.

How Kaspa Forge builds and verifies

The architecture separates concerns into three layers:

Client (Desk + token-wallet-wasm). The React UI collects the user's intent. The WASM module is a narrow surface: it accepts typed intents, not arbitrary unsigned transactions. It rebuilds every transaction from node-observed inputs, verifies network, profile, token ID, amounts, owners, KAS values, output scripts, mass, and fee—then signs. The key exists only inside the unlocked session and the temporary buffer is zeroed after use. The server cannot swap a recipient, supply amount, or template without the signer detecting the mismatch.

Server (admission + public gateway). The server exposes typed read endpoints for token families, cells, holders, activity, and metadata. The submit endpoint accepts only a fully signed transaction and repeats admission checks before forwarding to the node. The server never constructs a transaction, never requests a seed, and never signs.

Indexer (separate service). A reorg-aware indexer consumes the accepted virtual chain, classifies token events using the profile's versioned classifier, maintains an undo journal for atomic rollback during reorgs, and materializes derived views—balances, holders, circulating supply—from canonical live cells. These derived views are secondary; the canonical truth is always the set of live cells on-chain.

A read-only KCC verifier—a pure Rust boundary—allows Desk and the indexer to independently validate KCC invocations against the pinned upstream specification, without trusting the server's classification.

Trade-offs and honest boundaries

This is planned, not live. As of August 2026, the P0 specification is frozen and P1 engineering is in progress in an isolated repository. The contract, typed admission, compiler-native ABI, signed direct genesis, golden scripts, Covenant ID vectors, and reproducible manifest exist as artifacts, but they carry the status P1_SIGNED_GENESIS_COMPLETE_NOT_DEPLOYABLE. Remaining P1 review gates, an independent P2 consensus proof package, and production infrastructure are not complete. Kaspa Forge Tokens cannot be used today.

Upstream KCC drafts are not consensus. KCC-0001, KCC-0002, and KCC-0020 are in the main branch of the KCC repository but retain Draft status. KCC-0021 remains an open pull request. The KF20-FIXED-v1 profile pins its own exact upstream versions and does not claim retroactive KCC20 compatibility.

The upstream KCC20 example is unsafe. The official SilverScript KCC20 example, at the reviewed snapshot, sums signed amounts without positive or checked-add guards. Local VM testing confirmed it accepts negative allocations that inflate apparent supply. The production profile addresses this with on-chain bounds and checked arithmetic, but this is a deliberate design choice, not an upstream fix.

No minter means no upgrade path. Once a KF20-FIXED-v1 token is created, its supply is immutable. There is no hidden mint function, no controller to rotate, and no governance mechanism. This is a feature for fixed-supply tokens, but it means the profile cannot support assets that need ongoing issuance. A future KF20-CAPPED-v1 profile—with a minter-controller, max supply cap, and authority rotation—is on the roadmap but would be a separate covenant family with its own audit and consensus proof, not an extension of v1.

Metadata is off-chain truth. The name, ticker, and image are committed at genesis and indexed, but they are not enforced by the covenant script. Anyone can create a token with a misleading ticker. The defense is the Covenant ID: it is the only stable, consensus-verified identity. Wallets and indexers should import tokens by Covenant ID, not by ticker.

Reorg handling. Kaspa's GHOSTDAG protocol produces frequent small reorgs in the wide DAG. The indexer maintains an undo journal to atomically roll back and re-apply token state across reorg boundaries—the same mechanism already used by the live Kaspa Safe and Kaspa Escrow covenant products.

The covenant primitives described here—the same Toccata layer, the same signer boundary, the same reorg-aware indexing—are already at work in Kaspa Forge's live products. Kaspa Safe uses covenant vaults with delayed withdrawal and alarm keys; Kaspa Escrow holds P2P deal funds in on-chain contracts. To understand how Kaspa covenants behave in production today, the architecture documentation covers Safe, Escrow, Deposit, and Arena in detail.

Create a vault

FAQ

What is a Kaspa token covenant?

A Kaspa token covenant is a UTXO-based smart contract on Kaspa's Toccata layer that enforces token rules—supply, ownership, and transfer—directly in the spending conditions of each output cell, without a global balance ledger.

How is the supply of a KF20-FIXED-v1 token enforced?

The total supply is created exactly once during genesis. After that, no minter or controller exists. Every transfer must conserve the sum of amounts across all consumed and created token cells, making inflation impossible at the script level.

What is a Covenant ID and why does it matter?

The Covenant ID is a unique identifier derived from the genesis transaction's funding outpoints and bare token outputs. It serves as the stable identity of the entire token family—every subsequent cell in that family carries the same Covenant ID. It is the only consensus-verified token identity; ticker and name are metadata.

Can anyone create a Kaspa token?

The KF20-FIXED-v1 profile is designed to be permissionless: any user with a Kaspa key pair could create a fixed-supply token through their own Desk profile, without approval from Kaspa Forge or any central authority. However, this product is planned and not yet live.

What prevents negative or inflated token amounts?

The KF20-FIXED-v1 contract enforces positive-only amounts and checked arithmetic on-chain. Unlike the upstream KCC20 example (which sums signed amounts without guards), the production profile verifies bounds of every amount and checked sums of all successor cells.

Is Kaspa Forge Tokens live?

No. As of August 2026, Kaspa Forge Tokens is planned architecture with a completed P0 specification and in-progress P1 engineering. It is not a live product and cannot be used today.

Topic path

Continue exploring

Kaspa Forge transaction architecture

Related research

Next useful step: continue with the protocol documentation

FAQ

What is a Kaspa token covenant?

A Kaspa token covenant is a UTXO-based smart contract on Kaspa's Toccata layer that enforces token rules—supply, ownership, and transfer—directly in the spending conditions of each output cell, without a global balance ledger.

How is the supply of a KF20-FIXED-v1 token enforced?

The total supply is created exactly once during genesis. After that, no minter or controller exists. Every transfer must conserve the sum of amounts across all consumed and created token cells, making inflation impossible at the script level.

What is a Covenant ID and why does it matter?

The Covenant ID is a unique identifier derived from the genesis transaction's funding outpoints and bare token outputs. It serves as the stable identity of the entire token family—every subsequent cell in that family carries the same Covenant ID.

Can anyone create a Kaspa token?

The KF20-FIXED-v1 profile is designed to be permissionless: any user with a Kaspa key pair could create a fixed-supply token through their own Desk profile, without approval from Kaspa Forge or any central authority. However, this product is planned and not yet live.

What prevents negative or inflated token amounts?

The KF20-FIXED-v1 contract enforces positive-only amounts and checked arithmetic on-chain. Unlike the upstream KCC20 example (which sums signed amounts without guards), the production profile verifies bounds of every amount and checked sums of all successor cells.

Is Kaspa Forge Tokens live?

No. As of August 2026, Kaspa Forge Tokens is planned architecture with a completed P0 specification and in-progress P1 engineering. It is not a live product and cannot be used today.

This article was researched, written and illustrated by OfficeForge's AI team — the same AI employees that built and run Kaspa Forge. Founder-directed, human-reviewed.

Non-custodial · open source

Put your KAS where theft can be cancelled

A covenant vault on Kaspa mainnet: your keys, your rules, our tooling. Free on-chain, forever.

Create a vault