Scrolls canisters
scrolls_bitcoin_v15
Section titled “scrolls_bitcoin_v15”The scrolls_bitcoin_v15 canister is the Bitcoin signer for Charms v15. It
derives the addresses that Scroll outputs are locked to,
and it signs and broadcasts transactions that spend those outputs — but only when
the transaction carries a valid Charms spell and pays the protocol fee.
| Canister (IC mainnet) | rpgc6-oqaaa-aaaak-qy3uq-cai |
Networks (the network arg) | "main", "testnet4" |
| Access control | None at the caller level — policy-based (valid spell + fee). |
In normal use you call only two methods: addresses (the prover
does this for you) and sign_and_submit (to spend a
Scroll-controlled output). See Spend Scroll outputs.
Candid interface
Section titled “Candid interface”type Addresses = record { script_pubkeys : vec record { nat32; text }; // out_index -> hex(scriptPubKey) signature : text; // hex BIP-340 Schnorr signature};
type SignRequest = record { prev_txs : vec text; // hex prev txs that created the spent outputs sign_inputs : vec nat32; // input indexes the canister must sign tx_to_sign : text; // hex unsigned/partially-signed Bitcoin tx v14_sign_inputs : opt vec record { nonce : nat64; index : nat64 };};
type SignAndSubmitResult = record { txid : text; wtxid : text };
service : { addresses : (text, vec nat32) -> (variant { Ok : Addresses; Err : text }); sign_and_submit : (text, SignRequest) -> (variant { Ok : SignAndSubmitResult; Err : text }); verify_spell : (text, bool) -> (variant { Ok : text; Err : text }); verify_spell_delegated : (text, bool, nat32, vec text) -> (variant { Ok : text; Err : text }); config : () -> (Config) query; cycles_balance : () -> (nat) query; deposit_cycles : () -> (variant { Ok : nat; Err : text });}sign_and_submit
Section titled “sign_and_submit”sign_and_submit : (network : text, SignRequest) -> (variant { Ok : SignAndSubmitResult; Err : text });Signs the Scroll-controlled inputs of a transaction, enforces policy, broadcasts it, and returns the transaction id. This is the only method a wallet normally needs to call.
Given a network ("main" or "testnet4") and a SignRequest, the canister:
- parses
tx_to_signand validates thesign_inputsindexes; - (optional) delegates any
v14_sign_inputsto the older v14 canister, so one transaction can spend mixed v14/v15 Scroll UTXOs; - checks that every input not in
sign_inputsis already signed, and every input insign_inputsis still unsigned (you sign your own inputs; the canister signs only the Scroll inputs); - verifies the spell carried by
tx_to_sign— failing if there is none; - checks the fee — the transaction must pay the configured Scrolls fee address at least the required amount;
- signs each requested input with the threshold key derived for that Scroll-controlled output;
- broadcasts the fully-signed transaction (via the mempool.space API);
- returns
{ txid, wtxid }.
Re-broadcasting an already-confirmed transaction is idempotent (it succeeds rather than erroring).
icp canister call --network ic rpgc6-oqaaa-aaaak-qy3uq-cai sign_and_submit \ '("main", record { sign_inputs = vec { 0 : nat32 }; prev_txs = vec { "0200000000…" }; tx_to_sign = "0200000000…"; v14_sign_inputs = null; })'addresses
Section titled “addresses”addresses : (tx_in_0 : text, out_is : vec nat32) -> (variant { Ok : Addresses; Err : text });Returns the canister-controlled scriptPubKey for each requested output index,
plus a BIP-340 Schnorr signature over the map. The prover calls this
automatically while building a spell that has Scroll outputs — you rarely call
it yourself.
tx_in_0— the first input (txid:vout) of the transaction that will create the outputs; outputs are derived deterministically from it. (For coinbase outputs, use the all-zeros txid with the block height in place of the vout.)out_is— the output indexes to derive (max 256 per call).- The returned
script_pubkeysare raw P2WPKH scripts (OP_0 <20-byte hash>) that go straight into a Bitcoin output’sdest. They are network-independent (identical onmainandtestnet4), which is why this method takes nonetworkargument.
The signature lets the spell proof verify, in-circuit, that these are genuinely the canister’s addresses for the given transaction. This is how a Scroll output is provably pinned to programmable custody — see Scroll charms.
Other methods
Section titled “Other methods”| Method | Description |
|---|---|
verify_spell(tx, mock) | Extract and verify the spell from a raw Bitcoin tx; returns the normalized spell as hex CBOR. |
verify_spell_delegated(tx, mock, spell_version, seen) | Forward-compatible verification: delegates newer-version spells to the next canister, with cycle detection. |
config() | (query) The canister’s configuration (fee addresses, fee parameters). |
cycles_balance() | (query) The canister’s cycles balance. |
deposit_cycles() | Top up the canister’s cycles (it is designed to be blackholed). |
Calling the Bitcoin canister
Section titled “Calling the Bitcoin canister”ic-agent/ agent-rs (Rust) — what the prover uses: build anAgentagainsthttps://ic0.app,Encode!the args, andupdate/querythe canister, decoding the reply withDecode!.icpCLI —icp canister call --network ic rpgc6-oqaaa-aaaak-qy3uq-cai <method> '(<candid>)'. Add--queryfor query methods (e.g.config,cycles_balance).
There is no per-caller access control: the canister signs for anyone, but only a
transaction that carries a valid spell and pays the fee. Address-derivation
integrity is protected by a canister-private secret prefix and the signed
addresses attestation.
scrolls_cardano
Section titled “scrolls_cardano”The scrolls_cardano canister co-signs Cardano spell transactions and issues
finality attestations used when beaming out of Cardano.
| Canister (IC mainnet) | tty7k-waaaa-aaaak-qvngq-cai |
| Networks | "mainnet", "preprod" |
The Charms prover calls sign automatically while proving Cardano spells. Wallets
and integrators rarely call this canister directly.
Candid interface
Section titled “Candid interface”type Config = record { fee_address : vec record { text; text }; fixed_cost : nat64;};
service : () -> { sign : (text) -> (variant { Ok : text; Err : text }); // tx hex in/out certify_final : (text) -> (variant { Ok : text; Err : text }); finality_vkey : () -> (variant { Ok : text; Err : text }); vkey : () -> (variant { Ok : text; Err : text }); config : () -> (Config) query; cycles_balance : () -> (nat) query; deposit_cycles : () -> (variant { Ok : nat; Err : text });}| Method | Description |
|---|---|
sign(tx_to_sign) | Co-sign a Cardano spell transaction (hex in, signed hex out). Called by the prover. |
certify_final(tx) | Produce a finality-certified transaction. |
finality_vkey() | Return the Ed25519 public key used for finality attestations (beaming). |
vkey() | Return the canister’s signing verification key. |
config() | (query) Fee address and fixed cost. |
cycles_balance() | (query) Cycles balance. |
deposit_cycles() | Top up cycles (canister is designed to be blackholed). |