nexa-wallet-sdk
Version:
Wallet SDK for the Nexa blockchain
1,391 lines • 63.7 kB
TypeScript
import { HDPrivateKey, PublicKey, Networkish, Script, AddressType, TransactionBuilder, ScriptElement } from "libnexa-ts";
import { ElectrumClient, SubscribeCallback } from "@vgrunner/electrum-cash";
import { DAppInfo } from "wallet-comms-sdk";
type RostrumTransportScheme = 'ws' | 'wss' | "tcp" | "tcp_tls";
interface RostrumParams {
scheme: RostrumTransportScheme;
host: string;
port: number;
}
interface BlockTip {
height: number;
hex: string;
}
interface IFirstUse {
block_hash: string;
block_height: number;
height: number;
tx_hash: string;
}
interface ITokenGenesis {
decimal_places?: number;
document_hash?: string;
document_url?: string;
group: string;
height: number;
name?: string;
op_return?: string;
ticker?: string;
token_id_hex: string;
txid: string;
txidem: string;
op_return_id: number;
}
interface ITokensBalance {
cursor?: any;
confirmed: Record<string, bigint | number>;
unconfirmed: Record<string, bigint | number>;
}
interface ITokenUtxo {
group: string;
height: number;
outpoint_hash: string;
token_amount: number | bigint;
token_id_hex: string;
tx_hash: string;
tx_pos: number;
value: number;
permissions?: string[];
address?: string;
}
interface IListUnspentRecord {
has_token: boolean;
height: number;
outpoint_hash: string;
tx_hash: string;
tx_pos: number;
value: number;
}
interface IUtxo {
addresses: string[];
amount: number;
group: string;
group_authority: bigint | number;
group_quantity: bigint | number;
height: number;
scripthash: string;
scriptpubkey: string;
spent: ISpent;
status: string;
template_argumenthash: string;
template_scripthash: string;
token_id_hex: string;
tx_hash: string;
tx_idem: string;
tx_pos: number;
permissions?: string[];
}
interface ISpent {
height: number;
tx_hash: string;
tx_pos: number;
}
interface ITransaction {
blockhash: string;
blocktime: number;
confirmations: number;
fee: number;
fee_satoshi: number;
hash: string;
height: number;
hex: string;
locktime: number;
size: number;
time: number;
txid: string;
txidem: string;
version: number;
vin: ITXInput[];
vout: ITXOutput[];
}
interface ITXInput {
outpoint: string;
scriptSig: IScriptSig;
sequence: number;
value: number;
value_satoshi: bigint | number;
addresses: string[];
group: string;
groupAuthority: bigint | number;
groupQuantity: bigint | number;
}
interface ITXOutput {
n: number;
outpoint_hash: string;
scriptPubKey: IScriptPubKey;
type: number;
value: number;
value_satoshi: bigint | number;
}
interface IScriptSig {
asm: string;
hex: string;
}
interface IScriptPubKey {
addresses: string[];
argHash: string;
asm: string;
group: string;
groupAuthority: bigint | number;
groupQuantity: bigint | number;
hex: string;
scriptHash: string;
token_id_hex?: string;
type: string;
}
interface ITXHistory {
fee?: number;
height: number;
tx_hash: string;
}
export interface AccountKeys {
receiveKeys: AddressKey[];
changeKeys: AddressKey[];
}
export interface WatchOnlyAddress {
address: string;
xPub?: PublicKey;
derivationPath?: string;
}
export interface AccountIndexes {
rIndex: number;
cIndex: number;
}
export interface TxStatus {
height: number;
}
export interface HodlStatus {
idx: number;
}
export interface AddressKey {
key: HDPrivateKey;
address: string;
balance: string;
tokensBalance: Record<string, Balance>;
}
export interface Balance {
confirmed: string | number;
unconfirmed: string | number;
}
export class AccountKeysUtils {
static getAllKeys(keys: AccountKeys): AddressKey[];
static getAllAddresses(keys: AccountKeys): string[];
}
declare class RostrumProvider {
constructor();
/**
* Get Rostum Server Version
*/
getVersion(): Promise<string[]>;
/**
* Get the block tip of the network / chain we are currently connected to
*/
getBlockTip(): Promise<BlockTip>;
/**
* Get the nexa balance of an address without the token balances
* @param address
*/
getBalance(address: string): Promise<Balance>;
/**
* Get The transaction history for an address
* @param address
*/
getTransactionHistory(address: string): Promise<ITXHistory[]>;
/**
* Get the block height or block has of when the address was first used
* @param address
*/
getFirstUse(address: string): Promise<IFirstUse>;
/**
* Get a single transaction object
* @param id
* @param verbose
*/
getTransaction(id: string, verbose?: boolean): Promise<ITransaction>;
/**
* Get a single unspent output including group data
* @param outpoint
*/
getUtxo(outpoint: string): Promise<IUtxo>;
/**
* Get Utxos only containing nexa information
* @param address
*/
getNexaUtxos(address: string): Promise<IListUnspentRecord[]>;
/**
* Get all the utxo's for a token at an address
* @param address
* @param token
*/
getTokenUtxos(address: string, token: string): Promise<ITokenUtxo[]>;
/**
* Get the token balances for an address
* @param address
* @param token
*/
getTokensBalance(address: string, token?: string): Promise<ITokensBalance>;
/**
* Get the token genesis for a token
* @param token
*/
getTokenGenesis(token: string): Promise<ITokenGenesis>;
/**
* Subscribe to address call back notifications, handy for updating the user when they receive nexa or tokens in
* their wallet
* @param addresses
* @param callback
*/
subscribeToAddresses(addresses: string[], callback: SubscribeCallback): Promise<void>;
/**
* Unsubscribe from address notifications to prevent memory leaks
* @param addresses
* @param callback
*/
unsubscribeFromAddresses(addresses: string[], callback: SubscribeCallback): Promise<void>;
/**
* Broadcast a presigned transaction hash
* @param txHex
*/
broadcast(txHex: string): Promise<string>;
/**
* Get the latency of the server connection
*/
getLatency(): Promise<number>;
/**
* Create initial connection with the rostrum server
* @param netOrParams - Network identifier or RostrumParams object
* @param params - RostrumParams object (for backward compatibility)
* @param electrumClient - Optional pre-configured ElectrumClient instance
*/
connect(netOrParams?: Networkish | RostrumParams, params?: RostrumParams, electrumClient?: ElectrumClient): Promise<void>;
/**
* Disconnect from the rostrum server
* @param force
*/
disconnect(force?: boolean): Promise<boolean>;
}
export const rostrumProvider: RostrumProvider;
export type PermissionLabel = 'authorise' | 'mint' | 'melt' | 'rescript' | 'subgroup';
export type TxEntityState = 'incoming' | 'outgoing' | 'both';
export interface TxTemplateData {
templateScript: Script;
constraintScript: Script;
visibleArgs: any[];
publicKey?: PublicKey;
}
export interface TxOptions {
isConsolidate?: boolean;
toChange?: string;
templateData?: TxTemplateData;
feeFromAmount?: boolean;
}
export interface TokenAction {
token?: string;
parentToken?: string;
amount: bigint;
action: string;
extraData?: {
perms?: PermissionLabel[];
outpoint?: string;
opReturnData?: string;
address?: string;
quantity?: bigint;
};
}
export interface TransactionEntity {
txIdem: string;
txId: string;
time: number;
height: number;
payTo: string;
state: TxEntityState;
value: string;
fee: number;
token: string;
extraGroup: string;
txGroupType: number;
tokenAmount: string;
}
export abstract class BaseAccount {
get transactions(): Map<string, TransactionEntity>;
protected readonly _bip44Account: number;
protected constructor(_bip44Account: number);
abstract get accountIndexes(): AccountIndexes;
abstract get accountKeys(): AccountKeys;
abstract getNewChangeAddress(): string;
abstract getNewAddress(): string;
abstract getAccountStoreKey(): string;
abstract getAccountType(): AccountType;
abstract loadBalances(): Promise<void>;
abstract getKeyFromAddress(address: string): AddressKey;
abstract getTransactions(fromHeight?: number, address?: string): Promise<Map<string, TransactionEntity>>;
abstract getAddresses(): AddressKey[];
abstract hasChangeAddresses(): boolean;
abstract getPrimaryAddressKey(): AddressKey;
get balance(): Balance;
set balance(value: Balance);
get tokenBalances(): Record<string, Balance>;
set tokenBalances(value: Record<string, Balance>);
get tokenAuthorities(): Record<string, ITokenUtxo[]>;
set tokenAuthorities(value: Record<string, ITokenUtxo[]>);
protected fetchAndClassifyTransactions(transactionAddress: string, fromHeight?: number): Promise<Map<string, TransactionEntity>>;
}
export class DappAccount extends BaseAccount {
constructor(bip44Account: number, accountIndex: number, addressKey: AddressKey);
getAccountStoreKey(): string;
getAccountType(): AccountType;
getNewAddress(): string;
getNewChangeAddress(): string;
get accountIndexes(): AccountIndexes;
get accountKeys(): AccountKeys;
loadBalances(): Promise<void>;
getKeyFromAddress(address: string): AddressKey;
getTransactions(fromHeight?: number, address?: string): Promise<Map<string, TransactionEntity>>;
getAddresses(): AddressKey[];
hasChangeAddresses(): boolean;
getPrimaryAddressKey(): AddressKey;
}
export class DefaultAccount extends BaseAccount {
constructor(bip44Account: number, accountIndexes: AccountIndexes, accountKeys: AccountKeys);
getAccountStoreKey(): string;
getAccountType(): AccountType;
getNewAddress(): string;
getNewChangeAddress(): string;
get accountIndexes(): AccountIndexes;
get accountKeys(): AccountKeys;
loadBalances(): Promise<void>;
getKeyFromAddress(address: string): AddressKey;
getTransactions(fromHeight?: number, address?: string): Promise<Map<string, TransactionEntity>>;
getAddresses(): AddressKey[];
hasChangeAddresses(): boolean;
getPrimaryAddressKey(): AddressKey;
}
export class VaultAccount extends BaseAccount {
constructor(bip44Account: number, accountIndex: number, addressKey: AddressKey);
getAccountStoreKey(): string;
getAccountType(): AccountType;
getNewAddress(): string;
getNewChangeAddress(): string;
get accountIndexes(): AccountIndexes;
get accountKeys(): AccountKeys;
loadBalances(): Promise<void>;
getKeyFromAddress(address: string): AddressKey;
getTransactions(fromHeight?: number, address?: string): Promise<Map<string, TransactionEntity>>;
getAddresses(): AddressKey[];
hasChangeAddresses(): boolean;
getPrimaryAddressKey(): AddressKey;
}
export enum TxTokenType {
NO_GROUP = 0,
CREATE = 1,
MINT = 2,
MELT = 3,
RENEW = 4,
TRANSFER = 5
}
export enum AccountType {
NEXA_ACCOUNT = 0,
VAULT_ACCOUNT = 1,
DAPP_ACCOUNT = 2
}
export function isValidNexaAddress(address: string, network: Networkish, type?: AddressType): boolean;
/**
* Abstract base class for creating and managing transactions in the NEXA blockchain.
* Provides common functionality for transaction building including token operations,
* address validation, and output creation.
*/
declare abstract class TransactionCreator {
/**
* Creates a new TransactionCreator instance
* @param tx Optional existing TransactionBuilder, hex string, or buffer
*/
protected constructor(tx?: TransactionBuilder | string | Buffer);
/**
* Parse transaction from hex string with common logic
* @param tx Transaction hex string
* @returns This instance for chaining
*/
parseTxHex(tx: string): this;
/**
* Hook for subclasses to handle individual parsed inputs
* @param input The original input from the transaction
* @param utxo UTXO data for this input
* @param index Input index
*/
protected handleParsedInput(input: any, utxo: any, index: number): Promise<void>;
/**
* Hook for subclasses to perform post-processing after parsing is complete
*/
protected handleParsingComplete(): Promise<void>;
/** Parse transaction from buffer - must be implemented by subclasses */
abstract parseTxBuffer(tx: Buffer): this;
/**
* Sets the network for this transaction
* @param network Network name or Networkish object
* @returns This instance for chaining
*/
onNetwork(network: string | Networkish): this;
/** Gets transaction options */
get txOptions(): TxOptions;
/** Sets transaction options */
set txOptions(value: TxOptions);
/** Gets the network for this transaction */
get network(): Networkish;
/** Sets the network for this transaction */
set network(value: Networkish);
/** Gets the builder function array */
get builder(): (() => Promise<any>)[];
/** Sets the builder function array */
set builder(value: (() => Promise<any>)[]);
/** Gets the underlying transaction builder */
get transactionBuilder(): TransactionBuilder;
/** Sets the underlying transaction builder */
set transactionBuilder(value: TransactionBuilder);
/** Gets the set of token actions */
get tokens(): Set<TokenAction>;
/** Sets the set of token actions */
set tokens(value: Set<TokenAction>);
/** Gets the total NEXA value being sent */
get totalValue(): bigint;
/** Sets the total NEXA value being sent */
set totalValue(value: bigint);
/** Gets the set of spent outpoints */
get spentOutpoints(): Set<string>;
/**
* Updates the spent outpoints set with current transaction inputs
* @returns Set of outpoint hashes that are already spent
*/
protected updateSpentOutpoints(): Set<string>;
/**
* Validates and creates a token action
* @param toAddr Destination address
* @param amount Amount to send
* @param token Token ID
* @param action Action type (mint, melt, send, etc.)
* @param parent Optional parent token ID (for NFT/SFT minting)
* @throws Error if validation fails
*/
protected tokenAction(toAddr: string, amount: string, token: string, action: string, parent?: string): void;
/**
* Configures transaction to consolidate UTXOs to a single address
* @param toAddr Address to consolidate funds to
* @returns This instance for chaining
*/
consolidate(toAddr: string): this;
/**
* Configures transaction to deduct fee from the send amount
* @returns This instance for chaining
*/
feeFromAmount(): this;
/**
* Adds a token send operation to the transaction
* @param toAddr Destination address
* @param amount Amount of tokens to send
* @param token Token ID
* @param dustAmount Optional dust amount for the output (defaults to Transaction.DUST_AMOUNT)
* @returns This instance for chaining
*/
sendToToken(toAddr: string, amount: string, token: string, dustAmount?: number): this;
/**
* Adds a NEXA send operation to the transaction
* @param toAddr Destination address
* @param amount Amount of NEXA to send
* @returns This instance for chaining
*/
sendTo(toAddr: string, amount: string): this;
/**
* Adds a token authority renewal operation
* @param token Token ID to renew authority for
* @param perms Permissions to renew
* @param toAddr
* @returns This instance for chaining
*/
renewAuthority(token: string, perms: PermissionLabel[], toAddr?: string): this;
/**
* Adds a token authority deletion operation
* @param token Token ID to delete authority for
* @param outpoint Outpoint of the authority to delete
* @returns This instance for chaining
*/
deleteAuthority(token: string, outpoint: string): this;
/**
* Creates a legacy token (not implemented)
* @returns This instance for chaining
*/
legacyToken(name: string, ticker: string, decimals: number, docUrl: string, docHash: string): this;
/**
* Creates a legacy group (not implemented)
* @returns This instance for chaining
*/
legacyGroup(name: string, ticker: string, docUrl: string, docHash: string): this;
/**
* Creates a token with metadata
* @param name Token name
* @param ticker Token ticker symbol
* @param decimals Number of decimal places
* @param docUrl URL to token documentation
* @param docHash Hash of token documentation
* @returns This instance for chaining
*/
token(name: string, ticker: string, decimals: number, docUrl: string, docHash: string): this;
/**
* Creates an NFT collection with metadata
* @param name Collection name
* @param ticker Collection ticker symbol
* @param docUrl URL to collection documentation
* @param docHash Hash of collection documentation
* @returns This instance for chaining
*/
collection(name: string, ticker: string, docUrl: string, docHash: string): this;
/**
* Creates an NFT within a collection
* @param parent Parent collection token ID
* @param zipUrl URL to NFT content ZIP file
* @param zipHash Hash of NFT content ZIP file
* @returns This instance for chaining
*/
nft(parent: string, zipUrl: string, zipHash: string): this;
/**
* Creates an SFT (Semi-Fungible Token) within a collection with specified quantity
* @param parent Parent collection token ID
* @param zipUrl URL to SFT content ZIP file
* @param zipHash Hash of SFT content ZIP file
* @param quantity Quantity of SFTs to create
* @returns This instance for chaining
*/
sft(parent: string, zipUrl: string, zipHash: string, quantity: bigint): this;
/**
* Adds an OP_RETURN output to the transaction
* @param data Data to include in the OP_RETURN
* @param isFullScript Whether the data is already a complete script
* @returns This instance for chaining
*/
addOpReturn(data: Buffer | string | Script, isFullScript?: boolean): this;
/**
* Adds nexa contract constraint to spending inputs
* @param templateScript
* @param constraintScript
* @param visibleArgs
* @param pubKey
* @returns This instance for chaining
*/
addContract(templateScript: Script, constraintScript: Script, visibleArgs: any[], pubKey?: PublicKey): this;
/** Populates the transaction with inputs and outputs - must be implemented by subclasses */
abstract populate(): this;
/**
* Builds the transaction by executing all queued operations
* @returns Promise resolving to the serialized transaction hex
*/
build(): Promise<string>;
}
export class WalletTransactionCreator extends TransactionCreator {
constructor(fromAccount: BaseAccount, tx?: TransactionBuilder | string | Buffer);
fromAccount(fromAccount: BaseAccount): this;
parseTxHex(tx: string): this;
/**
* Handle wallet-specific logic for each parsed input (find and store private keys)
*/
protected handleParsedInput(input: any, utxo: any, index: number): Promise<void>;
/**
* Handle wallet-specific post-processing after parsing is complete
*/
protected handleParsingComplete(): Promise<void>;
parseTxBuffer(tx: Buffer): this;
mint(token: string, amount: string, parent?: string): this;
melt(token: string, amount: string, parent?: string): this;
sendAuthority(token: string, perms: PermissionLabel[], toAddr: string): this;
populate(): this;
sign(): this;
buildSatisfier(elements: ScriptElement[]): Script;
buildScriptSig(template: Script, constraint: Script | undefined, satisfierElements: ScriptElement[]): Script;
}
/**
* AccountStore manages a collection of wallet accounts of different types.
* It provides functionality to create, import, export, and manage accounts
* including DApp accounts, Vault accounts, and Default NEXA accounts.
*/
export class AccountStore {
/**
* Creates a new AccountStore instance
* Initializes an empty map to store accounts
*/
constructor();
/**
* Creates a new account of the specified type
* @param accountType Type of account to create (DAPP, VAULT, or DEFAULT)
* @param masterKey Master HD private key for deriving account keys
* @param forceNextIndex If true, forces the next sequential index regardless of blockchain usage
* @returns Promise resolving to the created account
*/
createAccount(accountType: AccountType, masterKey: HDPrivateKey, forceNextIndex?: boolean): Promise<BaseAccount>;
/**
* Finds the private key associated with a given address across all accounts
* @param address The address to search for
* @returns The AddressKey containing the private key, or null if not found
*/
findKeyForAddress(address: string): AddressKey | null;
/**
* Imports an existing account into the store
* @param accountData The account data to import
* @throws Error if an account with the same key already exists
*/
importAccount(accountData: BaseAccount): void;
/**
* Exports account data by index
* @param accountIndex The account index to export
* @returns The account data
* @throws Error if the account doesn't exist
*/
exportAccount(accountIndex: string): BaseAccount;
/**
* Removes an account from the store
* @param accountIndex The account index to remove
* @throws Error if the account doesn't exist
*/
removeAccount(accountIndex: string): void;
/**
* Returns all accounts in the store
* @returns Map of account store keys to BaseAccount objects
*/
listAccounts(): Map<string, BaseAccount>;
/**
* Retrieves a specific account by its index
* @param index The account index to retrieve
* @returns The account if found, undefined otherwise
*/
getAccount(index: string): BaseAccount | undefined;
/**
* Retrieves all accounts of a specific type
* @param accountType The type of accounts to retrieve
* @returns Array of accounts matching the specified type
*/
getAccountsByType(accountType: AccountType): BaseAccount[];
}
/** Type definition for constructor functions */
type Class<T> = new (...args: any[]) => T;
/**
* Utility class for validating arguments and state conditions
*
* Provides methods to validate function arguments and application state
* with consistent error handling and messaging.
*/
export class ValidationUtils {
/**
* Validate that a state condition is true
*
* @param condition - The condition to validate
* @param message - Error message to throw if condition is false
* @throws {Error} If condition is false
*
* @example
* ```typescript
* ValidationUtils.validateState(wallet.isInitialized, 'Wallet must be initialized');
* ```
*/
static validateState(condition: boolean, message: string): void;
/**
* Validate that an argument condition is true
*
* @param condition - The condition to validate
* @param argumentName - Name of the argument being validated
* @param message - Optional additional error message
* @throws {Error} If condition is false
*
* @example
* ```typescript
* ValidationUtils.validateArgument(
* typeof amount === 'number',
* 'amount',
* 'must be a number'
* );
* ```
*/
static validateArgument(condition: boolean, argumentName: string, message?: string): void;
/**
* Validate that an argument is of the expected type
*
* @param argument - The argument to validate
* @param type - Expected type (string name or constructor function)
* @param argumentName - Name of the argument being validated
* @throws {TypeError} If argument is not of expected type
*
* @example
* ```typescript
* ValidationUtils.validateArgumentType(buffer, 'Buffer', 'data');
* ValidationUtils.validateArgumentType(wallet, Wallet, 'wallet');
* ValidationUtils.validateArgumentType(amount, 'number', 'amount');
* ```
*/
static validateArgumentType<T>(argument: unknown, type: string | Class<T>, argumentName?: string): void;
}
/**
* Main Wallet class for managing Nexa blockchain wallet operations
*
* This class provides comprehensive wallet functionality including:
* - Creating wallets from seed phrases or private keys
* - Account discovery and management
* - Transaction creation and signing
* - Message signing and verification
* - Multi-account support with different account types
*
* @example
* ```typescript
* // Create a new wallet with random seed phrase
* const wallet = Wallet.create();
*
* // Restore wallet from existing seed phrase
* const wallet = Wallet.fromSeedPhrase('your twelve word seed phrase here');
*
* // Initialize wallet (discovers accounts and balances)
* await wallet.initialize();
*
* // Create a new account
* const account = await wallet.newAccount('DefaultAccount');
*
* // Create and send a transaction
* const tx = wallet.newTransaction(account)
* .to('nexa:address', 1000000) // 1 NEXA in satoshis
* .sign();
*
* const txId = await wallet.sendTransaction(tx.toHex());
* ```
*/
export class Wallet {
/**
* Creates a new Wallet instance
*
* @param data - Optional wallet data:
* - undefined: Generate new random seed phrase
* - string: Use as BIP39 seed phrase
* - HDPrivateKey: Use as master key directly
* @param network - Network name ('mainnet', 'testnet', 'regtest'). Defaults to 'mainnet'
*
* @example
* ```typescript
* // Create new wallet with random seed
* const wallet = new Wallet();
*
* // Create from seed phrase
* const wallet = new Wallet('abandon abandon abandon...');
*
* // Create from master key
* const masterKey = HDPrivateKey.fromString('xprv...');
* const wallet = new Wallet(masterKey);
*
* // Create on testnet
* const wallet = new Wallet(undefined, 'testnet');
* ```
*/
constructor(data?: string | HDPrivateKey | undefined, network?: string);
/**
* Create a new wallet with a randomly generated seed phrase
*
* This is the recommended way to create a new wallet for first-time users.
* The generated seed phrase should be securely stored by the user.
*
* @returns A new Wallet instance with a random 12-word seed phrase
*
* @example
* ```typescript
* const wallet = Wallet.create();
* console.log(wallet.export().phrase); // Store this securely!
* ```
*/
static create(): Wallet;
/**
* Create a wallet from an existing BIP39 seed phrase
*
* Use this method to restore a wallet from a previously generated seed phrase.
* The seed phrase should be a valid BIP39 mnemonic.
*
* @param phrase - The BIP39 seed phrase (12 or 24 words)
* @param network - Optional network name ('mainnet', 'testnet', 'regtest')
* @returns A new Wallet instance restored from the seed phrase
* @throws {Error} If the seed phrase is invalid or not provided
*
* @example
* ```typescript
* const wallet = Wallet.fromSeedPhrase(
* 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
* 'testnet'
* );
* ```
*/
static fromSeedPhrase(phrase: string, network?: string): Wallet;
/**
* Create a wallet from an extended private key (xpriv)
*
* Use this method to create a wallet from a master private key in extended format.
* This is useful for advanced users who want to use a specific key derivation.
*
* @param xpriv - The extended private key string (starts with 'xprv')
* @param network - Optional network name ('mainnet', 'testnet', 'regtest')
* @returns A new Wallet instance using the provided master key
* @throws {Error} If the private key is invalid or not provided
*
* @example
* ```typescript
* const wallet = Wallet.fromXpriv(
* 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'
* );
* ```
*/
static fromXpriv(xpriv: string, network?: string): Wallet;
/**
* Initialize the wallet by discovering accounts and loading balances
*
* This method performs account discovery using the BIP44 derivation path
* and scans for existing accounts with transaction history or balances.
* Must be called before using the wallet's accounts.
*
* @returns Promise that resolves when initialization is complete
*
* @example
* ```typescript
* const wallet = Wallet.fromSeedPhrase('your seed phrase');
* await wallet.initialize();
*
* // Now you can access discovered accounts
* const accounts = wallet.accountStore.listAccounts();
* ```
*/
initialize(): Promise<void>;
/**
* Create a new transaction builder for this wallet
*
* @param fromAccount - The account to send the transaction from
* @param x - Optional existing transaction data:
* - TransactionBuilder: Use existing transaction builder
* - string: Parse from hex string
* - Buffer: Parse from binary buffer
* - undefined: Create new empty transaction
* @returns A new WalletTransactionCreator instance
*
* @example
* ```typescript
* const account = wallet.accountStore.getAccount(0);
* const tx = wallet.newTransaction(account)
* .to('nexa:address', 1000000) // 1 NEXA
* .sign();
*
* // Or from existing transaction hex
* const tx = wallet.newTransaction(account, 'raw_tx_hex')
* .sign();
* ```
*/
newTransaction(fromAccount: BaseAccount, x?: TransactionBuilder | string | Buffer): WalletTransactionCreator;
/**
* Create a new account for this wallet
*
* @param accountType - The type of account to create:
* - 'DefaultAccount': Standard account for general use
* - 'VaultAccount': Secured account with additional protection
* - 'DappAccount': Account optimized for dApp interactions
* @returns Promise that resolves to the newly created account
*
* @example
* ```typescript
* const defaultAccount = await wallet.newAccount('DefaultAccount');
* const vaultAccount = await wallet.newAccount('VaultAccount');
* const dappAccount = await wallet.newAccount('DappAccount');
* ```
*/
newAccount(accountType: AccountType): Promise<BaseAccount>;
/**
* Broadcast a signed transaction to the Nexa network
*
* @param transaction - The signed transaction in hex format
* @returns Promise that resolves to the transaction ID (txid)
* @throws {Error} If the transaction is invalid or broadcast fails
*
* @example
* ```typescript
* const tx = wallet.newTransaction(account)
* .to('nexa:address', 1000000)
* .sign();
*
* const txId = await wallet.sendTransaction(tx.toHex());
* console.log('Transaction sent:', txId);
* ```
*/
sendTransaction(transaction: string): Promise<string>;
/**
* Subscribe to address notifications for transaction updates
*
* This method allows you to monitor one or more addresses for incoming and outgoing transactions.
* You can provide either a single address string or an array of addresses. The callback will be
* invoked whenever there are updates to any of the monitored addresses.
*
* @param addresses - A single address string or array of addresses to monitor
* @param callback - Function to call when address notifications are received
* @returns Promise that resolves when subscription is established
* @throws {Error} If addresses parameter is invalid or empty
*
* @example
* ```typescript
* // Subscribe to a single address
* await wallet.subscribeToAddressNotifications(
* 'nexa:address123',
* (notification) => {
* console.log('Address notification:', notification);
* }
* );
*
* // Subscribe to multiple addresses
* await wallet.subscribeToAddressNotifications(
* ['nexa:address1', 'nexa:address2', 'nexa:address3'],
* (notification) => {
* console.log('Address notification:', notification);
* }
* );
*
* // Subscribe to all wallet addresses
* const accounts = wallet.accountStore.listAccounts();
* const addresses = accounts.flatMap(account =>
* account.getAddresses().map(addr => addr.address)
* );
* await wallet.subscribeToAddressNotifications(addresses, callback);
* ```
*/
subscribeToAddressNotifications(addresses: string | string[], callback: SubscribeCallback): Promise<void>;
/**
* Unsubscribe from address notifications to prevent memory leaks
*
* This method stops listening for notifications on the specified addresses.
* It's important to call this method when you no longer need to monitor addresses
* to prevent memory leaks from accumulating callback references.
*
* @param addresses - Single address string or array of address strings to unsubscribe from
* @param callback - The exact same callback function used in subscribeToAddressNotifications
*
* @example
* ```typescript
* // Unsubscribe from a single address
* await wallet.unsubscribeFromAddressNotifications(
* 'nexa:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc',
* myCallback
* );
*
* // Unsubscribe from multiple addresses
* await wallet.unsubscribeFromAddressNotifications(addresses, myCallback);
* ```
*/
unsubscribeFromAddressNotifications(addresses: string | string[], callback: SubscribeCallback): Promise<void>;
/**
* Sign a message using a specific address from this wallet
*
* The message is signed using the private key associated with the given address.
* This can be used for authentication or to prove ownership of an address.
*
* @param message - The message to sign
* @param addressToUse - The address whose private key should sign the message
* @returns The signature as a base64-encoded string
* @throws {Error} If the address is not owned by this wallet
*
* @example
* ```typescript
* const account = wallet.accountStore.getAccount(0);
* const address = account.getReceiveAddress();
* const signature = wallet.signMessage('Hello World', address);
* ```
*/
signMessage(message: string, addressToUse: string): string;
/**
* Verify a message signature against an address
*
* This method can verify signatures created by any address, not just addresses
* owned by this wallet. It's useful for verifying messages from other parties.
*
* @param message - The original message that was signed
* @param signature - The signature to verify (base64-encoded)
* @param address - The address that supposedly signed the message
* @returns true if the signature is valid, false otherwise
* @throws {Error} If any parameters are missing or invalid
*
* @example
* ```typescript
* const isValid = wallet.verifyMessage(
* 'Hello World',
* 'signature_string',
* 'nexa:address'
* );
* console.log('Signature valid:', isValid);
* ```
*/
verifyMessage(message: string, signature: string, address: string): boolean;
/**
* Export the wallet data for backup or storage
*
* Returns an object containing the wallet's seed phrase, master key, and accounts.
* This data can be used to restore the wallet later. The seed phrase should be
* stored securely as it provides full access to the wallet.
*
* @returns Object containing wallet data
* @property {string} phrase - The BIP39 seed phrase (if available)
* @property {HDPrivateKey} masterKey - The master private key
* @property {BaseAccount[]} accounts - Array of discovered accounts
*
* @example
* ```typescript
* const walletData = wallet.export();
*
* // Store the seed phrase securely
* const seedPhrase = walletData.phrase;
*
* // Later, restore the wallet
* const restoredWallet = Wallet.fromSeedPhrase(seedPhrase);
* ```
*/
export(): any;
/**
* Get the account store for managing wallet accounts
*
* The account store provides methods to create, import, and manage accounts
* within this wallet. Each account has its own set of addresses and keys.
*
* @returns The wallet's account store
*
* @example
* ```typescript
* const accountStore = wallet.accountStore;
* const accounts = accountStore.listAccounts();
* const firstAccount = accountStore.getAccount(0);
* ```
*/
get accountStore(): AccountStore;
/**
* Get the network this wallet is operating on
*
* @returns The network object (mainnet, testnet, or regtest)
*
* @example
* ```typescript
* const network = wallet.network;
* console.log('Network:', network.name);
* ```
*/
get network(): Networkish;
/**
* Get the current sequential indexing setting
*
* @returns true if forcing sequential indexing, false if using discovery-based indexing
*
* @example
* ```typescript
* const isSequential = wallet.forceSequentialIndexing;
* console.log('Sequential indexing:', isSequential);
* ```
*/
get forceSequentialIndexing(): boolean;
/**
* Set whether to force sequential account indexing
*
* When enabled, new accounts will use sequential indexes (0, 1, 2, ...) regardless
* of blockchain activity. This is useful for multi-user wallets where each user
* needs a unique account even if they haven't used it yet.
*
* When disabled (default), account creation uses discovery-based indexing which
* scans the blockchain for existing activity before assigning indexes.
*
* @param force - true to force sequential indexing, false for discovery-based
*
* @example
* ```typescript
* // Enable sequential indexing for multi-user scenarios
* wallet.forceSequentialIndexing = true;
*
* // Create accounts - they'll be 2.0, 2.1, 2.2 regardless of usage
* const alice = await wallet.newAccount(AccountType.DAPP_ACCOUNT);
* const bob = await wallet.newAccount(AccountType.DAPP_ACCOUNT);
* const charlie = await wallet.newAccount(AccountType.DAPP_ACCOUNT);
*
* // Disable for normal discovery-based indexing
* wallet.forceSequentialIndexing = false;
* ```
*/
set forceSequentialIndexing(force: boolean);
}
/**
* WatchOnlyTransactionCreator extends TransactionCreator to handle transaction creation
* for watch-only wallets. It manages addresses without private keys and delegates
* UTXO selection and input population to specialized utility functions.
*/
export class WatchOnlyTransactionCreator extends TransactionCreator {
/**
* Creates a new WatchOnlyTransactionCreator
* @param tx Optional existing transaction builder or transaction data
*/
constructor(tx?: TransactionBuilder | string | Buffer);
/**
* Sets the source addresses for transaction inputs
* @param address Single address string, array of addresses, or WatchOnlyAddress objects
* @returns This instance for chaining
*/
from(address: string | string[] | WatchOnlyAddress[] | WatchOnlyAddress): this;
/**
* Adds a token minting operation to the transaction
* @param token Token ID to mint
* @param amount Amount to mint
* @param toAddr Destination address for minted tokens
* @param parent Optional parent token ID (for NFT/SFT minting)
* @returns This instance for chaining
*/
mint(token: string, amount: string, toAddr: string, parent?: string): this;
/**
* Adds a token melting operation to the transaction
* @param token Token ID to melt
* @param amount Amount to melt
* @param toAddr Destination address for change of melted tokens
* @param parent Optional parent token ID (for NFT/SFT melting)
* @returns This instance for chaining
*/
melt(token: string, amount: string, toAddr: string, parent?: string): this;
sendAuthority(token: string, perms: PermissionLabel[], toAddr: string): this;
/**
* Populates the transaction with inputs and outputs based on the configured actions.
* Handles different token operations (mint, melt, group creation, etc.) and
* populates NEXA inputs for transaction fees.
* @returns This instance for chaining
*/
populate(): this;
/**
* Parse transaction from buffer (not implemented for watch-only)
* @param tx Transaction buffer
* @returns This instance for chaining
* @throws Error indicating method not implemented
*/
parseTxBuffer(tx: Buffer): this;
/**
* Parse transaction from hex string using enhanced base class implementation
* @param tx Transaction hex string
* @returns This instance for chaining
*/
parseTxHex(tx: string): this;
/**
* Handle watch-only specific logic for each parsed input (track addresses for signing)
*/
protected handleParsedInput(_input: any, utxo: any, _index: number): Promise<void>;
}
/**
* WatchOnlyWallet provides functionality for monitoring and creating transactions
* for addresses without storing private keys. This allows users to track balances
* and create unsigned transactions that can be signed elsewhere.
*/
export class WatchOnlyWallet {
/**
* Creates a new WatchOnlyWallet instance
* @param addressesToWatch Array of addresses to monitor
* @param network Optional network name (defaults to mainnet)
* @throws Error if validation fails
*/
constructor(addressesToWatch: WatchOnlyAddress[], network?: string);
/**
* Creates a new transaction creator for this watch-only wallet
* @param x Optional transaction data - can be a TransactionBuilder, hex string, or Buffer
* @returns WatchOnlyTransactionCreator configured with wallet's addresses and network
*/
newTransaction(x?: TransactionBuilder | string | Buffer): WatchOnlyTransactionCreator;
/**
* Broadcasts a signed transaction to the network
* @param transaction Hex-encoded signed transaction
* @returns Promise resolving to transaction ID
* @throws Error if transaction is invalid or broadcast fails
*/
sendTransaction(transaction: string): Promise<string>;
subscribeToAddressNotifications(callback: SubscribeCallback): Promise<void>;
/**
* Unsubscribe from address notifications to prevent memory leaks
*
* This method stops listening for notifications on all watched addresses.
* The callback parameter must be the exact same function reference that was
* used in the subscribeToAddressNotifications call.
*
* @param callback - The exact same callback function used in subscribeToAddressNotifications
*
* @example
* ```typescript
* const myCallback = (notification) => console.log(notification);
* await watchOnlyWallet.subscribeToAddressNotifications(myCallback);
*
* // Later, to prevent memory leaks:
* await watchOnlyWallet.unsubscribeFromAddressNotifications(myCallback);
* ```
*/
unsubscribeFromAddressNotifications(callback: SubscribeCallback): Promise<void>;
/**
* Gets the list of addresses being watched
* @returns Array of watched addresses (copy to prevent mutation)
*/
getWatchedAddresses(): WatchOnlyAddress[];
}
/**
* Details for transaction signing approval request
*/
export interface TransactionApprovalDetails {
dApp: DAppInfo;
account: string;
transactionHex: string;
broadcast: boolean;
sighashSpec?: any;
recipients?: Array<{
address: string;
amount: string;
token?: string;
}>;
totalAmount?: string;
fees?: string;
opReturn?: string;
tokenOutputs?: Array<{
tokenId: string;
amount: string;
}>;
}
/**
* Details for message signing approval request
*/
export interface MessageApprovalDetails {
dApp: DAppInfo;
account: string;
message: string;
messagePreview: string;
}
/**
* Details for send transaction approval request
*/
export interface SendTransactionApprovalDetails {
dApp: DAppInfo;
fromAccount: string;
recipients: Array<{
address: string;
amount: string;
token?: string;
}>;
totalAmount: string;
estimatedFees?: string;
opReturn?: string;
}
/**
* Details for network switching approval request
*/
export interface NetworkSwitchApprovalDetails {
dApp: DAppInfo;
currentNetwork: string;
requestedNetwork: string;
}
/**
* Details for add token approval request
*/
export interface AddTokenApprovalDetails {
dApp: DAppInfo;
account: string;
tokenId: string;
tokenInfo?: {
name?: string;
symbol?: string;
decimals?: number;
};
}
/**
* Approval callbacks interface for handling user approval requests
*/
export interface ApprovalCallbacks {
/**
* Request approval for transaction signing
* @param details Transaction details for user review
* @returns Promise<boolean> true if approved, false if rejected
*/
approveTransaction?: (details: TransactionApprovalDetails) => Promise<boolean>;
/**
* Request approval for message signing
* @param details Message details for user review
* @returns Promise<boolean> true if approved, false if rejected
*/
approveMessage?: (details: MessageApprovalDetails) => Promise<boolean>;
/**
* Request approval for sending a transaction
* @param details Send transaction details for user review
* @returns Promise<boolean> true if approved, false if rejected
*/
approveSendTransaction?: (details: SendTransactionApprovalDetails) => Promise<boolean>;
/**
* Request approval for network switching
* @param details Network switch details for user review
* @returns Promise<boolean> true if approved, false if rejected
*/
approveNetworkSwitch?: (details: NetworkSwitchApprovalDetails) => Promise<boolean>;
/**
* Request approval for adding a token
* @param details Add token details for user review
* @returns Promise<boolean> true if approved, false if rejected
*/
approveAddToken?: (details: AddTokenApprovalDetails) => Promise<boolean>;
/**
* Request approval for connecting to a dApp
* @param dAppInfo DApp information for user review
* @returns Promise<boolean> true if approved, false if rejected
*/
approveConnection?: (dAppInfo: DAppInfo) => Promise<boolean>;
}
/**
* Default approval callbacks that auto-approve everything (for backwards compatibility)
*/
export const AUTO_APPROVE_CALLBACKS: ApprovalCallbacks;
/**
* Wallet-side WalletComms integration for receiving and handling dApp requests
*
* This class runs inside wallet applications and handles incoming requests from dApps.
* It manages session connections, message signing, transaction signing, and network switching.
* The wallet holds private keys and can actually sign transactions.
*
* @example
* ```typescript
* const wallet = Wallet.fromSeedPhrase('...');
* await wallet.initialize();
*
* const walletComms = new WalletCommsIntegration(wallet);
*
* // Connect to a dApp using a pairing URI (usually from QR code)
* const dAppInfo = await walletComms.connect('wl:1@relay.net/...');
* console.log('Connected to:', dAppInfo.name);
*
* // The integration automatically handles dApp requests
* ```
*/
export class WalletCommsIntegration {
constructor(wallet: Wallet, approvalCallbacks?: ApprovalCallbacks);
/**
* Set approval callbacks for handling user consent
*/
setApprovalCallbacks(callbacks: ApprovalCallbacks): void;
/**
* Connect to a dApp using a pairing URI
*
* This method will only use DApp accounts for security isolation.
* If no DApp account is provided, the first available one will be used or created.
*
* @param pairingURI - The pairing URI from the dApp (usually from QR code)
* @param dappAccount - Optional specific DApp account to use (defaults to first available)
* @returns Information about the connected dApp
*/
connect(pairingURI: string, dappAccount?: DAppAccount): Promise<DAppInfo>;
/**
* Disconnect from the current dApp session
*/
disconnect(): void;
/**
* Switch the active account
*/
setActiveAccount(account: BaseAccount): void;
/**
* Get the current active account
*/
getActiveAccount(): BaseAccount | null;
/**
* Check if connected to a dApp
*/
isConnectedToDApp(): boolean;
/**
* Get the current session details
*/
getSessionInfo(): any;
/*