Covenant building blocks: tokens, covenants, and the REF gate as composable primitives¶
Radiant’s genuinely differentiated capability is that a UTXO’s locking script can
inspect the transaction spending it — output scripts, values, and induction-capable
token references (refs) — at consensus level. That lets you build covenants: outputs
that constrain what any future spend must look like, with no trusted server enforcing it.
pyrxd ships four covenant-grade building blocks, each proven against a real
radiant-core node and each usable on its own or composed with the others. This page is
the map; each section links the import, the contract, and the proof.
Pre-audit caveat (applies to all four). These primitives are consensus-validated on regtest and several are proven on mainnet, but none has had an external security audit. Build and demo on regtest/testnet; do not gate real value on them yet.
1. HTLC covenants — lock RXD, an FT, or an NFT behind a hashlock + timelock¶
from pyrxd import build_htlc_covenant_rxd, build_htlc_covenant_ft, build_htlc_covenant_nft
pyrxd.gravity.htlc_covenant builds the funded covenant scriptPubKey — the UTXO a
maker locks an asset into for an atomic swap. Two spend paths are baked into the script:
claim (present the preimage p of the negotiated hashlock; pays the taker’s holder
script) and refund (after a consensus-enforced OP_CHECKSEQUENCEVERIFY maturity; pays
the maker). The three variants differ in how the asset binds:
Variant |
Asset binding |
|---|---|
|
native RXD — no ref at all |
|
the FT’s genesis ref + the FT |
|
the NFT singleton ref ( |
The covenant pins hash256(holder script) for output[0], so a claim/refund can only
pay the negotiated destination shape. Build-time guards run fail-closed: every push in
the assembled SPK is re-checked for MINIMALDATA minimality (a non-minimal push would
brick both spend branches on-chain — found the hard way, now impossible to ship).
Proofs: claim + CSV-refund proven on Radiant mainnet for all three variants;
consensus semantics (CSV maturity, holder-hash pinning, singleton conservation)
re-validated on the pinned regtest node in tests/test_htlc_regtest_e2e.py. These
covenants are exactly what RadiantCovenantLeg funds inside the
cross-chain swap.
One consensus fact worth internalizing: “exactly one NFT output” is covenant-enforced, not consensus-enforced — Radiant consensus permits burning a singleton (zero carrying outputs). Any “the token must go somewhere” property is your covenant’s job.
2. The soulbound NFT covenant — consensus-enforced non-transferability¶
from pyrxd import build_soulbound_nft_covenant # SoulboundNftCovenant result
pyrxd.glyph.soulbound_covenant builds an NFT whose locking script allows exactly two
futures: recur into a byte-identical clone of itself (same ref, same logic, same
immutable owner — enforced by OP_INPUTINDEX OP_UTXOBYTECODE vs OP_0 OP_OUTPUTBYTECODE
full-bytecode equality) or be burned. There is no transfer path; a clone with a
different owner is a different script and fails OP_EQUALVERIFY at consensus.
This matters because the ecosystem’s existing “soulbound” support is advisory only —
an ordinary transferable NFT plus an off-chain check an honest wallet runs voluntarily.
A counterparty running its own software can move it freely. The covenant version is the
chain-side mechanism that makes a soulbound token usable as a trust anchor against an
adversarial counterparty (reputation, compliance, credentials). A covenant of this design
is live on mainnet; this builder’s consensus behaviour (recur accepted / transfer
rejected / burn accepted) is pinned on the regtest node in
tests/test_soulbound_covenant_regtest.py.
3. The REF-authenticity gate — consensus enforces uniqueness, not provenance¶
from pyrxd import verify_ref_authenticity # async; RefAuthenticityIndexer/ResolvedRef in pyrxd.gravity
The sharpest lesson in the stack (audit finding R1, proven on a live node): a consensus-valid singleton ref need not be a genuinely minted Glyph. Consensus only requires output refs ⊆ input refs — a node will happily mine a covenant whose “NFT” ref is a plain wallet outpoint. A covenant cannot self-verify mint provenance. Anyone buying/swapping “the advertised asset” must resolve the ref off-chain.
verify_ref_authenticity makes that defense explicit and fail-closed: five bindings
against a trusted indexer’s resolution — genesis outpoint == advertised ref (a ref is
the genesis outpoint, never the reveal txid), a real gly envelope, the agreed payload
hash, asset identity, and a minimum genesis confirmation depth (a shallow genesis can be
reorged out after you pay). It is async on purpose: a sync wrapper that forgot to await
the indexer would return a truthy coroutine and fail open — the exact catastrophe the
gate exists to prevent. The SwapCoordinator runs it as a hard pre-lock gate for every
FT/NFT swap.
4. Credential-bound swap gating — composing 2 + 3 into the swap¶
from pyrxd.glyph.credential_binding import assert_soulbound_credential, verify_credential_binding
The blocks compose: a swap’s NegotiatedTerms.credential_ref can require the
counterparty to hold a soulbound credential (block 2) whose authenticity is resolved
through the same indexer discipline as block 3 — giving an HTLC swap (block 1) a
consensus-anchored “only credentialed counterparties” gate. tests/test_credential_binding.py
pins the binding rules; the swap coordinator consumes it via CredentialResolver.
Where everything lives¶
Block |
Import |
Proof |
|---|---|---|
HTLC covenants |
|
mainnet claims + |
Soulbound covenant |
|
|
REF gate |
|
live-node R1 reproduction + unit suite |
Credential binding |
|
|
Token issuance (the things these covenants hold) is covered by the tutorials: mint a Glyph FT, mint a Glyph NFT, dMint. The 5-minute quickstart gives you a local chain to try all of this on with zero real value.