npm.io
0.12.0 • Published 5d ago

@rialo/ts-cdk

Licence
Apache-2.0
Version
0.12.0
Deps
9
Size
2.8 MB
Vulns
0
Weekly
1.7K

@rialo/ts-cdk

TypeScript library for building on the Rialo blockchain. Provides Ed25519 cryptographic primitives, BIP39/SLIP-0010 HD wallet derivation, transaction construction and signing, a JSON-RPC client for node communication, program deployment, and HPKE encryption for TEE programs. Works in Node.js ≥ 18 and modern browsers (ESM and CJS bundles included).

Installation

npm install @rialo/ts-cdk
# or
pnpm add @rialo/ts-cdk
# or
yarn add @rialo/ts-cdk

Requires Node.js ≥ 18. Ships both ESM (dist/index.mjs) and CJS (dist/index.js) bundles with bundled TypeScript declarations. Works in modern browsers when bundled with Vite/webpack.

Key public types

Cryptography
Export Purpose
Keypair Ed25519 keypair; generate, derive from seed, sign, verify, dispose
PublicKey 32-byte Ed25519 public key; PDA derivation, base58 encoding
Signature 64-byte Ed25519 signature; base58 encoding
Mnemonic BIP39 mnemonic; generate, restore, derive keypairs via SLIP-0010
Keyring management
Export Purpose
RialoKeyring Named collection of Keypair instances with an active signing key
InMemoryKeyringProvider Create RialoKeyring from a mnemonic or a list of keypairs
DerivedKeypairInfo Metadata for a single derived keypair (index, pubkey, path)
Transactions
Export Purpose
TransactionBuilder Fluent builder for constructing transactions
Transaction Signed/unsigned transaction; serialize, deserialize, multi-sig
Message Compiled transaction message with account keys and instructions
Instruction Single operation: program ID, accounts, data
AccountMeta Account reference with isSigner / isWritable flags
AccountMetaTable Deduplication table for account references within a message
transferInstruction System-program transfer helper
createAccount System-program create-account helper
RPC
Export Purpose
createRialoClient Factory for RialoClient; accepts a chain preset or custom config
getDefaultRialoClientConfig Returns a RialoClientConfig for "mainnet", "devnet", "testnet", or "localnet"
RialoClient Full RPC surface for a Rialo node
RIALO_MAINNET_CHAIN / …TESTNET… / …DEVNET… / …LOCALNET… Chain presets
Other
Export Purpose
Signer / KeypairSigner Abstract signing interface for hardware wallets and custom signers
ProgramDeployment Deploy PolkaVM program binaries to the network
RexValue Typed wrapper for plain or HPKE-encrypted byte payloads
RialoError / RialoErrorType Structured error with discriminated type field

Usage

Keypair and signing
import { Keypair, PublicKey } from "@rialo/ts-cdk";

// Generate a random keypair
const keypair = Keypair.generate();
console.log("Address:", keypair.publicKey.toString());

// Restore from a known 32-byte secret key
const restored = Keypair.fromSecretKey(secretKeyBytes);

const message = new TextEncoder().encode("Hello Rialo");
const sig = keypair.sign(message);
const ok = keypair.verify(message, sig);

// Always dispose keypairs when finished to zero out the private key.
keypair.dispose();
BIP39 mnemonic and HD derivation

Rialo uses BIP44 coin type 756 with SLIP-0010 (m/44'/756'/{index}'/0').

import { Mnemonic } from "@rialo/ts-cdk";

// Generate a new 12-word mnemonic (pass 256 for 24-word)
const mnemonic = Mnemonic.generate();           // 128-bit entropy, 12 words
console.log(mnemonic.toString());
console.log("Words:", mnemonic.getWordCount()); // 12

// Validate a phrase without constructing a Mnemonic
const valid = Mnemonic.isValid("word1 word2 … word12");

// Restore from an existing phrase
const restored = Mnemonic.fromPhrase("word1 word2 … word12");

// Derive account keypairs
const account0 = await mnemonic.toKeypair(0);  // m/44'/756'/0'/0'
const account1 = await mnemonic.toKeypair(1);  // m/44'/756'/1'/0'

// With an optional BIP39 passphrase
const secure = await mnemonic.toKeypair(0, { passphrase: "my-secret" });

// Derive with an explicit full path (advanced)
const custom = await mnemonic.toKeypairWithPath("m/44'/756'/0'/0'");

