npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bubolabs/wallet-rn-sdk

v0.2.29

Published

React Native smoke SDK for bubo wallet UniFFI bridge

Downloads

789

Readme

@bubolabs/wallet-rn-sdk

React Native SDK for the Bubo wallet UniFFI bridge.

This package uses standard RN native-module layout and supports autolinking:

  • android/ React Native Android library module
  • ios/ Pod sources + vendored BuboWalletFFI.xcframework
  • react-native.config.js for Android package registration

Install

npm install @bubolabs/wallet-rn-sdk

iOS:

cd ios && pod install

API Overview

Public API is primarily chain-first. Generic chainId-routed low-level aggregators are not exported from package entry (deriveAddress*, deriveWallet*, buildAndSign*, signMessage*, signBytes*, signTypedData*), while higher-level cross-chain business helpers live under the wallets namespace.

v1 freeze policy:

  • canonical consumer entrypoints are namespaced core, btc, eth, solana, polkadot, aptos, cardano, cosmos, stellar, sui, ton, tron, xrpl
  • cross-chain business helpers are namespaced wallets
  • flat exports (for example btcSignMessage) and BTC FROST short aliases (for example btc.createFrostDkgSession) are compatibility layer
  • frozen surface baseline: packages/rn-sdk/api-freeze-v1.json
  • check command: node ./scripts/check-rn-sdk-api-freeze.mjs --check

Address Chain Detection

The SDK also exposes lightweight helpers for inferring candidate chain types from an address string:

import {
  detectAddressChainId,
  detectAddressChainIds,
} from "@bubolabs/wallet-rn-sdk";

Signatures:

function detectAddressChainIds(address: string): SupportedChainId[]
function detectAddressChainId(address: string): SupportedChainId | null

Supported SupportedChainId values:

type SupportedChainId =
  | "near"
  | "cosmos"
  | "cardano"
  | "aptos"
  | "btc"
  | "dogecoin"
  | "eth"
  | "polkadot"
  | "solana"
  | "starknet"
  | "stellar"
  | "sui"
  | "ton"
  | "tron"
  | "xrpl";

Behavior:

  • detectAddressChainIds(address) returns all matching candidate chains
  • detectAddressChainId(address) returns the chain only when the match is unique
  • ambiguous addresses return null from detectAddressChainId(address)
  • unknown addresses return [] / null
  • blank input throws WalletError("INVALID_ARGUMENT", ...)

Examples:

detectAddressChainIds("3sa7ojKe217pjvrsz6iUiFaSkpy8XQmEoiF1kC623rwo");
// ["solana"]

detectAddressChainId("3sa7ojKe217pjvrsz6iUiFaSkpy8XQmEoiF1kC623rwo");
// "solana"

detectAddressChainIds("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef");
// ["aptos", "sui"]

detectAddressChainId("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef");
// null

detectAddressChainIds("not-an-address");
// []

Signing Guide

Use signMessage* for UTF-8 text the user can read in the app.

Use signBytes* for raw payload bytes the app or backend must preserve exactly.

Practical rule:

  • use signMessage* for login text, challenge strings, and human-readable approvals
  • use signBytes* for canonical payload bytes, serialized protocol messages, or app-defined binary envelopes

For newer post-expansion chains, see:

  • docs/multichain-wallet-cookbook.md

Preferred (chain namespace API):

import { aptos, btc, cardano, cosmos, eth, polkadot, solana, stellar, sui, ton, tron, xrpl } from "@bubolabs/wallet-rn-sdk";

await btc.signMessage({
  mnemonic,
  account: 0,
  index: 0,
  message: "hello",
  mode: "bip322-simple",
});

await eth.signTypedData({
  mnemonic,
  account: 0,
  index: 0,
  typedData: JSON.stringify(typedData),
});

await solana.signTx({
  unsignedTx,
  unsignedTxEncoding: "base64",
  privateKey,
  keyEncoding: "base58",
});

await aptos.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await polkadot.buildAndSignFromPrivateKey({
  senderAddress,
  toAddress,
  amountPlancks: "10000000000",
  nonce: "7",
  specVersion: 1000,
  transactionVersion: 25,
  genesisHashHex,
  blockHashHex,
  privateKey,
  keyEncoding: "hex",
});

await cardano.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await cardano.buildAndSignFromPrivateKey({
  senderAddress,
  toAddress,
  changeAddress,
  amountLovelace: "1000000",
  feeLovelace: "170000",
  inputTxHash,
  inputTxIndex: 0,
  inputAmountLovelace: "2000000",
  changeAmountLovelace: "830000",
  ttl: 123456,
  networkId: 0,
  privateKey,
  keyEncoding: "hex",
});

await cardano.decodeSignedTx({
  signedTx,
  signedTxEncoding: "utf8",
});

await cosmos.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await cosmos.buildAndSignFromPrivateKey({
  senderAddress,
  toAddress,
  amount: "12345",
  denom: "uatom",
  feeAmount: "500",
  feeDenom: "uatom",
  gasLimit: "200000",
  sequence: "7",
  accountNumber: "42",
  chainId: "cosmoshub-4",
  memo: "bubo",
  timeoutHeight: "1234567",
  privateKey,
  keyEncoding: "hex",
});

await stellar.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await sui.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await ton.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await tron.deriveWallet({
  mnemonic,
  account: 0,
  index: 0,
});

await tron.buildAndSign({
  ownerAddress,
  toAddress,
  amountSun: 1_000_000,
  refBlockBytes,
  refBlockHash,
  expiration,
  timestamp,
  mnemonic,
});

await xrpl.deriveWalletFromPrivateKey({
  privateKey,
  keyEncoding: "hex",
});

await xrpl.buildAndSignFromPrivateKey({
  senderAddress,
  toAddress,
  amountDrops: "1000000",
  feeDrops: "12",
  sequence: 7,
  privateKey,
  keyEncoding: "hex",
});

await xrpl.decodeSignedTx({
  signedTx,
  signedTxEncoding: "utf8",
});

Business-layer helpers are also available when you want one private key import flow to auto-detect candidate chains from the private key itself:

import { wallets } from "@bubolabs/wallet-rn-sdk";

const imported = await wallets.importPrivateKey(privateKey);
const importedFromMnemonic = await wallets.importMnemonic(mnemonic);

Both helpers return a shared candidate contract with source, ambiguous, and candidates[]; BTC expands into 8 candidate accounts (mainnet/testnet x 4 address types) and the consumer chooses the final one.

Legacy flat function exports are still fully supported:

