A Typescript implementation of the Bitcoin Runestone protocol To see the original version, please go to the Ordinals repo; you can find various data structures and indexer implementation there. General documentation of the runes protocol and how runestones are used can be found here.
To encode a runestone, use encodeRunestone() method, with an example below:
import { encodeRunestone } from '@magiceden-oss/runestone-lib';
// To deploy a new rune ticker // (this will require a commitment in an input script) const etchingRunestone = encodeRunestone({ etching: { runeName: 'THIS•IS•AN•EXAMPLE•RUNE', divisibility: 0, premine: 0, symbol: '', terms: { cap: 69, amount: 420, offset: { end: 9001, }, }, turbo: true, }, });
// To mint UNCOMMON•GOODS const mintRunestone = encodeRunestone({ mint: { block: 1n, tx: 0, }, });
// Transfer 10 UNCOMMON•GOODS to output 1 const edictRunestone = encodeRunestone({ edicts: [ { id: { block: 1n, tx: 0, }, amount: 10n, output: 1, }, ], });
Decoding a runestone within a transaction is as simple as passing in the transaction data from Bitcoin Core RPC server.
import { tryDecodeRunestone, isRunestoneArtifact, RunestoneSpec, Cenotaph } from '@magiceden-oss/runestone-lib';
// transaction retrieved with getrawtransaction RPC call const tx = ...;
const artifact = tryDecodeRunestone(tx);
if (isRunestone(artifact)) { const runestone: RunestoneSpec = artifact; ... } else { const cenotaph: Cenotaph = artifact; ... }
To index, initialize a RunestoneIndexer, implement the interface arguments to RunestoneIndexer constructor. Then it is just a matter of start() to finish initializing the indexer, and then controlling the rate of syncing indexing to latest state in RPC server.
// Initialize indexer const indexer = new RunestoneIndexer(...);
// Preps the indexer to be ready to run updateRuneUtxoBalances() await indexer.start()
// Example of a polling job running updateRuneUtxoBalances() // every minute, with stop cleanup handling let stop = false; ...
const intervalId = setInterval(async () => { try { await indexer.updateRuneUtxoBalances(); } catch (err) { console.error('Error occurred while indexing runes', err); }
if (stop) { clearInterval(intervalId); await indexer.stop(); } }, 60 * 1000 /* one minute */);