Note: This package is currently in beta. Please test thoroughly in development environments before using in production.
A simple and secure package to manage BIP-44 wallets for the Spark blockchain. This package provides a clean API for creating, managing, and interacting with Spark wallets using BIP-39 seed phrases and Liquid Bitcoin (LBTC) derivation paths.
🔍 About WDK
This module is part of the WDK (Wallet Development Kit) project, which empowers developers to build secure, non-custodial wallets with unified blockchain access, stateless architecture, and complete user control.
For detailed documentation about the complete WDK ecosystem, visit docs.wallet.tether.io.
🌟 Features
Liquid Bitcoin (LBTC) Derivation Paths: Support for BIP-44 standard derivation paths (m/44'/998')
Multi-Account Management: Create and manage multiple accounts from a single seed phrase
Transaction Management: Send transactions and get fee estimates with zero fees
To install the @tetherto/wdk-wallet-spark package, follow these instructions:
You can install it using npm:
npm install @tetherto/wdk-wallet-spark
🚀 Quick Start
Importing from @tetherto/wdk-wallet-spark
WalletManagerSpark: Main class for managing wallets
WalletAccountSpark: Use this for full access accounts
WalletAccountReadOnlySpark: Use this for read-only accounts
Creating a New Wallet
import WalletManagerSpark from '@tetherto/wdk-wallet-spark'// Use a BIP-39 seed phrase (replace with your own secure phrase)const seedPhrase = 'test only example nut use this real life secret phrase must random'// Create wallet manager with Spark network configurationconst wallet = new WalletManagerSpark(seedPhrase, { network: 'MAINNET' // 'MAINNET', 'TESTNET', or 'REGTEST'})// Get a full access accountconst account = await wallet.getAccount(0)// Get the account's Spark addressconst address = await account.getAddress()console.log('Account address:', address)
Note: The Spark wallet integrates with the Spark network using the @buildonspark/spark-sdk. Network configuration is limited to predefined networks, and there's no custom RPC provider option.
Managing Multiple Accounts
import WalletManagerSpark from '@tetherto/wdk-wallet-spark'// Assume wallet is already created// Get the first account (index 0)const account = await wallet.getAccount(0)const address = await account.getAddress()console.log('Account 0 address:', address)// Get the second account (index 1)const account1 = await wallet.getAccount(1)const address1 = await account1.getAddress()console.log('Account 1 address:', address1)// Get the third account (index 2)const account2 = await wallet.getAccount(2)const address2 = await account2.getAddress()console.log('Account 2 address:', address2)// Note: All accounts use BIP-44 derivation paths with pattern:// m/44'/998'/{network}'/0/{index} where 998 is the coin type for Liquid Bitcoin// and {network} is the network number (MAINNET=0, TESTNET=1, REGTEST=2)
Important Note: Custom derivation paths via getAccountByPath() are not supported on the Spark blockchain. Only indexed accounts using the standard BIP-44 pattern are available.
Checking Balances
import WalletManagerSpark from '@tetherto/wdk-wallet-spark'// Assume wallet and account are already created// Get native token balance (in satoshis)const balance = await account.getBalance()console.log('Native balance:', balance, 'satoshis')// Get transfer history (default: 10 most recent transfers)const transfers = await account.getTransfers()console.log('Transfer history:', transfers)// Get transfer history with optionsconst recentTransfers = await account.getTransfers({ direction: 'all', // 'all', 'incoming', or 'outgoing' limit: 20, // Number of transfers to fetch skip: 0 // Number of transfers to skip})console.log('Recent transfers:', recentTransfers)// Get only incoming transfersconst incomingTransfers = await account.getTransfers({ direction: 'incoming', limit: 5})console.log('Incoming transfers:', incomingTransfers)
Sending Transactions
// Send native tokens (satoshis)const result = await account.sendTransaction({ to: 'spark1...', // Recipient's Spark address value: 1000000 // Amount in satoshis})console.log('Transaction hash:', result.hash)console.log('Transaction fee:', result.fee) // Always 0 for Spark transactions// Get transaction fee estimateconst quote = await account.quoteSendTransaction({ to: 'spark1...', value: 1000000})console.log('Estimated fee:', quote.fee) // Always returns 0// Example with different amountsconst smallTransaction = await account.sendTransaction({ to: 'spark1...', value: 100000 // 0.001 BTC in satoshis})const largeTransaction = await account.sendTransaction({ to: 'spark1...', value: 10000000 // 0.1 BTC in satoshis})
Important Notes:
Spark transactions have zero fees (fee: 0)
Memo/description functionality is not supported in sendTransaction
All amounts are specified in satoshis (1 BTC = 100,000,000 satoshis)
Note: Uses derivation path pattern m/44'/998'/{network}'/0/{index} where 998 is the coin type for Liquid Bitcoin and {network} is the network number (MAINNET=0, TESTNET=1, REGTEST=2).
getAccountByPath(path)
Not supported on Spark blockchain. This method throws an error when called. Use getAccount(index) instead.
getFeeRates()
Returns current fee rates for Spark transactions from the network.
Returns:Promise<FeeRates> - Object containing fee rates in satoshis
normal: Standard fee rate for normal confirmation speed (always 0)
fast: Higher fee rate for faster confirmation (always 0)
Example:
const feeRates = await wallet.getFeeRates()console.log('Normal fee rate:', feeRates.normal, 'satoshis')console.log('Fast fee rate:', feeRates.fast, 'satoshis')// Use in transaction (fees are always 0 on Spark)const result = await account.sendTransaction({ to: 'spark1...', value: 1000000 // 0.01 BTC in satoshis})
dispose()
Disposes all Spark wallet accounts and clears sensitive data from memory.
Returns:void
Example:
wallet.dispose()// All accounts and private keys are now securely wiped from memory
Important Notes:
All Spark transactions have zero fees
Network configuration is limited to predefined values
Uses BIP-44 derivation paths with coin type 998 for Liquid Bitcoin
WalletAccountReadOnlySpark
A read-only Spark wallet account for querying wallet data without needing private keys. Uses the SparkReadonlyClient from @buildonspark/spark-sdk for all queries.
Constructor
new WalletAccountReadOnlySpark(address, config)
Parameters:
address (string): The account's Spark address
config (object, optional): Configuration object
network (string, optional): 'MAINNET', 'TESTNET', or 'REGTEST' (default: 'MAINNET')
Example:
import { WalletAccountReadOnlySpark } from '@tetherto/wdk-wallet-spark'const readOnly = new WalletAccountReadOnlySpark('sp1pgs...', { network: 'MAINNET'})
Methods
Method
Description
Returns
getBalance()
Returns the available (spendable) bitcoin balance in satoshis
Promise<bigint>
getTokenBalance(tokenAddress)
Returns the available-to-send balance for a specific token
Returns:Promise<{invoiceStatuses: Array, offset: number}> - Invoice statuses with pagination offset
Example:
const result = await readOnly.getSparkInvoices({ invoices: ['spark1invoice1', 'spark1invoice2']})console.log('Invoice statuses:', result.invoiceStatuses)
WalletAccountSpark
Represents an individual Spark wallet account with full write access. Implements IWalletAccount from @tetherto/wdk-wallet. Extends WalletAccountReadOnlySpark, inheriting all read-only methods.
Note: WalletAccountSpark instances are created internally by WalletManagerSpark.getAccount() and are not intended to be constructed directly.
Methods
All methods from WalletAccountReadOnlySpark are inherited. The following additional methods are available:
Method
Description
Returns
getAddress()
Returns the account's Spark address
Promise<SparkAddressFormat>
sign(message)
Signs a message using the account's identity key
Promise<string>
sendTransaction(tx)
Sends a Spark transaction
Promise<{hash: string, fee: bigint}>
transfer(options)
Transfers tokens to another address
Promise<{hash: string, fee: bigint}>
getSingleUseDepositAddress()
Generates a single-use Bitcoin deposit address
Promise<string>
claimDeposit(txId)
Claims a Bitcoin deposit to the wallet
Promise<WalletLeaf[] | undefined>
claimStaticDeposit(txId)
Claims a static Bitcoin deposit to the wallet
Promise<WalletLeaf[] | undefined>
refundStaticDeposit(options)
Refunds a static deposit back to a Bitcoin address
Promise<string>
quoteWithdraw(options)
Gets a fee quote for withdrawing funds
Promise<CoopExitFeeQuote>
withdraw(options)
Withdraws funds to a Bitcoin address
Promise<CoopExitRequest | null | undefined>
createLightningInvoice(options)
Creates a Lightning invoice
Promise<LightningReceiveRequest>
getLightningReceiveRequest(invoiceId)
Gets Lightning receive request by id
Promise<LightningReceiveRequest | null>
getLightningSendRequest(requestId)
Gets Lightning send request by id
Promise<LightningSendRequest | null>
payLightningInvoice(options)
Pays a Lightning invoice
Promise<LightningSendRequest>
quotePayLightningInvoice(options)
Gets fee estimate for Lightning payments
Promise<bigint>
createSparkSatsInvoice(options)
Creates a Spark invoice for receiving sats
Promise<SparkAddressFormat>
createSparkTokensInvoice(options)
Creates a Spark invoice for receiving tokens
Promise<SparkAddressFormat>
paySparkInvoice(invoices)
Pays one or more Spark invoices
Promise<FulfillSparkInvoiceResponse>
toReadOnlyAccount()
Creates a read-only version of this account
Promise<WalletAccountReadOnlySpark>
dispose()
Disposes the wallet account, clearing private keys
void
getAddress()
Returns the account's Spark network address.
Returns:Promise<SparkAddressFormat> - The account's Spark address
Returns the account's total owned bitcoin balance in satoshis. This includes both available (spendable) sats and sats locked in pending outgoing transfers. This differs from WalletAccountReadOnlySpark.getBalance(), which only returns the available balance.
Returns:Promise<bigint> - Total owned balance in satoshis
Returns the available-to-send balance for a specific token. Inherited from WalletAccountReadOnlySpark; both classes return the same available-to-send value.
// Withdraw funds to a Bitcoin address (fee quote is fetched internally)const withdrawal = await account.withdraw({ onchainAddress: 'bc1q...', amountSats: 1000000})console.log('Withdrawal request:', withdrawal)
Note: The fee quote is automatically fetched internally by the withdraw() method. Use quoteWithdraw() if you want to preview the fees before initiating a withdrawal.
createLightningInvoice(options)
Creates a Lightning invoice for receiving payments.