Covenants became first-class citizens on Kaspa with the Toccata hard fork in June 2026. Covenants is an umbrella term for the building blocks that fork introduced.
This page starts in plain language and ends at the byte level. The first half assumes nothing; the second half is the mental model the rest of the Covenants group in the sidebar builds on.
The idea
Normally, coins do not care what happens to them. If you hold the key to some KAS, you can send it anywhere, in any amount, to anyone. The only rule attached is “prove you own this.”
A covenant attaches a second kind of rule: “and here is what you are allowed to do with it next.”
The rule is not stored in a database somewhere, and it is not enforced by a company. It is part of the coins themselves, and the network checks it automatically every time someone tries to spend them.
An analogy
Think of ordinary coins as cash in an envelope. Whoever holds the envelope can spend the contents however they like.
A covenant is closer to money inside a box with rules engraved on the lid. To take anything out, you have to satisfy the engraving — and typically the engraving says “whatever is left must go straight into another box exactly like this one.”
That last part is the important bit. It is what lets a rule survive across time, rather than applying once and evaporating:
The rules do not just permit or deny the spend — they require the leftover to be re-locked under the same rules. That is how a covenant persists.
Why this is a big deal
Without covenants, a coin’s rules end the moment it is spent. You can say “Alice may spend this,” but not “Alice may spend this, and only in these ways.”
That single limitation is what has historically kept UTXO chains like Bitcoin and Kaspa from supporting things account-based chains take for granted. Covenants remove it, and a surprising amount follows:
| What it enables | Why it needs covenants |
|---|---|
| Tokens | A token is just a rule that says “the total can never change and only the owner may move it” — and that rule has to survive every transfer |
| Vaults | “Withdrawals must sit in a visible waiting period first, and can be cancelled during it” — the delay must persist across spends |
| Escrow | Funds that can only move to one of a few pre-agreed destinations |
| Time-delayed spending | Coins that literally cannot move until a certain point |
| Whitelisting | Funds that can only ever be sent to approved recipients |
| Congestion control | Committing now to a payout structure that can be settled later |
Many of these examples come from KIP-17, the proposal that introduced the covenant opcodes.
How it differs from a smart contract
If you are used to Ethereum, “programmable money” suggests a contract: a program living at an address, holding state, that anyone can call.
Kaspa works differently, and the difference is not cosmetic.
| Account-based chains | Kaspa covenants | |
|---|---|---|
| Where state lives | In one shared global account | Inside individual coins |
| What a “program” is | Code at an address that anyone calls | Rules travelling with specific coins |
| How it advances | A call mutates shared state | A spend consumes coins and creates successors carrying the updated state |
| Parallelism | Contract calls contend for the same state | Independent coins are independent — no contention |
The practical upshot is a trade. Kaspa gets parallelism and predictability essentially for free, because there is no global state for transactions to fight over. In exchange, anything involving many participants at once has to be arranged as an explicit transaction rather than assumed.
It also means covenants are not “deployed” the way contracts are. There is no contract address to send funds to. A covenant exists only as coins locked under its rules — spend the last of them without a successor, and it is simply gone.
Two building blocks
Covenants is really two capabilities that work together.
Introspection lets a coin’s rules examine the transaction trying to spend it. Without this, rules can only ask “do you have the key?” With it, they can ask “where exactly is this money going, and how much?” — and refuse if the answer is wrong. This arrived through KIP-10 and was substantially expanded by KIP-17.
Covenant IDs solve a subtler problem: identity. Rules alone cannot tell a genuine coin from a convincing imitation. Anyone can copy a token’s rules, create their own coins under them, and claim to hold the real thing — the copy would look identical.
KIP-20 fixes this by having the network itself track lineage. Each covenant gets a unique identity when it is first created, and every successor inherits it. The network verifies the inheritance directly, so a lookalike created separately simply has a different identity and cannot pass as the original — no matter how perfectly its rules match.
Together: introspection decides whether a spend follows the rules, and covenant IDs establish that the coins were genuine to begin with.
The one idea everything rests on
That is the concept. The mechanism is one sentence:
A covenant program is a script that contains its own state as literal bytes, and whose address is the hash of those bytes.
That has a surprising consequence, and it is what every covenant on Kaspa is built out of:
Because the script is the state, and the address is the hash of the script, a covenant can compute the exact address its successor must have — by taking its own bytes, splicing in the new state, and hashing the result.
The script does not need to “remember” anything. It reconstructs its own future from bytes it can already see.
Building up to it
1. P2SH hides the script until you spend
A Pay-To-Script-Hash output commits only to a 32-byte hash. Nobody can read the script from the chain while the output is unspent. To spend it you must reveal the script (the redeem script) and it must hash to the committed value.
Call that revealed redeem script R. Throughout the KCC documents, R means the entire covenant program.
2. The program carries its state
R is not just logic. It begins with a run of data pushes holding the covenant’s current values, followed by the code that acts on them:
Spending the output reveals all of it — so the running script can read its own current state directly out of its own bytes.
3. Splice new state into the same logic
The logic bytes are the template. Keep them, swap the state, and you have the successor program R_next. Here is the same contract compiled with count = 8:
4. The address follows from the bytes
R_next hashes to a different value than R, so it has a different address:
blake2b(R) = e9c4ef0278b3d9f5d6d234ae89e2e38f30462fb9b9eeb32ed7caa76625552706
blake2b(R_next) = c4497fd43fe47ddf0a83fb58130ad999ce587f0e00a52a5b380c3f51fa6fd511 The script computes that second hash while it is running, wraps it in the standard P2SH script public key, and requires that one of the transaction’s outputs pays to exactly it. If the spender tries to pay anywhere else, the script fails.
That is the whole covenant loop:
The consumed instance validates its own successor. Consensus never has to understand the contract — the script does the checking.
Vocabulary
KCC1 fixes these terms, and the rest of the series uses them precisely.
| Term | Meaning |
|---|---|
| Covenant | A spending program that inspects transaction context and restricts how this transaction’s outputs may be spent later |
Covenant program (R) | The complete executable byte string, including every embedded value and its current encoded state. The P2SH redeem script |
| Covenant instance | A UTXO locked to a covenant program. Identified uniquely by its outpoint |
| Transition | A transaction consuming one or more covenant instances and creating zero or more continuations |
| Continuation | An output the consumed instance accepts as its successor |
| Template | What is left of R when the state range is removed — an ordered prefix and suffix |
Two distinctions worth internalizing early, because they are easy to blur:
- A program is bytes; an instance is a UTXO. Several UTXOs can hold the identical program.
blake2b(R)therefore identifies a contract-in-a-state, not a coin. - A template is shared by every state a contract can be in. It is the closest thing to “the contract’s identity” that pure script can express — which is why so much of KCC1 is about hashing and authenticating templates.
Where consensus helps
Reconstructing the successor address proves the next output is correct. It does not, on its own, prove that the UTXO you are spending descends from a legitimate origin rather than from a lookalike someone else deployed. That is what Covenant IDs are for, and the split is clean:
- The script proves the successor’s contents are correct.
- Consensus proves the successor’s lineage is correct.
The OpCov* and OpAuth* opcodes let a script query that structure directly. Covenant IDs are covered in depth in Covenant IDs & Bindings.
What the KCC documents standardize
The opcodes and Covenant IDs are consensus primitives. They say what a script is allowed to inspect and enforce, and deliberately say nothing about how a covenant should lay out its data.
That is a convention problem, and conventions are what the KCC (Kaspa Covenant Conventions) documents standardize. Without them, every covenant is a private binary format that only its own author’s tooling can read.
That line — what the network enforces versus what programs merely agree on — is the most useful one to keep straight, and it is why the sidebar splits the series into two groups. Break a consensus rule and your transaction is rejected. Break a convention and your covenant still works; it just becomes unreadable to everyone else’s tooling.
| Document | Scope |
|---|---|
| KCC1 | Byte layouts and ABI: value encodings, entrypoints and dispatch tags, the P2SH envelope, state and templates, lineage roles, virtual elements |
| KCC2 | How a program ABI declares who controls a covenant, so observers can answer “whose is this?” |
| KCC20 | A fungible-token covenant surface: required state prefix, transfer interface, and a published descriptor |
KCC1 is deliberately independent of any source language or compiler. SilverScript is the reference compiler that produces programs in this shape, and every hex example above is real output from it.
How to read this series
The pages are ordered so each one only relies on the pages before it, and grouped by whether they describe a network rule or a convention.
Consensus — enforced by the network. True of every covenant, whatever conventions it follows.
| Page | What it adds |
|---|---|
| Covenant Opcodes | The full opcode surface a covenant can call |
| Covenant IDs & Bindings | KIP-20 lineage — how a covenant gets a forgery-proof identity |
Conventions — the KCC documents. Agreements about byte layout that make covenants interoperable.
| Page | What it adds |
|---|---|
| The P2SH Covenant Envelope | How R is committed to, revealed, and executed |
| The Value ABI | How typed values become bytes — the alphabet everything else is written in |
| Entrypoints & Dispatch | How one program exposes several callable branches |
| State, Templates & Continuations | How state is carved out of R and spliced back in |
| Template Views & Virtual Elements | Partial state mutation, and committing to data too large to embed |
| Leaders & Delegators | Coordinating a transition across several covenant inputs |
| Control Principals | KCC2 — declaring who controls a covenant |
| KCC20 Fungible Tokens | The whole stack applied to a real token standard |
If you only read two, read Covenant IDs & Bindings and State, Templates & Continuations — one from each half, and together they cover the concepts that most often trip people up.
Where things stand
The primitives are live on mainnet. You can watch adoption directly:
The tooling above them is younger. Writing covenants in raw script is punishing, so most work now goes through SilverScript, a higher-level language that compiles down to it, with Argent layered above for multi-contract applications.
KCC1, KCC2, and KCC20 are all Draft, and SilverScript is explicitly experimental — its authors recommend testnet-10 only for now. Where the current compiler and the draft specs differ, this series says so on the page where it matters. The primitives underneath them are not draft; they have been active on mainnet since Toccata.
So: the foundation is finished and in production. What gets built on it is the part still in motion.
Working examples
Runnable covenant code, useful for seeing the primitives exercised end to end:
covenant_id.rs— Covenant ID genesis and continuation, in rusty-kaspacovenants.rs— introspection-based covenants, in rusty-kaspaforced_recipient.py— building a covenant transaction with the Kaspa Python SDKcounter.py— a stateful covenant walked through real transitions on testnet-10- SilverScript example contracts — including
kcc20.silandkcc20-minter.sil - The SilverScript KCC20 book — a full walkthrough of the token and minter contracts
Specifications
The KIPs are merged and active on mainnet. The KCCs are open pull requests against the kccs repository — nothing is merged there yet, so the PR is the document.
| Spec | Covers |
|---|---|
| KCC1 | Covenant definition, concepts, byte layouts and ABI |
| KCC2 | Control principal references in program ABIs |
| KCC20 | Fungible token covenant specification (discussion thread) |
| KIP-10 | New transaction opcodes for enhanced script functionality |
| KIP-16 | New transaction opcodes for verifiable computation (the ZK precompile) |
| KIP-17 | Covenants and improved scripting capabilities |
| KIP-20 | Covenant IDs |
Going deeper
Conceptual
- Programmability — how covenants fit alongside ZK and the rest
- Toccata hard fork — what shipped, and when
- UTXO Model — the coin model covenants build on
- KIPs — the proposals themselves
- KIP-21 explained on Kaspa.com
Prior art
Covenants are a long-running idea in the UTXO world, and much of the design vocabulary comes from Bitcoin research:
- BIP-119 (
OP_CHECKTEMPLATEVERIFY), BIP-345 (OP_VAULT), BIP-347 (OP_CAT) - CAT Protocol — covenant-based fungible and non-fungible tokens
- Covenant use cases and UTXOs.org
- Awesome OP_CAT
- ZK covenants and verifiable programs (vprogs)