// Derive multiple at once (indices 0–4)
const keypairs = await mnemonic.deriveKeypairs(5);

// Convert to raw 64-byte BIP39 seed
const seed = await mnemonic.toSeed();
Keyring management

RialoKeyring manages a set of derived keypairs and tracks the active signing key, useful when an application needs to sign on behalf of multiple accounts.

import { Mnemonic, InMemoryKeyringProvider } from "@rialo/ts-cdk";

const mnemonic = Mnemonic.generate();
const provider = new InMemoryKeyringProvider();

// Derive 3 keypairs into a single keyring
const keyring = await provider.createFromMnemonic(mnemonic, 3);

// Switch the active keypair
keyring.setActiveKeypair(2);
console.log("Active:", keyring.pubkeyString());

// Sign with the active keypair
const sig = keyring.sign(messageBytes);

// Sign with a specific keypair without switching active
const sig1 = keyring.signWithKeypair(messageBytes, 1);

// Inspect all keypairs
for (const info of keyring.getKeypairsInfo()) {
  console.log(`index=${info.index}  pubkey=${info.pubkeyString}`);
}

// Securely zero all private keys when done
keyring.dispose();
Build and send a transaction

TransactionBuilder requires a configHashPrefix fetched from the network. Every transaction submitted to a live node must carry the current prefix or it will be rejected.

import {
  TransactionBuilder,
  transferInstruction,
  createRialoClient,
  getDefaultRialoClientConfig,
  RIALO_DEVNET_CHAIN,
} from "@rialo/ts-cdk";

// Using a chain preset directly
const client = createRialoClient({ chain: RIALO_DEVNET_CHAIN });

// Or by network name — useful when network comes from config/env
// const client = createRialoClient(getDefaultRialoClientConfig("devnet"));

const configHashPrefix = await client.getConfigHashPrefix();  // required

const transfer = transferInstruction(
  keypair.publicKey,
  recipientPubkey,
  1_000_000n,       // amount in kelvin; 1 RLO = 1_000_000_000 kelvin
);

const tx = TransactionBuilder.create()
  .setPayer(keypair.publicKey)
  .setValidFrom(BigInt(Date.now()))
  .setConfigHashPrefix(configHashPrefix)
  .addInstruction(transfer)
  .build();

const signedTx = tx.sign(keypair);
const sig = await client.sendTransaction(signedTx.serialize());
console.log("Signature:", sig.toString());
Multi-sig transactions
// Each partial sign adds one signer's signature; isSigned() returns true when all
// required signers have contributed.
const partial = tx.partialSign(signer1);
const complete = partial.partialSign(signer2);
complete.ensureSigned();              // throws if any signature is missing

// Async signer interface (hardware wallets, browser extensions, etc.)
const signedAsync = await tx.signWith(new KeypairSigner(keypair));
Deserialize a transaction

Transaction.deserialize reconstructs a transaction from its wire bytes — useful for inspecting or re-signing transactions received from another party.

import { Transaction } from "@rialo/ts-cdk";

// Reconstruct from wire bytes (e.g. received over a socket)
const tx = Transaction.deserialize(wireBytes);

// Inspect the compiled message
for (const ix of tx.message.instructions) {
  console.log("program:", ix.programId.toString());
}

// Re-sign (e.g. when acting as co-signer)
const reSigned = tx.partialSign(myKeypair);
Borsh serialization for instruction data

Use Borsh to encode typed parameters into the opaque data field of an Instruction.

import { field, serialize, deserialize } from "@dao-xyz/borsh";
import { Instruction, AccountMeta } from "@rialo/ts-cdk";

class TransferParams {
  @field({ type: "u64" }) amount!: bigint;
  constructor(amount: bigint) { this.amount = amount; }
}

const params = new TransferParams(1_000_000n);
const data = Buffer.from(serialize(params));

const ix = new Instruction({
  programId: myProgramId,
  accounts: [new AccountMeta({ pubkey: myAccount, isSigner: false, isWritable: true })],
  data,
});
Program Derived Addresses (PDAs)

PDAs are off-curve addresses deterministically derived from seeds and a program ID. No private key exists; only the program can sign on their behalf.

import { PublicKey } from "@rialo/ts-cdk";