import {
  aptos,
  btc,
  cardano,
  cosmos,
  core,
  eth,
  polkadot,
  solana,
  stellar,
  sui,
  ton,
  tron,
  xrpl,
  wallets,
  aptosBuildAndSign,
  aptosBuildAndSignFromPrivateKey,
  aptosBuildTx,
  aptosDecodeSignedTx,
  aptosDeriveAddress,
  aptosDeriveAddressFromPrivateKey,
  aptosDeriveWallet,
  aptosDeriveWalletFromPrivateKey,
  aptosInspectSignedTx,
  aptosSignTx,
  polkadotBuildAndSign,
  polkadotBuildAndSignFromPrivateKey,
  polkadotSignBytes,
  polkadotSignBytesFromPrivateKey,
  polkadotSignMessage,
  polkadotSignMessageFromPrivateKey,
  polkadotBuildTx,
  polkadotDecodeSignedTx,
  polkadotDeriveAddress,
  polkadotDeriveAddressFromPrivateKey,
  polkadotDeriveWallet,
  polkadotDeriveWalletFromPrivateKey,
  polkadotInspectSignedTx,
  polkadotSignTx,
  btcBuildAndSign,
  btcBuildAndSignFromPrivateKey,
  btcBuildPsbt,
  btcBuildTx,
  btcDeriveAddress,
  btcDeriveAddressFromPrivateKey,
  btcDeriveWallet,
  btcDeriveWalletFromPrivateKey,
  btcFrostDkgFinalize,
  btcFrostDkgRound1,
  btcFrostDkgRound2,
  btcFrostAggregateSignature,
  btcFrostBuildSigningPackage,
  btcFrostRound1Commit,
  btcFrostRound2SignShare,
  btcFrostTaprootComputeTweak,
  btcFrostNonceSessionScope,
  btcFrostResetNonceGuard,
  btcFrostTrustedDealerKeygen,
  createBtcPsbtMultiSignerSession,
  runBtcPsbtMultiSignerSession,
  createBtcFrostDkgSession,
  createBtcFrostSigningSession,
  runBtcFrostDkgSession,
  runBtcFrostSigningSession,
  btcInspectPsbt,
  btcPartialSignPsbt,
  btcSignBytes,
  btcSignBytesFromPrivateKey,
  btcSignMessage,
  btcSignMessageFromPrivateKey,
  btcSignPsbt,
  btcSignPsbtWithSigners,
  btcSignTx,
  btcVerifyPsbtFinalized,
  cardanoBuildAndSign,
  cardanoBuildAndSignFromPrivateKey,
  cardanoBuildTx,
  cardanoDecodeSignedTx,
  cardanoDeriveAddress,
  cardanoDeriveAddressFromPrivateKey,
  cardanoDeriveWallet,
  cardanoDeriveWalletFromPrivateKey,
  cardanoInspectSignedTx,
  cardanoSignTx,
  cosmosBuildAndSign,
  cosmosBuildAndSignFromPrivateKey,
  cosmosBuildTx,
  cosmosDecodeSignedTx,
  cosmosDeriveAddress,
  cosmosDeriveAddressFromPrivateKey,
  cosmosDeriveWallet,
  cosmosDeriveWalletFromPrivateKey,
  cosmosInspectSignedTx,
  cosmosSignTx,
  ethBuildAndSign,
  ethBuildAndSignFromPrivateKey,
  ethBuildTx,
  ethDeriveAddress,
  ethDeriveAddressFromPrivateKey,
  ethDeriveWallet,
  ethDeriveWalletFromPrivateKey,
  ethBuildEip1271IsValidSignatureCall,
  ethBuildEip1271RpcCall,
  ethBuildUserOperationHashInput,
  ethComputeUserOperationHash,
  ethDecodeSignedTx,
  ethRecoverUserOperationSigner,
  ethVerifyMessageSignature,
  ethVerifyTypedDataSignature,
  ethValidateUserOperation,
  importMnemonic,
  generateMnemonic,
  importPrivateKey,
  validateMnemonic,
  init,
  listChainExtensions,
  listSupportedChains,
  ethEcrecover,
  ethRecoverTypedDataSigner,
  ethSignUserOperation,
  ethSignMessage,
  ethSignMessageFromPrivateKey,
  ethSignTx,
  ethSignTypedData,
  ethSignTypedDataFromPrivateKey,
  ethVerifyEip1271IsValidSignatureResult,
  generateMnemonic,
  init,
  listChainExtensions,
  listSupportedChains,
  solanaBuildAndSign,
  solanaBuildAndSignFromPrivateKey,
  solanaBuildTx,
  solanaDecodeSignedTx,
  solanaDeriveAddress,
  solanaDeriveAddressFromPrivateKey,
  solanaDeriveWallet,
  solanaDeriveWalletFromPrivateKey,
  solanaInspectSignedTx,
  solanaSignBytes,
  solanaSignBytesFromPrivateKey,
  solanaSignMessage,
  solanaSignMessageFromPrivateKey,
  solanaVerifyBytesSignature,
  solanaVerifyMessageSignature,
  solanaSignTx,
  stellarBuildAndSign,
  stellarBuildAndSignFromPrivateKey,
  stellarBuildTx,
  stellarDecodeSignedTx,
  stellarDeriveAddress,
  stellarDeriveAddressFromPrivateKey,
  stellarDeriveWallet,
  stellarDeriveWalletFromPrivateKey,
  stellarInspectSignedTx,
  stellarSignTx,
  suiDeriveAddress,
  suiDeriveAddressFromPrivateKey,
  suiDeriveWallet,
  suiDeriveWalletFromPrivateKey,
  ton,
  tonBuildAndSign,
  tonBuildAndSignFromPrivateKey,
  tonBuildTx,
  tonDeriveAddress,
  tonDeriveAddressFromPrivateKey,
  tonDeriveWallet,
  tonDeriveWalletFromPrivateKey,
  tonSignTx,
  tron,
  tronBuildAndSign,
  tronBuildAndSignFromPrivateKey,
  tronBuildTx,
  tronDeriveAddress,
  tronDeriveAddressFromPrivateKey,
  tronDeriveWallet,
  tronDeriveWalletFromPrivateKey,
  tronSignTx,
  validateMnemonic,
} from "@bubolabs/wallet-rn-sdk";
  • Shared discovery + lifecycle:
    • namespaced: core.init, core.listSupportedChains, core.listChainExtensions
    • flat: init, listSupportedChains, listChainExtensions
  • Cross-chain wallet business layer:
    • namespaced: wallets.importPrivateKey, wallets.importMnemonic
    • flat: importPrivateKey, importMnemonic
    • result contract: returns chain candidates, with BTC expanding into 8 accounts (mainnet/testnet x 4 address types)
  • BTC core API:
    • wallet management: btcDeriveAddress, btcDeriveWallet, btcDeriveAddressFromPrivateKey, btcDeriveWalletFromPrivateKey
    • transaction signing: btcBuildAndSign, btcBuildAndSignFromPrivateKey
    • transaction lifecycle: btcBuildTx, btcSignTx (PSBT-backed)
    • message/bytes signing: btcSignMessage, btcSignMessageFromPrivateKey, btcSignBytes, btcSignBytesFromPrivateKey
    • PSBT flow: btcBuildPsbt, btcSignPsbt, btcSignPsbtWithSigners, btcPartialSignPsbt, btcVerifyPsbtFinalized, btcInspectPsbt
    • PSBT multi-signer session helpers: createBtcPsbtMultiSignerSession, runBtcPsbtMultiSignerSession
    • FROST key setup: btcFrostTrustedDealerKeygen, btcFrostDkgRound1, btcFrostDkgRound2, btcFrostDkgFinalize
    • FROST share lifecycle helpers: btcFrostRefreshRound1, btcFrostRefreshRound2, btcFrostRefreshFinalize, btcFrostReshareRound1, btcFrostReshareRound2, btcFrostReshareFinalize
    • FROST public-state guards: btcFrostValidateShare, btcFrostValidatePublicState, btcFrostCompareGroupPublicKey
    • FROST threshold signing: btcFrostRound1Commit, btcFrostBuildSigningPackage, btcFrostRound2SignShare, btcFrostAggregateSignature, btcFrostTaprootComputeTweak, btcFrostVerifySignatureShare
    • FROST nonce lifecycle guard: btcFrostNonceSessionScope, btcFrostResetNonceGuard
    • FROST Taproot PSBT bridge: btcFrostBuildTaprootPsbtSigningInputs, btcFrostFinalizeTaprootPsbt
    • FROST offline orchestration helpers: createBtcFrostDkgSession, runBtcFrostDkgSession, createBtcFrostSigningSession, runBtcFrostSigningSession
    • consumer cookbook: docs/btc-wallet-cookbook.md
  • ETH core API:
    • wallet management: ethDeriveAddress, ethDeriveWallet, ethDeriveAddressFromPrivateKey, ethDeriveWalletFromPrivateKey
    • transaction signing: ethBuildAndSign, ethBuildAndSignFromPrivateKey
    • transaction lifecycle: ethBuildTx, ethSignTx
    • message/typed-data signing: ethSignMessage, ethSignMessageFromPrivateKey, ethSignTypedData, ethSignTypedDataFromPrivateKey
    • verify/recovery helpers: ethVerifyMessageSignature, ethVerifyTypedDataSignature, ethEcrecover, ethRecoverTypedDataSigner, ethDecodeSignedTx
    • contract-wallet helpers (EIP-1271): ethBuildEip1271IsValidSignatureCall, ethBuildEip1271RpcCall, ethVerifyEip1271IsValidSignatureResult, ethBuildEip1271RpcCallAndVerify
    • account-abstraction helpers (EIP-4337): ethBuildUserOperationHashInput, ethValidateUserOperation, ethComputeUserOperationHash, ethSignUserOperation, ethRecoverUserOperationSigner
    • consumer cookbook: docs/eth-wallet-cookbook.md
    • app-layer orchestration reference: docs/eth-eip1271-consumer-template.md
  • SOL core API:
    • wallet management: solanaDeriveAddress, solanaDeriveWallet, solanaDeriveAddressFromPrivateKey, solanaDeriveWalletFromPrivateKey
    • transaction signing: solanaBuildAndSign, solanaBuildAndSignFromPrivateKey
    • transaction lifecycle: solanaBuildTx, solanaSignTx, solanaInspectSignedTx, solanaDecodeSignedTx (supports versioned_message payload path and multi-signer progress inspection / decode summary)
    • message/bytes signing + verify: solanaSignMessage, solanaSignMessageFromPrivateKey, solanaSignBytes, solanaSignBytesFromPrivateKey, solanaVerifyMessageSignature, solanaVerifyBytesSignature
    • consumer cookbook: docs/solana-wallet-cookbook.md
    • app-layer multi-signer orchestration reference: docs/solana-multisigner-consumer-template.md
  • Aptos core API:
    • wallet management: aptosDeriveAddress, aptosDeriveWallet, aptosDeriveAddressFromPrivateKey, aptosDeriveWalletFromPrivateKey
    • message signing: aptosSignMessage, aptosSignMessageFromPrivateKey, aptosSignBytes, aptosSignBytesFromPrivateKey
    • transfer lifecycle: aptosBuildTx, aptosSignTx (native-transfer)
    • signed-tx review: aptosInspectSignedTx, aptosDecodeSignedTx
    • one-shot transfer signing: aptosBuildAndSign, aptosBuildAndSignFromPrivateKey
    • current scope: wallet derivation + restore plus native APT transfer and offline message/bytes signing; signer/build helpers emit SDK JSON envelopes together with raw/signed BCS hex, inspect/decode currently targets SDK-generated signed JSON envelopes, derivation uses ed25519 path m/44'/637'/account'/0'/index', aptosSignMessage* signs UTF-8 text, and aptosSignBytes* signs raw bytes
  • Dogecoin core API:
    • wallet management: dogecoinDeriveAddress, dogecoinDeriveWallet, dogecoinDeriveAddressFromPrivateKey, dogecoinDeriveWalletFromPrivateKey
    • message signing: dogecoinSignMessage, dogecoinSignMessageFromPrivateKey, dogecoinSignBytes, dogecoinSignBytesFromPrivateKey
    • transfer lifecycle: dogecoinBuildTx, dogecoinSignTx (native-transfer)
    • signed-tx review: dogecoinInspectSignedTx, dogecoinDecodeSignedTx
    • one-shot transfer signing: dogecoinBuildAndSign, dogecoinBuildAndSignFromPrivateKey
    • current scope: P2PKH wallet derivation + restore plus native DOGE transfer and offline message/bytes signing; private-key restore accepts hex / base64 or Dogecoin WIF, dogecoinSignMessage* signs UTF-8 text with secp256k1/SHA-256, dogecoinSignBytes* signs raw bytes with secp256k1/SHA-256, build/sign helpers emit SDK JSON envelopes together with unsigned/signed transaction hex and txid, and inspect/decode currently target SDK-generated signed JSON envelopes
  • Cardano core API:
    • wallet management: cardanoDeriveAddress, cardanoDeriveWallet, cardanoDeriveAddressFromPrivateKey, cardanoDeriveWalletFromPrivateKey
    • message signing: cardanoSignMessage, cardanoSignMessageFromPrivateKey, cardanoSignBytes, cardanoSignBytesFromPrivateKey
    • transfer lifecycle: cardanoBuildTx, cardanoSignTx (native-payment)
    • signed-tx review: cardanoInspectSignedTx, cardanoDecodeSignedTx
    • one-shot transfer signing: cardanoBuildAndSign, cardanoBuildAndSignFromPrivateKey
    • current scope: enterprise-address derivation + restore plus native ADA payment and offline message/bytes signing; signer/build helpers emit SDK JSON envelopes together with transaction-body / signing-hash / signed-transaction hex, inspect/decode currently targets SDK-generated signed JSON envelopes, derivation uses m/1852'/1815'/account'/0/index', cardanoSignMessage* signs UTF-8 text, and cardanoSignBytes* signs raw bytes
  • Cosmos core API:
    • wallet management: cosmosDeriveAddress, cosmosDeriveWallet, cosmosDeriveAddressFromPrivateKey, cosmosDeriveWalletFromPrivateKey
    • message signing: cosmosSignMessage, cosmosSignMessageFromPrivateKey, cosmosSignBytes, cosmosSignBytesFromPrivateKey
    • transfer lifecycle: cosmosBuildTx, cosmosSignTx (native-transfer / MsgSend)
    • signed-tx review: cosmosInspectSignedTx, cosmosDecodeSignedTx
    • one-shot transfer signing: cosmosBuildAndSign, cosmosBuildAndSignFromPrivateKey
    • current scope: Cosmos SDK secp256k1 derivation + restore plus native MsgSend and offline message/bytes signing; signer/build helpers emit SDK JSON envelopes together with sign-doc body/auth-info bytes and signed tx bytes, inspect/decode currently targets SDK-generated signed JSON envelopes, derivation uses m/44'/118'/account'/0/index, cosmosSignMessage* signs UTF-8 text with secp256k1/SHA-256, and cosmosSignBytes* signs raw bytes with secp256k1/SHA-256
  • Polkadot core API:
    • wallet management: polkadotDeriveAddress, polkadotDeriveWallet, polkadotDeriveAddressFromPrivateKey, polkadotDeriveWalletFromPrivateKey
    • message signing: polkadotSignMessage, polkadotSignMessageFromPrivateKey, polkadotSignBytes, polkadotSignBytesFromPrivateKey
    • transfer lifecycle: polkadotBuildTx, polkadotSignTx (native-transfer)
    • signed-tx review: polkadotInspectSignedTx, polkadotDecodeSignedTx
    • one-shot transfer signing: polkadotBuildAndSign, polkadotBuildAndSignFromPrivateKey
    • current scope: Polkadot SS58 prefix 0 derivation + restore and offline ed25519 message/bytes signing; transaction lifecycle currently supports native-transfer with caller-supplied runtime metadata such as specVersion, transactionVersion, genesisHashHex, and blockHashHex; polkadotSignMessage* signs UTF-8 text, polkadotSignBytes* signs raw bytes, and inspect/decode currently target SDK-generated signed JSON envelopes
  • NEAR core API:
    • wallet management: nearDeriveAddress, nearDeriveWallet, nearDeriveAddressFromPrivateKey, nearDeriveWalletFromPrivateKey
    • message signing: nearSignMessage, nearSignMessageFromPrivateKey, nearSignBytes, nearSignBytesFromPrivateKey
    • transfer lifecycle: nearBuildTx, nearSignTx (native-transfer)
    • signed-tx review: nearInspectSignedTx, nearDecodeSignedTx
    • one-shot transfer signing: nearBuildAndSign, nearBuildAndSignFromPrivateKey
    • current scope: implicit-account derivation + restore plus native NEAR transfer and ed25519 message/bytes signing; signer/build helpers emit SDK JSON envelopes together with unsigned/signed transaction bytes, inspect/decode currently target SDK-generated signed JSON envelopes, derivation uses hardened ed25519 path m/44'/397'/account'/0'/index', private-key restore accepts 32-byte seed, 64-byte keypair bytes, or ed25519: secret-key text, nearSignMessage* signs UTF-8 text, and nearSignBytes* signs raw bytes
  • Stellar core API:
    • wallet management: stellarDeriveAddress, stellarDeriveWallet, stellarDeriveAddressFromPrivateKey, stellarDeriveWalletFromPrivateKey
    • message signing: stellarSignMessage, stellarSignMessageFromPrivateKey, stellarSignBytes, stellarSignBytesFromPrivateKey
    • transfer lifecycle: stellarBuildTx, stellarSignTx (native-payment)
    • signed-tx review: stellarInspectSignedTx, stellarDecodeSignedTx for SDK-generated signed JSON envelopes
    • one-shot transfer signing: stellarBuildAndSign, stellarBuildAndSignFromPrivateKey
    • current scope: wallet derivation + restore plus native XLM payment and offline message/bytes signing; build/sign helpers emit SDK JSON envelopes together with unsigned/signed XDR base64, inspect/decode currently targets SDK-generated signed JSON envelopes, mnemonic path uses SLIP-0010 ed25519 m/44'/148'/account', mnemonic derivation currently supports index=0 only, private-key restore accepts 32-byte seed, 64-byte keypair bytes, or StrKey secret seed text, stellarSignMessage* signs UTF-8 text, and stellarSignBytes* signs raw bytes
  • SUI core API:
    • wallet management: suiDeriveAddress, suiDeriveWallet, suiDeriveAddressFromPrivateKey, suiDeriveWalletFromPrivateKey
    • message signing: suiSignMessage, suiSignMessageFromPrivateKey, suiSignBytes, suiSignBytesFromPrivateKey
    • transfer lifecycle: suiBuildTx, suiSignTx (native-transfer)
    • signed-tx review: suiInspectSignedTx, suiDecodeSignedTx for SDK-generated signed JSON envelopes
    • one-shot transfer signing: suiBuildAndSign, suiBuildAndSignFromPrivateKey
    • current scope: native SUI transfer plus offline message/bytes signing; caller provides gas object reference, gas budget, and gas price, suiSignMessage* signs UTF-8 text, and suiSignBytes* signs raw bytes
  • Starknet core API:
    • wallet management: starknetDeriveAddress, starknetDeriveWallet, starknetDeriveAddressFromPrivateKey, starknetDeriveWalletFromPrivateKey
    • message signing: starknetSignMessage, starknetSignMessageFromPrivateKey, starknetSignBytes, starknetSignBytesFromPrivateKey
    • transaction hash lifecycle: starknetBuildTx, starknetSignTx, starknetInspectSignedTx, starknetDecodeSignedTx
    • one-shot hash signing: starknetBuildAndSign, starknetBuildAndSignFromPrivateKey
    • account helper: starknetComputeAccountAddress
    • current scope: Stark curve key derivation + restore, OpenZeppelin AccountUpgradeable address precompute using constructor calldata [publicKey], and offline signature envelopes for app-supplied Starknet transaction hashes; RPC fee estimation, v3 transaction-hash construction, broadcasting, and deployed-account state remain app-layer responsibilities
  • TON core API:
    • wallet management: tonDeriveAddress, tonDeriveWallet, tonDeriveAddressFromPrivateKey, tonDeriveWalletFromPrivateKey
      • derive controls: walletVersion: "v4r2" | "v5r1" and addressFormat (user-friendly or raw, plus bounceable / testOnly / urlSafe)
    • transfer lifecycle: tonBuildTx, tonSignTx (native-transfer + jetton-transfer)
    • signed-tx review: tonInspectSignedTx, tonDecodeSignedTx (wallet v5r1 single send-action summaries for native transfer and jetton transfer)
    • one-shot transfer signing: tonBuildAndSign, tonBuildAndSignFromPrivateKey
    • current scope: derive supports v4r2 and v5r1; transfer remains wallet v5r1 only, and signed-tx review/decode currently targets the single send-action path produced by this SDK
    • important boundary: TON mnemonic semantics are separate from generic BIP-39 helpers, so wallets.importMnemonic does not include TON
  • TRON core API:
    • wallet management: tronDeriveAddress, tronDeriveWallet, tronDeriveAddressFromPrivateKey, tronDeriveWalletFromPrivateKey
    • message / bytes signing: tronSignMessage, tronSignMessageFromPrivateKey, tronSignBytes, tronSignBytesFromPrivateKey
    • transfer lifecycle: tronBuildTx, tronSignTx (trx-transfer + trc20-transfer)
    • signed-tx review: tronInspectSignedTx, tronDecodeSignedTx (covers TransferContract and TriggerSmartContract/TRC20 transfer summaries)
    • one-shot transfer signing: tronBuildAndSign, tronBuildAndSignFromPrivateKey
    • message signing uses the TRON prefix + Keccak/secp256k1 policy; signMessage* is UTF-8 only and signBytes* signs raw bytes
  • Low-level fallback:
    • invokeChainExtension is kept only as escape hatch for chain-specific experiments.

