@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 moduleios/Pod sources + vendoredBuboWalletFFI.xcframeworkreact-native.config.jsfor Android package registration
Install
npm install @bubolabs/wallet-rn-sdkiOS:
cd ios && pod installAPI 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 examplebtc.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 | nullSupported 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 chainsdetectAddressChainId(address)returns the chain only when the match is unique- ambiguous addresses return
nullfromdetectAddressChainId(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
- namespaced:
- 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)
- namespaced:
- 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
- wallet management:
- 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
- wallet management:
- SOL core API:
- wallet management:
solanaDeriveAddress,solanaDeriveWallet,solanaDeriveAddressFromPrivateKey,solanaDeriveWalletFromPrivateKey - transaction signing:
solanaBuildAndSign,solanaBuildAndSignFromPrivateKey - transaction lifecycle:
solanaBuildTx,solanaSignTx,solanaInspectSignedTx,solanaDecodeSignedTx(supportsversioned_messagepayload 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
- wallet management:
- 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/decodecurrently targets SDK-generated signed JSON envelopes, derivation uses ed25519 pathm/44'/637'/account'/0'/index',aptosSignMessage*signs UTF-8 text, andaptosSignBytes*signs raw bytes
- wallet management:
- 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, andinspect/decodecurrently target SDK-generated signed JSON envelopes
- wallet management:
- 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/decodecurrently targets SDK-generated signed JSON envelopes, derivation usesm/1852'/1815'/account'/0/index',cardanoSignMessage*signs UTF-8 text, andcardanoSignBytes*signs raw bytes
- wallet management:
- 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
MsgSendand offline message/bytes signing; signer/build helpers emit SDK JSON envelopes together with sign-doc body/auth-info bytes and signed tx bytes,inspect/decodecurrently targets SDK-generated signed JSON envelopes, derivation usesm/44'/118'/account'/0/index,cosmosSignMessage*signs UTF-8 text with secp256k1/SHA-256, andcosmosSignBytes*signs raw bytes with secp256k1/SHA-256
- wallet management:
- 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
0derivation + restore and offline ed25519 message/bytes signing; transaction lifecycle currently supportsnative-transferwith caller-supplied runtime metadata such asspecVersion,transactionVersion,genesisHashHex, andblockHashHex;polkadotSignMessage*signs UTF-8 text,polkadotSignBytes*signs raw bytes, andinspect/decodecurrently target SDK-generated signed JSON envelopes
- wallet management:
- 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/decodecurrently target SDK-generated signed JSON envelopes, derivation uses hardened ed25519 pathm/44'/397'/account'/0'/index', private-key restore accepts32-byte seed,64-byte keypair bytes, ored25519:secret-key text,nearSignMessage*signs UTF-8 text, andnearSignBytes*signs raw bytes
- wallet management:
- 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,stellarDecodeSignedTxfor 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/decodecurrently targets SDK-generated signed JSON envelopes, mnemonic path uses SLIP-0010 ed25519m/44'/148'/account', mnemonic derivation currently supportsindex=0only, private-key restore accepts32-byte seed,64-byte keypair bytes, or StrKey secret seed text,stellarSignMessage*signs UTF-8 text, andstellarSignBytes*signs raw bytes
- wallet management:
- 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,suiDecodeSignedTxfor 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, andsuiSignBytes*signs raw bytes
- wallet management:
- 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
- wallet management:
- TON core API:
- wallet management:
tonDeriveAddress,tonDeriveWallet,tonDeriveAddressFromPrivateKey,tonDeriveWalletFromPrivateKey- derive controls:
walletVersion: "v4r2" | "v5r1"andaddressFormat(user-friendlyorraw, plusbounceable/testOnly/urlSafe)
- derive controls:
- transfer lifecycle:
tonBuildTx,tonSignTx(native-transfer+jetton-transfer) - signed-tx review:
tonInspectSignedTx,tonDecodeSignedTx(walletv5r1single send-action summaries for native transfer and jetton transfer) - one-shot transfer signing:
tonBuildAndSign,tonBuildAndSignFromPrivateKey - current scope: derive supports
v4r2andv5r1; transfer remains walletv5r1only, 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.importMnemonicdoes not include TON
- wallet management:
- 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(coversTransferContractandTriggerSmartContract/TRC20 transfer summaries) - one-shot transfer signing:
tronBuildAndSign,tronBuildAndSignFromPrivateKey - message signing uses the TRON prefix + Keccak/secp256k1 policy;
signMessage*is UTF-8 only andsignBytes*signs raw bytes
- wallet management:
- Low-level fallback:
invokeChainExtensionis 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
- account/address:
- 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
- account/address:
- SOL:
- account/address:
solanaDeriveAddress,solanaDeriveWallet,solanaDeriveAddressFromPrivateKey,solanaDeriveWalletFromPrivateKey - signing:
solanaBuildAndSign,solanaBuildAndSignFromPrivateKey,solanaBuildTx,solanaSignTx,solanaInspectSignedTx(incl.versioned_messagepath + multi-signer state),solanaSignMessage*,solanaSignBytes* - app-layer multi-signer orchestration reference:
docs/solana-multisigner-consumer-template.md
- account/address:
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:
- each participant runs
btcFrostDkgRound1; coordinator collectscoefficientCommitmentsHex. - each participant runs
btcFrostDkgRound2; coordinator routesshares[].toIdentifier. - each participant runs
btcFrostDkgFinalizewith full round1 commitments + routed shares. - 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)
- round request builders (
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/FinalizebtcFrostReshareRound1/2/FinalizebtcFrostValidateSharebtcFrostValidatePublicStatebtcFrostCompareGroupPublicKey- session helpers:
createBtcFrostRefreshSession,runBtcFrostRefreshSessioncreateBtcFrostReshareSession,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:
btcFrostRound1CommitbtcFrostBuildSigningPackagebtcFrostRound2SignSharebtcFrostAggregateSignature
Nonce lifecycle guard:
btcFrostRound2SignSharenow enforces one-time use for eachnonceSecretHexwithin 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/btcDeriveWalletsupport:network:mainnet,testnet,signet,regtest(defaultmainnet)addressType:p2pkh,p2sh-p2wpkh,p2wpkh,p2tr(defaultp2pkh)
btcDeriveWalletreturns:privateKeyin WIF (privateKeyEncoding: "wif")- compressed
publicKeyin hex (publicKeyEncoding: "hex")
btcDeriveWalletFromPrivateKeyaccepts both:- WIF private key (
keyEncoding: "wif") - hex private key (
keyEncoding: "hex")
- WIF private key (
btcSignPsbtis strict finalize path:- uses one private key
- requires all inputs to be finalizable in one call
btcSignPsbtWithSignerssupports production multi-signer orchestration:- accepts multiple signer keys in one call
- optional
targetInputIndexesper signer - supports
finalize: falsefor round-based signing andfinalize: truefor strict completion
btcBuildPsbt/btcBuildTxsupport both:- single-input fallback (
prevTxid,prevVout,prevScriptPubkeyHex,prevValueSat) - multi-UTXO mode (
inputs[]with per-inputtxid,vout,scriptPubkeyHex,valueSat, optional derivation path selectors)
- single-input fallback (
btcPartialSignPsbtis non-finalizing friendly:- signs only inputs controlled by the provided key
- returns
finalized+missingFinalizedInputsso multi-party rounds can continue
- DKG orchestration helpers (
0.2.7+):createBtcFrostDkgSession: stateful coordinator with replay protection andtoState/fromStaterunBtcFrostDkgSession: round1/round2/finalize convenience runner for offline coordinator workflows
- signing orchestration helpers (
0.2.14+):createBtcFrostSigningSession: stateful signing coordinator with replay protection andtoState/fromStaterunBtcFrostSigningSession: round1/build/round2/aggregate convenience runner for offline coordinator workflows
- SDK public API is chain-first:
- prefer
btc.*namespace (orbtcXxxflat chain-specific exports) - do not route wallet operations through generic
chainId-based aggregator methods
- prefer
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_kinddefaults tosystem_transferwhen omitted.spl_token_transferuses SPL Token program transferChecked (amountin raw token units).- optional
token_program_idcan override the default SPL Token program id. message_versionsupportslegacy(default) andv0.address_lookup_tablescan be provided whenmessage_version=v0; each table hastable_address+addresses[].versioned_messagelets app/backend provide precompiled message bytes (ALT flows included).- for
versioned_message,recent_blockhashis 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_FEATURESis not set, packaging auto-enables allchain-*features fromcrates/ffi/Cargo.toml. signMessage*is implemented foreth,btc,solana,near,cosmos, andstarknet.signBytes*is implemented forbtc,solana,near,cosmos, andstarknet.signTypedData*is implemented only foreth.- You can still override for focused builds, for example:
BUBO_RUST_FEATURES=chain-eth,chain-btc,chain-ton ./scripts/build-rn-sdk-native-artifacts.shCompatibility 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.shBuilds a publishable tarball and verifies runtime assets are present/synced.
./scripts/verify-rn-sdk-distribution.shInstalls the tarball into example/ and verifies iOS/Android native builds.
./scripts/publish-rn-sdk.sh --dry-run
./scripts/publish-rn-sdk.sh --publish --tag latestPublish wrapper:
- default is dry-run
- real publish requires
--publish