// Automatic bump discovery — returns [address, bump]
const [vaultPda, bump] = PublicKey.findProgramAddress(
  ["vault", userPubkey.toBytes()],
  programId,
);

// With known bump (more efficient)
const pda = PublicKey.createProgramAddress(
  ["metadata", mintPubkey.toBytes(), new Uint8Array([bump])],
  metadataProgramId,
);

Note: Each seed must be ≤ 32 bytes; at most 16 seeds per derivation. String seeds are UTF-8-encoded automatically.

Deploy a program
import { ProgramDeployment } from "@rialo/ts-cdk";

const deployment = new ProgramDeployment({
  programData: fs.readFileSync("program.polkavm"),
  programKeypair: programKeypair,
  config: {
    chunkSize: 900,         // bytes per upload chunk
    maxRetries: 5,
  },
});

const programId = await deployment.deploy(client, payerKeypair);
console.log("Program deployed:", programId.toString());
Encrypt a secret for TEE programs

RexValue wraps a plain or HPKE-encrypted payload. Use it to pass sensitive data to programs that run inside a Trusted Execution Environment (TEE). The node's HPKE public key is fetched via getSecretSharingPubkey(); the CDK handles the HPKE encryption.

import { RexValue } from "@rialo/ts-cdk";

// 1. Fetch the TEE's HPKE public key from the node
const skPub = await client.getSecretSharingPubkey();

// 2. Encrypt your secret — RexValue.fromPlaintext performs HPKE encryption
const plaintext = new TextEncoder().encode("Bearer sk-…");
const rexValue = await RexValue.fromPlaintext(plaintext, skPub);

// 3. Serialise as Borsh bytes and embed in your instruction data
const borshBytes = rexValue.toBorsh();

To include unencrypted bytes (for non-sensitive payloads):

const plain = RexValue.plain(new TextEncoder().encode("public-data"));
const borshBytes = plain.toBorsh();
Custom signer (hardware wallets)
import { type Signer, PublicKey, Signature } from "@rialo/ts-cdk";

class LedgerSigner implements Signer {
  async getPublicKey(): Promise<PublicKey> {
    return PublicKey.fromBytes(await ledger.getPublicKey());
  }
  async signMessage(message: Uint8Array): Promise<Signature> {
    const sigBytes = await ledger.sign(message);
    return Signature.fromBytes(sigBytes);
  }
}

const signedTx = await tx.signWith(new LedgerSigner());
Subscription workflows (REX)

REX subscriptions let a program trigger downstream transactions automatically. Use getSubscription to inspect an active subscription and getTriggeredTransactions to audit which transactions it has fired.

import { createRialoClient, RIALO_DEVNET_CHAIN } from "@rialo/ts-cdk";

const client = createRialoClient({ chain: RIALO_DEVNET_CHAIN });

// Look up a subscription by subscriber address and nonce
const subscription = await client.getSubscription(subscriberPubkey, nonce);
console.log("Topic:", subscription.topic);
console.log("Kind:", subscription.kind);

// List the last 10 transactions triggered by this subscription account
const triggered = await client.getTriggeredTransactions(subscriptionAccount, 10);
for (const tx of triggered) {
  console.log(`sig=${tx.signature}  block=${tx.blockNumber}`);
}
Workflow lineage
const lineage = await client.getWorkflowLineage(request);
// lineage.nodes contains the DAG of related transactions.

Error handling

import { RialoError, RialoErrorType } from "@rialo/ts-cdk";

try {
  await client.sendTransaction(signedTx.serialize());
} catch (err) {
  if (err instanceof RialoError) {
    switch (err.type) {
      case RialoErrorType.RPC:
        console.error("Node error", err.details?.code, err.details?.message);
        break;
      case RialoErrorType.NETWORK:
        console.error("Network failure:", err.cause);
        break;
      case RialoErrorType.INVALID_INPUT:
        console.error("Bad argument:", err.message);
        break;
      default:
        throw err;
    }
  }
}
Error types
RialoErrorType Condition
RPC Node rejected the request
NETWORK HTTP/network failure
TRANSACTION Transaction build or signing error
WALLET Keypair load or create failure
ENCRYPTION HPKE encryption/decryption failure
BIP32 HD key derivation error
INVALID_INPUT Invalid parameter or data
PARSE_PUBKEY Public key parse failure
INVALID_BLOCKHASH_FORMAT Blockhash format error
CONFIG Configuration load or parse failure
JSON JSON parse error
SERIALIZATION Borsh/bincode serialisation error
PASSWORD Password validation failure