Migration Guide (0.1.14)

Starting from 0.1.14, app code should use chain-specific core APIs by default.

Recommended migration:

| Previous style | Chain-specific style | | --- | --- | | deriveAddress({ chainId: "btc", ... }) | btc.deriveAddress({ ... }) (or btcDeriveAddress) | | deriveWallet({ chainId: "btc", ... }) | btc.deriveWallet({ ... }) (or btcDeriveWallet) | | deriveAddressFromPrivateKey({ chainId: "eth", ... }) | eth.deriveAddressFromPrivateKey({ ... }) (or ethDeriveAddressFromPrivateKey) | | buildAndSign({ chainId: "solana", ... }) | solana.buildAndSign({ ... }) (or solanaBuildAndSign) | | signMessage({ chainId: "eth", ... }) | eth.signMessage({ ... }) (or ethSignMessage) | | signBytes({ chainId: "btc", ... }) | btc.signBytes({ ... }) (or btcSignBytes) | | signTypedData({ chainId: "eth", ... }) | eth.signTypedData({ ... }) (or ethSignTypedData) |

Before:

await signMessage({
  chainId: "btc",
  mnemonic,
  account: 0,
  index: 0,
  message: "hello",
});

After:

await btc.signMessage({
  mnemonic,
  account: 0,
  index: 0,
  message: "hello",
});

invokeChainExtension is still supported, but treat it as low-level fallback, not the primary wallet integration path.

Chain Capability Matrix

The matrix is generated from chain adapter source and validated in CI. Sync command:

node ./scripts/check-capability-matrix.mjs --write

| chainId | deriveAddress | deriveAddressFromPrivateKey | deriveWallet | deriveWalletFromPrivateKey | buildAndSign | buildAndSignFromPrivateKey | signBytes | signBytesFromPrivateKey | signMessage | signMessageFromPrivateKey | signTypedData | signTypedDataFromPrivateKey | buildTx | signTx | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | aptos | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | btc | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | cardano | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | cosmos | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | dogecoin | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | eth | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | Yes | Yes | Yes | Yes | | near | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | polkadot | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | solana | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | stellar | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | sui | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | ton | Yes | Yes | Yes | Yes | Yes | Yes | No | No | No | No | No | No | Yes | Yes | | tron | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | No | Yes | Yes | | xrpl | Yes | Yes | Yes | Yes | Yes | Yes | No | No | No | No | No | No | Yes | Yes |

Signing Semantics By Chain

signMessage, signBytes, and signTypedData are chain-specific. Do not assume one chain's signing semantics on another chain.

| chainId | signMessage | signBytes | signTypedData | | --- | --- | --- | --- | | eth | EIP-191 style message hash signing (hash_message) | Not supported | EIP-712 typed data signing. typedData must be valid EIP-712 JSON | | btc | Supports mode: "ecdsa" \| "bip322-simple" (ecdsa default) | Signs provided raw bytes with BTC secp256k1 flow | Not supported | | cosmos | Signs UTF-8 text with secp256k1 over SHA-256 (messageEncoding fixed to utf8) | Signs provided raw bytes with secp256k1 over SHA-256 | Not supported | | dogecoin | Signs UTF-8 text with secp256k1 over SHA-256 (messageEncoding fixed to utf8) | Signs provided raw bytes with secp256k1 over SHA-256 | Not supported | | near | Signs UTF-8 text message with ed25519 (messageEncoding fixed to utf8) | Signs provided raw bytes with ed25519 | Not supported | | polkadot | Signs UTF-8 text message with ed25519 (messageEncoding fixed to utf8) | Signs provided raw bytes with ed25519 | Not supported | | solana | Signs UTF-8 text message with ed25519 (messageEncoding fixed to utf8) | Signs provided raw bytes with ed25519 | Not supported |

For btc, cosmos, dogecoin, near, polkadot, and solana, signatures depend on exact input bytes. Keep serialization deterministic across client/server. For cosmos, dogecoin, near, polkadot, and solana, use *SignBytes* for binary payloads (hex/base64); *SignMessage* is reserved for human-readable UTF-8 message text.

Chain-Specific Core API

The SDK is now organized by chain core capabilities instead of forcing everything into homogeneous APIs.

  • BTC:
    • account/address: btcDeriveAddress, btcDeriveWallet, btcDeriveAddressFromPrivateKey, btcDeriveWalletFromPrivateKey
    • signing: btcBuildAndSign, btcBuildAndSignFromPrivateKey, btcBuildTx, btcSignTx, btcSignMessage*, btcSignBytes*
    • PSBT: btcBuildPsbt, btcSignPsbt, btcSignPsbtWithSigners, btcPartialSignPsbt, btcVerifyPsbtFinalized, btcInspectPsbt
    • FROST key setup: btcFrostTrustedDealerKeygen, btcFrostDkgRound1, btcFrostDkgRound2, btcFrostDkgFinalize
    • FROST share lifecycle helpers: btcFrostRefreshRound1, btcFrostRefreshRound2, btcFrostRefreshFinalize, btcFrostReshareRound1, btcFrostReshareRound2, btcFrostReshareFinalize
    • FROST public-state guards: btcFrostValidateShare, btcFrostValidatePublicState, btcFrostCompareGroupPublicKey
    • FROST threshold signing: btcFrostRound1Commit, btcFrostBuildSigningPackage, btcFrostRound2SignShare, btcFrostAggregateSignature, btcFrostTaprootComputeTweak, btcFrostVerifySignatureShare
    • FROST nonce lifecycle guard: btcFrostNonceSessionScope, btcFrostResetNonceGuard
    • FROST Taproot PSBT bridge: btcFrostBuildTaprootPsbtSigningInputs, btcFrostFinalizeTaprootPsbt
    • FROST offline orchestration: createBtcFrostDkgSession, runBtcFrostDkgSession, createBtcFrostSigningSession, runBtcFrostSigningSession, createBtcFrostRefreshSession, runBtcFrostRefreshSession, createBtcFrostReshareSession, runBtcFrostReshareSession
  • ETH:
    • account/address: ethDeriveAddress, ethDeriveWallet, ethDeriveAddressFromPrivateKey, ethDeriveWalletFromPrivateKey
    • signing: ethBuildAndSign, ethBuildAndSignFromPrivateKey, ethBuildTx, ethSignTx, ethSignMessage*, ethSignTypedData*
    • verification/recovery: ethEcrecover, ethRecoverTypedDataSigner, ethDecodeSignedTx
    • contract-wallet helpers (EIP-1271): ethBuildEip1271IsValidSignatureCall, ethBuildEip1271RpcCall, ethVerifyEip1271IsValidSignatureResult, ethBuildEip1271RpcCallAndVerify
    • account-abstraction helpers (EIP-4337): ethBuildUserOperationHashInput, ethValidateUserOperation, ethComputeUserOperationHash, ethSignUserOperation, ethRecoverUserOperationSigner
    • app-layer orchestration reference: docs/eth-eip1271-consumer-template.md
  • SOL:
    • account/address: solanaDeriveAddress, solanaDeriveWallet, solanaDeriveAddressFromPrivateKey, solanaDeriveWalletFromPrivateKey
    • signing: solanaBuildAndSign, solanaBuildAndSignFromPrivateKey, solanaBuildTx, solanaSignTx, solanaInspectSignedTx (incl. versioned_message path + multi-signer state), solanaSignMessage*, solanaSignBytes*
    • app-layer multi-signer orchestration reference: docs/solana-multisigner-consumer-template.md

