Covenants++ Overview
An overview of Covenants++, Kaspa's advanced UTXO-based covenant environment — use cases, KIPs, covenant IDs, and resources.Covenants++ is a broad term referring to the advanced UTXO-based covenants enabled by covenant primitives/building blocks on Kaspa. Covenants are (soon to be) first-class citizens on the Kaspa network. From a technical perspective, these building blocks can be grouped into two approximate (but related) categories:
- Covenant IDs
- Opcodes
These building blocks are in various statuses - some are active on mainnet while others are currently on testnet.
Use Cases
Kaspa’s covenant building blocks enable many use cases, including (but certainly not limited to):
- Tokens (fungible & non-fungible). See CAT Protocol for reference though a standard for covenant based tokens on Kaspa is WIP.
- Vaults (reference)
- Congestion control (reference)
- Whitelisting
- Escrow
- Time-delayed spending
Credit KIP-17 for many of these.
KIPs
- KIP-10 - New Transaction Opcodes for Enhanced Script Functionality
- KIP-17 - Covenants and Improved Scripting Capabilities
- KIP-20 - Covenant IDs
Covenant IDs (& Covenant Bindings)
Introduced by KIP-20, covenant IDs are a consensus mechanism that stores, tracks, and enforces covenant lineage. Covenant IDs greatly simplify lineage related transaction scripting logic.
A Covenant ID is a optional 32 byte hash stored on a UTXO in the field covenant_id. When Some(covenant_id), the UTXO belongs to the given covenant’s lineage. It can be thought of as a member UTXO of the given covenant.
A Covenant Binding is an optional field on a transaction output. Covenant bindings contain two pieces of data:
authorizing_input- the index of transaction input that “authorizes” the output’s creationcovenant_id- the covenant that the output belongs to
Covenant bindings are only allowed on transaction versions >= 1.
Covenant UTXOs can be created in two ways:
- Genesis: The creation of a covenant ID. The authorizing input does not have the same covenant ID as the output. Covenant ID is computed via blake2b hash of select data in a manner that ensures uniqueness.
- Continuation: The output inherits the covenant ID of the UTXO spent by the authorizing input.
Genesis
The genesis process requires that the transaction creator compute the same covenant ID as the consensus engine. So, the creator must create a blake2b hash (in a manner commensurate with consensus), store it in the covenant_id. field of the transaction output’s covenant binding, and submit the transaction. If the consensus engine calculates the same covenant ID hash, it is valid. The authorizing_input field can be any valid input index.
The genesis process guarantees covenant id uniqueness and prevents forgery. More detail is available in KIP-20.
covenant_id = BLAKE2b("CovenantID",
outpoint.tx_id
|| le_u32(outpoint.index)
|| le_u64(len(auth_outputs))
|| for each output:
le_u32(output_index)
|| le_u64(output.value)
|| le_u16(spk.version)
|| le_u64(len(spk.script))
|| spk.script
) Continuation
The output’s covenant binding ties the output back to an input with the same covenant ID. The output inherits the covenant ID from the input. This is referred to as authorization - the authorizing input for the given output. Consensus validates that the covenant IDs match and the transaction’s script validates transition.
The output’s covenant binding looks like:
authorizing_input: the index of the input from the same covenant lineage (with the same covenant ID).covenant_id: the covenant ID
Other Resources
- ZK covenants and verifiable programs (vprogs)
- CAT Protocol tokens (fungible & nonfungible)
- Bitcoin Covenants Use Cases
- UTXOs.org
- OP_CAT use cases
- In Bitcoin, the primary covenant BIPs are BIP-119 (OP_CHECKTEMPLATEVERIFY), BIP-345 (OP_VAULT), and BIP-347 (OP_CAT).
Examples
- covenant_id.rs in rusty-kaspa covpp branch
- covenants.rs in rusty-kaspa covpp branch
- forced_recipient.py in Kaspa Python SDK tn12 branch