RPC reference

Method Returns Notes
getConfigHashPrefix() ConfigHashPrefix Required for every TransactionBuilder
getBalance(pubkey) Kelvin Balance as bigint
sendTransaction(bytes, opts?) Signature Submit signed bytes
sendAndConfirmTransaction(bytes, opts?) ConfirmedTransaction Submit and poll
confirmTransaction(sig, opts?) ConfirmedTransaction Poll by signature
getAccountInfo(pubkey) AccountInfo Raw account data
getMultipleAccounts(pubkeys) OptionalAccountInfo[] Batch query
getAccountsByOwner(owner, filter?) [OwnerAccount[], PaginationInfo?] Program accounts
getBlockHeight() bigint Finalized height
getTransaction(sig) TransactionResponse By signature
getEpochInfo() EpochInfo Current epoch
getSignaturesForAddress(pubkey) SignatureInfo[] Transaction history for an account
requestAirdrop(pubkey, kelvin) Signature Devnet/testnet only
requestAirdropAndConfirm(pubkey, kelvin) ConfirmedTransaction Airdrop + wait
getFeeForMessage(base64Msg) FeeResponse Estimate fee before sending
getMinimumBalanceForRentExemption(size) bigint Rent-exempt threshold
getSecretSharingPubkey() SecretSharingPubkey TEE HPKE public key
getWorkflowLineage(req) GetWorkflowLineageResponse Workflow DAG traversal
getSubscription(subscriber, nonce) Subscription REX subscription lookup
getTriggeredTransactions(account, limit?) TriggeredTransaction[] Subscription-triggered txs

Constants

import {
  KELVIN_PER_RLO,         // 1_000_000_000
  SYSTEM_PROGRAM_ID,       // "11111111111111111111111111111111"
  PUBLIC_KEY_LENGTH,       // 32
  SECRET_KEY_LENGTH,       // 32
  SIGNATURE_LENGTH,        // 64
  URL_MAINNET,             // "https://mainnet.rialo.io:4101"
  URL_TESTNET,             // "https://testnet.rialo.io:4101"
  URL_DEVNET,              // "https://devnet.rialo.io:4101"
  URL_LOCALNET,            // "http://localhost:4104"
} from "@rialo/ts-cdk";

// Currency conversion (KELVIN_PER_RLO is a number; use BigInt() when passing to RPC methods)
const kelvin = BigInt(Math.round(1.5 * KELVIN_PER_RLO));   // 1.5 RLO → 1_500_000_000n kelvin

Caveats

  • configHashPrefixTransactionBuilder.setConfigHashPrefix() is required. Omitting it or using a stale value causes the node to reject the transaction with a replay-protection error.

  • Currency units — all RPC amounts are in kelvin; 1 RLO = KELVIN_PER_RLO (1 000 000 000) kelvin. The transferInstruction helper takes kelvin as bigint.

  • Derivation path — Rialo uses BIP44 coin type 756. Mnemonic.toKeypair(index) uses m/44'/756'/{index}'/0'. Keys derived on other coin types are not compatible.

  • Keypair disposal — call keypair.dispose() (and keyring.dispose()) when the keypair is no longer needed. After disposal, signing methods throw CryptoError.

  • PDA seeds — strings are UTF-8-encoded; Uint8Array seeds are used as-is. A seed exceeding 32 bytes throws CryptoError.MAX_SEED_LENGTH_EXCEEDED.

  • Node.js version — requires Node.js ≥ 18 for the native crypto module and TextEncoder/TextDecoder globals.

  • AccountMetaTable — used internally by TransactionBuilder to deduplicate account references in a compiled Message. Constructing it manually is only needed for advanced multi-program transactions.

Development

pnpm install
pnpm build       # compiles ESM + CJS bundles to dist/
pnpm test        # runs vitest suite
pnpm lint        # biome check

See also

  • rialo-cdk — underlying Rust crate; source of truth for wire format and error codes
  • rialo-py-cdk — Python bindings with equivalent API surface
  • developer-frameworks/cdk/spec.wit — WIT specification from which the RPC surface is derived
  • developer-frameworks/cdk/rialo-ts-cdk/examples/ — runnable end-to-end examples

Keywords