Alkanes protocol docs

Reference

Reference

Vocabulary, how state is actually derived, what happens when the chain reorganises, and what to check before you ship an implementation.

Terminology

Alkane
A contract, and by extension the token it issues. Identified by an AlkaneId.
AlkaneId
A pair of u128 values written block:tx. The block half also encodes the id's kind, see ID-3.
Cellpack
The call payload: a target AlkaneId followed by inputs, LEB128 encoded. inputs[0] is the opcode by convention.
Cenotaph
A malformed runestone. Balances on the inputs are burned rather than transferred.
Edict
One transfer instruction: id, amount, destination output.
Fuel
The metering unit for contract execution. Budgeted per block and shared out per transaction by virtual size.
Message
The calldata field of a protostone. Carries the cellpack.
Metashrew
The indexing framework alkanes-rs builds on. A WebAssembly indexer program plus a key/value store plus view functions.
Outpoint
A transaction output, identified by txid and index. Balances are recorded against outpoints.
Pointer
The output index that receives a protostone's result on success. The Runes layer has its own separate pointer, tag 22.
Protoburn
A protostone that bridges Runes-layer balances into a sub-protocol. Parsed but not processed in the released indexer.
Protorune
The sub-protocol layer over Runes that protostones belong to. Originated outside this organisation.
Protostone
One record inside the runestone's tag 16383 field. Names a protocol tag and carries edicts, a message, or both.
Refund pointer
The output index that receives balances when a message fails.
Runestone
The OP_RETURN payload format that Alkanes rides inside. Originated outside this organisation, with the Runes protocol.
Sequence
A single global counter that assigns ids of the form 2:n to newly deployed contracts.
Trace
The recorded execution of a protostone message, retrievable per outpoint or per block.
Virtual output
The shadow output index a protostone occupies, N + 1 + i for a transaction with N real outputs.

Indexer semantics

Alkanes has no chain and no nodes of its own. State exists only because indexers derive it. alkanes-rs is compiled to wasm32-unknown-unknown and run inside metashrew.

How alkanes-rs runs inside metashrew A Bitcoin node feeds blocks to the metashrew sync engine. The sync engine calls the underscore start entry point of the alkanes WASM program once per block. The program reads and writes through host functions into a height-indexed key value store backed by a sparse Merkle tree. Read queries arrive separately as view function calls over JSON-RPC and run the same program in read-only mode. Bitcoin nodeblocks, hashes JSON-RPC clientmetashrew_view metashrew syncreorg check, rollback alkanes.wasm_start per block height-indexedkey / value storeSMT roots
The indexer program is a pure function of the block sequence. The same blocks always produce the same store, which is what makes independent indexers agree.

JSON-RPC surface

Methods metashrew exposes. Endpoint hosts are deployment specific and not published here.
MethodPurpose
metashrew_viewCall a named view function with input data at a height.
metashrew_heightThe height the indexer has processed to.
metashrew_getblockhashThe block hash the indexer recorded for a height.
metashrew_staterootThe state root at a height, for verifying two indexers agree.
metashrew_previewRun a view against supplied block data without persisting anything.

The alkanes view functions themselves are listed in the guide.

Confirmation

Reorg behaviour

metashrew detects and repairs reorgs itself; alkanes-rs does not carry reorg logic.

  1. On each sync step the engine compares local block hashes against the node's, walking back over a configurable reorg_check_threshold window.
  2. At the first height where the hashes differ, the store is rolled back to that height.
  3. Indexing resumes from the height after the common ancestor and replays the new chain.

Rollback removes the indexed data written above the target height, not only the metadata. An earlier version deleted the height-to-hash and state-root keys but left the data written by the indexer program in place, which could leave chain A rows visible while chain B was being indexed. That was fixed with a shared SMT rollback implementation that identifies every key modified after the target height and restores it.

What this means for you

An alkanes balance is exactly as final as the Bitcoin block that produced it. A reorg that removes the block removes the balance change with it, cleanly. What is not automatic is anything an application built on top of that read: the Bitcoin Universe snapshot records automatic reconciliation as false for alkanes, because there is no executable order state to roll back.

Mempool

Fee and size considerations

Limits

LimitValueWhere it comes from
Bytes per script data push520MAX_SCRIPT_ELEMENT_SIZE
Payload bytes per protostone chunk15The 15-byte rule, to stay inside varint limits
Maximum varint length18 bytes usableLonger is a flaw and makes a cenotaph
Value rangeu128Ids, amounts, and cellpack inputs
Protostone virtual output ceilingnum_outputs + 100Bounds message-bearing protostones per transaction
Pointer and refund pointer ceilingnum_outputs + num_protostonesprocess_message validation
Nested call depth75Checkpoint depth guard
Contract memory43,554,432 bytesMEMORY_LIMIT
Block fuel, Bitcoin mainnet100,000,000, then 1,000,000,000 from height 899,087src/vm/fuel.rs
Minimum cellpack values2Target block and tx must both be present

Security considerations

Payload correctness is the main risk

The failure modes that actually cost people assets are all encoding mistakes, and none of them is visible on chain. A wrong envelope strands the balance; a wrong protocol tag destroys it; a malformed edict body silently does nothing. This is covered in full on the encoding page, and it is worth building payload verification into your signing flow rather than trusting your encoder.

Contracts can mint their own token without limit

The protocol permits a contract to transfer more of its own token than it holds. That is how issuance works, and there is no protocol-level cap. Supply control lives entirely in contract code. Before treating an alkane as scarce, read the contract, not the metadata.

Code is not a guarantee of behaviour

Factory deployments share a template's code but keep their own storage and balances, and upgradeable patterns exist in the standard library. An id that shares bytecode with a contract you trust is not thereby trustworthy. Check the id, the deployment form, and any admin authority the contract exposes.

Determinism is the security property

The sandbox has no network, no filesystem, no clock, and no randomness, and wasmi is a deterministic interpreter. Any divergence between two indexers running the same version is a bug, and comparing metashrew_stateroot at a height is the cheapest way to detect one. Do not run a modified indexer and expect its state to be interoperable.

Denial of service is bounded by fuel, not by goodwill

Fuel budgets, the memory limit, the call depth guard, and the virtual output ceiling all exist to bound what one transaction can cost an indexer. On failure the transaction's remaining fuel is drained rather than returned, which removes the incentive to fail cheaply on purpose.

Reporting

Report a vulnerability in this documentation or in the site itself privately through GitHub security advisories. Issues in the protocol implementation belong in alkanes-rs. Do not open a public issue for a vulnerability.

Implementation checklist

For anyone writing an indexer, a wallet, or an encoder.

Encoding

Decoding

Indexing

Display