invokeChainExtension remains available as a low-level escape hatch, but app code should prefer chain-specific core APIs.

BTC FROST DKG Flow

The SDK supports two key-setup modes for BTC FROST Taproot:

  • Trusted dealer setup:
    • btcFrostTrustedDealerKeygen
  • Decentralized DKG setup:
    • btcFrostDkgRound1 -> btcFrostDkgRound2 -> btcFrostDkgFinalize

Recommended coordinator process for DKG:

  1. each participant runs btcFrostDkgRound1; coordinator collects coefficientCommitmentsHex.
  2. each participant runs btcFrostDkgRound2; coordinator routes shares[].toIdentifier.
  3. each participant runs btcFrostDkgFinalize with full round1 commitments + routed shares.
  4. coordinator verifies all finalize outputs have identical groupPublicKeyXOnlyHex.

Production offline orchestration helper:

  • createBtcFrostDkgSession(config) gives a stateful session object with:
    • round request builders (buildRound1Request, buildRound2Request, buildFinalizeRequest)
    • per-round replay protection (acceptRound1Result, acceptRound2Result, acceptFinalizeResult)
    • persistence hooks (toState, BtcFrostDkgSession.fromState)
  • runBtcFrostDkgSession(config) runs round1/round2/finalize end-to-end using SDK executor defaults.

Coordinator helper example:

const dkg = await runBtcFrostDkgSession({
  threshold: 2,
  participants: 3,
});
// dkg.groupPublicKeyXOnlyHex
// dkg.participants[i].secretShareHex (store per participant securely)

Refresh/Reshare boundary helpers (0.2.8+ API surface):

  • btcFrostRefreshRound1/2/Finalize
  • btcFrostReshareRound1/2/Finalize
  • btcFrostValidateShare
  • btcFrostValidatePublicState
  • btcFrostCompareGroupPublicKey
  • session helpers:
    • createBtcFrostRefreshSession, runBtcFrostRefreshSession
    • createBtcFrostReshareSession, runBtcFrostReshareSession

Signing orchestration helpers (0.2.14+ API surface):

  • createBtcFrostSigningSession:
    • stateful signing session with replay protection
    • supports toState / BtcFrostSigningSession.fromState
    • explicit steps: round1 commit -> build signing package -> round2 shares -> aggregate
  • runBtcFrostSigningSession:
    • one-call offline runner for the full signing path
    • consumes participant identifiers + per-participant secret shares

These APIs are offline primitives for consumer-side orchestration. Coordinator policy (refresh cadence, roster governance, approval flow, transport) stays in app/backend layer.

After setup (trusted dealer or DKG), run threshold signing with:

  1. btcFrostRound1Commit
  2. btcFrostBuildSigningPackage
  3. btcFrostRound2SignShare
  4. btcFrostAggregateSignature

Nonce lifecycle guard:

  • btcFrostRound2SignShare now enforces one-time use for each nonceSecretHex within process lifecycle; nonce reuse will be rejected.

For Taproot output-key context, apply:

  • btcFrostTaprootComputeTweak

FROST offline verification + PSBT bridge:

  • btcFrostVerifySignatureShare (single-share verification / blame attribution)
  • btcFrostBuildTaprootPsbtSigningInputs (extract per-input Taproot key-spend message hashes)
  • btcFrostFinalizeTaprootPsbt (inject aggregated Schnorr signatures into PSBT inputs)

Consumer orchestration references:

  • DKG template: docs/btc-frost-dkg-consumer-template.md
  • signing-session + PSBT bridge template: docs/btc-frost-signing-session-consumer-template.md

Types

type SupportedChainInfo = {
  chainId: string;
  capabilities: string[];
};

type ChainExtensionInfo = {
  chainId: string;
  methods: string[];
};

type DeriveAddressRequest = {
  chainId: string;
  mnemonic: string;
  account: number; // uint32
  index: number; // uint32
  passphrase?: string | null;
};

type DeriveAddressFromPrivateKeyRequest = {
  chainId: string;
  privateKey: string;
  keyEncoding?: "utf8" | "hex" | "base64" | "wif"; // default: hex
};

type DerivedWallet = {
  address: string;
  privateKey: string;
  privateKeyEncoding: "hex" | "base58" | "wif";
  publicKey: string;
  publicKeyEncoding: "hex" | "base58" | "wif";
};

