Lock funds, pre-commit to specific distribution transactions
19. Covenant Script Proposals (OP_CTV)
Overview
Covenants are restrictions on how UTXOs can be spent — not just who can spend them. Bitcoin currently lacks native covenant opcodes, but several proposals exist. OP_CHECKTEMPLATEVERIFY (OP_CTV, BIP 119) is the most mature proposal, introduced by Jeremy Rubin. It commits to a specific template of the spending transaction, enabling use cases like vaults, payment pools, and congestion control.
What OP_CTV Does
OP_CTV (opcode 0xb3) verifies that the current spending transaction matches a pre-committed template hash. The "template hash" commits to specific fields of the transaction:
CTV hash commits to:
- nVersion (4 bytes)
- nLockTime (4 bytes)
- scriptSig hash (if any inputs have scriptSig)
- Input count
- Sequences hash
- Output count
- Outputs hash
- Input index (the index of the input being checked)
DOES NOT commit to:
- Input outpoints (which UTXO is being spent)
- Input amounts
Script Usage
CTV locking script:
<32-byte template_hash> OP_CTV
CTV unlocking script:
(empty — the script itself is the entire check)
Or combined with other conditions:
<pubkey> OP_CHECKSIGVERIFY
<template_hash> OP_CTV
Computing the CTV Hash
def compute_ctv_hash(tx: Transaction, input_index: int) -> bytes:
import struct
h = hashlib.sha256()
h.update(struct.pack('<i', tx.version)) # nVersion
h.update(struct.pack('<I', tx.locktime)) # nLockTime
if any(inp.script_sig for inp in tx.inputs):
scriptsig_hash = sha256d(b"".join(
compact_size(len(inp.script_sig)) + inp.script_sig
for inp in tx.inputs
))
h.update(scriptsig_hash)
h.update(struct.pack('<I', len(tx.inputs))) # input count
seq_hash = sha256d(b"".join(
struct.pack('<I', inp.sequence) for inp in tx.inputs
))
h.update(seq_hash) # sequences hash
h.update(struct.pack('<I', len(tx.outputs))) # output count
outputs_hash = sha256d(b"".join(
serialize_output(out) for out in tx.outputs
))
h.update(outputs_hash) # outputs hash
h.update(struct.pack('<I', input_index)) # input index
return h.digest()
Use Cases
1. Non-interactive payment channels (udi channels):
# Lock funds, pre-commit to specific distribution transactions
# Recipient can claim their portion without sender interaction after commitment
2. Congestion control trees:
Root CTV → Branch CTV_1 → Branch CTV_2 → Leaf payments
Branch CTV_3 → ...
Allows one on-chain transaction to "commit" to thousands of future payments,
settled lazily during low-fee periods.
3. Vaults (described in detail in Section 20).
Opposition and Controversy
OP_CTV remains unactivated due to controversy in the Bitcoin community:
Arguments for activation:
- Simple, well-defined semantics
- Enables vaults without trusted setup
- Non-recursive (cannot create unbounded covenant chains)
- Congestion control use case is valuable
Arguments against:
- Insufficient ecosystem demand demonstrated
- Alternative proposals (OP_VAULT, TXHASH, MATT) may be superior
- Activation process (speedy trial vs. BIP 8) disputed
- Some argue covenants reduce fungibility
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: