Skip to content

Latest commit

 

History

History
334 lines (257 loc) · 13.3 KB

File metadata and controls

334 lines (257 loc) · 13.3 KB

API Reference — @radiant-core/sdk

Full reference for every public export. For a narrative quickstart see the README; for a hosted guide see radiantcore.org/docs/sdk.html.

Units. Every amount is in photons as a BigInt. 1 RXD = 100,000,000 photons. Convert only at the UI edge with rxdToPhotons / photonsToRxd.

Contents


Install & import

npm install @radiant-core/sdk
# Node < 22 has no global WebSocket — also install the optional peer:
npm install ws

Requires Node 20.19+ or 22+ (radiantjs pulls in an ESM-only dependency that needs require(ESM) support). Dual ESM + CJS, types included.

import { ElectrumClient, HDWallet, selectRxdFunding } from "@radiant-core/sdk";
// CommonJS:
const { ElectrumClient } = require("@radiant-core/sdk");

ElectrumClient

A reconnecting ElectrumX WebSocket client. All scripthash methods accept either a plain address (P2PKH scripthash is computed for you) or a 64-hex scripthash.

const client = new ElectrumClient({ network: "mainnet" });
await client.connect();

new ElectrumClient(options?)

Option Type Default Notes
endpoint string network default Full wss:///ws:// URL. Overrides network.
network "mainnet" | "testnet" | "regtest" "mainnet" Selects the default endpoint.
requestTimeoutMs number 15000 Per-request timeout.
reconnect boolean true Auto-reconnect with exponential backoff + jitter (1s → 30s).
webSocketCtor WebSocket ctor auto Inject a WebSocket implementation (tests/custom transport).

Mainnet default endpoint: wss://electrumx.radiantcore.org:443.

Methods

Method Returns Description
connect() Promise<void> Open the socket (idempotent).
connected boolean Whether the socket is open.
serverVersion(client?, protocol?) Promise<unknown> Negotiate protocol version.
getBalance(addressOrScriptHash) Promise<ScriptHashBalance> { confirmed, unconfirmed } in photons.
listUnspent(addressOrScriptHash) Promise<Utxo[]> UTXOs as SDK Utxos. For an address the script is filled (P2PKH); for a raw scripthash script is "". Token UTXOs include refs.
getHistory(addressOrScriptHash) Promise<unknown[]> Raw confirmed/mempool history.
getTransaction(txid, verbose?) Promise<unknown> Raw tx hex, or verbose object.
subscribe(addressOrScriptHash, onUpdate) Promise<string | null> Fires onUpdate(status) on change; returns the current status.
unsubscribe(addressOrScriptHash) Promise<unknown> Stop updates.
broadcastTx(rawHex) Promise<string> Returns the txid. Treats "already in blockchain" as success.
request(method, ...params) Promise<T> Escape hatch for any ElectrumX JSON-RPC method.
close() void Close and stop reconnecting.
const { confirmed } = await client.getBalance(address);
const utxos = await client.listUnspent(address);
await client.subscribe(address, (status) => console.log("changed:", status));
const txid = await client.broadcastTx(rawHex);

HDWallet

BIP44 HD derivation at the Radiant path m/44'/512'/account'/change/index (SLIP-0044 coin type 512). Derives keys only — it never touches the network.

Constructors

Static Signature
HDWallet.fromMnemonic(phrase, options?) BIP39 mnemonic → wallet
HDWallet.fromSeed(seed, options?) Buffer/hex seed → wallet
HDWallet.fromXprv(xprv, options?) extended private key → wallet
HDWallet.generateMnemonic() → fresh 12-word phrase (string)

HDWalletOptions: network ("mainnet" default), passphrase (BIP39 "25th word"), account (hardened, default 0), coinType (default 512; pass 0 only to recover legacy wallets).

Instance methods

Method Returns Description
deriveKey(index, change?) DerivedKey { index, change, path, wif, publicKey, address, scriptHash }
deriveRange(start, count, change?) DerivedKey[] Batch derive (e.g. a receive gap).
address(index?, change?) string Address at an index.
wif(index?, change?) string WIF at an index.
privateKey(index, change?) radiantjs PrivateKey Raw key (escape hatch).
pathFor(index, change?) string The full derivation path.
const mnemonic = HDWallet.generateMnemonic();
const wallet = HDWallet.fromMnemonic(mnemonic, { network: "mainnet" });
const me = wallet.deriveKey(0);          // m/44'/512'/0'/0/0
const receive = wallet.deriveRange(0, 20);

Keys

Stateless helpers for callers who manage their own WIFs:

Keys.addressFromWif(wif, network?);   // -> address
Keys.publicKeyFromWif(wif);           // -> compressed pubkey hex
Keys.scriptHashFromWif(wif, network?);// -> ElectrumX scripthash

Funding selection

The core safety primitive. RXD funding is never gathered by a value heuristic: a UTXO carrying a token ref (FT/NFT/dMint) looks like plain value but spending it as funding silently burns the token. Every candidate is screened two ways — indexer-reported refs and a local script scan — before it can fund a transaction.

Function Description
selectRxdFunding(utxos, target, feeRate, options?) Greedy, ref-safe selection. Silently excludes token UTXOs, so you can pass a raw listUnspent() result. Returns FundingSelection. Throws InsufficientFundsError if the token-free pool can't cover target.
filterFundingCandidates(utxos) Drop every token-bearing UTXO.
isFundingSafe(utxo) boolean — no refs and no OP_PUSHINPUTREF opcodes.
assertFundingSafe(utxos) Throw TokenBurnGuardError on the first token UTXO (opt-in strict guard).
estimateFee(inputCount, outputCount, feeRate, extraInputBytes?) Photon fee estimate.
sumValue(utxos) Sum of photon values.

SelectRxdFundingOptions: baseOutputCount (non-change outputs, default 1), extraInputBytes (bytes from inputs you've already committed), withChange (default true).

const sel = selectRxdFunding(utxos, rxdToPhotons("0.5"), 10_000n);
// sel.inputs, sel.fee, sel.total, sel.change  (all token-free, all BigInt)

Transactions

Function Description
buildRxdTransfer({ address, wif, to, amount, utxos, feeRate, network? }) Build + sign a simple RXD payment, funded ref-safely. Returns BuiltTx.
buildTx(params) Low-level builder (manual inputs/outputs + a per-input scriptSig hook). Used internally by the token flows.

BuiltTx = { tx, hex, txid, outputs } where outputs carry resolved photon values (including change). buildTx measures the real signed size and sets an explicit fee (size + headroom) × feeRate so token transactions reliably clear the node's min-relay floor.

const { hex, txid } = buildRxdTransfer({
  address: me.address, wif: me.wif,
  to: "1Recipient...", amount: rxdToPhotons("1.25"),
  utxos, feeRate: 10_000n,
});
await client.broadcastTx(hex);

Glyph tokens

Mint and move Glyph tokens via the commit/reveal pattern. These reproduce the proven Photonic-Wallet on-chain templates and are regtest-validated. They broadcast real, irreversible transactions — test your flow on regtest/testnet first.

Function Description
mintFT({ client, address, wif, ticker, supply, fundingUtxos, metadata?, feeRate?, network? }) Mint a fungible token. supply is in base units (FT amount == output photons). Returns MintResult.
mintNFT({ client, address, wif, fundingUtxos, mutable?, outputValue?, metadata?, feeRate?, network? }) Mint an NFT singleton. mutable: truep:[2,5]. Returns MintResult.
transferToken({ client, address, wif, tokenUtxo, toAddress, fundingUtxos, feeRate?, network? }) Move an FT or NFT to a new owner (kind-agnostic; preserves the covenant, re-binds the owner P2PKH).
encodeGlyph(payload) { revealScriptSig, payloadHash } — CBOR envelope + hash.
ftScript(address, ref, network?) / nftScript(...) Build the on-chain token output script.
parseTokenRef(scriptHex) Extract the 72-hex packed ref from a token script (null if none).

MintResult = { ref, refDisplay, commitTxid, revealTxid }. ref is the packed 72-hex ref; refDisplay is "txid:vout".

const funding = filterFundingCandidates(await client.listUnspent(me.address));

const ft = await mintFT({
  client, address: me.address, wif: me.wif,
  ticker: "DEMO", supply: 1_000_000n,
  metadata: { name: "Demo Token", desc: "Minted with @radiant-core/sdk" },
  fundingUtxos: funding,
});

await transferToken({
  client, address: me.address, wif: me.wif,
  tokenUtxo,                    // the FT/NFT UTXO (must include its on-chain script)
  toAddress: "1Recipient...",
  fundingUtxos: funding,        // covers the fee; token value is conserved
});

Discovering token UTXOs. The indexer keys a token UTXO under scriptHash(zeroRefs(tokenScript)), not the owner's plain P2PKH scripthash. To list a held token: client.listUnspent(scriptHash(zeroRefs( ftScript(owner, ref)))). The returned entries carry refs:[{ ref, type }] (type is "normal" for FT, "single" for an NFT singleton).


WAVE names

Function Description
waveResolve(name, options?) Resolve a WAVE name → WaveResolution (registered: false for unregistered, not an error).
waveResolveAddress(name, options?) Resolve straight to the target address, or null.
waveLabel(name) Normalise to the bare label the indexer resolves on.

WaveResolveOptions: restBase (default https://radiantcore.org/api), fetchImpl (inject a fetch), signal (AbortSignal).

const rec = await waveResolve("alice.rxd"); // ".rxd" stripped
if (rec.registered) console.log(rec.address, rec.owner, rec.expires);

const addr = await waveResolveAddress("alice"); // string | null

Script helpers

Pure, dependency-light primitives (these mirror RXinDexer's exact algorithms, so scripthashes line up with the indexer).

Function Description
scriptHash(scriptHex) ElectrumX scripthash = sha256(script) reversed, hex.
addressToScriptHash(address) Scripthash for a plain (P2PKH) address.
p2pkhScript(address) P2PKH output script hex for an address.
isTokenBearing(scriptHex) true if the script has an OP_PUSHINPUTREF-family opcode (0xd0–0xd8) in opcode position — i.e. it carries a token.
zeroRefs(scriptHex) Zero the 36-byte ref operands (only when a CHECKSIG is present) — how the indexer keys covenant scripts.
packRef(txid, vout) Outpoint → 72-hex packed ref (internal byte order).
unpackRef(ref) Packed ref → { txid, vout } (display order).

Unit helpers

Function Description
rxdToPhotons(rxd: string | number) RXD → photons (BigInt). String form avoids float rounding.
photonsToRxd(photons: bigint) Photons → fixed-point RXD string.
PHOTONS_PER_RXD 100_000_000n.
RXD_DECIMALS 8.
rxdToPhotons("1.5")        // 150000000n
photonsToRxd(150000000n)   // "1.5"

Errors

All extend RadiantSdkError, so you can instanceof to branch:

Class Thrown when
RadiantSdkError Base class.
InsufficientFundsError Token-free UTXOs can't cover target + fee. Has requiredPhotons, availablePhotons.
TokenBurnGuardError A token-bearing UTXO was about to fund a tx. Has txid, vout.
ElectrumError ElectrumX transport/protocol failure. Optional code.
ValidationError Malformed input/argument.

Constants

PHOTONS_PER_RXD, RADIANT_COIN_TYPE (512), MIN_RELAY_FEE_RATE ({ mainnet: 10_000n, testnet: 1_000n, regtest: 1_000n }), DUST_LIMIT (1_000n), DEFAULT_ELECTRUM_ENDPOINT, DEFAULT_REST_BASE, GLYPH_PROTOCOL ({ FT: 1, NFT: 2, MUTABLE: 5, CONTAINER: 7, ENCRYPTED: 8, WAVE: 11 }).

The raw underlying library is exported as radiantjs for advanced use.


Types

NetworkName, Utxo, UtxoRef, TxOutput, FundingSelection, ScriptHashBalance, WaveResolution, DerivedKey, HDWalletOptions, BuildTxParams, BuildTxInput, BuiltTx, GlyphPayload, MintResult, MintFtParams, MintNftParams, TransferTokenParams, SelectRxdFundingOptions, ElectrumClientOptions, WaveResolveOptions.

interface Utxo {
  txid: string;
  vout: number;
  value: bigint;          // photons
  script: string;         // scriptPubKey hex
  height?: number;        // 0/undefined = unconfirmed
  refs?: { ref: string; type: string }[]; // present => token-bearing
}