What Is a Charm?
Charms are UTxO-native programmable assets inspired by Bitcoin metaprotocols like Ordinals and Runes, but extended with full app contract logic. Structurally, a Charm is an entry in anapp → data mapping attached to a Bitcoin UTXO. Multiple Charms can coexist on a single UTXO, and each Charm carries its own app contract that defines its minting, burning, and transfer rules.
Every Charms transaction contains a spell — Charms-related metadata encoded in an OP_RETURN output as a CBOR-serialized (NormalizedSpell, Proof) tuple. The proof is a Groth16 zk-SNARK attesting that the app contract was satisfied. Anyone can verify the proof; no one can fake a valid spell without actually satisfying the contract.
Protocol Versions
Sundial supports two versions of the Charms bridge, selectable per transaction by a beacon NFT in the transaction’s reference inputs.- V1 — Scrolls (ICP-Signed)
- V2 — Groth16 (Fully Trustless)
Scrolls is the initial bridge version. Rather than verifying a ZK proof on-chain, it delegates authorization to a threshold-signing canister hosted on the Internet Computer Protocol (ICP).How it works:
- You construct a consuming transaction on the destination chain with a proof that the app rules were satisfied.
- You submit the transaction to the ICP Scrolls verifier canister.
- The canister re-verifies the ZK proof independently from the raw transaction — it does not trust the caller.
- The canister threshold-signs the transaction and returns a witnessed transaction hex.
- You submit the witnessed transaction; the Scrolls validator on L1 confirms the ICP canister’s signature.
How Beaming Works
“Beaming” is the Charms term for a cross-chain transfer. To beam a Charm from Bitcoin to the settlement layer, you execute a sequence spanning both chains:1
Prepare a destination on L1
Submit an L1 transaction that creates a placeholder UTxO — a small output at the address where your beamed token will land — and a separate collateral UTxO. This establishes the exact on-chain reference that the Bitcoin-side commitment will name.
2
Mint or locate a Charm on Bitcoin
If you do not already hold a Charm, mint one on Bitcoin testnet by proving a
mint-nft spell, broadcasting the transaction, and waiting for confirmation. The Charm is identified by its app ID at a specific output index.3
Commit cross-chain on Bitcoin (beam-send)
Broadcast a Bitcoin transaction that destroys the Charm (spends its UTXO) and encodes a cryptographic commitment to the L1 placeholder in its This writes the cross-chain intent into the Bitcoin ledger itself — not in a database, but in a confirmed Bitcoin transaction.
beamed_outs field. The commitment is:4
Prove and receive on L1 (beam-receive)
A worker fetches the Bitcoin Merkle proof and header chain, then calls the Charms prover with the finality bundle. The prover generates a
beam-receive transaction on L1. The transaction is either:- V1 (Scrolls): submitted to the ICP canister for threshold-signing, then broadcast.
- V2 (Groth16): broadcast directly with the Groth16 proof attached.
Milestone 5.2 Live Evidence
The beaming mechanism was demonstrated end-to-end on real public testnets in July 2026, with every transaction independently verifiable against public infrastructure.Charm Minted on Bitcoin
Bitcoin testnet4 · Block 143,987A
mint-nft spell was proven, signed, and broadcast on Bitcoin testnet4, creating a Charm at output 0.Txid: 3be09f7f…c693d4ccVerified independently by both mempool.space and the Charms Explorer.Destination Prepared on L1
Preprod · Block 4,936,319An L1 transaction split one funded UTxO into a beam-receive placeholder (5 ADA) and a collateral UTxO (5 ADA).Txid:
8c287322…5fd9e55Verified via Koios preprod API.Cross-Chain Commitment (beam-send)
Bitcoin testnet4 · Block 144,111A Bitcoin transaction destroyed the Charm from step 1 and committed — in the Bitcoin ledger — to the exact L1 placeholder from step 2.Txid:
53245515…67ea162Confirmed after the L1 placeholder (correct chronological order enforced by the protocol).Threshold Authorization (Scrolls)
ICP mainnet — Scrolls canisterScrolls independently re-verified the ZK proof from the raw transaction and issued a threshold signature over the receive transaction.
Result: Ok(<witnessed tx hex>).Canister: tty7k-waaaa-aaaak-qvngq-caiSettlement Layer Smart Contracts
The bridge deploys four Plutus v3 smart contracts on L1. They work together through a modular, version-agnostic routing pattern.main — Routing Validator
main — Routing Validator
A thin routing script. It accepts a redeemer specifying the beacon NFT asset name for the desired protocol version, locates the corresponding beacon UTxO in the transaction’s reference inputs, reads the versioned validator’s script hash from the
reference_script field, and asserts that the versioned validator is invoked as a staking withdrawal (Withdraw(Script(charms_validator_sh))) in the same transaction.main contains no application-level validation logic. All substantive checks — signature verification or ZK proof verification — are delegated to the versioned validator.scrolls — V1 ICP Signature Validator
scrolls — V1 ICP Signature Validator
Verifies that the ICP Scrolls threshold-signer canister has co-signed the transaction. The redeemer carries the verifier’s signature. This validator is invoked by
main when the Scrolls beacon NFT is present in the reference inputs.staking_groth16 — V2 Trustless Validator
staking_groth16 — V2 Trustless Validator
Verifies a Groth16 zk-SNARK proof using BLS12-381 pairings as Plutus builtins. The validator:If the equation does not hold, the transaction fails. No trusted party is involved at any step.
- Reads the
SpellDatum { spell, proof }from the last output of the transaction. - Checks that
spell.version == charms_version(baked in at deployment). - Serializes public inputs as
SHA256(CBOR(spell_vk, spell)). - Runs the Groth16 verification equation:
free_mint — Beacon Token Minting Policy
free_mint — Beacon Token Minting Policy
Manages the creation of beacon NFTs that enable on-chain discoverability and verification of the versioned validators. Each protocol version has its own beacon NFT; the asset name acts as a selector that routes
main to the correct validator.Security Properties
No Shared UTxOs
Each Charm occupies its own UTXO. There are no shared liquidity pools or shared state UTxOs that an attacker can contend for. Bitcoin’s UTXO model provides base-layer replay protection.
Version Binding
The
charms_version parameter is baked into the staking_groth16 script at deployment. A proof generated for a different circuit version cannot be submitted to a different validator deployment — cross-version replay is impossible.Datum Position Enforcement
The V2 validator always reads the last output of the transaction as the spell output. Off-chain tooling must place the
SpellDatum at this position; an incorrectly positioned datum fails the expect check and rejects the transaction.Mock Proof Isolation
The
NormalizedSpell type includes a mock flag. Because this flag is part of the serialized public inputs, a proof generated with mock: true cannot be submitted as mock: false. Test proofs cannot appear in production transactions.Cardinal Bridge (Alternative Path)
For users who prefer a different security model, the Cardinal bridge provides an alternative cross-chain path using MuSig2 + HTLC + BitVMX fraud proofs. Rather than ZK proof verification, Cardinal relies on a multi-party signature scheme combined with hash time-locked contracts and an optimistic fraud proof layer backed by BitVMX. Cardinal is suited for situations where ZK proving overhead is a concern, at the cost of a more complex liveness and trust model.The Charms V2 Groth16 bridge is the path used by Alchemy (FIRE and ICE). All reserve constraint enforcement for those assets runs through the
staking_groth16 validator. See the Alchemy page for details.