type BuildAndSignRequest = {
  chainId: string;
  mnemonic: string;
  txPayload: string;
  txEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type BuildAndSignResult = {
  chainId: string;
  signedTxHex: string;
};

type BuildAndSignFromPrivateKeyRequest = {
  chainId: string;
  privateKey: string;
  keyEncoding?: "utf8" | "hex" | "base64" | "wif"; // default: hex
  txPayload: string;
  txEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type BuildAndSignFromPrivateKeyResult = BuildAndSignResult;

type BtcSignMessageMode = "ecdsa" | "bip322-simple";

type SignMessageRequest = {
  chainId: string;
  mnemonic: string;
  account: number;
  index: number;
  passphrase?: string | null;
  message: string;
  messageEncoding?: "utf8" | "hex" | "base64"; // default: utf8
  mode?: BtcSignMessageMode; // btc only, default: ecdsa
};

type SignMessageFromPrivateKeyRequest = {
  chainId: string;
  privateKey: string;
  keyEncoding?: "utf8" | "hex" | "base64" | "wif"; // default: hex
  message: string;
  messageEncoding?: "utf8" | "hex" | "base64"; // default: utf8
  mode?: BtcSignMessageMode; // btc only, default: ecdsa
};

type SignBytesRequest = {
  chainId: string;
  mnemonic: string;
  account: number;
  index: number;
  passphrase?: string | null;
  bytes: string;
  bytesEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type SignBytesFromPrivateKeyRequest = {
  chainId: string;
  privateKey: string;
  keyEncoding?: "utf8" | "hex" | "base64" | "wif"; // default: hex
  bytes: string;
  bytesEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type SignTypedDataRequest = {
  chainId: string;
  mnemonic: string;
  account: number;
  index: number;
  passphrase?: string | null;
  typedData: string;
  typedDataEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type SignTypedDataFromPrivateKeyRequest = {
  chainId: string;
  privateKey: string;
  keyEncoding?: "utf8" | "hex" | "base64" | "wif"; // default: hex
  typedData: string;
  typedDataEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type SignResult = {
  chainId: string;
  signatureHex: string;
};

type InvokeChainExtensionRequest = {
  chainId: string;
  method: string;
  payload: string;
  payloadEncoding?: "utf8" | "hex" | "base64"; // default: utf8
};

type EthEcrecoverRequest = {
  message: string;
  messageEncoding?: "utf8" | "hex" | "base64"; // default: utf8
  signature: string;
  signatureEncoding?: "hex" | "base64"; // default: hex
};

type BtcNetwork = "mainnet" | "testnet" | "signet" | "regtest";
type BtcAddressType = "p2pkh" | "p2sh-p2wpkh" | "p2wpkh" | "p2tr";

type BtcDeriveAddressRequest = {
  mnemonic: string;
  account?: number; // default: 0
  change?: number; // default: 0
  index?: number; // default: 0
  passphrase?: string | null;
  network?: BtcNetwork; // default: mainnet
  addressType?: BtcAddressType; // default: p2pkh
};

type BtcDeriveAddressFromPrivateKeyRequest = {
  privateKey: string;
  keyEncoding?: "utf8" | "hex" | "wif"; // default: wif
  network?: BtcNetwork; // default: mainnet
  addressType?: BtcAddressType; // default: p2pkh
};

type BtcDerivedWallet = DerivedWallet & {
  network: BtcNetwork;
  addressType: BtcAddressType;
};

BTC API Notes

  • btcDeriveAddress / btcDeriveWallet support:
    • network: mainnet, testnet, signet, regtest (default mainnet)
    • addressType: p2pkh, p2sh-p2wpkh, p2wpkh, p2tr (default p2pkh)
  • btcDeriveWallet returns:
    • privateKey in WIF (privateKeyEncoding: "wif")
    • compressed publicKey in hex (publicKeyEncoding: "hex")
  • btcDeriveWalletFromPrivateKey accepts both:
    • WIF private key (keyEncoding: "wif")
    • hex private key (keyEncoding: "hex")
  • btcSignPsbt is strict finalize path:
    • uses one private key
    • requires all inputs to be finalizable in one call
  • btcSignPsbtWithSigners supports production multi-signer orchestration:
    • accepts multiple signer keys in one call
    • optional targetInputIndexes per signer
    • supports finalize: false for round-based signing and finalize: true for strict completion
  • btcBuildPsbt / btcBuildTx support both:
    • single-input fallback (prevTxid, prevVout, prevScriptPubkeyHex, prevValueSat)
    • multi-UTXO mode (inputs[] with per-input txid, vout, scriptPubkeyHex, valueSat, optional derivation path selectors)
  • btcPartialSignPsbt is non-finalizing friendly:
    • signs only inputs controlled by the provided key
    • returns finalized + missingFinalizedInputs so multi-party rounds can continue
  • DKG orchestration helpers (0.2.7+):
    • createBtcFrostDkgSession: stateful coordinator with replay protection and toState/fromState
    • runBtcFrostDkgSession: round1/round2/finalize convenience runner for offline coordinator workflows
  • signing orchestration helpers (0.2.14+):
    • createBtcFrostSigningSession: stateful signing coordinator with replay protection and toState/fromState
    • runBtcFrostSigningSession: round1/build/round2/aggregate convenience runner for offline coordinator workflows
  • SDK public API is chain-first:
    • prefer btc.* namespace (or btcXxx flat chain-specific exports)
    • do not route wallet operations through generic chainId-based aggregator methods

Example

import {
  btcBuildPsbt,
  btcBuildTx,
  btcDeriveAddress,
  btcDeriveWallet,
  btcDeriveAddressFromPrivateKey,
  btcDeriveWalletFromPrivateKey,
  btcPartialSignPsbt,
  btcSignPsbt,
  btcSignPsbtWithSigners,
  btcSignTx,
  btcVerifyPsbtFinalized,
  ethBuildAndSignFromPrivateKey,
  ethDeriveAddressFromPrivateKey,
  ethSignMessage,
  generateMnemonic,
  validateMnemonic,
  init,
  listSupportedChains,
  ethEcrecover,
} from "@bubolabs/wallet-rn-sdk";

const mnemonic = await generateMnemonic();
const isValid = await validateMnemonic(mnemonic);
if (!isValid) throw new Error("generated mnemonic must be valid");

await init();
const chains = await listSupportedChains();
const address = await btcDeriveAddress({
  mnemonic,
  account: 0,
  change: 0,
  index: 0,
  passphrase: null,
});

const wallet = await btcDeriveWallet({
  mnemonic,
  account: 0,
  change: 0,
  index: 0,
});
// btc privateKey is WIF
const restoredBtc = await btcDeriveWalletFromPrivateKey({
  privateKey: wallet.privateKey,
  keyEncoding: "wif",
});

const btcTestnetTaproot = await btcDeriveWallet({
  mnemonic,
  account: 0,
  change: 0,
  index: 0,
  network: "testnet",
  addressType: "p2tr",
});

const btcNestedSegwitAddr = await btcDeriveAddressFromPrivateKey({
  privateKey: wallet.privateKey,
  keyEncoding: "wif",
  network: "mainnet",
  addressType: "p2sh-p2wpkh",
});

const signed = await btcBuildAndSign({
  mnemonic,
  txPayload: "<tx payload>",
  txEncoding: "utf8",
});

const signedFromPk = await ethBuildAndSignFromPrivateKey({
  privateKey: "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
  keyEncoding: "hex",
  txPayload: "<tx payload>",
  txEncoding: "utf8",
});

const messageSig = await ethSignMessage({
  mnemonic,
  account: 0,
  index: 0,
  passphrase: null,
  message: "hello from bubo",
  messageEncoding: "utf8",
});

const restored = await ethDeriveAddressFromPrivateKey({
  privateKey: "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
  keyEncoding: "hex",
});

const recovered = await ethEcrecover({
  message: "hello from bubo",
  messageEncoding: "utf8",
  signature: messageSig.signatureHex,
  signatureEncoding: "hex",
});

const builtPsbt = await btcBuildPsbt({
  mnemonic,
  account: 0,
  addressIndex: 0,
  changeIndex: 0,
  network: "testnet",
  addressType: "p2wpkh",
  prevTxid: "6000000000000000000000000000000000000000000000000000000000000006",
  prevVout: 0,
  prevScriptPubkeyHex: "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
  prevValueSat: 100000,
  toAddress: "tb1q4ryc5g5q2sz66mh58f9x7w6j5xw5lf7k0k4a2s",
  amountSat: 10000,
  feeSat: 1000,
});

const builtPsbtMultiInput = await btcBuildPsbt({
  mnemonic,
  account: 0,
  addressIndex: 0,
  changeIndex: 0,
  network: "testnet",
  addressType: "p2wpkh",
  inputs: [
    {
      txid: "7000000000000000000000000000000000000000000000000000000000000007",
      vout: 0,
      scriptPubkeyHex: "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
      valueSat: 60000,
    },
    {
      txid: "8000000000000000000000000000000000000000000000000000000000000008",
      vout: 1,
      scriptPubkeyHex: "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
      valueSat: 50000,
    },
  ],
  toAddress: "tb1q4ryc5g5q2sz66mh58f9x7w6j5xw5lf7k0k4a2s",
  amountSat: 100000,
  feeSat: 1000,
});

const signedPsbt = await btcSignPsbt({
  psbt: builtPsbt.psbtHex,
  privateKey: wallet.privateKey, // WIF
  keyEncoding: "wif",
  network: "testnet",
});

const signedByMultiSigners = await btcSignPsbtWithSigners({
  psbt: builtPsbtMultiInput.psbtHex,
  network: "testnet",
  finalize: false,
  signers: [
    {
      privateKey: wallet.privateKey, // WIF
      keyEncoding: "wif",
      targetInputIndexes: [0],
    },
  ],
});

const partiallySigned = await btcPartialSignPsbt({
  psbt: builtPsbt.psbtHex,
  privateKey: wallet.privateKey, // WIF
  keyEncoding: "wif",
  network: "testnet",
});

const builtTx = await btcBuildTx({
  mnemonic,
  account: 0,
  addressIndex: 0,
  changeIndex: 0,
  network: "testnet",
  addressType: "p2wpkh",
  prevTxid: "6000000000000000000000000000000000000000000000000000000000000006",
  prevVout: 0,
  prevScriptPubkeyHex: "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
  prevValueSat: 100000,
  toAddress: "tb1q4ryc5g5q2sz66mh58f9x7w6j5xw5lf7k0k4a2s",
  amountSat: 10000,
  feeSat: 1000,
});

const signedTx = await btcSignTx({
  psbt: builtTx.psbtHex,
  privateKey: wallet.privateKey, // WIF
  keyEncoding: "wif",
  network: "testnet",
});

const verifiedPsbt = await btcVerifyPsbtFinalized({
  psbt: signedTx.psbtHex,
});

txPayload JSON Examples

txEncoding uses "utf8" by default, so pass JSON text directly. For full canonical schemas (required/optional/default fields), see repo doc: docs/chain-payload-schemas.md.

BTC:

{
  "account": 0,
  "address_index": 0,
  "change_index": 0,
  "network": "mainnet",
  "address_type": "p2pkh",
  "prev_txid": "0000000000000000000000000000000000000000000000000000000000000001",
  "prev_vout": 0,
  "prev_script_pubkey_hex": "76a914d986ed01b7a22225a70edbf2ba7cfb63a15cb3aa88ac",
  "prev_value_sat": 100000,
  "to_address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
  "amount_sat": 10000,
  "fee_sat": 1000,
  "lock_time": 0,
  "sequence": 4294967295
}

address_type supports p2pkh, p2sh-p2wpkh, p2wpkh, p2tr (default p2pkh).

ETH (legacy transfer):

{
  "account": 0,
  "index": 0,
  "chain_id": 1,
  "nonce": 0,
  "gas_price_wei": "1000000000",
  "gas_limit": 21000,
  "to_address": "0x1111111111111111111111111111111111111111",
  "value_wei": "1000000000000000"
}

ETH (EIP-1559 transfer):

{
  "account": 0,
  "index": 0,
  "chain_id": 1,
  "nonce": 0,
  "max_fee_per_gas_wei": "1000000000",
  "max_priority_fee_per_gas_wei": "100000000",
  "gas_limit": 21000,
  "to_address": "0x1111111111111111111111111111111111111111",
  "value_wei": "1000000000000000"
}

For ETH tx payload, use either legacy (gas_price_wei) or EIP-1559 (max_fee_per_gas_wei + max_priority_fee_per_gas_wei), not both.

ETH build-path APIs (ethBuildTx, ethBuildAndSign*, and generic buildAndSign* with chainId: "eth") run adapter preflight checks for txEncoding: "utf8" JSON payloads:

  • required fields: nonce, gas_limit, to_address
  • fee-model exclusivity: legacy vs EIP-1559 cannot be mixed
  • EIP-1559 constraint: max_priority_fee_per_gas_wei <= max_fee_per_gas_wei
  • supports camelCase aliases and normalizes to snake_case before native call: chainId, gasLimit, toAddress, gasPriceWei, maxFeePerGasWei, maxPriorityFeePerGasWei, valueWei, dataHex

Solana (system transfer):

{
  "tx_kind": "system_transfer",
  "account": 0,
  "index": 0,
  "to_address": "11111111111111111111111111111111",
  "lamports": 1000,
  "message_version": "legacy",
  "recent_blockhash": "11111111111111111111111111111111"
}

Solana (SPL token transfer, transferChecked):

{
  "tx_kind": "spl_token_transfer",
  "account": 0,
  "index": 0,
  "source_token_account": "11111111111111111111111111111111",
  "destination_token_account": "11111111111111111111111111111111",
  "mint_address": "11111111111111111111111111111111",
  "amount": 1000,
  "decimals": 6,
  "message_version": "legacy",
  "recent_blockhash": "11111111111111111111111111111111"
}

Solana (high-level v0 compile with ALT lookup tables):

{
  "tx_kind": "system_transfer",
  "account": 0,
  "index": 0,
  "to_address": "11111111111111111111111111111111",
  "lamports": 1000,
  "message_version": "v0",
  "address_lookup_tables": [
    {
      "table_address": "11111111111111111111111111111111",
      "addresses": ["11111111111111111111111111111111"]
    }
  ],
  "recent_blockhash": "11111111111111111111111111111111"
}

Solana (precompiled versioned message, including ALT-compiled message bytes):

{
  "tx_kind": "versioned_message",
  "versioned_message": "<base64-serialized-VersionedMessage>",
  "versioned_message_encoding": "base64"
}

For Solana tx payload:

  • tx_kind defaults to system_transfer when omitted.
  • spl_token_transfer uses SPL Token program transferChecked (amount in raw token units).
  • optional token_program_id can override the default SPL Token program id.
  • message_version supports legacy (default) and v0.
  • address_lookup_tables can be provided when message_version=v0; each table has table_address + addresses[].
  • versioned_message lets app/backend provide precompiled message bytes (ALT flows included).
  • for versioned_message, recent_blockhash is not required in payload (already embedded in message bytes).
  • for solanaBuildTx + versioned_message, signer fields are optional; for other Solana tx kinds signer is required.

Chain Feature Notes

  • Published package content depends on Rust feature set at build time.
  • When BUBO_RUST_FEATURES is not set, packaging auto-enables all chain-* features from crates/ffi/Cargo.toml.
  • signMessage* is implemented for eth, btc, solana, near, cosmos, and starknet.
  • signBytes* is implemented for btc, solana, near, cosmos, and starknet.
  • signTypedData* is implemented only for eth.
  • You can still override for focused builds, for example:
BUBO_RUST_FEATURES=chain-eth,chain-btc,chain-ton ./scripts/build-rn-sdk-native-artifacts.sh

Compatibility Smoke API

Legacy smoke APIs remain available for regression checks:

  • runSmoke()
  • runBtcSmoke()
type WalletSmokeResult = {
  supportedChains: Array<{ chainId: string; capabilities: string[] }>;
  deriveChainId: string;
  derivedAddress: string;
  signChainId: string | null;
  signedTxHex: string | null;
};

Distribution Scripts

cd ../..
./scripts/package-rn-sdk.sh

Builds a publishable tarball and verifies runtime assets are present/synced.

./scripts/verify-rn-sdk-distribution.sh

Installs the tarball into example/ and verifies iOS/Android native builds.

./scripts/publish-rn-sdk.sh --dry-run
./scripts/publish-rn-sdk.sh --publish --tag latest

Publish wrapper:

  • default is dry-run
  • real publish requires --publish