Core TypeScript SDK (`@rivellum/sdk`)
The official TypeScript/JavaScript SDK for interacting with the Rivellum network. Covers account queries, encrypted envelope submission, smart contracts, NFTs, the native ledger, randomness, prefabs, governance, bridge, XCM, tokenomics, and the constraint engine.
Installation
npm install @rivellum/sdk
# or
pnpm add @rivellum/sdk
# or
yarn add @rivellum/sdk
Quick Start
import { RivellumClient } from '@rivellum/sdk';
const client = new RivellumClient({
nodeUrl: 'https://rpc.rivellum.network',
timeout: 30_000,
});
// Check health
const ok = await client.isHealthy();
// Get balance
const balance = await client.getBalance('a1b2c3...64hexchars');
console.log(balance.balance); // e.g. "1000000000"
RivellumClient
Constructor
new RivellumClient(config: ClientConfig)
| Parameter | Type | Required | Description |
|---|---|---|---|
config.nodeUrl | string | ✅ | Node RPC URL. Must be https:// — localhost/loopback throws ValidationError. |
config.timeout | number | ❌ | Request timeout in milliseconds. Default: 30000. |
Properties:
.prefabs—PrefabClientinstance (prefab discovery).random—RandomnessClientinstance (VRF randomness)
const client = new RivellumClient({
nodeUrl: 'https://rpc.rivellum.network',
timeout: 60_000,
});
Account Methods
getBalance(address)
async getBalance(address: string): Promise<Balance>
Returns the native balance, nonce, and all asset sub-balances for an address.
Parameters:
| Name | Type | Description |
|---|---|---|
address | string | 32-byte hex address. 0x prefix optional. Must be 64 hex chars. |
Returns: Balance
interface Balance {
address: string;
balance: string; // Native balance as decimal string
nonce: number; // Replay-protection nonce
balances?: Record<string, string>; // Asset sub-balances keyed by asset ID (hex)
}
Throws: ValidationError if address is not 64 hex characters.
const bal = await client.getBalance('a1b2...c3d4');
console.log(`Native: ${bal.balance}, Nonce: ${bal.nonce}`);
if (bal.balances) {
for (const [assetId, amount] of Object.entries(bal.balances)) {
console.log(`Asset ${assetId}: ${amount}`);
}
}
getSessionKeys(address)
async getSessionKeys(address: string): Promise<SessionKey[]>
Returns all session keys associated with an account.
Parameters:
| Name | Type | Description |
|---|---|---|
address | string | 32-byte hex address (64 chars, 0x prefix optional). |
Returns: SessionKey[]
interface SessionKey {
public_key: { key: string };
policy: {
allowed_contracts: string[];
max_gas_per_intent: number;
expiration_ms: number;
max_calls: number;
};
calls_used: number;
revoked: boolean;
created_at_ms: number;
}
const keys = await client.getSessionKeys('a1b2...c3d4');
for (const sk of keys) {
if (!sk.revoked) {
console.log(`Key: ${sk.public_key.key}`);
console.log(`Calls: ${sk.calls_used} / ${sk.policy.max_calls}`);
}
}
createSessionKey(params)
async createSessionKey(params): Promise<string>
Creates an account-scoped session key using the auth endpoints. The SDK attempts these routes in order:
/v1/session-keys/create/v1/account/session-keys/create/v1/auth/session-keys/create
Returns the transaction/intent identifier reported by the node.
revokeSessionKey(params)
async revokeSessionKey(params): Promise<string>
Revokes an account-scoped session key. The SDK attempts these routes in order:
/v1/session-keys/revoke/v1/account/session-keys/revoke/v1/auth/session-keys/revoke
Returns the transaction/intent identifier reported by the node.
getAccountAuth(address)
async getAccountAuth(address: string): Promise<AccountAuth | null>
Returns the account's authentication configuration, or null if using the default Dilithium3 key scheme.
Envelope Submission
Rivellum uses encrypted envelopes as the canonical way to submit intents. Plaintext intent submission is permanently disabled. Envelopes flow through the lifecycle:
received → admitted → batched → sealed → decrypted → ordered → executed → finalized
submitEnvelope(envelope)
async submitEnvelope(envelope: EncryptedEnvelope): Promise<EnvelopeSubmitResult>
Submits a single encrypted envelope. This is the canonical submission method.
Parameters:
| Name | Type | Description |
|---|---|---|
envelope | EncryptedEnvelope | Pre-built encrypted envelope (see Envelope Builder). |
Returns: EnvelopeSubmitResult
interface EnvelopeSubmitResult {
status: 'accepted' | 'rejected';
envelope_id: string; // 64-hex identifier for status polling
batch_window_id?: string; // Assigned batch window (present on accepted)
rejection_reason?: string; // Error code (present on rejected)
}
const result = await client.submitEnvelope(myEnvelope);
if (result.status === 'accepted') {
console.log(`Envelope ${result.envelope_id} in batch ${result.batch_window_id}`);
// Poll until finalized
let status = await client.getEnvelopeStatus(result.envelope_id);
while (status && status.status !== 'finalized' && status.status !== 'rejected') {
await new Promise(r => setTimeout(r, 2000));
status = await client.getEnvelopeStatus(result.envelope_id);
}
}
submitEnvelopeBatch(envelopes)
async submitEnvelopeBatch(envelopes: EncryptedEnvelope[]): Promise<EnvelopeBatchSubmitResult>
Submits up to 10,000 envelopes in a single HTTP request. Each envelope is validated independently.
Parameters:
| Name | Type | Description |
|---|---|---|
envelopes | EncryptedEnvelope[] | Array of encrypted envelopes. Max 10,000. |
Returns: EnvelopeBatchSubmitResult
interface EnvelopeBatchSubmitResult {
accepted: number;
rejected: number;
}
getEnvelopeStatus(envelopeId)
async getEnvelopeStatus(envelopeId: string): Promise<EnvelopeStatusResponse | null>
Returns the current lifecycle stage of an envelope, or null if not found.
Returns: EnvelopeStatusResponse | null
interface EnvelopeStatusResponse {
envelope_id: string;
status: EnvelopeStatusValue;
sender: string;
nonce: number;
lane_id: string;
epoch_id: number;
max_fee: string;
batch_id?: string; // Set once batched
rejection_reason?: string; // Set if rejected
admitted_at_ms?: number;
sealed_at_ms?: number;
intent_id?: string; // Set once decrypted/ordered
}
type EnvelopeStatusValue =
| 'received' // Received by node, not yet validated
| 'admitted' // Passed admission checks, in a batch window
| 'batched' // Added to a batch
| 'sealed' // Batch sealed, contents still encrypted
| 'decrypted' // Epoch key released, contents revealed
| 'ordered' // Intent placed in execution order
| 'executed' // Intent executed by Mist VM
| 'finalized' // State root committed
| 'rejected'; // Rejected (see rejection_reason)
getBatchInfo(batchId)
async getBatchInfo(batchId: string): Promise<BatchInfoResponse | null>
Returns metadata about a sealed batch, or null if not found.
Returns: BatchInfoResponse | null
interface BatchInfoResponse {
batch_id: string;
lane_id: string;
epoch_id: number;
state: BatchLifecycleState;
envelope_count: number;
total_bytes: number;
seal_hash?: string; // Commitment hash (after sealing)
envelope_ids: string[];
sealed_at_ms?: number;
}
type BatchLifecycleState =
| 'filling' // Accepting new envelopes
| 'sealed' // Closed, contents encrypted
| 'decrypted' // Epoch key applied
| 'ordered' // Intents ordered for execution
| 'dispatched' // Sent to execution engine
getAdmissionTicket(intentId)
async getAdmissionTicket(intentId: string): Promise<AdmissionTicket | null>
Returns the admission ticket tracking an intent's pipeline lifecycle, or null if not found.
Returns: AdmissionTicket | null
interface AdmissionTicket {
admission_id: string;
sender: string;
validated_nonce: number;
intent_id: string;
idempotency_key?: string;
accepted_at_ms: number;
status: 'admitted' | 'dispatched' | 'committed' | 'finalized';
}
sendIntent() 🚫 Permanently Disabled
async sendIntent(intent: Intent): Promise<SendIntentResult>
Status: PERMANENTLY DISABLED. The plaintext intent endpoint returns
410 Gone. Calling this method throws immediately with an error explaining to usesubmitEnvelope().
submitTransparentIntent() 🚫 Permanently Disabled
Status: PERMANENTLY DISABLED. Same as above — throws immediately.
Contract Methods
contract(contractId)
contract(contractId: string): ContractHandle
Returns a ContractHandle bound to a deployed Mist contract.
interface ContractHandle {
call(functionName: string, args?: Record<string, unknown>): Promise<ContractCallResult>;
}
interface ContractCallResult {
receipt_id: string;
contract_id: string;
function: string;
status: string;
intent_id?: string;
}
const counter = client.contract('0xdeadbeef...64hex');
const result = await counter.call('increment', { by: 5 });
console.log(result.receipt_id);
simulateIntent(intent, options?)
async simulateIntent(intent: Intent, options?: SimulateIntentOptions): Promise<SimulationResult>
Dry-run an intent to predict gas usage, fees, and state changes without committing.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
intent | Intent | ✅ | Intent to simulate (signed or unsigned). |
options.atHeight | number | — | Simulate at a specific ledger height. |
options.maxGasOverride | number | — | Override max gas limit. |
options.validateSignature | boolean | false | Check signature validity. |
Returns: SimulationResult
interface SimulationResult {
status: 'success' | 'failed';
gas_used: number;
fee_estimate: string; // In native token units
state_diff?: {
touched_accounts: string[];
balance_changes: [string, string, string][]; // [address, assetId, delta]
};
failure_reason?: string;
}
const sim = await client.simulateIntent(intent, { validateSignature: true });
if (sim.status === 'success') {
console.log(`Costs ${sim.fee_estimate} — proceeds`);
for (const [addr, asset, delta] of sim.state_diff?.balance_changes ?? []) {
console.log(` ${addr}: ${asset} ${delta}`);
}
}
Ledger Methods
getLedgerTip()
async getLedgerTip(): Promise<LedgerTip>
Returns the latest committed ledger state.
Returns:
interface LedgerTip {
height: number; // Global ledger height
root: string; // Meta-root hash (hex)
timestamp_ms: number;
}
getLedgerEntries(from?, to?)
async getLedgerEntries(from?: number, to?: number): Promise<LedgerEntriesResponse>
Query ledger events in a height range.
| Parameter | Type | Description |
|---|---|---|
from | number? | Start height (inclusive). |
to | number? | End height (inclusive). |
getRecentIntents(n?)
async getRecentIntents(n?: number): Promise<RecentIntentsResponse>
Returns up to n (default 50, max 1000) recently executed intents, deduplicated and sorted by batch height descending.
Returns:
interface RecentIntentsResponse {
intents: IntentSummary[];
total: number;
}
interface IntentSummary {
intent_id: string;
sender: string;
height: number;
status: 'committed' | 'failed';
gas_used: number;
fee_charged: number;
timestamp_ms: number;
}
getAccountTimeline(address, options?)
async getAccountTimeline(
address: string,
options?: { limit?: number; beforeHeight?: number }
): Promise<AccountTimelineResponse>
Returns all events touching an account. Performs a parallel fan-out over 5 event query filters:
- Events by address
- Events by contract
native.minteventsnative.transfereventsnative.asset_transferevents
Results are deduplicated, filtered to match the address, and sorted by batch height descending.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
address | string | ✅ | 32-byte hex address (64 chars). |
options.limit | number | 50 | Max entries. Capped at 1000. |
options.beforeHeight | number | — | Only return events before this height. |
Note: Internally fetches up to max(limit × 20, 2000) events per query (paginated, max 50 pages each) to ensure coverage.
getIntent(intentId)
async getIntent(intentId: string): Promise<IntentDetailsResponse>
Returns all events associated with a specific intent ID. Paginates /v1/events/query?intent_id= until exhausted.
getTopAccounts(n?) 🚫 Unsupported
async getTopAccounts(n?: number): Promise<TopAccountsResponse>
Status: 501 Intentionally Unsupported. Throws
NodeError. Not part of production-critical distributed network APIs.
PoUW Methods
getProvers()
async getProvers(): Promise<ProverStats[]>
Returns statistics for all registered PoUW provers.
Returns: ProverStats[]
interface ProverStats {
prover_id: string;
jobs_completed: number;
jobs_failed: number;
total_fee_earned: string;
avg_completion_time_ms: number;
last_seen_ms: number;
}
getProverStats(proverId)
async getProverStats(proverId: string): Promise<ProverStats>
Returns stats for one specific prover. Internally calls getProvers() and filters. Throws NodeError with 404 status if not found.
getPendingJobs()
async getPendingJobs(): Promise<JobSummary[]>
Returns the list of pending proof jobs.
Returns: JobSummary[]
interface JobSummary {
job_id: string;
tier: 'Low' | 'Medium' | 'High';
trace_hash: number[];
fee_budget: string;
created_at_ms: number;
deadline_ms: number;
}
Health Methods
health()
async health(): Promise<HealthResponse>
Returns:
interface HealthResponse {
status: string; // 'ok' when healthy
service: string;
}
isHealthy()
async isHealthy(): Promise<boolean>
Returns true if health().status === 'ok', false on any error.
getNodeUrl()
getNodeUrl(): string
Returns the configured node URL string.
Epoch Methods
getCurrentEpoch()
async getCurrentEpoch(): Promise<CurrentEpochResponse>
Derives the current epoch from governance params (epoch length in slots) and the current ledger height.
Returns:
interface CurrentEpochResponse {
epoch_id: number;
start_height: number;
end_height: number;
current_height: number;
progress: number; // 0.0 – 1.0
}
getEpochInfo(epochId)
async getEpochInfo(epochId: number): Promise<EpochInfoResponse>
Returns start/end height range for a historical epoch.
Returns:
interface EpochInfoResponse {
epoch_id: number;
start_height: number;
end_height: number;
status: string;
}
Bridge Methods
lockAsset(from, asset, amount, destinationChain, foreignRecipient)
async lockAsset(
from: string,
asset: string,
amount: string,
destinationChain: string,
foreignRecipient: string
): Promise<BridgeOperationResponse>
Locks an asset on Rivellum to initiate a bridge transfer to a foreign chain.
| Parameter | Type | Description |
|---|---|---|
from | string | Sender address on Rivellum (hex). |
asset | string | Asset ID to lock (hex). |
amount | string | Amount as decimal string (avoids precision loss). |
destinationChain | string | Target chain ID, e.g. 'ethereum-mainnet'. |
foreignRecipient | string | Recipient address on the foreign chain (hex). |
mintBridgedAsset(proof, asset, amount, recipient)
async mintBridgedAsset(
proof: BridgeProofData,
asset: string,
amount: string,
recipient: string
): Promise<BridgeOperationResponse>
Mints bridged assets on Rivellum after presenting a proof from the foreign chain.
getBridgeMessages(query?)
async getBridgeMessages(query?: BridgeMessagesQuery): Promise<BridgeMessage[]>
Lists bridge messages with optional filters.
interface BridgeMessagesQuery {
status?: string;
chain?: string;
direction?: string; // 'inbound' | 'outbound'
}
sendCrossChainMessage(params)
Submits a cross-chain message through the XCM/bridge send surface. The SDK attempts these routes in order:
/xcm/send/v1/xcm/send/bridge/send/v1/bridge/send
Returns a normalized response with msg_id, nonce, and status.
getCrossChainMessages(query?)
async getCrossChainMessages(query?: XcmMessagesQuery): Promise<XcmMessagesResponse>
interface XcmMessagesQuery {
source_chain?: string;
dest_chain?: string;
src_address?: string;
dest_address?: string;
status?: string;
limit?: number;
cursor?: string;
}
interface XcmMessagesResponse {
messages: CrossChainMessage[];
total: number;
next_cursor?: string;
}
getCrossChainMessage(msgId)
async getCrossChainMessage(msgId: string): Promise<CrossChainMessage>
Get full details for a specific XCM message by ID.
watchCrossChainMessage(msgId, callback, pollingIntervalMs?)
watchCrossChainMessage(
msgId: string,
callback: (message: CrossChainMessage) => void,
pollingIntervalMs?: number // Default: 5000
): () => void
Polls for status changes on a cross-chain message and calls callback whenever the status changes. Returns a cleanup function.
const stop = client.watchCrossChainMessage('0x1234...', (msg) => {
console.log('Status:', msg.status);
if (msg.status === 'Executed') stop();
});
Governance Methods
createProposal(request)
async createProposal(request: CreateProposalRequest): Promise<GovernanceOperationResponse>
interface CreateProposalRequest {
governanceAddress: string;
paramKey: string;
newValue: unknown;
votingPeriodMs?: number; // Default: 86400000 (24h)
from: string;
}
vote(request)
async vote(request: VoteRequest): Promise<GovernanceOperationResponse>
interface VoteRequest {
governanceAddress: string;
proposalId: number;
support: boolean;
from: string;
}
executeProposal(governanceAddress, proposalId, from?)
async executeProposal(
governanceAddress: string,
proposalId: number,
from?: string
): Promise<GovernanceOperationResponse>
Executes a passed governance proposal.
listProposals(governanceAddress)
async listProposals(governanceAddress: string): Promise<Proposal[]>
Lists governance history from /governance/history.
getProposal(governanceAddress, proposalId)
async getProposal(governanceAddress: string, proposalId: number): Promise<Proposal>
Fee Tiers
getFeeTiers()
getFeeTiers(): FeeTierInfo[]
Returns the three fee tier definitions. Synchronous.
type IntentTier = 'Premium' | 'Medium' | 'Micro';
interface FeeTierInfo {
tier: IntentTier;
range: { min_usd_micros: number; max_usd_micros: number };
description: string;
use_cases: string[];
}
| Tier | Fee Range | Use Cases |
|---|---|---|
Premium | $0.10 – $0.50 | Contract calls, ZK proofs, bridge, DeFi |
Medium | $0.01 – $0.05 | NFTs, hooks, marketplace, contract game actions |
Micro | $0.001 – $0.005 | Wallet transfers, game loops, AI agent updates |
isValidFeeForTier(tier, feeUsdMicros)
isValidFeeForTier(tier: IntentTier, feeUsdMicros: number): boolean
Returns true if feeUsdMicros falls within the tier's range. Synchronous.
getRecommendedFee(tier)
getRecommendedFee(tier: IntentTier): number
Returns the midpoint of the tier's range. Synchronous.
getOperationTier(operationType)
getOperationTier(operationType: OperationType): IntentTier
Classifies an operation type into its fee tier. Synchronous.
getOperationInfo(operationType)
getOperationInfo(operationType: OperationType): OperationInfo
Returns full fee info (typical, min, max, description) for an operation. Synchronous.
interface OperationInfo {
type: OperationType;
tier: IntentTier;
typical_fee_usd_micros: number;
min_fee_usd_micros: number;
max_fee_usd_micros: number;
description: string;
}
Operation type fees (usd micros):
| Operation | Typical | Min | Max |
|---|---|---|---|
BasicContractCall | 200,000 | 200,000 | 200,000 |
StatefulContractUpdate | 250,000 | 250,000 | 250,000 |
AmmSwapSingle | 250,000 | 250,000 | 250,000 |
AmmSwapMulti | 350,000 | 300,000 | 400,000 |
LendingOperation | 275,000 | 250,000 | 300,000 |
Liquidation | 450,000 | 400,000 | 500,000 |
OraclePublish | 250,000 | 200,000 | 300,000 |
ZkProofVerification | 400,000 | 300,000 | 500,000 |
BridgeTransfer | 425,000 | 350,000 | 500,000 |
BridgeMessage | 300,000 | 250,000 | 350,000 |
BridgeProofVerification | 350,000 | 300,000 | 400,000 |
NftTransfer | 20,000 | 20,000 | 20,000 |
NftMintBurn | 35,000 | 30,000 | 40,000 |
MarketplaceSale | 45,000 | 40,000 | 50,000 |
TokenTransferWithHook | 25,000 | 20,000 | 30,000 |
GameActionContract | 20,000 | 20,000 | 20,000 |
WalletTransfer | 1,000 | 1,000 | 1,000 |
GameTick | 1,500 | 1,000 | 2,000 |
GameResourceUpdate | 1,500 | 1,000 | 2,000 |
AiAgentUpdate | 2,500 | 2,000 | 3,000 |
AgentMessaging | 2,000 | 1,000 | 3,000 |
getOperationsForTier(tier)
getOperationsForTier(tier: IntentTier): OperationType[]
Returns all operation types in a given tier. Synchronous.
getOperationFee(operationType)
getOperationFee(operationType: OperationType): number
Returns the typical fee for one operation type. Synchronous.
Tokenomics Methods
All tokenomics methods accept an optional indexerUrl parameter. If omitted, they use the default public indexer: https://api.rivellum.network.
getTokenomicsStats(indexerUrl?)
async getTokenomicsStats(indexerUrl?: string): Promise<TokenomicsStats>
Returns top-level tokenomics statistics (total supply, circulating supply, burned, etc.).
getPoolSnapshots(params?, indexerUrl?)
async getPoolSnapshots(
params?: { start_height?: number; end_height?: number; limit?: number },
indexerUrl?: string
): Promise<MiningPoolSnapshot[]>
Returns historical Mining Pool balance snapshots.
getLatestPoolSnapshot(indexerUrl?)
async getLatestPoolSnapshot(indexerUrl?: string): Promise<MiningPoolSnapshot>
Returns the most recent Mining Pool snapshot.
getAllocations(indexerUrl?)
async getAllocations(indexerUrl?: string): Promise<AllocationRecord[]>
Returns all genesis allocation records.
getVestingUnlocks(allocationType?, limit?, indexerUrl?)
async getVestingUnlocks(
allocationType?: string,
limit?: number, // Default 100, max 1000
indexerUrl?: string
): Promise<VestingUnlock[]>
Returns vesting unlock events for a specific allocation type, or aggregates all types if allocationType is omitted.
getFeeFlows(params?, indexerUrl?)
async getFeeFlows(
params?: { start_height?: number; end_height?: number; limit?: number },
indexerUrl?: string
): Promise<TokenomicsFeeFlow[]>
Returns fee flow history. Fee split: 65% validator/proving pool, 25% Rivellum treasury, 10% burn.
getOperatorRewards(params?, indexerUrl?)
async getOperatorRewards(
params?: { start_height?: number; end_height?: number; limit?: number },
indexerUrl?: string
): Promise<OperatorRewardDistribution[]>
getCpiAdjustments(params?, indexerUrl?)
async getCpiAdjustments(
params?: { start_height?: number; end_height?: number; limit?: number },
indexerUrl?: string
): Promise<CpiAdjustment[]>
Returns CPI adjustment history.
getProverRewards(proverId, indexerUrl?)
async getProverRewards(proverId: string, indexerUrl?: string): Promise<ProverRewardsSummary>
Returns accumulated reward data for a specific prover.
getFeeSummary(options?, indexerUrl?)
async getFeeSummary(
options?: { from_height?: number; to_height?: number; limit?: number },
indexerUrl?: string
): Promise<FeeSummary>
getSupplySnapshots(limit?, indexerUrl?)
async getSupplySnapshots(limit?: number, indexerUrl?: string): Promise<SupplySnapshotsResponse>
Analytics Methods
Analytics methods use https://api.rivellum.network as the default base URL. Override with analyticsUrl.
getAnalyticsEvents(params?, analyticsUrl?)
async getAnalyticsEvents(
params?: EventsQueryParams,
analyticsUrl?: string
): Promise<EventsResponse>
interface EventsQueryParams {
topic?: string;
contract?: string;
limit?: number;
cursor?: string;
}
getAccountActivity(address, params?, analyticsUrl?)
async getAccountActivity(
address: string,
params?: AnalyticsQueryParams,
analyticsUrl?: string
): Promise<AccountActivityResponse>
Returns the activity timeline for an account via the analytics indexer.
getContractEvents(params?, analyticsUrl?)
async getContractEvents(
params?: EventsQueryParams,
analyticsUrl?: string
): Promise<EventsResponse>
getContractCalls(address, params?, analyticsUrl?)
async getContractCalls(
address: string,
params?: ContractCallsQueryParams,
analyticsUrl?: string
): Promise<ContractCallsResponse>
interface ContractCallsQueryParams {
entrypoint?: string;
limit?: number;
cursor?: string;
}
Protocol Methods
getProtocolVersion()
async getProtocolVersion(): Promise<ProtocolVersionInfo>
Returns chain version, chain ID, genesis hash, and active feature flags from /v1/chain.
getProtocolUpgrades()
async getProtocolUpgrades(): Promise<UpgradesListResponse>
Returns all past and scheduled protocol upgrades with activation heights.
NFT Methods
getNftMetadata(nftId)
async getNftMetadata(nftId: string): Promise<NftMetadata>
Returns NFT metadata for a given NFT ID (hex-encoded).
getNftsOwnedBy(address, page?, limit?)
async getNftsOwnedBy(
address: string,
page?: number, // Default: 1
limit?: number // Default: 50
): Promise<NftListResponse>
getNftTransferHistory(nftId, page?, limit?)
async getNftTransferHistory(
nftId: string,
page?: number, // Default: 1
limit?: number // Default: 50
): Promise<NftTransferHistoryResponse>
listCollections(page?, limit?)
async listCollections(page?: number, limit?: number): Promise<CollectionListResponse>
getCollection(collectionId)
async getCollection(collectionId: string): Promise<NftCollection>
getCollectionNfts(collectionId, page?, limit?)
async getCollectionNfts(
collectionId: string,
page?: number,
limit?: number
): Promise<NftListResponse>
Native Ledger Methods
The Native Ledger handles fungible tokens and NFTs on-chain. Asset IDs are derived using BLAKE3 — see NativeLedger Helpers.
getNativeLedgerBalance(address, assetId)
async getNativeLedgerBalance(
address: string,
assetId: string
): Promise<NativeLedgerBalance>
Returns the balance of a specific asset for an account.
Both address and assetId must be 64 hex characters.
interface NativeLedgerBalance {
address: string;
asset_id: string;
balance: string;
}
getNativeLedgerBalances(address)
async getNativeLedgerBalances(address: string): Promise<NativeLedgerBalance[]>
Returns all asset balances for an account.
nativeLedgerTransfer(params)
async nativeLedgerTransfer(params: NativeLedgerTransferParams): Promise<NativeLedgerOperationResult>
interface NativeLedgerTransferParams {
from: string;
to: string;
assetId: string;
amount: string;
privacy?: boolean; // Default: true
maxGas?: number;
}
interface NativeLedgerOperationResult {
txHash: string;
status: string;
gas_used?: number;
}
nativeLedgerMint(params)
async nativeLedgerMint(params: NativeLedgerMintParams): Promise<NativeLedgerOperationResult>
interface NativeLedgerMintParams {
account: string;
assetId: string;
amount: string;
privacy?: boolean;
maxGas?: number;
}
nativeLedgerBurn(params)
async nativeLedgerBurn(params: NativeLedgerBurnParams): Promise<NativeLedgerOperationResult>
interface NativeLedgerBurnParams {
account: string;
assetId: string;
amount: string;
privacy?: boolean;
maxGas?: number;
}
getNativeLedgerEvents(query)
async getNativeLedgerEvents(query: NativeLedgerEventsQuery): Promise<NativeLedgerEventsResponse>
interface NativeLedgerEventsQuery {
asset_id?: string;
account?: string;
from_height?: number;
to_height?: number;
cursor?: string;
limit?: number;
}
estimateNativeLedgerTransferGas(params)
async estimateNativeLedgerTransferGas(params: NativeLedgerTransferParams): Promise<NativeLedgerGasEstimate>
interface NativeLedgerGasEstimate {
base_gas: number;
privacy_overhead: number;
total_gas: number;
fee_estimate: string;
}
Gas constants:
| Operation | Gas Units |
|---|---|
| Transfer (base) | 500 |
| Mint (base) | 1,000 |
| Burn (base) | 500 |
| Privacy overhead | 2,000 |
| Balance query | 100 |
estimateNativeLedgerMintGas(params) / estimateNativeLedgerBurnGas(params)
Same signature as estimateNativeLedgerTransferGas but for mint/burn params respectively.
Constraint Engine Methods
The constraint engine enforces per-asset compliance rules (transfer limits, freeze lists, KYC requirements).
getAssetConstraints(assetId)
async getAssetConstraints(assetId: string): Promise<AssetConstraintInfo>
Returns the full constraint binding, policies, capability flags, and pause state for an asset. If the asset has no constraint binding, constrained will be false.
assetId must be 64 hex characters.
interface AssetConstraintInfo {
asset_id: string;
constrained: boolean;
policy_id?: string;
paused?: boolean;
capabilities?: string[];
}
preflightConstraint(assetId, sender, receiver, amount)
async preflightConstraint(
assetId: string,
sender: string,
receiver: string,
amount: string
): Promise<ConstraintPreflightResult>
Dry-run a constraint check: tests whether a transfer would pass without actually submitting.
interface ConstraintPreflightResult {
allowed: boolean;
denial_reason?: string;
}
getConstraintPolicy(policyId)
async getConstraintPolicy(policyId: string): Promise<ConstraintPolicyDefinition>
Returns the policy definition for a given policy ID (64 hex chars).
getAccountFreezeStatus(assetId, account)
async getAccountFreezeStatus(assetId: string, account: string): Promise<AccountFreezeStatus>
Checks whether an account is frozen for a specific asset.
interface AccountFreezeStatus {
frozen: boolean;
reason?: string;
frozen_at_ms?: number;
}
RandomnessClient (client.random)
VRF-based randomness backed by the Rivellum beacon chain. All values are derived from BLAKE3 with domain separation.
getBeacon()
async getBeacon(): Promise<BeaconOutput>
Returns the latest VRF beacon output.
interface BeaconOutput {
height: number;
output: string; // Hex-encoded VRF output
proof: string; // Hex-encoded VRF proof
producer: string; // Producer address
timestamp_ms: number;
verified: boolean;
}
u64(seed?)
async u64(seed?: string): Promise<number>
Returns a random u64 as a JS number (safe up to 2^53). Derived from 8 random beacon bytes.
| Parameter | Type | Description |
|---|---|---|
seed | string? | Optional domain seed for deterministic derivation. |
bytes(len, seed?)
async bytes(len: number, seed?: string): Promise<Uint8Array>
Returns len random bytes (max 65,536).
pickIndex(len, seed?)
async pickIndex(len: number, seed?: string): Promise<number>
Returns a uniformly random integer in [0, len).
shuffleSmall(items, seed?)
async shuffleSmall<T>(items: T[], seed?: string): Promise<T[]>
Fisher-Yates shuffle. Maximum 256 items.
raffleWinner(addresses, seed?)
async raffleWinner(addresses: string[], seed?: string): Promise<string>
Selects a random winner from an array of addresses.
enableReplayMode(config) / disableReplayMode()
enableReplayMode(config: ReplayConfig): void
disableReplayMode(): void
Testing only. Blocked on mainnet. Replay mode uses a fixed beacon output for deterministic tests.
PrefabsClient (client.prefabs)
Prefabs are pre-built contract templates discoverable via the Rivellum manifest.
Categories
| Category | Description |
|---|---|
'CASUAL' | Casual gaming & social contracts |
'WORLD' | Open-world / MMO game contracts |
'UNIVERSAL' | Chain-agnostic utility contracts |
getAvailable(category?)
async getAvailable(category?: 'CASUAL' | 'WORLD' | 'UNIVERSAL'): Promise<PrefabDefinition[]>
Lists available prefabs, optionally filtered by category.
getManifest()
async getManifest(): Promise<PrefabManifest>
Returns the full prefab manifest. Cached for 5 minutes.
findById(prefabId)
async findById(prefabId: string): Promise<PrefabDefinition | undefined>
Searches the manifest for a prefab by exact ID.
search(query)
async search(query: string): Promise<PrefabDefinition[]>
Case-insensitive search across prefab name, description, and tags.
getCasual() / getWorld() / getUniversal()
async getCasual(): Promise<PrefabDefinition[]>
async getWorld(): Promise<PrefabDefinition[]>
async getUniversal(): Promise<PrefabDefinition[]>
Convenience wrappers for each prefab category.
LightClientVerifier
Standalone class for verifying sealed-batch ZK proofs. Import separately.
import { LightClientVerifier } from '@rivellum/sdk/lightclient';
const verifier = new LightClientVerifier({ nodeUrl: 'https://rpc.rivellum.network' });
fetchProofBundle(batchId)
async fetchProofBundle(batchId: string): Promise<LightClientProofBundle>
Fetches the proof bundle for a sealed batch from /batches/{batchId}/proof-bundle.
interface LightClientProofBundle {
batch: ExecutionBatchSummary;
traceProofs: TraceProof[];
batchProof?: unknown;
}
verifyBundle(bundle, mode)
async verifyBundle(
bundle: LightClientProofBundle,
mode: 'mock' | 'real'
): Promise<VerificationResult>
| Mode | Status | Description |
|---|---|---|
'mock' | ✅ Working | Re-hashes traces and compares proof hashes. |
'real' | ⚠️ Stubbed | ZK proof verification (TODO, not yet implemented). |
interface VerificationResult {
verified: boolean;
mode: 'mock' | 'real';
error?: string;
details?: {
batchId: string;
height: number;
intentCount: number;
traceProofsVerified: number;
batchProofVerified: boolean;
};
}
NativeLedger Helpers
Standalone utility functions for asset ID derivation. Import directly.
import { deriveFungibleAssetId, deriveNftAssetId } from '@rivellum/sdk/nativeLedger';
deriveFungibleAssetId(params)
function deriveFungibleAssetId(params: {
creator: string; // 64 hex chars (32 bytes)
symbol: string; // 1–32 characters
decimals: number; // 0–18
}): string // 64-hex AssetId
Derives a deterministic asset ID using BLAKE3(creator || symbol || decimals).
const assetId = deriveFungibleAssetId({
creator: 'a1b2...c3d4',
symbol: 'GOLD',
decimals: 8,
});
deriveNftAssetId(params)
function deriveNftAssetId(params: {
creator: string; // 64 hex chars
symbol: string; // Collection name
tokenId: string; // Token identifier
}): string // 64-hex AssetId
Derives a deterministic NFT asset ID using BLAKE3(creator || symbol || tokenId).
PrivacyClient
Standalone class for shielded private balances and transfers using view keys.
import { PrivacyClient } from '@rivellum/sdk/privacy';
const privacy = new PrivacyClient({
nodeUrl: 'https://rpc.rivellum.network',
viewKeyHex: 'abcdef...64hex', // 32-byte view key
timeoutMs: 30_000,
});
Constructor Parameters
| Name | Type | Required | Description |
|---|---|---|---|
nodeUrl | string | ✅ | Node URL (https only). |
viewKeyHex | string | ✅ | 64 hex chars (32 bytes) view key for decrypting private balances. |
timeoutMs | number | ❌ | Request timeout in ms. |
getPrivateBalance()
async getPrivateBalance(): Promise<PrivateBalance>
Decrypts and returns the private balance visible to the configured view key.
submitPrivateTransfer(builder)
async submitPrivateTransfer(builder: PrivateTransferBuilder): Promise<PrivateTransferResult>
Types:
interface PrivacyRoutingHint {
circuit_class: string;
input_count: number;
output_count: number;
max_fee: string;
domain_hint?: string;
}
interface AntiSpamProof {
pow_nonce: string;
fee_commitment?: string;
sender_pk: string;
nonce: number;
}
Envelope Builder
Low-level utilities for constructing encrypted envelopes. Requires Dilithium3 WASM initialization.
import {
initDilithium,
generateKeypair,
addressFromPublicKey,
computeLaneHint,
serializeTransferPayload,
buildEncryptedEnvelope,
} from '@rivellum/sdk/envelope';
initDilithium()
async function initDilithium(): Promise<void>
Must be called once before using any key generation or signing functions. Initializes the Dilithium3 WASM module.
generateKeypair()
function generateKeypair(): { publicKey: Uint8Array; secretKey: Uint8Array }
Generates a Dilithium3 post-quantum keypair. Requires initDilithium() to have been called.
addressFromPublicKey(publicKey)
function addressFromPublicKey(publicKey: Uint8Array): Uint8Array // 32 bytes
Derives a Rivellum address from a Dilithium3 public key using BLAKE3(0x03 || pk).
computeLaneHint(sender, laneCount)
function computeLaneHint(sender: Uint8Array, laneCount: number): number
Computes the preferred lane for a sender: BLAKE3(sender)[0] & (laneCount - 1).
serializeTransferPayload(to, amount)
function serializeTransferPayload(to: Uint8Array, amount: bigint): Uint8Array // 52 bytes
Serializes a transfer intent payload in bincode layout (variant 0 = Transfer, 32-byte recipient, 16-byte amount).
buildEncryptedEnvelope(params)
async function buildEncryptedEnvelope(params: EnvelopeBuilderParams): Promise<EncryptedEnvelope>
Constructs a complete encrypted envelope using:
- Signing: Dilithium3 (post-quantum)
- Encryption: ChaCha20-Poly1305
interface EncryptedEnvelope {
sender: string; // Hex-encoded sender address
nonce: number;
lane_hint: number;
epoch_id: number;
max_fee: string;
encrypted_payload: string; // Hex-encoded ciphertext
signature: string; // Dilithium3 signature
}
Error Types
import { NetworkError, NodeError, ValidationError } from '@rivellum/sdk/errors';
NetworkError
Thrown when the HTTP request fails (no response received, timeout, DNS failure).
class NetworkError extends Error {
code?: number;
}
NodeError
Thrown when the node returns an error response (4xx/5xx).
class NodeError extends Error {
data: unknown; // Raw response body
}
Check error.data for structured error details. The status field in data maps to HTTP status codes (404, 501, etc.).
ValidationError
Thrown for invalid client-side input before any request is made (e.g., address length ≠ 64 hex chars, localhost URL).
class ValidationError extends Error {}
Common Patterns
Poll Until Finalized
async function waitForFinalization(client: RivellumClient, envelopeId: string): Promise<void> {
const terminal = new Set(['finalized', 'rejected']);
while (true) {
const status = await client.getEnvelopeStatus(envelopeId);
if (!status || terminal.has(status.status)) break;
await new Promise(r => setTimeout(r, 2_000));
}
}
Derive and Mint a Custom Token
import { deriveFungibleAssetId } from '@rivellum/sdk/nativeLedger';
const assetId = deriveFungibleAssetId({
creator: myAddress,
symbol: 'GEMS',
decimals: 6,
});
const result = await client.nativeLedgerMint({
account: playerAddress,
assetId,
amount: '1000000',
});
Check if a Transfer Would Pass Constraints
const check = await client.preflightConstraint(assetId, sender, receiver, '500000');
if (!check.allowed) {
console.error('Transfer blocked:', check.denial_reason);
}
Pick a Random Raffle Winner
const winner = await client.random.raffleWinner([
'addr1...', 'addr2...', 'addr3...'
]);
console.log('Winner:', winner);
Build and Submit an Encrypted Envelope
import { initDilithium, generateKeypair, addressFromPublicKey,
computeLaneHint, serializeTransferPayload, buildEncryptedEnvelope } from '@rivellum/sdk/envelope';
await initDilithium();
const { publicKey, secretKey } = generateKeypair();
const senderAddr = addressFromPublicKey(publicKey);
const payload = serializeTransferPayload(
Buffer.from(recipientAddress, 'hex'),
BigInt(1_000_000)
);
const epoch = await client.getCurrentEpoch();
const laneHint = computeLaneHint(senderAddr, 8);
const envelope = await buildEncryptedEnvelope({
sender: senderAddr,
secretKey,
payload,
nonce: 1,
laneHint,
epochId: epoch.epoch_id,
maxFee: '5000',
});
const result = await client.submitEnvelope(envelope);