import { W as WalletChainName, a as WalletNetworkConfig, K as Keystore, b as WalletProvider, N as NetworkConfig, A as AddressType, D as DerivedKey, U as Utxo, S as SignerInfo } from './types-BttWXI8x.cjs'; export { B as BroadcastTxOptions, c as DEFAULT_WALLET_NETWORK, G as GetUtxosOptions, I as InvalidAddressError, d as InvalidMnemonicError, e as InvalidNetworkError, P as PsbtError, R as REGTEST, f as RestUtxo, g as RpcEndpoints, h as SIGNET, i as SUPPORTED_WALLET_CHAINS, j as SUPPORTED_WALLET_NETWORKS, k as UserKeyDescriptor, l as UtxoStatus, V as VerifyResult, m as WalletError, n as WalletLockedError, o as WalletSigningRequest, p as broadcastTx, q as buildAccountPath, r as buildAddressPath, s as buildDescriptor, t as deriveAddressFromAccountNode, u as deriveUserKey, v as generateMnemonic, w as getUtxos, x as getWalletNetwork, y as normalizeMnemonic, z as prepareForWalletSigning, C as requireUserKey, E as resolveUserKey, F as rpcCall, H as userKeyMatches, J as validateMnemonic, L as verifyBip322Signature } from './types-BttWXI8x.cjs'; import * as bitcoin from 'bitcoinjs-lib'; import 'bip32'; /** * Xverse browser-extension connector, wrapping sats-connect. * * sats-connect's `getAddress` / `signTransaction` / `signMessage` use a * callback (`onFinish` / `onCancel`) style; each helper here adapts them into * a Promise. Install peer dep: `sats-connect`. */ type NamedNetwork = Pick; declare const XVERSE_SUPPORTED_CHAINS: readonly WalletChainName[]; declare function isXverseSupportedChain(chain: string): boolean; interface XverseConnection { paymentAddress: string; ordinalsAddress: string; publicKey: string; walletType: "xverse"; } interface XverseInputToSign { address: string; signingIndexes: number[]; } interface SignedMessage { signature: string; protocol: "bip322"; } declare function connectXverse(network: NamedNetwork): Promise; declare function signPsbtXverse(psbtBase64: string, inputsToSign: XverseInputToSign[], network?: NamedNetwork): Promise; declare function signMessageXverse(message: string, address: string, network?: NamedNetwork): Promise; declare function isXverseInstalled(): boolean; /** * Seed-phrase (BIP39 mnemonic) import connector — the non-extension half of the * browser import-wallet flow, and the ONLY path that works on both supported * chains. * * Why this exists * --------------- * The import flow offers two chains, signet and regtest, but the Xverse * connector speaks signet only (`connectXverse` throws for regtest — see * `toBitcoinNetworkType` in ./xverse.ts). Without a local signer, selecting * regtest in the UI could only ever produce an error. This module closes that * gap: a mnemonic is derived locally, so it works identically on signet and * regtest, and both chains resolve their balance through the same hosted Tachi * JSON-RPC gateway (`scantxoutset`) that already backs regtest. * * Capability boundary vs. Xverse * ------------------------------ * • Key custody is LOCAL. The mnemonic never leaves the process, and the * derived account node lives in a `Keystore` whose `lock()` zeros it. The * caller owns the mnemonic string itself (JS strings are immutable and * cannot be wiped — see the security note in the README). * • Signing is SYNCHRONOUS and local: `signPsbtSeed` signs with the derived * key rather than round-tripping to an extension. * • BIP-322 message signing is NOT implemented here. The SDK ships a * verifier (`verifyBip322Signature`) but no signer, so seed wallets have no * message-signing path; use Xverse (signet) if a consumer needs one. * * Chain switching is deliberately mnemonic-free: signet and regtest share * BIP-44 coin type 1, so a keystore imported on one is byte-identical to the * other and only the address ENCODING differs ("tb" vs "bcrt" HRP). See * `deriveSeedAddress`, which re-encodes from the retained account xpub instead * of asking for the seed phrase a second time. */ declare const SEED_SUPPORTED_CHAINS: readonly WalletChainName[]; /** * The result of importing a mnemonic: the connected account's public material, * shaped to parallel {@link XverseConnection} so the hook can treat both wallet * types uniformly. * * Public material only — the signer lives in the `Keystore` returned alongside * this by {@link connectSeed}, never on this object. */ interface SeedConnection { paymentAddress: string; publicKey: string; walletType: "seed"; path: string; scriptPubKey: string; fingerprint: string; accountXpub: string; chain: WalletChainName; account: number; change: boolean; index: number; } interface ImportSeedOptions { passphrase?: string; account?: number; index?: number; change?: boolean; } /** * Import a BIP39 mnemonic and derive the account's payment address on `network`. * * Throws `InvalidMnemonicError` for a mnemonic that fails BIP39 checksum * validation, so a mistyped word is rejected at import rather than silently * producing a valid-looking address for the wrong wallet. * * Returns the public connection details AND the live `Keystore`. The caller * owns the keystore's lifetime and MUST call `keystore.lock()` on disconnect — * {@link useTestnetWallet} does this for the hook-driven flow. */ declare function connectSeed(mnemonic: string, network: WalletNetworkConfig, options?: ImportSeedOptions): { connection: SeedConnection; keystore: Keystore; }; /** * Re-encode an already-imported account's address for a different chain, * WITHOUT the mnemonic. * * signet and regtest both use BIP-44 coin type 1, so the account node — and * therefore the private key and pubkey — is identical on both; only the bech32 * HRP differs ("tb" vs "bcrt"). This derives from the keystore's retained * account xpub, so switching chains never asks the user for their seed phrase * again and never re-materializes seed bytes. * * Throws if the target network's coin type differs from the imported one: that * would be a genuinely different BIP-44 account and MUST be re-imported rather * than silently re-encoded under the wrong path. */ declare function deriveSeedAddress(keystore: Keystore, network: WalletNetworkConfig, options?: { change?: boolean; index?: number; }): SeedConnection; /** * Which PSBT inputs to sign, and with which derived key. * * `change`/`addressIndex` default to the imported address's own position, which * is the common case for the single-address import flow. Provide them * explicitly when a PSBT spends from several addresses of the same account. */ interface SeedInputToSign { index: number; change?: boolean; addressIndex?: number; } interface SignPsbtSeedOptions { inputs?: readonly SeedInputToSign[]; defaultChange?: boolean; defaultIndex?: number; finalize?: boolean; } /** * Sign a PSBT locally with the imported seed's keys and return the updated PSBT * as base64. * * Accepts the PSBT as base64 or hex, matching the hook's `signPsbt` contract. * Only the named inputs are signed — an input this account does not own is left * untouched, so a multi-provider PSBT cannot be over-signed here. * * SECURITY: signing attests to whatever the PSBT says. This function does NOT * verify each input's value or scriptPubKey against its parent transaction — * a PSBT built from gateway-reported UTXOs must be checked with * `verifyParentOutput` (src/psbt.ts) first, or a tampered gateway can induce a * signature over an unintended fee. See the TRUST BOUNDARY note on `getUtxos`. */ declare function signPsbtSeed(psbtBase64OrHex: string, keystore: Keystore, network: WalletNetworkConfig, options?: SignPsbtSeedOptions): string; /** * Watch-only output descriptor for a seed-imported single address, matching the * `addr(...)` form the gateway's `scantxoutset` consumes. */ declare function seedAddressDescriptor(connection: SeedConnection): string; declare function isSeedImportAvailable(): boolean; declare function isSeedSupportedChain(name: string): name is WalletChainName; /** * XverseProvider — a {@link WalletProvider} adapter that lets an Xverse * browser-extension connection plug into {@link WalletAggregator.addProvider} * and sit alongside imported (seed) keystore accounts under one aggregator. * * IMPORTANT — capability boundary * -------------------------------- * Xverse is fundamentally different from the built-in HD `KeystoreProvider`: * * • It exposes ONE externally-controlled payment address, not an HD chain. * There is no xpub and no way to derive fresh receive/change addresses, so * `deriveReceiveAddresses`/`deriveChangeAddresses` return that single * address repeated to satisfy the consuming `Wallet`'s gap-limit loop. * `scantxoutset` dedupes outputs across descriptors, so the repetition does * not affect balances. * • The SDK's `AddressType` union is p2wpkh-only today. Rather than assert * `"p2wpkh"` nominally, the constructor verifies the connected account's * resolved scriptPubKey really is a native witness-v0 key-hash and rejects * anything else (nested segwit / taproot) until the union is widened — so a * reported `addressType` is always the account's real on-chain script. * • Signing is asynchronous and delegated to the extension. `signPsbt` * forwards to {@link signPsbtXverse} and merges the returned signatures. * * As a result this provider supports REGISTRATION, BALANCE / UTXO AGGREGATION, * and EXTERNAL PSBT SIGNING. It does NOT support the aggregator's internal * `Wallet.send()` flow: the aggregator holds no local signer for Xverse's * externally-controlled key, so spending an Xverse wallet must go through the browser flow * (`prepareForWalletSigning()` + `signPsbtXverse()` / the `useTestnetWallet` * hook), not `wallet.send()`. */ interface XverseProviderOptions { name?: string; account?: number; } declare class XverseProvider implements WalletProvider { #private; readonly name: string; readonly account: number; readonly supportsInternalSend = false; constructor(connection: XverseConnection, network: WalletNetworkConfig, options?: XverseProviderOptions); get network(): NetworkConfig; get addressType(): AddressType; get fingerprint(): string; get accountPath(): string | null; get accountXpub(): string | null; get locked(): boolean; deriveReceiveAddresses(count: number): DerivedKey[]; deriveChangeAddresses(count: number): DerivedKey[]; signPsbt(psbt: bitcoin.Psbt, inputs: readonly Utxo[]): Promise; buildDescriptor(_change: boolean): string; getSignerInfo(): SignerInfo; lock(): void; toJSON(): Record; } /** * Unified React hook wrapping BOTH import paths — the Xverse extension and a * locally-derived seed phrase — behind one connect / disconnect / sign / * balance API. * * Chain coverage * -------------- * The import flow offers two chains, and they are NOT equally reachable by both * wallet types: * * • `"xverse"` → signet only. The extension has no regtest mode. * • `"seed"` → signet AND regtest. Keys are derived locally, so both chains * work identically. * * Balances for both wallet types resolve through whatever the SELECTED CHAIN * configures — the import method never changes which node is queried. Signet * reads from its Esplora indexer with the Tachi JSON-RPC node as fallback; * regtest uses `scantxoutset` on its node directly (see src/lib/rpcClient.ts). * `chainsFor()` reports the per-wallet-type support so a chain selector can be * gated up front instead of surfacing a failed connect. * * Concurrency: every action that changes which wallet/chain the state describes * bumps a generation counter, and async results are dropped if the generation * moved on. Without that, a signet balance scan (which can take ~14s on the * fallback path) could resolve after a chain switch and paint the old chain's * balance onto the new one. * * Seed custody: the mnemonic is used once, at import, to derive an account * `Keystore`; the hook retains the keystore (not the mnemonic) and `lock()`s it * on disconnect and on unmount. Chain switching re-encodes the address from the * retained account xpub, so the user is never asked for the seed phrase twice. */ type WalletType = "xverse" | "seed"; type WalletStatus = "idle" | "connecting" | "connected" | "error"; declare function chainsFor(walletType: WalletType): WalletChainName[]; interface WalletBalance { confirmed: number; total: number; } interface TestnetWalletState { walletType: WalletType | null; chain: WalletChainName; network: WalletNetworkConfig; address: string | null; publicKey: string | null; balance: WalletBalance | null; status: WalletStatus; error: string | null; derivationPath: string | null; } interface UseTestnetWallet extends TestnetWalletState { supportedChains: WalletChainName[]; chainsFor: (walletType: WalletType) => WalletChainName[]; connect: (walletType: WalletType, chain?: WalletChainName) => Promise; importSeedPhrase: (mnemonic: string, chain?: WalletChainName, options?: ImportSeedOptions) => Promise; switchNetwork: (chain: WalletChainName) => Promise; disconnect: () => void; refreshBalance: () => Promise; signPsbt: (psbtBase64OrHex: string, inputsToSign?: XverseInputToSign[] | SeedInputToSign[]) => Promise; signMessage: (message: string) => Promise; } declare function useTestnetWallet(): UseTestnetWallet; export { type ImportSeedOptions, Keystore, SEED_SUPPORTED_CHAINS, type SeedConnection, type SeedInputToSign, type SignPsbtSeedOptions, type SignedMessage, type TestnetWalletState, type UseTestnetWallet, WalletChainName, WalletNetworkConfig, type WalletStatus, type WalletType, XVERSE_SUPPORTED_CHAINS, type XverseConnection, type XverseInputToSign, XverseProvider, type XverseProviderOptions, chainsFor, connectSeed, connectXverse, deriveSeedAddress, isSeedImportAvailable, isSeedSupportedChain, isXverseInstalled, isXverseSupportedChain, seedAddressDescriptor, signMessageXverse, signPsbtSeed, signPsbtXverse, useTestnetWallet };