{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/network.ts","../src/units.ts","../src/derivation.ts","../src/migration.ts","../src/scan-retry.ts","../src/rpc/client.ts","../src/rpc/index.ts","../src/user-key.ts","../src/psbt.ts","../src/lib/rpcClient.ts","../src/lib/verify.ts","../src/coin-selection.ts","../src/providers/keystore-provider.ts","../src/aggregator.ts","../src/wallet.ts"],"sourcesContent":["// Core types\nexport type {\n  AddressType,\n  NetworkName,\n  WalletChainName,\n  NetworkConfig,\n  RpcEndpoints,\n  WalletNetworkConfig,\n  WalletConfig,\n  DerivedKey,\n  HdDerivedKey,\n  Utxo,\n  WalletBalance,\n  WalletInfo,\n  SendOptions,\n  BroadcastResult,\n  SignerInfo,\n} from \"./types.js\";\n\n// Errors\nexport {\n  WalletError,\n  InvalidMnemonicError,\n  InvalidNetworkError,\n  InvalidAddressError,\n  InvalidAmountError,\n  InsufficientFundsError,\n  WalletLockedError,\n  RpcError,\n  RpcTransportError,\n  FeeRateError,\n  PsbtError,\n} from \"./errors.js\";\n\n// Network\nexport {\n  getNetwork,\n  registerNetwork,\n  unregisterNetwork,\n  listNetworks,\n  isAddressOnNetwork,\n  validateAddress,\n  SIGNET,\n  REGTEST,\n  DEFAULT_WALLET_NETWORK,\n  SUPPORTED_WALLET_NETWORKS,\n  SUPPORTED_WALLET_CHAINS,\n  getWalletNetwork,\n} from \"./network.js\";\n\n// Units\nexport {\n  SATS_PER_BTC,\n  DUST_THRESHOLD_SATS,\n  SAFE_DUST_THRESHOLD_SATS,\n  btcToSats,\n  satsToBtc,\n  coerceSats,\n} from \"./units.js\";\n\n// Derivation primitives\nexport {\n  Keystore,\n  generateMnemonic,\n  validateMnemonic,\n  normalizeMnemonic,\n  buildAccountPath,\n  buildAddressPath,\n  deriveAddressFromAccountNode,\n  buildDescriptor,\n} from \"./derivation.js\";\n\n// Legacy P2PKH (m/44') migration safeguards — detect/sweep funds stranded by\n// the 0.3.0 switch to the p2wpkh-only signer, and re-derive the legacy account\n// pubkeys for consumers that committed one as an identity (e.g. a Taproot\n// internal key) before the cutover.\nexport {\n  scanLegacyP2pkh,\n  assertNoStrandedLegacyFunds,\n  sweepLegacy,\n  deriveLegacyUserKeys,\n} from \"./migration.js\";\nexport type {\n  LegacyScanOptions,\n  LegacyScanResult,\n  LegacyUserKey,\n  LegacyUserKeyOptions,\n  LegacyUtxo,\n  SweepLegacyArgs,\n  SweepLegacyResult,\n} from \"./migration.js\";\n\n// Vault user keys — derivation metadata to persist at vault creation, plus\n// recovery for vaults recorded before that metadata existed (including ones\n// created under the unsupported legacy m/44' scheme).\nexport {\n  deriveUserKey,\n  resolveUserKey,\n  requireUserKey,\n  isLegacyUserKey,\n  assertSupportedUserKeyScheme,\n  userKeyMatches,\n  USER_KEY_RECORD_VERSION,\n  CURRENT_USER_KEY_SCHEME,\n  LEGACY_USER_KEY_SCHEME,\n} from \"./user-key.js\";\nexport type {\n  UserKeyScheme,\n  UserKeyDescriptor,\n  DeriveUserKeyOptions,\n  ResolveUserKeyOptions,\n} from \"./user-key.js\";\n\n// PSBT primitives\nexport {\n  buildPsbt,\n  signPsbt,\n  extractTransaction,\n  prepareForWalletSigning,\n  RBF_SEQUENCE,\n} from \"./psbt.js\";\nexport type {\n  BuildPsbtArgs,\n  SignPsbtArgs,\n  WalletSigningRequest,\n} from \"./psbt.js\";\n\n// Browser-wallet RPC adapter (node-safe; fetch-based gateway client).\nexport { rpcCall, getUtxos, broadcastTx } from \"./lib/rpcClient.js\";\nexport type {\n  GetUtxosOptions,\n  BroadcastTxOptions,\n  RestUtxo,\n  UtxoStatus,\n} from \"./lib/rpcClient.js\";\n\n// BIP-322 signature verification.\nexport { verifyBip322Signature } from \"./lib/verify.js\";\nexport type { VerifyResult } from \"./lib/verify.js\";\n\n// RPC layer\nexport {\n  BitcoinCoreRpcClient,\n  scanForUtxos,\n  broadcastRawTransaction,\n  getRawTransaction,\n  getMempoolInfo,\n  getBlockchainInfo,\n  estimateFeeRate,\n  estimateFeeRateTagged,\n  createDefaultRpcClient,\n} from \"./rpc/index.js\";\n\nexport type {\n  RpcClient,\n  RpcConfig,\n  ScannedUtxo,\n  ScanForUtxosOptions,\n  ScanRetryOptions,\n  ScantxoutsetResult,\n  ScantxoutsetUnspent,\n  RawTransaction,\n  MempoolInfo,\n  BlockchainInfo,\n  FeeEstimate,\n  FeeRateSource,\n} from \"./rpc/index.js\";\n\n// Coin selection\nexport { estimateVsize, selectCoins } from \"./coin-selection.js\";\nexport type {\n  CoinSelectionInput,\n  CoinSelectionResult,\n} from \"./coin-selection.js\";\n\n// Providers\nexport type { WalletProvider } from \"./providers/index.js\";\nexport { KeystoreProvider } from \"./providers/index.js\";\n\n// Consumers\nexport { WalletAggregator } from \"./aggregator.js\";\nexport type {\n  AggregatorConfig,\n  AccountSpec,\n  AggregatorInfo,\n} from \"./aggregator.js\";\n\nexport { Wallet } from \"./wallet.js\";\nexport type { WalletOptions, WalletState } from \"./wallet.js\";\n","export class WalletError extends Error {\n  public readonly code: string;\n\n  constructor(code: string, message: string) {\n    super(message);\n    this.name = \"WalletError\";\n    this.code = code;\n    // Maintain a clean prototype chain across CJS/ESM bundlers.\n    Object.setPrototypeOf(this, new.target.prototype);\n  }\n}\n\nexport class InvalidMnemonicError extends WalletError {\n  constructor(message = \"Invalid mnemonic phrase\") {\n    super(\"INVALID_MNEMONIC\", message);\n    this.name = \"InvalidMnemonicError\";\n  }\n}\n\nexport class InvalidNetworkError extends WalletError {\n  constructor(network: string) {\n    super(\"INVALID_NETWORK\", `Invalid network: ${network}`);\n    this.name = \"InvalidNetworkError\";\n  }\n}\n\nexport class InvalidAddressError extends WalletError {\n  constructor(address: string, reason?: string) {\n    const msg = reason\n      ? `Invalid address \"${address}\": ${reason}`\n      : `Invalid address: ${address}`;\n    super(\"INVALID_ADDRESS\", msg);\n    this.name = \"InvalidAddressError\";\n  }\n}\n\nexport class InvalidAmountError extends WalletError {\n  constructor(message = \"Invalid amount\") {\n    super(\"INVALID_AMOUNT\", message);\n    this.name = \"InvalidAmountError\";\n  }\n}\n\nexport class InsufficientFundsError extends WalletError {\n  readonly available: bigint;\n  readonly required: bigint;\n\n  constructor(available: bigint, required: bigint) {\n    super(\n      \"INSUFFICIENT_FUNDS\",\n      `Insufficient funds: available ${available} sats, required ${required} sats`,\n    );\n    this.name = \"InsufficientFundsError\";\n    this.available = available;\n    this.required = required;\n  }\n}\n\nexport class WalletLockedError extends WalletError {\n  constructor() {\n    super(\n      \"WALLET_LOCKED\",\n      \"Wallet has been locked — re-derive from mnemonic before signing\",\n    );\n    this.name = \"WalletLockedError\";\n  }\n}\n\nexport class RpcError extends WalletError {\n  readonly method: string;\n  readonly rpcCode: number | undefined;\n\n  constructor(method: string, message: string, rpcCode?: number) {\n    super(\"RPC_ERROR\", `RPC ${method} failed: ${message}`);\n    this.name = \"RpcError\";\n    this.method = method;\n    this.rpcCode = rpcCode;\n  }\n}\n\nexport class RpcTransportError extends WalletError {\n  readonly httpStatus: number | undefined;\n\n  constructor(message: string, httpStatus?: number) {\n    super(\"RPC_TRANSPORT_ERROR\", message);\n    this.name = \"RpcTransportError\";\n    this.httpStatus = httpStatus;\n  }\n}\n\nexport class FeeRateError extends WalletError {\n  constructor(message = \"Invalid fee rate\") {\n    super(\"FEE_RATE_ERROR\", message);\n    this.name = \"FeeRateError\";\n  }\n}\n\nexport class PsbtError extends WalletError {\n  constructor(message: string) {\n    super(\"PSBT_ERROR\", message);\n    this.name = \"PsbtError\";\n  }\n}\n","import * as bitcoin from \"bitcoinjs-lib\";\nimport { InvalidAddressError, InvalidNetworkError } from \"./errors.js\";\nimport type {\n  NetworkConfig,\n  WalletChainName,\n  WalletNetworkConfig,\n} from \"./types.js\";\n\n// Built-in network names (used to guard unregisterNetwork). This SDK ships as a\n// testnet wallet: only signet and regtest are selectable networks. Mainnet and\n// public testnet are intentionally not registered.\nconst BUILT_IN_NETWORKS = new Set([\"signet\", \"regtest\"]);\n\nconst registry = new Map<string, NetworkConfig>();\n\n// signet and regtest are registered further down as full WalletNetworkConfigs\n// (with hosted rpc endpoints) once those configs are defined.\n\nexport function getNetwork(name: string): NetworkConfig {\n  const config = registry.get(name);\n  if (!config) {\n    throw new InvalidNetworkError(name);\n  }\n  return { ...config };\n}\n\n// Register a custom network\nexport function registerNetwork(name: string, config: NetworkConfig): void {\n  if (registry.has(name)) {\n    throw new Error(\n      `Network \"${name}\" is already registered. Unregister it first to replace.`,\n    );\n  }\n  registry.set(name, { ...config });\n}\n\n// Remove a custom registered network\nexport function unregisterNetwork(name: string): void {\n  if (BUILT_IN_NETWORKS.has(name)) {\n    throw new Error(`Cannot unregister built-in network \"${name}\".`);\n  }\n  if (!registry.has(name)) {\n    throw new InvalidNetworkError(name);\n  }\n  registry.delete(name);\n}\n\nexport function listNetworks(): string[] {\n  return [...registry.keys()];\n}\n\n// Check address is on the given network\nexport function isAddressOnNetwork(address: string, name: string): boolean {\n  const config = registry.get(name);\n  if (!config) {\n    throw new InvalidNetworkError(name);\n  }\n\n  try {\n    bitcoin.address.toOutputScript(address, config.network);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n// Check address is valid on the given network\nexport function validateAddress(address: string, name: string): void {\n  if (!isAddressOnNetwork(address, name)) {\n    throw new InvalidAddressError(address, `not valid for network ${name}`);\n  }\n}\n\n// Read an env var without assuming `process` exists. In the browser entry\n// there is no `process`, so a bare `process.env.X` would throw a ReferenceError;\n// bundlers (tsup/vite/webpack) statically inline `process.env.X` at build time,\n// so this resolves to the configured value for bundled consumers and falls back\n// to undefined in a raw browser context.\nfunction readEnv(name: string): string | undefined {\n  try {\n    return typeof process !== \"undefined\" ? process.env?.[name] : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\n// Validate a gateway endpoint at config-construction time. RPC/REST base URLs\n// flow straight into fetch (see src/lib/rpcClient.ts), so an env override to an\n// attacker-controlled or cleartext host would silently redirect every balance\n// lookup, getUtxos, and broadcastTx call — enabling SSRF (CWE-918), address\n// harvesting, and cleartext exposure of addresses/raw transactions (CWE-319).\n// We require an absolute https:// URL, allowing http:// only for loopback hosts\n// (local regtest/dev gateways), and reject anything else loudly rather than\n// issuing the request.\nexport function requireSecureUrl(raw: string, label: string): string {\n  let u: URL;\n  try {\n    u = new URL(raw);\n  } catch {\n    throw new Error(`${label}: invalid URL \"${raw}\"`);\n  }\n  const isLoopback =\n    u.hostname === \"localhost\" ||\n    u.hostname === \"127.0.0.1\" ||\n    u.hostname === \"[::1]\" ||\n    u.hostname === \"::1\";\n  if (u.protocol !== \"https:\" && !(u.protocol === \"http:\" && isLoopback)) {\n    throw new Error(\n      `${label}: must be an https:// URL (got \"${u.protocol}//${u.hostname}\")`,\n    );\n  }\n  // Drop a single trailing slash so `${base}/rest` and `${rest}/address/...`\n  // derivations don't produce double slashes.\n  return u.toString().replace(/\\/$/, \"\");\n}\n\n// --- Signet (default import-wallet chain) ------------------------------------\n//\n// Hosted signet endpoints, defaulting to the tachibtc signet validator node and\n// overridable via env so consumers aren't pinned to this tenant (rate limits,\n// self-hosted gateways). Both the default and any override are validated by\n// requireSecureUrl.\n//\n//   jsonRpc  <- https://rpc-signet.tachibtc.com (Bitcoin Core JSON-RPC 1.0 proxy;\n//               also backs getUtxos()/broadcastTx() — see src/lib/rpcClient.ts)\n//   rest     <- mirrors jsonRpc (deprecated compat field; no env override)\n//   explorer <- https://explorer.bc-2.jp (human-facing links only)\n//\n// All methods (read and broadcast) are served without authentication, so no API\n// key is configured.\nconst SIGNET_JSONRPC = requireSecureUrl(\n  readEnv(\"TAURUS_SIGNET_RPC\") ?? \"https://rpc-signet.tachibtc.com\",\n  \"TAURUS_SIGNET_RPC\",\n);\n\n// Esplora/Electrs indexer for signet — Xverse's public signet infrastructure by\n// default. This is the SAME chain the Tachi signet node serves (verified: both\n// report identical UTXOs and tip height for the global/public signet), so the\n// two are interchangeable views of one chain, not two networks.\n//\n// It is preferred over `scantxoutset` for reads because it is ~35x faster\n// (~0.4s vs ~14s for a full signet UTXO-set scan), takes no node-global lock,\n// and reports genuine mempool/confirmation status. `jsonRpc` remains the\n// authoritative fallback — see the `esplora` field docs in types.ts.\n//\n// TAURUS_SIGNET_ELECTRS is honoured as the legacy name for this endpoint.\nconst SIGNET_ESPLORA = requireSecureUrl(\n  readEnv(\"TAURUS_SIGNET_ESPLORA\") ??\n    readEnv(\"TAURUS_SIGNET_ELECTRS\") ??\n    \"https://btc-signet.xverse.app\",\n  \"TAURUS_SIGNET_ESPLORA\",\n);\n\n// Block explorer for signet — human-facing links only, never network I/O (see\n// RpcEndpoints.explorer). Defaults to the public bc-2.jp signet explorer, which\n// indexes the same global/public signet the endpoints above serve, and is\n// overridable via TAURUS_SIGNET_EXPLORER. Validated by requireSecureUrl like\n// every other endpoint.\nconst SIGNET_EXPLORER = requireSecureUrl(\n  readEnv(\"TAURUS_SIGNET_EXPLORER\") ?? \"https://explorer.bc-2.jp\",\n  \"TAURUS_SIGNET_EXPLORER\",\n);\n\n// Pre-configured signet network wired to the hosted tachibtc gateway, exported\n// as a named constant so consumers can import and pass it directly into the\n// browser-wallet helpers (rpcClient, the Xverse connector, and\n// useTestnetWallet). Registered below so getNetwork(\"signet\") and\n// listNetworks() expose it as a built-in network.\n//\n// bitcoinjs-lib has no separate Network object for signet, so it reuses\n// networks.testnet for address and script encoding (shared \"tb\" HRP).\nexport const SIGNET: WalletNetworkConfig = {\n  name: \"signet\",\n  network: bitcoin.networks.testnet,\n  bitcoinjsNetwork: bitcoin.networks.testnet,\n  coinType: 1,\n  bech32: \"tb\",\n  rpc: {\n    jsonRpc: SIGNET_JSONRPC,\n    rest: SIGNET_JSONRPC,\n    esplora: SIGNET_ESPLORA,\n    explorer: SIGNET_EXPLORER,\n  },\n};\n\n// --- Regtest (import-wallet chain) -------------------------------------------\n//\n// Hosted regtest endpoints run by tachibtc, overridable via env. These are\n// non-loopback hosts, so requireSecureUrl requires https for the default and any\n// override (a local regtest node may still be pointed at via http://127.0.0.1).\n//\n//   jsonRpc  <- https://rpc-regtest.tachibtc.com  (Bitcoin Core JSON-RPC 1.0\n//               proxy; also backs getUtxos()/broadcastTx())\n//   rest     <- mirrors jsonRpc (deprecated compat field; no env override)\n//   explorer <- https://explorer-regtest.tachibtc.com (human-facing links only)\n//\n// All methods (read and broadcast) are served without authentication, so no API\n// key is configured.\nconst REGTEST_JSONRPC = requireSecureUrl(\n  readEnv(\"TAURUS_REGTEST_RPC\") ?? \"https://rpc-regtest.tachibtc.com\",\n  \"TAURUS_REGTEST_RPC\",\n);\nconst REGTEST_EXPLORER = requireSecureUrl(\n  readEnv(\"TAURUS_REGTEST_EXPLORER\") ?? \"https://explorer-regtest.tachibtc.com\",\n  \"TAURUS_REGTEST_EXPLORER\",\n);\n\nexport const REGTEST: WalletNetworkConfig = {\n  name: \"regtest\",\n  network: bitcoin.networks.regtest,\n  bitcoinjsNetwork: bitcoin.networks.regtest,\n  coinType: 1,\n  bech32: \"bcrt\",\n  rpc: {\n    jsonRpc: REGTEST_JSONRPC,\n    rest: REGTEST_JSONRPC,\n    explorer: REGTEST_EXPLORER,\n  },\n};\n\n// Register the full signet/regtest configs as built-in networks. A\n// WalletNetworkConfig is a structural superset of NetworkConfig, so\n// getNetwork() returns the full config (including rpc/bitcoinjsNetwork).\nregistry.set(\"signet\", SIGNET);\nregistry.set(\"regtest\", REGTEST);\n\n// The only chains the browser import-wallet flow supports, keyed by name for\n// easy chain switching. Signet is the default.\nexport const SUPPORTED_WALLET_NETWORKS: Record<\n  WalletChainName,\n  WalletNetworkConfig\n> = {\n  signet: SIGNET,\n  regtest: REGTEST,\n};\n\n// Ordered list of supported import-wallet chains (signet first / default).\nexport const SUPPORTED_WALLET_CHAINS: WalletChainName[] = [\"signet\", \"regtest\"];\n\n// The default chain used when the import-wallet flow is not told otherwise.\nexport const DEFAULT_WALLET_NETWORK: WalletNetworkConfig = SIGNET;\n\n// Resolve a supported import-wallet chain name to its full config. Throws for\n// any name outside the supported set (mainnet/testnet/custom are intentionally\n// rejected here — the import flow supports signet and regtest only).\nexport function getWalletNetwork(name: WalletChainName): WalletNetworkConfig {\n  const config = SUPPORTED_WALLET_NETWORKS[name];\n  if (!config) {\n    throw new InvalidNetworkError(\n      `${name} (import wallet supports only: ${SUPPORTED_WALLET_CHAINS.join(\", \")})`,\n    );\n  }\n  return { ...config };\n}\n","import { InvalidAmountError } from \"./errors.js\";\n\nexport const SATS_PER_BTC = 100_000_000n;\nexport const DUST_THRESHOLD_SATS = 546n;\nexport const SAFE_DUST_THRESHOLD_SATS = 1000n;\n\nexport function btcToSats(btc: string | number): bigint {\n  // Number inputs: convert directly via float arithmetic. This avoids the\n  // trap where small values like 1e-8 stringify to \"1e-8\" and fail the\n  // decimal regex below.\n  if (typeof btc === \"number\") {\n    if (!Number.isFinite(btc)) {\n      throw new InvalidAmountError(`Invalid BTC amount: ${btc}`);\n    }\n    const sats = Math.round(btc * 1e8);\n    if (!Number.isSafeInteger(sats)) {\n      throw new InvalidAmountError(\n        `BTC amount out of safe integer range: ${btc}`,\n      );\n    }\n    return BigInt(sats);\n  }\n\n  const trimmed = btc.trim();\n  if (trimmed === \"\" || trimmed === \"-\") {\n    throw new InvalidAmountError(`Invalid BTC amount: \"${btc}\"`);\n  }\n\n  // Preferred path: plain decimal strings convert via bigint arithmetic for\n  // full precision, and the max-decimal-places check kicks in here.\n  const match = trimmed.match(/^-?(\\d+)(?:\\.(\\d+))?$/);\n  if (match) {\n    const negative = trimmed.startsWith(\"-\");\n    const wholePart = match[1];\n    const fracPart = (match[2] ?? \"\").padEnd(8, \"0\");\n\n    if (fracPart.length > 8) {\n      throw new InvalidAmountError(\n        `BTC amount has too many decimal places (max 8): \"${btc}\"`,\n      );\n    }\n\n    const sats = BigInt(wholePart) * SATS_PER_BTC + BigInt(fracPart);\n    return negative ? -sats : sats;\n  }\n\n  // Fallback for strings the decimal regex rejects (e.g. scientific notation\n  // like \"1e-8\"): validate via Number() then use the same float-based path.\n  const asNumber = Number(trimmed);\n  if (!Number.isFinite(asNumber)) {\n    throw new InvalidAmountError(`Invalid BTC amount: \"${btc}\"`);\n  }\n  const sats = Math.round(asNumber * 1e8);\n  if (!Number.isSafeInteger(sats)) {\n    throw new InvalidAmountError(\n      `BTC amount out of safe integer range: \"${btc}\"`,\n    );\n  }\n  return BigInt(sats);\n}\n\nexport function satsToBtc(sats: bigint): string {\n  const negative = sats < 0n;\n  const absolute = negative ? -sats : sats;\n\n  const whole = absolute / SATS_PER_BTC;\n  const frac = absolute % SATS_PER_BTC;\n\n  const fracStr = frac.toString().padStart(8, \"0\").replace(/0+$/, \"\");\n  const prefix = negative ? \"-\" : \"\";\n\n  if (fracStr === \"\") {\n    return `${prefix}${whole}.0`;\n  }\n\n  return `${prefix}${whole}.${fracStr}`;\n}\n\n// Coerce a `bigint | number` amount to a `bigint`, rejecting unsafe floating values\nexport function coerceSats(value: bigint | number | string): bigint {\n  if (typeof value === \"bigint\") {\n    return value;\n  }\n  if (typeof value === \"number\") {\n    if (!Number.isSafeInteger(value)) {\n      throw new InvalidAmountError(\n        `Satoshi value must be a safe integer, got ${value}`,\n      );\n    }\n    return BigInt(value);\n  }\n  if (typeof value === \"string\") {\n    const trimmed = value.trim();\n    if (!/^-?\\d+$/.test(trimmed)) {\n      throw new InvalidAmountError(`Invalid satoshi value: \"${value}\"`);\n    }\n    return BigInt(trimmed);\n  }\n  throw new InvalidAmountError(`Cannot coerce value to sats: ${value}`);\n}\n","/**\n * BIP39/32/84 HD key derivation (p2wpkh only).\n *\n * Security notes:\n *   - Seed bytes are held in a private field on `Keystore`, hidden from\n *     JSON.stringify, structured clones, and util.inspect.\n *   - `lock()` is best-effort memory hygiene: it zeros the seed and attempts\n *     to zero the private key bytes on the account node before dropping the reference.\n *   - Intermediate seed buffers created during construction are zeroed as\n *     soon as they are no longer needed.\n *   - Public derivations expose only pubkeys and scriptPubKeys;\n *     `signerFor()` is package-internal and used only by `psbt.ts`.\n */\n\nimport * as bip39 from \"bip39\";\nimport { BIP32Factory, type BIP32Interface } from \"bip32\";\nimport * as ecc from \"@bitcoinerlab/secp256k1\";\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { InvalidMnemonicError, WalletLockedError } from \"./errors.js\";\nimport type { AddressType, HdDerivedKey, NetworkConfig } from \"./types.js\";\n\nconst bip32 = BIP32Factory(ecc);\nbitcoin.initEccLib(ecc);\n\n// BIP43 purpose field for p2wpkh (BIP84).\nconst PURPOSE: Record<AddressType, number> = {\n  p2wpkh: 84,\n};\n\nexport function generateMnemonic(\n  strength: 128 | 160 | 192 | 224 | 256 = 256,\n): string {\n  return bip39.generateMnemonic(strength);\n}\n\nexport function validateMnemonic(mnemonic: string): boolean {\n  return bip39.validateMnemonic(normalizeMnemonic(mnemonic));\n}\n\nexport function normalizeMnemonic(mnemonic: string): string {\n  return mnemonic.trim().split(/\\s+/).join(\" \").toLowerCase();\n}\n\n// Builds a BIP84 account path `m/84'/coin'/account'`.\nexport function buildAccountPath(\n  addressType: AddressType,\n  coinType: number,\n  account: number,\n): string {\n  return `m/${PURPOSE[addressType]}'/${coinType}'/${account}'`;\n}\n\nexport function buildAddressPath(\n  addressType: AddressType,\n  coinType: number,\n  account: number,\n  change: boolean,\n  index: number,\n): string {\n  const accountPath = buildAccountPath(addressType, coinType, account);\n  return `${accountPath}/${change ? 1 : 0}/${index}`;\n}\n\nexport function deriveAddressFromAccountNode(\n  accountNode: BIP32Interface,\n  addressType: AddressType,\n  networkConfig: NetworkConfig,\n  account: number,\n  change: boolean,\n  index: number,\n): HdDerivedKey {\n  const child = accountNode.derive(change ? 1 : 0).derive(index);\n  if (!child.publicKey) {\n    throw new Error(\"Failed to derive child public key\");\n  }\n  const pubkey = Buffer.from(child.publicKey);\n  const payment = makePayment(addressType, pubkey, networkConfig);\n\n  if (!payment.address || !payment.output) {\n    throw new Error(`Failed to build ${addressType} payment`);\n  }\n\n  return {\n    index,\n    change,\n    path: buildAddressPath(\n      addressType,\n      networkConfig.coinType,\n      account,\n      change,\n      index,\n    ),\n    address: payment.address,\n    scriptPubKey: Buffer.from(payment.output).toString(\"hex\"),\n    publicKey: pubkey.toString(\"hex\"),\n  };\n}\n\nfunction makePayment(\n  addressType: AddressType,\n  pubkey: Buffer,\n  networkConfig: NetworkConfig,\n): bitcoin.Payment {\n  const net = networkConfig.network;\n  switch (addressType) {\n    case \"p2wpkh\":\n      return bitcoin.payments.p2wpkh({ pubkey, network: net });\n    default: {\n      const exhaustive: never = addressType;\n      throw new Error(`Unhandled address type: ${exhaustive as string}`);\n    }\n  }\n}\n\n// Best-effort wipe of BIP32 private key bytes; zeroes exposed buffer but not guaranteed to clear all internal copies\nfunction tryWipeNode(node: BIP32Interface | null): void {\n  if (!node) return;\n  const pk = node.privateKey;\n  if (pk && typeof (pk as Uint8Array).fill === \"function\") {\n    try {\n      (pk as Uint8Array).fill(0);\n    } catch {\n      // Some buffer-backed getters are read-only — ignore.\n    }\n  }\n}\n\nexport class Keystore {\n  readonly #network: NetworkConfig;\n  readonly #addressType: AddressType;\n  readonly #account: number;\n  readonly #fingerprint: string;\n  readonly #accountXpub: string;\n  readonly #accountPath: string;\n\n  // Account node holds the private key material used by `signerFor`.\n  // `lock()` zeros and drops it. No full seed is retained here.\n  #accountNode: BIP32Interface | null;\n  #locked: boolean;\n\n  private constructor(args: {\n    network: NetworkConfig;\n    addressType: AddressType;\n    account: number;\n    fingerprint: string;\n    accountNode: BIP32Interface;\n  }) {\n    this.#network = args.network;\n    this.#addressType = args.addressType;\n    this.#account = args.account;\n    this.#fingerprint = args.fingerprint;\n    this.#accountNode = args.accountNode;\n    this.#locked = false;\n\n    this.#accountPath = buildAccountPath(\n      args.addressType,\n      args.network.coinType,\n      args.account,\n    );\n    this.#accountXpub = args.accountNode.neutered().toBase58();\n  }\n\n  static fromMnemonic(\n    mnemonic: string,\n    passphrase: string,\n    network: NetworkConfig,\n    addressType: AddressType,\n    account: number,\n  ): Keystore {\n    const cleaned = normalizeMnemonic(mnemonic);\n    if (!bip39.validateMnemonic(cleaned)) {\n      throw new InvalidMnemonicError();\n    }\n    // mnemonicToSeedSync returns a Buffer; wipe it once we've finished\n    // deriving the account node.\n    const seedBuf = bip39.mnemonicToSeedSync(cleaned, passphrase);\n    try {\n      return Keystore.fromSeedBuffer(seedBuf, network, addressType, account);\n    } finally {\n      seedBuf.fill(0);\n    }\n  }\n\n  // Build a Keystore directly from raw seed bytes.\n  // The caller's `seed` argument is NOT zeroed — the caller owns that buffer.\n  // An internal copy is made, used for derivation, then zeroed.\n  static fromSeedBytes(\n    seed: Uint8Array,\n    network: NetworkConfig,\n    addressType: AddressType,\n    account: number,\n  ): Keystore {\n    const working = Buffer.from(seed);\n    try {\n      return Keystore.fromSeedBuffer(working, network, addressType, account);\n    } finally {\n      working.fill(0);\n    }\n  }\n\n  // Internal: derive the root and account node from a seed Buffer.\n  // Zeros the root's private material before returning so only the account\n  // node retains private bytes.\n  private static fromSeedBuffer(\n    seed: Buffer,\n    network: NetworkConfig,\n    addressType: AddressType,\n    account: number,\n  ): Keystore {\n    const root = bip32.fromSeed(seed, network.network);\n    const fingerprint = Buffer.from(root.fingerprint).toString(\"hex\");\n    const accountPath = buildAccountPath(\n      addressType,\n      network.coinType,\n      account,\n    );\n    const accountNode = root.derivePath(accountPath);\n    // Root has served its purpose — wipe its private key bytes.\n    tryWipeNode(root);\n    return new Keystore({\n      network,\n      addressType,\n      account,\n      fingerprint,\n      accountNode,\n    });\n  }\n\n  get fingerprint(): string {\n    return this.#fingerprint;\n  }\n\n  get accountPath(): string {\n    return this.#accountPath;\n  }\n\n  get accountXpub(): string {\n    return this.#accountXpub;\n  }\n\n  get addressType(): AddressType {\n    return this.#addressType;\n  }\n\n  get account(): number {\n    return this.#account;\n  }\n\n  get network(): NetworkConfig {\n    return this.#network;\n  }\n\n  get locked(): boolean {\n    return this.#locked;\n  }\n\n  watchOnlyAccountNode(): BIP32Interface {\n    return bip32.fromBase58(this.#accountXpub, this.#network.network);\n  }\n\n  deriveAddress(change: boolean, index: number): HdDerivedKey {\n    const node = this.watchOnlyAccountNode();\n    return deriveAddressFromAccountNode(\n      node,\n      this.#addressType,\n      this.#network,\n      this.#account,\n      change,\n      index,\n    );\n  }\n\n  signerFor(change: boolean, index: number): BIP32Interface {\n    if (this.#locked || !this.#accountNode) {\n      throw new WalletLockedError();\n    }\n    return this.#accountNode.derive(change ? 1 : 0).derive(index);\n  }\n\n  // Best-effort wipe: zeros the account node's private bytes, drops the\n  // reference, and marks the keystore locked. See file header for limits.\n  lock(): void {\n    tryWipeNode(this.#accountNode);\n    this.#accountNode = null;\n    this.#locked = true;\n  }\n\n  [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n    return `Keystore(${this.#addressType} ${this.#accountPath} fp=${this.#fingerprint} locked=${this.#locked})`;\n  }\n\n  toJSON(): Record<string, unknown> {\n    return {\n      addressType: this.#addressType,\n      accountPath: this.#accountPath,\n      accountXpub: this.#accountXpub,\n      fingerprint: this.#fingerprint,\n      locked: this.#locked,\n    };\n  }\n}\n\n// Builds a BDK-style output descriptor (e.g. `wpkh([fp/84'/1'/0']tpub.../0/*)`) for interop with bdk-cli or Sparrow.\nexport function buildDescriptor(\n  addressType: AddressType,\n  fingerprint: string,\n  accountPath: string,\n  accountXpub: string,\n  change: boolean,\n): string {\n  const origin = accountPath.replace(/^m\\//, \"\");\n  const inner = `[${fingerprint}/${origin}]${accountXpub}/${change ? 1 : 0}/*`;\n  switch (addressType) {\n    case \"p2wpkh\":\n      return `wpkh(${inner})`;\n    default: {\n      const exhaustive: never = addressType;\n      throw new Error(`Unhandled address type: ${exhaustive as string}`);\n    }\n  }\n}\n","/**\n * Legacy P2PKH (m/44') migration safeguards.\n *\n * 0.3.0 switched the built-in HD signer to native segwit (p2wpkh, BIP84) and\n * dropped P2PKH support. The same mnemonic now derives only m/84'/… addresses,\n * so any balance previously received on the legacy m/44'/… P2PKH chain becomes\n * invisible to scanning, balance, and send flows. Upgrading without first\n * sweeping those UTXOs makes the funds *look* gone.\n *\n * This module is an opt-in, temporary migration aid:\n *   - `scanLegacyP2pkh()`    — read-only detection of non-empty m/44' chains.\n *   - `assertNoStrandedLegacyFunds()` — hard abort when legacy funds exist.\n *   - `sweepLegacy()`        — moves all legacy UTXOs to a new p2wpkh address.\n *\n * It deliberately re-derives P2PKH *locally* (BIP44 purpose 44) without\n * re-adding `p2pkh` to the supported `AddressType` union, so the main wallet,\n * PSBT builder, and signer stay p2wpkh-only. Treat it as a one-time bridge to\n * run before cutting over, not as a general-purpose legacy wallet.\n *\n * Seed hygiene mirrors `derivation.ts`: intermediate seed buffers and derived\n * private-key bytes are zeroed on a best-effort basis once they are no longer\n * needed.\n */\n\nimport * as bip39 from \"bip39\";\nimport { BIP32Factory, type BIP32Interface } from \"bip32\";\nimport * as ecc from \"@bitcoinerlab/secp256k1\";\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { normalizeMnemonic } from \"./derivation.js\";\nimport {\n  InsufficientFundsError,\n  InvalidAddressError,\n  InvalidMnemonicError,\n  FeeRateError,\n  PsbtError,\n  WalletError,\n} from \"./errors.js\";\nimport { scanForUtxos } from \"./rpc/index.js\";\nimport type { RpcClient } from \"./rpc/types.js\";\nimport type { NetworkConfig } from \"./types.js\";\nimport { DUST_THRESHOLD_SATS } from \"./units.js\";\n\nconst bip32 = BIP32Factory(ecc);\nbitcoin.initEccLib(ecc);\n\n// BIP43 purpose field for legacy P2PKH.\nconst LEGACY_PURPOSE = 44;\n\nconst DEFAULT_LEGACY_GAP_LIMIT = 20;\n// Caps adaptive rescans so a malicious RPC that always reports \"one more used\n// address\" cannot drive an unbounded derivation loop (same defense as\n// Wallet.sync()).\nconst DEFAULT_MAX_SCAN_ITERATIONS = 32;\n\n// Conservative vsize estimates (vBytes) for the single-output legacy sweep tx.\nconst LEGACY_P2PKH_INPUT_VBYTES = 148;\nconst P2WPKH_OUTPUT_VBYTES = 31;\nconst TX_OVERHEAD_VBYTES = 11;\n\nexport interface LegacyScanOptions {\n  // BIP44 account index to scan (default 0).\n  account?: number;\n  // Optional BIP39 passphrase; must match what the legacy wallet used.\n  passphrase?: string;\n  // Unused-address gap limit per chain (default 20).\n  gapLimit?: number;\n  // Bound on adaptive rescans (default 32).\n  maxScanIterations?: number;\n}\n\nexport interface LegacyUserKeyOptions {\n  // BIP44 account index (default 0).\n  account?: number;\n  // Optional BIP39 passphrase; must match what the legacy wallet used.\n  passphrase?: string;\n  // How many indices to derive on the chain (default 20).\n  count?: number;\n  // Derive the change chain (`…/1/i`) instead of the receive chain (`…/0/i`).\n  // Legacy vault creation used the receive chain, so this defaults to false;\n  // it exists so a recovery search can cover both.\n  change?: boolean;\n}\n\nexport interface LegacyUserKey {\n  readonly index: number;\n  readonly change: boolean;\n  // Full BIP44 path, e.g. `m/44'/1'/0'/0/4`.\n  readonly path: string;\n  // Hex-encoded 33-byte compressed secp256k1 pubkey.\n  readonly compressedHex: string;\n  // The P2PKH address this pubkey encodes to. Informational — the p2wpkh-only\n  // signer cannot spend from it; use `sweepLegacy()` for that.\n  readonly address: string;\n}\n\nexport interface LegacyUtxo {\n  readonly txid: string;\n  readonly vout: number;\n  readonly valueSats: bigint;\n  readonly address: string;\n  readonly scriptPubKey: string;\n  readonly path: string;\n  readonly change: boolean;\n  readonly addressIndex: number;\n}\n\nexport interface LegacyScanResult {\n  // Sum of all discovered legacy UTXO values.\n  readonly totalSats: bigint;\n  readonly utxos: LegacyUtxo[];\n  // Number of addresses derived/scanned across both chains.\n  readonly scannedAddresses: number;\n  // The m/44' account path that was scanned.\n  readonly accountPath: string;\n}\n\ninterface DerivedLegacyAddress {\n  address: string;\n  scriptPubKey: string;\n  path: string;\n  change: boolean;\n  index: number;\n}\n\n// Best-effort wipe of BIP32 private-key bytes (see derivation.ts for limits).\nfunction tryWipeNode(node: BIP32Interface | null): void {\n  if (!node) return;\n  const pk = node.privateKey;\n  if (pk && typeof (pk as Uint8Array).fill === \"function\") {\n    try {\n      (pk as Uint8Array).fill(0);\n    } catch {\n      // Read-only buffer-backed getters — ignore.\n    }\n  }\n}\n\nfunction legacyAccountPath(network: NetworkConfig, account: number): string {\n  return `m/${LEGACY_PURPOSE}'/${network.coinType}'/${account}'`;\n}\n\n// Derive the legacy m/44'/coin'/account' node (retains private material so the\n// same node can both scan and sign a sweep). The caller MUST `tryWipeNode()` it\n// when finished.\nfunction deriveLegacyAccountNode(\n  mnemonic: string,\n  network: NetworkConfig,\n  account: number,\n  passphrase: string,\n): BIP32Interface {\n  const cleaned = normalizeMnemonic(mnemonic);\n  if (!bip39.validateMnemonic(cleaned)) {\n    throw new InvalidMnemonicError();\n  }\n  const seed = bip39.mnemonicToSeedSync(cleaned, passphrase);\n  try {\n    const root = bip32.fromSeed(seed, network.network);\n    const node = root.derivePath(legacyAccountPath(network, account));\n    // Root has served its purpose — wipe its private bytes.\n    tryWipeNode(root);\n    return node;\n  } finally {\n    seed.fill(0);\n  }\n}\n\nfunction deriveLegacyAddresses(\n  accountNode: BIP32Interface,\n  network: NetworkConfig,\n  account: number,\n  change: boolean,\n  count: number,\n): DerivedLegacyAddress[] {\n  const branch = accountNode.derive(change ? 1 : 0);\n  const out: DerivedLegacyAddress[] = [];\n  for (let index = 0; index < count; index++) {\n    const child = branch.derive(index);\n    if (!child.publicKey) {\n      throw new Error(\"Failed to derive legacy child public key\");\n    }\n    const pubkey = Buffer.from(child.publicKey);\n    const payment = bitcoin.payments.p2pkh({\n      pubkey,\n      network: network.network,\n    });\n    if (!payment.address || !payment.output) {\n      throw new Error(\"Failed to build legacy p2pkh payment\");\n    }\n    out.push({\n      address: payment.address,\n      scriptPubKey: Buffer.from(payment.output).toString(\"hex\"),\n      path: `${legacyAccountPath(network, account)}/${change ? 1 : 0}/${index}`,\n      change,\n      index,\n    });\n  }\n  return out;\n}\n\n/**\n * Derive the PUBLIC keys of one chain of the legacy m/44' account.\n *\n * The 0.3.0 cutover stranded more than balances. Anything that reused the\n * account's secp256k1 pubkey as an identity — most notably a vault's user key\n * or a Taproot internal key — silently changed with it, because\n * m/44'/coin'/0'/0/i and m/84'/coin'/0'/0/i are different keys from the same\n * mnemonic. A consumer that committed the pre-cutover pubkey into a vault or an\n * on-chain script cannot reproduce it from a post-cutover wallet at ANY index,\n * and has no way to derive the old key either: `AddressType` is p2wpkh-only, so\n * `Keystore.fromMnemonic` can no longer reach purpose 44. This is the escape\n * hatch for exactly that case.\n *\n * Prefer `resolveUserKey()` (src/user-key.ts) when you hold the recorded pubkey\n * and want to know which scheme and path produced it; this is the lower-level\n * enumeration it is built on.\n *\n * Public keys only — no signing capability is returned, and the private material\n * derived along the way is wiped before returning. Sweeping legacy funds is\n * still `sweepLegacy()`; this is for reconstructing a legacy IDENTITY.\n */\nexport function deriveLegacyUserKeys(\n  mnemonic: string,\n  network: NetworkConfig,\n  opts: LegacyUserKeyOptions = {},\n): LegacyUserKey[] {\n  const account = opts.account ?? 0;\n  if (!Number.isInteger(account) || account < 0) {\n    throw new RangeError(\n      `deriveLegacyUserKeys: account must be a non-negative integer, got ${account}`,\n    );\n  }\n  const count = opts.count ?? DEFAULT_LEGACY_GAP_LIMIT;\n  if (!Number.isInteger(count) || count < 1) {\n    throw new RangeError(\n      `deriveLegacyUserKeys: count must be a positive integer, got ${count}`,\n    );\n  }\n  const change = opts.change ?? false;\n\n  const accountNode = deriveLegacyAccountNode(\n    mnemonic,\n    network,\n    account,\n    opts.passphrase ?? \"\",\n  );\n  try {\n    const branch = accountNode.derive(change ? 1 : 0);\n    const accountPath = legacyAccountPath(network, account);\n    const out: LegacyUserKey[] = [];\n    for (let index = 0; index < count; index++) {\n      const child = branch.derive(index);\n      if (!child.publicKey) {\n        throw new Error(\n          `Failed to derive legacy child public key at index ${index}`,\n        );\n      }\n      const pubkey = Buffer.from(child.publicKey);\n      const payment = bitcoin.payments.p2pkh({\n        pubkey,\n        network: network.network,\n      });\n      if (!payment.address) {\n        throw new Error(\n          `Failed to build legacy p2pkh address at index ${index}`,\n        );\n      }\n      out.push({\n        index,\n        change,\n        path: `${accountPath}/${change ? 1 : 0}/${index}`,\n        compressedHex: pubkey.toString(\"hex\"),\n        address: payment.address,\n      });\n      tryWipeNode(child);\n    }\n    tryWipeNode(branch);\n    return out;\n  } finally {\n    tryWipeNode(accountNode);\n  }\n}\n\n// Adaptive gap-limit scan over the legacy receive + change chains using the\n// supplied (private-bearing) account node. Shared by scanLegacyP2pkh() and\n// sweepLegacy() so the node is derived once.\nasync function scanWithNode(\n  accountNode: BIP32Interface,\n  network: NetworkConfig,\n  account: number,\n  rpc: RpcClient,\n  gapLimit: number,\n  maxScanIterations: number,\n): Promise<LegacyScanResult> {\n  const accountPath = legacyAccountPath(network, account);\n  let receive = deriveLegacyAddresses(\n    accountNode,\n    network,\n    account,\n    false,\n    gapLimit,\n  );\n  let change = deriveLegacyAddresses(\n    accountNode,\n    network,\n    account,\n    true,\n    gapLimit,\n  );\n\n  let iterations = 0;\n  while (true) {\n    const scriptMap = new Map<string, DerivedLegacyAddress>();\n    for (const d of receive) scriptMap.set(d.scriptPubKey, d);\n    for (const d of change) scriptMap.set(d.scriptPubKey, d);\n\n    const descriptors = [...receive, ...change].map(\n      (d) => `addr(${d.address})`,\n    );\n    const { utxos: scanned } = await scanForUtxos(rpc, descriptors);\n\n    let highestUsedReceive = -1;\n    let highestUsedChange = -1;\n    const matched: LegacyUtxo[] = [];\n    let totalSats = 0n;\n\n    for (const u of scanned) {\n      const derived = scriptMap.get(u.scriptPubKey);\n      if (!derived) continue;\n      if (derived.change) {\n        if (derived.index > highestUsedChange)\n          highestUsedChange = derived.index;\n      } else {\n        if (derived.index > highestUsedReceive)\n          highestUsedReceive = derived.index;\n      }\n      matched.push({\n        txid: u.txid,\n        vout: u.vout,\n        valueSats: u.valueSats,\n        address: derived.address,\n        scriptPubKey: u.scriptPubKey,\n        path: derived.path,\n        change: derived.change,\n        addressIndex: derived.index,\n      });\n      totalSats += u.valueSats;\n    }\n\n    const wantReceive = highestUsedReceive + 1 + gapLimit;\n    const wantChange = highestUsedChange + 1 + gapLimit;\n    const needExtend =\n      wantReceive > receive.length || wantChange > change.length;\n\n    if (needExtend && iterations < maxScanIterations) {\n      iterations++;\n      if (wantReceive > receive.length) {\n        receive = deriveLegacyAddresses(\n          accountNode,\n          network,\n          account,\n          false,\n          wantReceive,\n        );\n      }\n      if (wantChange > change.length) {\n        change = deriveLegacyAddresses(\n          accountNode,\n          network,\n          account,\n          true,\n          wantChange,\n        );\n      }\n      continue;\n    }\n\n    return {\n      totalSats,\n      utxos: matched,\n      scannedAddresses: receive.length + change.length,\n      accountPath,\n    };\n  }\n}\n\nfunction sanitizeGapLimit(value: number | undefined): number {\n  const n = Number(value);\n  if (!Number.isFinite(n) || n < 1) return DEFAULT_LEGACY_GAP_LIMIT;\n  return Math.floor(n);\n}\n\nfunction sanitizeMaxScanIterations(value: number | undefined): number {\n  const n = Number(value);\n  const int = Number.isFinite(n) ? Math.floor(n) : DEFAULT_MAX_SCAN_ITERATIONS;\n  return Math.max(0, Math.min(DEFAULT_MAX_SCAN_ITERATIONS, int));\n}\n\n/**\n * Detect funds stranded on the legacy m/44' (P2PKH) chain for `mnemonic`.\n * Read-only: derives legacy addresses for a gap-limit window, scans the UTXO\n * set, and reports the total. The derived private material is wiped before\n * returning.\n */\nexport async function scanLegacyP2pkh(\n  mnemonic: string,\n  network: NetworkConfig,\n  rpc: RpcClient,\n  opts: LegacyScanOptions = {},\n): Promise<LegacyScanResult> {\n  const account = opts.account ?? 0;\n  const gapLimit = sanitizeGapLimit(opts.gapLimit);\n  const maxScanIterations = sanitizeMaxScanIterations(opts.maxScanIterations);\n\n  const accountNode = deriveLegacyAccountNode(\n    mnemonic,\n    network,\n    account,\n    opts.passphrase ?? \"\",\n  );\n  try {\n    return await scanWithNode(\n      accountNode,\n      network,\n      account,\n      rpc,\n      gapLimit,\n      maxScanIterations,\n    );\n  } finally {\n    tryWipeNode(accountNode);\n  }\n}\n\n/**\n * Guard intended for first-run / upgrade paths: throws if any legacy P2PKH\n * funds are discovered so they cannot silently strand under the p2wpkh-only\n * signer. Resolves quietly when the legacy chain is empty.\n */\nexport async function assertNoStrandedLegacyFunds(\n  mnemonic: string,\n  network: NetworkConfig,\n  rpc: RpcClient,\n  opts: LegacyScanOptions = {},\n): Promise<void> {\n  const legacy = await scanLegacyP2pkh(mnemonic, network, rpc, opts);\n  if (legacy.totalSats > 0n) {\n    throw new WalletError(\n      \"LEGACY_FUNDS_DETECTED\",\n      `Legacy P2PKH funds detected (${legacy.totalSats} sats on ${legacy.accountPath}). ` +\n        `Sweep with sweepLegacy() before using the P2WPKH-only signer.`,\n    );\n  }\n}\n\nexport interface SweepLegacyArgs extends LegacyScanOptions {\n  mnemonic: string;\n  network: NetworkConfig;\n  rpc: RpcClient;\n  // Destination address (typically the new p2wpkh receive address). Must be\n  // valid on `network`.\n  destination: string;\n  // Fee rate in sat/vB.\n  feeRate: number;\n  // Broadcast the signed transaction (default true). When false, the caller\n  // gets the raw hex back to broadcast/inspect themselves.\n  broadcast?: boolean;\n}\n\nexport interface SweepLegacyResult {\n  // null when `broadcast` is false (tx built/signed but not sent).\n  readonly txid: string | null;\n  readonly hex: string;\n  readonly sweptSats: bigint;\n  readonly feeSats: bigint;\n  readonly inputCount: number;\n  readonly destination: string;\n}\n\n// Parse the parent tx and confirm the referenced prevout matches the\n// scanner-reported value and scriptPubKey before it is signed over (mirrors the\n// p2wpkh builder's prevout verification so a tampered RPC cannot misstate an\n// input).\nfunction verifyLegacyParent(parentBuf: Buffer, utxo: LegacyUtxo): void {\n  let parentTx: bitcoin.Transaction;\n  try {\n    parentTx = bitcoin.Transaction.fromBuffer(parentBuf);\n  } catch (err) {\n    throw new PsbtError(\n      `Failed to parse parent tx ${utxo.txid}: ${\n        err instanceof Error ? err.message : String(err)\n      }`,\n    );\n  }\n  if (parentTx.getId() !== utxo.txid) {\n    throw new PsbtError(\n      `Parent tx id mismatch: expected ${utxo.txid}, got ${parentTx.getId()}`,\n    );\n  }\n  const prevout = parentTx.outs[utxo.vout];\n  if (!prevout) {\n    throw new PsbtError(`Parent tx ${utxo.txid} has no vout ${utxo.vout}`);\n  }\n  if (BigInt(prevout.value) !== utxo.valueSats) {\n    throw new PsbtError(\n      `UTXO amount mismatch for ${utxo.txid}:${utxo.vout} — ` +\n        `scan reported ${utxo.valueSats} sats, parent tx has ${BigInt(\n          prevout.value,\n        )}`,\n    );\n  }\n  if (Buffer.from(prevout.script).toString(\"hex\") !== utxo.scriptPubKey) {\n    throw new PsbtError(\n      `UTXO scriptPubKey mismatch for ${utxo.txid}:${utxo.vout}`,\n    );\n  }\n}\n\n/**\n * Sweep every discovered legacy m/44' (P2PKH) UTXO into a single output at\n * `destination` (your new p2wpkh address). Builds, signs, and — unless\n * `broadcast: false` — broadcasts the transaction.\n *\n * Legacy inputs are non-witness, so each parent transaction is fetched in full,\n * verified against the scan result, and attached as `nonWitnessUtxo`. The\n * derived private material is wiped before returning.\n */\nexport async function sweepLegacy(\n  args: SweepLegacyArgs,\n): Promise<SweepLegacyResult> {\n  const { mnemonic, network, rpc, destination } = args;\n  const account = args.account ?? 0;\n  const gapLimit = sanitizeGapLimit(args.gapLimit);\n  const maxScanIterations = sanitizeMaxScanIterations(args.maxScanIterations);\n  const broadcast = args.broadcast ?? true;\n\n  if (!Number.isFinite(args.feeRate) || args.feeRate <= 0) {\n    throw new FeeRateError(\n      `Fee rate must be a positive number: ${args.feeRate}`,\n    );\n  }\n\n  // Reject destinations that aren't encodable on this network before we touch\n  // any key material.\n  let destinationScript: Buffer;\n  try {\n    destinationScript = Buffer.from(\n      bitcoin.address.toOutputScript(destination, network.network),\n    );\n  } catch {\n    throw new InvalidAddressError(\n      destination,\n      `not valid on network ${network.name}`,\n    );\n  }\n\n  const accountNode = deriveLegacyAccountNode(\n    mnemonic,\n    network,\n    account,\n    args.passphrase ?? \"\",\n  );\n\n  try {\n    const scan = await scanWithNode(\n      accountNode,\n      network,\n      account,\n      rpc,\n      gapLimit,\n      maxScanIterations,\n    );\n\n    if (scan.utxos.length === 0 || scan.totalSats === 0n) {\n      throw new WalletError(\n        \"NO_LEGACY_FUNDS\",\n        `No legacy P2PKH funds found on ${scan.accountPath} to sweep.`,\n      );\n    }\n\n    const vbytes =\n      TX_OVERHEAD_VBYTES +\n      scan.utxos.length * LEGACY_P2PKH_INPUT_VBYTES +\n      P2WPKH_OUTPUT_VBYTES;\n    const feeSats = BigInt(Math.ceil(vbytes * args.feeRate));\n    const sweepSats = scan.totalSats - feeSats;\n\n    if (sweepSats < DUST_THRESHOLD_SATS) {\n      // Not enough to cover the fee and leave a non-dust output.\n      throw new InsufficientFundsError(\n        scan.totalSats,\n        feeSats + DUST_THRESHOLD_SATS,\n      );\n    }\n\n    const psbt = new bitcoin.Psbt({ network: network.network });\n\n    for (const utxo of scan.utxos) {\n      const parent = await rpc.call<{ hex?: string }>(\"getrawtransaction\", [\n        utxo.txid,\n        true,\n      ]);\n      if (!parent.hex || typeof parent.hex !== \"string\") {\n        throw new PsbtError(\n          `getrawtransaction did not return hex for parent ${utxo.txid}`,\n        );\n      }\n      const parentBuf = Buffer.from(parent.hex, \"hex\");\n      verifyLegacyParent(parentBuf, utxo);\n      psbt.addInput({\n        hash: utxo.txid,\n        index: utxo.vout,\n        nonWitnessUtxo: parentBuf,\n      });\n    }\n\n    psbt.addOutput({ script: destinationScript, value: sweepSats });\n\n    scan.utxos.forEach((utxo, i) => {\n      const signer = accountNode\n        .derive(utxo.change ? 1 : 0)\n        .derive(utxo.addressIndex);\n      psbt.signInput(i, signer);\n    });\n\n    try {\n      psbt.finalizeAllInputs();\n    } catch (err) {\n      throw new PsbtError(\n        `Failed to finalize legacy sweep PSBT: ${\n          err instanceof Error ? err.message : String(err)\n        }`,\n      );\n    }\n\n    const tx = psbt.extractTransaction();\n    const hex = tx.toHex();\n    let txid: string | null = null;\n    if (broadcast) {\n      txid = await rpc.call<string>(\"sendrawtransaction\", [hex]);\n    }\n\n    return {\n      txid,\n      hex,\n      sweptSats: sweepSats,\n      feeSats,\n      inputCount: scan.utxos.length,\n      destination,\n    };\n  } finally {\n    tryWipeNode(accountNode);\n  }\n}\n","/**\n * Shared backoff policy for `scantxoutset` lock contention.\n *\n * `scantxoutset` takes a single node-global, single-threaded lock: only ONE scan\n * runs on the whole node at a time, ACROSS every client of a shared hosted\n * gateway. An overlapping scan — another user of the same node, a retried\n * import, a double-clicked \"refresh balance\", a React StrictMode double-invoke —\n * fails immediately with Bitcoin Core error -8 \"Scan already in progress\". A long\n * scan (~14s on signet) can also exceed the caller's request timeout.\n *\n * Both are transient: the in-progress scan finishes and the slot frees. Failing\n * outright on them turns a shared node into a coin flip, so both scan paths retry\n * with the same bounded backoff.\n *\n * Two paths consume this, and they detect the retryable condition differently\n * because their transports report it differently — the Core RPC client raises\n * typed `RpcError`/`RpcTransportError` (matched on `rpcCode === -8`), while the\n * browser gateway adapter only has message text. What they MUST agree on is the\n * policy — attempt count, delays, jitter — which lives here so the two cannot\n * drift apart again:\n *\n *   - `src/rpc/index.ts`     — `scanForUtxos`, the Core RPC / `Wallet.sync()` path\n *   - `src/lib/rpcClient.ts` — `getUtxos`, the browser hosted-gateway path\n */\n\n/** Total attempts including the first; `1` disables retrying. */\nexport const SCAN_RETRY_ATTEMPTS = 4;\n/** Delay before the first retry, doubling thereafter. */\nexport const SCAN_RETRY_BASE_DELAY_MS = 2_000;\n/** Ceiling for the backoff delay. */\nexport const SCAN_RETRY_MAX_DELAY_MS = 8_000;\n\n/** Promise-based delay. Works in both Node and the browser. */\nexport function sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Exponential backoff (2s, 4s, 8s, 8s, …) with ±20% jitter, so several clients\n * backing off the same shared node do not resynchronize and collide again on\n * every retry. `attempt` is zero-based.\n */\nexport function scanRetryDelay(\n  attempt: number,\n  baseDelayMs: number = SCAN_RETRY_BASE_DELAY_MS,\n  maxDelayMs: number = SCAN_RETRY_MAX_DELAY_MS,\n): number {\n  const base = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);\n  const jitter = base * 0.2 * (Math.random() * 2 - 1);\n  return Math.max(0, Math.round(base + jitter));\n}\n","import { RpcError, RpcTransportError, WalletError } from \"../errors.js\";\n\nimport type { RpcClient, RpcConfig } from \"./types.js\";\n\ninterface JsonRpcRequest {\n  jsonrpc: \"1.0\";\n  id: string;\n  method: string;\n  params: readonly unknown[];\n}\n\ninterface JsonRpcResponse<T> {\n  result: T | null;\n  error: { code: number; message: string } | null;\n  id: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport class BitcoinCoreRpcClient implements RpcClient {\n  readonly #url: string;\n  readonly #authHeader: string | null;\n  readonly #fetchImpl: typeof fetch;\n  readonly #timeoutMs: number;\n  readonly #requestInit: Omit<RequestInit, \"method\" | \"body\" | \"signal\">;\n\n  #idCounter = 0;\n\n  constructor(config: RpcConfig) {\n    if (!config.url || typeof config.url !== \"string\") {\n      throw new WalletError(\n        \"INVALID_RPC_CONFIG\",\n        \"rpc.url is required and must be a string\",\n      );\n    }\n\n    // Extract inlined user:pass from the URL into the auth header so credentials never appear in the request line.\n    const { url, embeddedAuth } = stripEmbeddedAuth(config.url);\n    this.#url = url;\n\n    if (config.authHeader) {\n      this.#authHeader = config.authHeader;\n    } else if (config.username !== undefined && config.password !== undefined) {\n      this.#authHeader = buildBasicAuth(config.username, config.password);\n    } else if (embeddedAuth) {\n      this.#authHeader = embeddedAuth;\n    } else {\n      this.#authHeader = null;\n    }\n\n    this.#fetchImpl =\n      config.fetchImpl ??\n      (globalThis.fetch as typeof fetch | undefined) ??\n      unsupportedFetch;\n    this.#timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n    this.#requestInit = config.requestInit ?? {};\n  }\n\n  async call<T>(method: string, params: readonly unknown[] = []): Promise<T> {\n    const id = `taurus-${Date.now()}-${++this.#idCounter}`;\n    const body: JsonRpcRequest = {\n      jsonrpc: \"1.0\",\n      id,\n      method,\n      params,\n    };\n\n    const headers = new Headers(this.#requestInit.headers);\n    headers.set(\"Content-Type\", \"application/json\");\n    if (this.#authHeader) {\n      headers.set(\"Authorization\", this.#authHeader);\n    }\n\n    const controller = new AbortController();\n    const timeout = setTimeout(() => controller.abort(), this.#timeoutMs);\n\n    let response: Response;\n    try {\n      response = await this.#fetchImpl(this.#url, {\n        ...this.#requestInit,\n        method: \"POST\",\n        body: JSON.stringify(body),\n        headers,\n        signal: controller.signal,\n      });\n    } catch (err) {\n      const message =\n        err instanceof Error\n          ? err.name === \"AbortError\"\n            ? `RPC ${method} timed out after ${this.#timeoutMs}ms`\n            : err.message\n          : \"unknown fetch error\";\n      throw new RpcTransportError(message);\n    } finally {\n      clearTimeout(timeout);\n    }\n\n    if (!response.ok) {\n      // Read the body for error context\n      const text = (await safeText(response)).slice(0, 512);\n      throw new RpcTransportError(\n        `RPC ${method} HTTP ${response.status}: ${text}`,\n        response.status,\n      );\n    }\n\n    let json: JsonRpcResponse<T>;\n    try {\n      json = (await response.json()) as JsonRpcResponse<T>;\n    } catch (err) {\n      throw new RpcTransportError(\n        `RPC ${method} returned non-JSON response: ${\n          err instanceof Error ? err.message : String(err)\n        }`,\n      );\n    }\n\n    if (json.error) {\n      throw new RpcError(method, json.error.message, json.error.code);\n    }\n    // `result` may legitimately be `null` for some void RPCs\n    return json.result as T;\n  }\n\n  /** Hide the auth header from console.log / util.inspect. */\n  [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n    return `BitcoinCoreRpcClient(${this.#url} auth=${\n      this.#authHeader ? \"set\" : \"none\"\n    })`;\n  }\n\n  toJSON(): Record<string, unknown> {\n    return { url: this.#url, authConfigured: this.#authHeader !== null };\n  }\n}\n\nfunction buildBasicAuth(username: string, password: string): string {\n  // Use Buffer in Node, btoa in the browser. Both produce the same base64\n  const raw = `${username}:${password}`;\n  const encoded =\n    typeof Buffer !== \"undefined\"\n      ? Buffer.from(raw, \"utf8\").toString(\"base64\")\n      : btoa(raw);\n  return `Basic ${encoded}`;\n}\n\nfunction stripEmbeddedAuth(url: string): {\n  url: string;\n  embeddedAuth: string | null;\n} {\n  try {\n    const parsed = new URL(url);\n    if (parsed.username || parsed.password) {\n      const auth = buildBasicAuth(\n        decodeURIComponent(parsed.username),\n        decodeURIComponent(parsed.password),\n      );\n      parsed.username = \"\";\n      parsed.password = \"\";\n      return { url: parsed.toString(), embeddedAuth: auth };\n    }\n    return { url, embeddedAuth: null };\n  } catch {\n    // On URL parse failure, return the input and let fetch surface a clearer error.\n    return { url, embeddedAuth: null };\n  }\n}\n\nasync function safeText(response: Response): Promise<string> {\n  try {\n    return await response.text();\n  } catch {\n    return \"<unreadable response body>\";\n  }\n}\n\nfunction unsupportedFetch(): never {\n  throw new RpcTransportError(\n    \"No global fetch available — pass `rpc.fetchImpl` (e.g. undici.fetch on Node <18)\",\n  );\n}\n","// High-level RPC helpers built on top of `BitcoinCoreRpcClient`\nimport { RpcError, RpcTransportError } from \"../errors.js\";\nimport {\n  SCAN_RETRY_ATTEMPTS,\n  SCAN_RETRY_BASE_DELAY_MS,\n  SCAN_RETRY_MAX_DELAY_MS,\n  scanRetryDelay,\n  sleep as defaultSleep,\n} from \"../scan-retry.js\";\nimport { btcToSats } from \"../units.js\";\n\nimport { BitcoinCoreRpcClient } from \"./client.js\";\nimport type {\n  BlockchainInfo,\n  MempoolInfo,\n  RawTransaction,\n  RpcClient,\n  RpcConfig,\n  ScantxoutsetResult,\n  ScantxoutsetUnspent,\n} from \"./types.js\";\n\nexport { BitcoinCoreRpcClient } from \"./client.js\";\nexport type {\n  RpcClient,\n  RpcConfig,\n  ScantxoutsetResult,\n  ScantxoutsetUnspent,\n  RawTransaction,\n  MempoolInfo,\n  BlockchainInfo,\n} from \"./types.js\";\n\nexport interface ScannedUtxo {\n  txid: string;\n  vout: number;\n  valueSats: bigint;\n  scriptPubKey: string;\n  height: number;\n  confirmations: number;\n  coinbase: boolean;\n}\n\n/** Tunables for the `scantxoutset` retry loop; every field has a default. */\nexport interface ScanRetryOptions {\n  /** Total attempts, including the first (default 4). `1` disables retrying. */\n  attempts?: number;\n  /** Delay before the first retry, doubling thereafter (default 2000ms). */\n  baseDelayMs?: number;\n  /** Ceiling for the backoff delay (default 8000ms). */\n  maxDelayMs?: number;\n  /** Injectable sleep, so tests need not wait in real time. */\n  sleepImpl?: (ms: number) => Promise<void>;\n}\n\n/** Options for {@link scanForUtxos}. */\nexport interface ScanForUtxosOptions {\n  retry?: ScanRetryOptions;\n}\n\n/**\n * True for the two transient conditions the shared policy in `src/scan-retry.ts`\n * describes, and nothing else.\n *\n * Error -8 arrives structurally as `RpcError.rpcCode`, so it is matched on the\n * code rather than on the message text. A timeout arrives as an\n * `RpcTransportError` with no HTTP status (the request never got a response);\n * an HTTP status means the gateway answered and rejected us, which retrying\n * would not fix. Everything else — a bad descriptor, auth failure, a malformed\n * response — is deterministic and must surface on the first attempt.\n */\nfunction isRetryableScanError(err: unknown): boolean {\n  if (err instanceof RpcError) return err.rpcCode === -8;\n  if (err instanceof RpcTransportError) {\n    return err.httpStatus === undefined && /\\btimed out\\b/i.test(err.message);\n  }\n  return false;\n}\n\n// Scan the UTXO set for one or more output descriptors.\nexport async function scanForUtxos(\n  client: RpcClient,\n  descriptors: readonly string[],\n  options: ScanForUtxosOptions = {},\n): Promise<{ utxos: ScannedUtxo[]; scanHeight: number }> {\n  if (descriptors.length === 0) {\n    return { utxos: [], scanHeight: 0 };\n  }\n\n  const retry = options.retry ?? {};\n  const attempts = Math.max(1, retry.attempts ?? SCAN_RETRY_ATTEMPTS);\n  const baseDelayMs = retry.baseDelayMs ?? SCAN_RETRY_BASE_DELAY_MS;\n  const maxDelayMs = retry.maxDelayMs ?? SCAN_RETRY_MAX_DELAY_MS;\n  const sleep = retry.sleepImpl ?? defaultSleep;\n\n  const params = [\"start\", descriptors.map((desc) => ({ desc }))];\n\n  let result: ScantxoutsetResult | undefined;\n  for (let attempt = 0; ; attempt++) {\n    try {\n      result = await client.call<ScantxoutsetResult>(\"scantxoutset\", params);\n      break;\n    } catch (err) {\n      if (attempt >= attempts - 1 || !isRetryableScanError(err)) throw err;\n      await sleep(scanRetryDelay(attempt, baseDelayMs, maxDelayMs));\n    }\n  }\n\n  const scanHeight = result.height;\n  const utxos: ScannedUtxo[] = (result.unspents ?? []).map(\n    (u: ScantxoutsetUnspent) => ({\n      txid: u.txid,\n      vout: u.vout,\n      valueSats: btcToSats(u.amount.toString()),\n      scriptPubKey: u.scriptPubKey,\n      height: u.height,\n      confirmations: scanHeight - u.height + 1,\n      coinbase: !!u.coinbase,\n    }),\n  );\n\n  return { utxos, scanHeight };\n}\n\nexport async function broadcastRawTransaction(\n  client: RpcClient,\n  rawHex: string,\n): Promise<string> {\n  return client.call<string>(\"sendrawtransaction\", [rawHex]);\n}\n\nexport async function getRawTransaction(\n  client: RpcClient,\n  txid: string,\n): Promise<RawTransaction> {\n  return client.call<RawTransaction>(\"getrawtransaction\", [txid, true]);\n}\n\nexport async function getMempoolInfo(client: RpcClient): Promise<MempoolInfo> {\n  return client.call<MempoolInfo>(\"getmempoolinfo\");\n}\n\nexport async function getBlockchainInfo(\n  client: RpcClient,\n): Promise<BlockchainInfo> {\n  return client.call<BlockchainInfo>(\"getblockchaininfo\");\n}\n\n// Indicates fee source: \"node\" from estimatesmartfee, or \"fallback\" if estimation failed\nexport type FeeRateSource = \"node\" | \"fallback\";\n\nexport interface FeeEstimate {\n  satPerVb: number;\n  source: FeeRateSource;\n}\n\n// Estimate fee rate (sat/vB) using `estimatesmartfee`\nexport async function estimateFeeRateTagged(\n  client: RpcClient,\n  targetBlocks = 6,\n  fallbackSatVb = 1,\n): Promise<FeeEstimate> {\n  let result: { feerate?: number; errors?: string[] };\n  try {\n    result = await client.call<{ feerate?: number; errors?: string[] }>(\n      \"estimatesmartfee\",\n      [targetBlocks],\n    );\n  } catch (err) {\n    // Transport failures are loud. Only the \"insufficient data\" case is a\n    // legitimate reason to quietly fall back.\n    if (err instanceof RpcTransportError) {\n      throw err;\n    }\n    return { satPerVb: fallbackSatVb, source: \"fallback\" };\n  }\n\n  if (typeof result.feerate === \"number\" && result.feerate > 0) {\n    const satPerKvb = Math.round(result.feerate * 1e8);\n    const satPerVb = Math.max(1, Math.round(satPerKvb / 1000));\n    return { satPerVb, source: \"node\" };\n  }\n  return { satPerVb: fallbackSatVb, source: \"fallback\" };\n}\n\n// Backwards-compatible wrapper returning only sat/vB; prefer `estimateFeeRateTagged` to detect fallback usage\nexport async function estimateFeeRate(\n  client: RpcClient,\n  targetBlocks = 6,\n  fallbackSatVb = 1,\n): Promise<number> {\n  try {\n    const { satPerVb } = await estimateFeeRateTagged(\n      client,\n      targetBlocks,\n      fallbackSatVb,\n    );\n    return satPerVb;\n  } catch {\n    // Preserve the historical behavior of never throwing from this legacy\n    // helper. Callers that need error visibility should use the tagged form.\n    return fallbackSatVb;\n  }\n}\n\nexport function createDefaultRpcClient(config: RpcConfig): RpcClient {\n  return new BitcoinCoreRpcClient(config);\n}\n","/**\n * Vault user keys: derivation metadata that makes a recorded pubkey\n * self-describing, plus recovery for records created before that metadata\n * existed.\n *\n * ## The problem this closes\n *\n * `m/84'` (p2wpkh, BIP84) is the only supported scheme — the daemon's contract\n * is correct as written and does not need to accept `m/44'`. But an earlier\n * client flow created vaults from `m/44'` (p2pkh, BIP44) derived keys, before\n * the SDK enforced the scheme. Those vault records are still on file, and the\n * current SDK cannot reconstruct them: `AddressType` is p2wpkh-only, so\n * `Keystore.fromMnemonic()` can no longer reach purpose 44, and nothing in the\n * record says which purpose produced its user key. That is a legacy-data\n * problem, not a daemon-acceptance one.\n *\n * ## The two halves of the fix\n *\n *  1. **Recovery** — `resolveUserKey()` takes the pubkey a vault already\n *     recorded and searches the current `m/84'` chain first, then the legacy\n *     `m/44'` chain, and reports which scheme, path, and index produced it. The\n *     legacy key is still derivable locally from the mnemonic, so a stranded\n *     vault can be identified and reconstructed even though the signer is\n *     p2wpkh-only.\n *\n *  2. **Prevention** — `deriveUserKey()` returns a `UserKeyDescriptor`:\n *     scheme, purpose, coin type, account, chain, index, full path, master\n *     fingerprint, and the pubkey itself. Vault creation should persist this\n *     whole record alongside the vault, so no future record is ambiguous about\n *     the derivation that produced it. `assertSupportedUserKeyScheme()` is the\n *     fail-closed guard for creation paths: it rejects a legacy-scheme\n *     descriptor outright.\n *\n * No signing capability is returned anywhere in this module — descriptors carry\n * public material only, and private bytes derived along the way are wiped\n * before returning. Stranded *funds* are a separate concern: see\n * `scanLegacyP2pkh()` / `sweepLegacy()` in migration.ts.\n */\n\nimport { Keystore, deriveAddressFromAccountNode } from \"./derivation.js\";\nimport { WalletError } from \"./errors.js\";\nimport { deriveLegacyUserKeys } from \"./migration.js\";\nimport type { AddressType, NetworkConfig } from \"./types.js\";\n\n/**\n * Schema version of a persisted `UserKeyDescriptor`. Bump when the record shape\n * changes so consumers can migrate stored vault metadata deterministically.\n */\nexport const USER_KEY_RECORD_VERSION = 1;\n\n/**\n * Derivation schemes a vault user key can have been created under.\n *   - `bip84-p2wpkh` — the only supported scheme; what new vaults must use.\n *   - `bip44-p2pkh`  — legacy, recovery-only. Vaults created before the SDK\n *                      enforced BIP84. Never valid for new vaults.\n */\nexport type UserKeyScheme = \"bip84-p2wpkh\" | \"bip44-p2pkh\";\n\nexport const CURRENT_USER_KEY_SCHEME = \"bip84-p2wpkh\" as const;\nexport const LEGACY_USER_KEY_SCHEME = \"bip44-p2pkh\" as const;\n\n// BIP43 purpose per scheme.\nconst SCHEME_PURPOSE: Record<UserKeyScheme, number> = {\n  \"bip84-p2wpkh\": 84,\n  \"bip44-p2pkh\": 44,\n};\n\n// Address type each scheme encodes to. Only the current scheme's value is a\n// member of `AddressType` — that union is deliberately p2wpkh-only, and the\n// legacy scheme is reported as a plain string rather than widening it.\nconst SCHEME_ADDRESS_TYPE: Record<UserKeyScheme, AddressType | \"p2pkh\"> = {\n  \"bip84-p2wpkh\": \"p2wpkh\",\n  \"bip44-p2pkh\": \"p2pkh\",\n};\n\n/**\n * The full derivation record for a vault's user key. Persist ALL of it at vault\n * creation — the pubkey alone is what made the legacy records unrecoverable.\n */\nexport interface UserKeyDescriptor {\n  // Schema version of this record (see USER_KEY_RECORD_VERSION).\n  readonly version: number;\n  readonly scheme: UserKeyScheme;\n  // BIP43 purpose: 84 for the supported scheme, 44 for legacy records.\n  readonly purpose: number;\n  // BIP44 coin type of the network the key was derived on (0 mainnet, 1 test).\n  readonly coinType: number;\n  // Network name, e.g. \"signet\" — coinType alone does not disambiguate\n  // signet/testnet/regtest.\n  readonly network: string;\n  readonly account: number;\n  // false = receive chain (`…/0/i`), true = change chain (`…/1/i`).\n  readonly change: boolean;\n  readonly index: number;\n  // Full derivation path, e.g. `m/84'/1'/0'/0/0`.\n  readonly path: string;\n  // Hex-encoded 33-byte compressed secp256k1 pubkey — the user key itself.\n  readonly publicKey: string;\n  // Master (root) key fingerprint, hex. Identifies WHICH seed this came from\n  // when a consumer holds more than one.\n  readonly masterFingerprint: string;\n  // Address this pubkey encodes to under `scheme`. Informational: for a legacy\n  // descriptor this is a p2pkh address the current signer cannot spend from.\n  readonly address: string;\n  // Address type for `scheme`. \"p2pkh\" only ever appears on legacy records.\n  readonly addressType: AddressType | \"p2pkh\";\n}\n\nexport interface DeriveUserKeyOptions {\n  // BIP44 account index (default 0).\n  account?: number;\n  // Optional BIP39 passphrase.\n  passphrase?: string;\n  // Chain to derive on (default false — the receive chain).\n  change?: boolean;\n  // Address index within the chain (default 0).\n  index?: number;\n}\n\nexport interface ResolveUserKeyOptions {\n  // BIP44 account index to search (default 0).\n  account?: number;\n  // Optional BIP39 passphrase; must match what the vault was created with.\n  passphrase?: string;\n  // Indices to search per chain (default 20).\n  count?: number;\n  // Also search the change chain (default true). Vault creation used the\n  // receive chain, but a mis-specified legacy flow may not have.\n  includeChange?: boolean;\n  // Also search the legacy m/44' chain when the current scheme misses\n  // (default true). Set false to check only that a record is well-formed under\n  // the supported scheme.\n  includeLegacy?: boolean;\n}\n\nconst DEFAULT_SEARCH_COUNT = 20;\n\n// Compressed secp256k1 pubkey: 0x02/0x03 prefix + 32-byte X coordinate.\nconst COMPRESSED_RE = /^0[23][0-9a-f]{64}$/;\n// BIP340 x-only pubkey (a Taproot internal key committed as an identity).\nconst X_ONLY_RE = /^[0-9a-f]{64}$/;\n\ninterface NormalizedKey {\n  hex: string;\n  xOnly: boolean;\n}\n\n/**\n * Accepts a compressed (66 hex chars) or x-only/BIP340 (64 hex chars) pubkey,\n * with or without a `0x` prefix, in any case. X-only input matches on the X\n * coordinate alone, so a Taproot internal key recorded without its parity byte\n * still resolves.\n */\nfunction normalizeUserKey(publicKey: string): NormalizedKey {\n  if (typeof publicKey !== \"string\") {\n    throw new WalletError(\n      \"INVALID_USER_KEY\",\n      `User key must be a hex string, got ${typeof publicKey}`,\n    );\n  }\n  const hex = publicKey.trim().replace(/^0x/i, \"\").toLowerCase();\n  if (COMPRESSED_RE.test(hex)) return { hex, xOnly: false };\n  if (X_ONLY_RE.test(hex)) return { hex, xOnly: true };\n  throw new WalletError(\n    \"INVALID_USER_KEY\",\n    `User key must be a 33-byte compressed (66 hex chars) or x-only ` +\n      `(64 hex chars) secp256k1 pubkey, got ${publicKey.length} chars`,\n  );\n}\n\n// Compare a derived compressed pubkey against normalized search input.\nfunction keyEquals(\n  candidateCompressed: string,\n  target: NormalizedKey,\n): boolean {\n  const candidate = candidateCompressed.toLowerCase();\n  return target.xOnly\n    ? candidate.slice(2) === target.hex\n    : candidate === target.hex;\n}\n\nfunction assertSearchOpts(account: number, count: number): void {\n  if (!Number.isInteger(account) || account < 0) {\n    throw new RangeError(\n      `account must be a non-negative integer, got ${account}`,\n    );\n  }\n  if (!Number.isInteger(count) || count < 1) {\n    throw new RangeError(`count must be a positive integer, got ${count}`);\n  }\n}\n\n/**\n * Derive a vault user key under the supported scheme (`m/84'`, p2wpkh) and\n * return the full derivation record to persist with the vault.\n *\n * This is what vault creation should call. Store the returned descriptor —\n * every field of it — so the vault is never ambiguous about which key and which\n * derivation produced it. Public material only; the keystore is locked before\n * returning.\n */\nexport function deriveUserKey(\n  mnemonic: string,\n  network: NetworkConfig,\n  opts: DeriveUserKeyOptions = {},\n): UserKeyDescriptor {\n  const account = opts.account ?? 0;\n  const index = opts.index ?? 0;\n  const change = opts.change ?? false;\n  if (!Number.isInteger(account) || account < 0) {\n    throw new RangeError(\n      `deriveUserKey: account must be a non-negative integer, got ${account}`,\n    );\n  }\n  if (!Number.isInteger(index) || index < 0) {\n    throw new RangeError(\n      `deriveUserKey: index must be a non-negative integer, got ${index}`,\n    );\n  }\n\n  const keystore = Keystore.fromMnemonic(\n    mnemonic,\n    opts.passphrase ?? \"\",\n    network,\n    \"p2wpkh\",\n    account,\n  );\n  try {\n    const derived = keystore.deriveAddress(change, index);\n    return {\n      version: USER_KEY_RECORD_VERSION,\n      scheme: CURRENT_USER_KEY_SCHEME,\n      purpose: SCHEME_PURPOSE[CURRENT_USER_KEY_SCHEME],\n      coinType: network.coinType,\n      network: network.name,\n      account,\n      change,\n      index,\n      path: derived.path,\n      publicKey: derived.publicKey,\n      masterFingerprint: keystore.fingerprint,\n      address: derived.address,\n      addressType: SCHEME_ADDRESS_TYPE[CURRENT_USER_KEY_SCHEME],\n    };\n  } finally {\n    keystore.lock();\n  }\n}\n\n/**\n * Identify which derivation produced a user key a vault already recorded.\n *\n * Searches the supported `m/84'` chain first, then — unless `includeLegacy` is\n * false — the legacy `m/44'` chain, over `count` indices of the receive chain\n * and (by default) the change chain. Returns the reconstructed descriptor, or\n * null when no derivation in the searched window matches.\n *\n * A non-null result with `scheme === \"bip44-p2pkh\"` is the diagnosis for a\n * stranded legacy vault: the record is real and reproducible from this\n * mnemonic, but was created outside the supported scheme. Use it to reconstruct\n * the vault; do NOT feed it to a creation path (see\n * `assertSupportedUserKeyScheme()`).\n */\nexport function resolveUserKey(\n  mnemonic: string,\n  network: NetworkConfig,\n  publicKey: string,\n  opts: ResolveUserKeyOptions = {},\n): UserKeyDescriptor | null {\n  const target = normalizeUserKey(publicKey);\n  const account = opts.account ?? 0;\n  const count = opts.count ?? DEFAULT_SEARCH_COUNT;\n  assertSearchOpts(account, count);\n  const passphrase = opts.passphrase ?? \"\";\n  const includeChange = opts.includeChange ?? true;\n  const includeLegacy = opts.includeLegacy ?? true;\n  const chains = includeChange ? [false, true] : [false];\n\n  // Current scheme first — a correctly created vault resolves without ever\n  // touching the legacy derivation.\n  const keystore = Keystore.fromMnemonic(\n    mnemonic,\n    passphrase,\n    network,\n    \"p2wpkh\",\n    account,\n  );\n  const masterFingerprint = keystore.fingerprint;\n  try {\n    const accountNode = keystore.watchOnlyAccountNode();\n    for (const change of chains) {\n      for (let index = 0; index < count; index++) {\n        const derived = deriveAddressFromAccountNode(\n          accountNode,\n          \"p2wpkh\",\n          network,\n          account,\n          change,\n          index,\n        );\n        if (!keyEquals(derived.publicKey, target)) continue;\n        return {\n          version: USER_KEY_RECORD_VERSION,\n          scheme: CURRENT_USER_KEY_SCHEME,\n          purpose: SCHEME_PURPOSE[CURRENT_USER_KEY_SCHEME],\n          coinType: network.coinType,\n          network: network.name,\n          account,\n          change,\n          index,\n          path: derived.path,\n          publicKey: derived.publicKey,\n          masterFingerprint,\n          address: derived.address,\n          addressType: SCHEME_ADDRESS_TYPE[CURRENT_USER_KEY_SCHEME],\n        };\n      }\n    }\n  } finally {\n    keystore.lock();\n  }\n\n  if (!includeLegacy) return null;\n\n  for (const change of chains) {\n    const candidates = deriveLegacyUserKeys(mnemonic, network, {\n      account,\n      passphrase,\n      count,\n      change,\n    });\n    for (const candidate of candidates) {\n      if (!keyEquals(candidate.compressedHex, target)) continue;\n      return {\n        version: USER_KEY_RECORD_VERSION,\n        scheme: LEGACY_USER_KEY_SCHEME,\n        purpose: SCHEME_PURPOSE[LEGACY_USER_KEY_SCHEME],\n        coinType: network.coinType,\n        network: network.name,\n        account,\n        change: candidate.change,\n        index: candidate.index,\n        path: candidate.path,\n        publicKey: candidate.compressedHex,\n        masterFingerprint,\n        address: candidate.address,\n        addressType: SCHEME_ADDRESS_TYPE[LEGACY_USER_KEY_SCHEME],\n      };\n    }\n  }\n\n  return null;\n}\n\n/**\n * `resolveUserKey()` that throws instead of returning null. Use when a vault\n * record is known to belong to this mnemonic and a miss is a genuine error\n * (wrong mnemonic, wrong passphrase, wrong network, or an index beyond the\n * search window).\n */\nexport function requireUserKey(\n  mnemonic: string,\n  network: NetworkConfig,\n  publicKey: string,\n  opts: ResolveUserKeyOptions = {},\n): UserKeyDescriptor {\n  const resolved = resolveUserKey(mnemonic, network, publicKey, opts);\n  if (resolved) return resolved;\n  const count = opts.count ?? DEFAULT_SEARCH_COUNT;\n  throw new WalletError(\n    \"USER_KEY_NOT_FOUND\",\n    `No derivation of this mnemonic produced user key ${publicKey} on ` +\n      `${network.name} (searched account ${opts.account ?? 0}, ${count} ` +\n      `indices per chain, ` +\n      `${opts.includeLegacy === false ? \"m/84' only\" : \"m/84' and legacy m/44'\"}). ` +\n      `Check the passphrase, network, and account, or widen \\`count\\`.`,\n  );\n}\n\n/** True when the descriptor came from the legacy, unsupported m/44' scheme. */\nexport function isLegacyUserKey(descriptor: UserKeyDescriptor): boolean {\n  return descriptor.scheme === LEGACY_USER_KEY_SCHEME;\n}\n\n/**\n * Fail-closed guard for vault CREATION paths: throws unless the descriptor was\n * produced by the supported `m/84'` scheme. Recovery paths should not call this\n * — a legacy descriptor is exactly what they expect to handle.\n */\nexport function assertSupportedUserKeyScheme(\n  descriptor: UserKeyDescriptor,\n): void {\n  if (descriptor.scheme === CURRENT_USER_KEY_SCHEME) return;\n  throw new WalletError(\n    \"UNSUPPORTED_USER_KEY_SCHEME\",\n    `User key at ${descriptor.path} uses the unsupported \"${descriptor.scheme}\" ` +\n      `scheme; only \"${CURRENT_USER_KEY_SCHEME}\" (m/84' p2wpkh) may be used to ` +\n      `create a vault. Legacy records are recovery-only — see resolveUserKey().`,\n  );\n}\n\n/**\n * Check a recorded pubkey against a descriptor without re-deriving. Accepts the\n * same compressed or x-only forms as `resolveUserKey()`.\n */\nexport function userKeyMatches(\n  descriptor: UserKeyDescriptor,\n  publicKey: string,\n): boolean {\n  return keyEquals(descriptor.publicKey, normalizeUserKey(publicKey));\n}\n","/**\n * PSBT construction, signing, and finalization (p2wpkh only).\n *\n * p2wpkh inputs are witness-based: the prevout (scriptPubKey + value) is\n * supplied as `witnessUtxo`. The full parent tx is still fetched via RPC and\n * verified, so a tampered scanner result cannot misstate an input's value or\n * script before it is signed over.\n *\n * Per address type (for the types returning in a future release):\n *   p2pkh       - non-witness; requires full parent tx as `nonWitnessUtxo`.\n *   p2sh-p2wpkh - witness; also needs redeem script.\n *   p2wpkh      - witness only.\n *   p2tr        - taproot key-path; signer tweaked per BIP86 before schnorr signing.\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport type { Keystore } from \"./derivation.js\";\nimport { PsbtError } from \"./errors.js\";\nimport type { RpcClient } from \"./rpc/types.js\";\nimport type { AddressType, Utxo } from \"./types.js\";\n\nexport type { RpcClient } from \"./rpc/types.js\";\n\n// BIP125 opt-in RBF sequence number.\nexport const RBF_SEQUENCE = 0xfffffffd;\n\ninterface RawTransaction {\n  hex?: string;\n  [key: string]: unknown;\n}\n\nexport interface BuildPsbtArgs {\n  network: bitcoin.networks.Network;\n  inputs: readonly Utxo[];\n  outputs: readonly { address: string; valueSats: bigint }[];\n  inputAddressType: AddressType;\n  rpc: RpcClient;\n}\n\nexport async function buildPsbt(args: BuildPsbtArgs): Promise<bitcoin.Psbt> {\n  const psbt = new bitcoin.Psbt({ network: args.network });\n\n  for (const input of args.inputs) {\n    switch (args.inputAddressType) {\n      case \"p2wpkh\": {\n        const parent = await args.rpc.call<RawTransaction>(\n          \"getrawtransaction\",\n          [input.txid, true],\n        );\n        if (!parent.hex || typeof parent.hex !== \"string\") {\n          throw new PsbtError(\n            `getrawtransaction did not return hex for parent ${input.txid}`,\n          );\n        }\n        const parentBuf = Buffer.from(parent.hex, \"hex\");\n        verifyParentOutput(parentBuf, input);\n        // Witness input: supply only the spent output (script + value), verified\n        // above against the real parent tx. No nonWitnessUtxo needed for segwit.\n        psbt.addInput({\n          hash: input.txid,\n          index: input.vout,\n          witnessUtxo: {\n            script: Buffer.from(input.scriptPubKey, \"hex\"),\n            value: input.valueSats,\n          },\n          sequence: RBF_SEQUENCE,\n        });\n        break;\n      }\n      default: {\n        const exhaustive: never = args.inputAddressType;\n        throw new PsbtError(`Unhandled input type: ${exhaustive as string}`);\n      }\n    }\n  }\n\n  for (const out of args.outputs) {\n    psbt.addOutput({\n      address: out.address,\n      value: out.valueSats,\n    });\n  }\n\n  return psbt;\n}\n\n// Parses the parent transaction and confirms the referenced prevout matches\n// the scanner-reported value and scriptPubKey. Any mismatch throws before\n// the input is added to the PSBT, so a tampered RPC cannot trick a signer\n// into producing a transaction that over-allocates value.\nfunction verifyParentOutput(parentBuf: Buffer, input: Utxo): void {\n  let parentTx: bitcoin.Transaction;\n  try {\n    parentTx = bitcoin.Transaction.fromBuffer(parentBuf);\n  } catch (err) {\n    throw new PsbtError(\n      `Failed to parse parent tx ${input.txid}: ${\n        err instanceof Error ? err.message : String(err)\n      }`,\n    );\n  }\n  if (parentTx.getId() !== input.txid) {\n    throw new PsbtError(\n      `Parent tx id mismatch: expected ${input.txid}, got ${parentTx.getId()}`,\n    );\n  }\n  const prevout = parentTx.outs[input.vout];\n  if (!prevout) {\n    throw new PsbtError(`Parent tx ${input.txid} has no vout ${input.vout}`);\n  }\n  const prevoutValue = BigInt(prevout.value);\n  if (prevoutValue !== input.valueSats) {\n    throw new PsbtError(\n      `UTXO amount mismatch for ${input.txid}:${input.vout} — ` +\n        `scan reported ${input.valueSats} sats, parent tx has ${prevoutValue}`,\n    );\n  }\n  const prevoutScriptHex = Buffer.from(prevout.script).toString(\"hex\");\n  if (prevoutScriptHex !== input.scriptPubKey) {\n    throw new PsbtError(\n      `UTXO scriptPubKey mismatch for ${input.txid}:${input.vout}`,\n    );\n  }\n}\n\nexport interface SignPsbtArgs {\n  psbt: bitcoin.Psbt;\n  inputs: readonly Utxo[];\n  keystore: Keystore;\n}\n\n// Signs every PSBT input via the keystore using each input's derivation path.\nexport function signPsbt(args: SignPsbtArgs): void {\n  const { psbt, inputs, keystore } = args;\n\n  inputs.forEach((utxo, i) => {\n    const signer = keystore.signerFor(utxo.change, utxo.addressIndex);\n    psbt.signInput(i, signer);\n  });\n\n  try {\n    psbt.finalizeAllInputs();\n  } catch (err) {\n    throw new PsbtError(\n      `Failed to finalize PSBT: ${err instanceof Error ? err.message : String(err)}`,\n    );\n  }\n}\n\nexport function extractTransaction(psbt: bitcoin.Psbt): {\n  txid: string;\n  hex: string;\n  vsize: number;\n} {\n  const tx = psbt.extractTransaction();\n  return {\n    txid: tx.getId(),\n    hex: tx.toHex(),\n    vsize: tx.virtualSize(),\n  };\n}\n\nexport interface WalletSigningRequest {\n  // Xverse / sats-connect consumes the PSBT as base64.\n  psbtBase64: string;\n  // Hex serialization for any wallet that consumes a PSBT as hex.\n  psbtHex: string;\n  // Which inputs the external wallet should sign. Defaults to every input,\n  // all attributed to `signerAddress`.\n  inputsToSign: { address: string; signingIndexes: number[] }[];\n}\n\n// Serialize a built (unsigned) PSBT into the shapes browser wallets expect.\n// This does NOT sign — the internal-signer path (signPsbt) stays untouched, so\n// the same builder output can be routed to either signer.\nexport function prepareForWalletSigning(\n  psbt: bitcoin.Psbt,\n  signerAddress: string,\n): WalletSigningRequest {\n  const signingIndexes = psbt.txInputs.map((_, index) => index);\n  return {\n    psbtBase64: psbt.toBase64(),\n    psbtHex: psbt.toHex(),\n    inputsToSign: [{ address: signerAddress, signingIndexes }],\n  };\n}\n","/**\n * Thin, dependency-free RPC adapter for the hosted Tachi Bitcoin gateways.\n *\n * These helpers are intentionally decoupled from the existing\n * `src/rpc/` Bitcoin Core client: they target the gateway shape used by\n * {@link WalletNetworkConfig} and work with any network object exposing those\n * endpoints — SIGNET, REGTEST, or any future network defined the same way.\n *\n * TWO BACKENDS, one API\n * ---------------------\n * `getUtxos` / `broadcastTx` can talk to either of two very different servers,\n * and pick per network based on what that network configures:\n *\n *  1. **Esplora/Electrs indexer** (`rpc.esplora`) — PREFERRED when set. Signet\n *     points at Xverse's public signet indexer. An indexer answers an address\n *     query from a prebuilt index: ~0.4s vs ~14s, no node-global lock, and it\n *     sees the MEMPOOL, so `status.confirmed` carries real information.\n *\n *  2. **Bitcoin Core JSON-RPC 1.0 proxy** (`rpc.jsonRpc`) — the authoritative\n *     node, and the automatic fallback. The hosted Tachi daemons\n *     (rpc-signet / rpc-regtest.tachibtc.com) are NOT Esplora servers; they\n *     expose this proxy at `POST /`. Here `getUtxos` scans the on-chain UTXO\n *     set via `scantxoutset` and `broadcastTx` submits via\n *     `sendrawtransaction`. Regtest uses this path exclusively — its chain is\n *     small enough that a full scan is already fast.\n *\n * Both reflect the wallet's real L1 balance (not the daemon's L2/VTXO balance),\n * and for signet both serve the same public signet chain.\n *\n * FALLBACK BOUNDARY: only a TRANSPORT failure from the indexer (connection\n * error, timeout, HTTP status, non-JSON body) falls through to the node. A\n * malformed indexer *body* throws instead — falling back on bad data would let\n * a tampered or broken indexer hide behind the node rather than surface as a\n * wrong balance. A broadcast rejection (4xx) is likewise reported, not retried.\n *\n * All methods on both backends are unauthenticated — no API key is sent.\n *\n * Uses the global `fetch` (Node >= 18 and all browsers).\n */\n\nimport { SCAN_RETRY_ATTEMPTS, scanRetryDelay, sleep } from \"../scan-retry.js\";\nimport { btcToSats } from \"../units.js\";\nimport type { WalletNetworkConfig } from \"../types.js\";\n\n// Only the `rpc` endpoints are required, so callers may pass a full\n// WalletNetworkConfig or any structurally-compatible object.\ntype NetworkWithRpc = Pick<WalletNetworkConfig, \"rpc\">;\n\n// Abort hosted-gateway requests that hang so a stalled endpoint can't wedge the\n// browser flow indefinitely (mirrors the 30s cap on the Core RPC client).\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n// fetch wrapper that aborts after `timeoutMs` and reports the timeout clearly.\nasync function fetchWithTimeout(\n  input: string,\n  init: RequestInit = {},\n  timeoutMs: number = DEFAULT_TIMEOUT_MS,\n): Promise<Response> {\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), timeoutMs);\n  try {\n    return await fetch(input, { ...init, signal: controller.signal });\n  } catch (err) {\n    if (err instanceof Error && err.name === \"AbortError\") {\n      throw new Error(`request to ${input} timed out after ${timeoutMs}ms`);\n    }\n    throw err;\n  } finally {\n    clearTimeout(timeout);\n  }\n}\n\n// A confirmation status. The Esplora-style field names are retained as the\n// stable return shape; `getUtxos` populates `confirmed`/`block_height` from the\n// node's `scantxoutset` result (which only sees confirmed outputs).\nexport interface UtxoStatus {\n  confirmed: boolean;\n  block_height?: number;\n  block_hash?: string;\n  block_time?: number;\n}\n\n// A single unspent output, in the Esplora-style shape `getUtxos` returns.\nexport interface RestUtxo {\n  txid: string;\n  vout: number;\n  value: number;\n  status: UtxoStatus;\n}\n\ninterface JsonRpcResponse<T> {\n  result: T;\n  error: { code: number; message: string } | null;\n  id: number | string;\n}\n\nlet rpcIdCounter = 0;\n\n// POST a Bitcoin Core JSON-RPC 1.0 call to the node proxy and return its\n// `result` (throws on RPC/HTTP error). The hosted Tachi daemon serves every\n// method — read and write — without authentication, so no auth header is sent.\nexport async function rpcCall<T = unknown>(\n  network: NetworkWithRpc,\n  method: string,\n  params: readonly unknown[] = [],\n): Promise<T> {\n  const headers: Record<string, string> = {\n    \"content-type\": \"application/json\",\n  };\n  const res = await fetchWithTimeout(network.rpc.jsonRpc, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify({\n      jsonrpc: \"1.0\",\n      id: `taurus-${++rpcIdCounter}`,\n      method,\n      params,\n    }),\n  });\n  if (!res.ok) {\n    // Surface the body for context — the Tachi proxy returns a plain-text\n    // reason (e.g. \"method not permitted\") that is far more actionable than the\n    // bare status line.\n    const detail = (await res.text().catch(() => \"\")).trim().slice(0, 512);\n    throw new Error(\n      `RPC ${method} failed: HTTP ${res.status} ${res.statusText}${\n        detail ? ` — ${detail}` : \"\"\n      }`,\n    );\n  }\n  const body = (await res.json()) as JsonRpcResponse<T>;\n  if (body.error) {\n    throw new Error(`RPC ${method} error: ${body.error.message}`);\n  }\n  return body.result;\n}\n\n// Validate that an arbitrary value from the gateway has the shape and ranges of\n// a RestUtxo. The hosted gateway is untrusted (it can be MITM'd, DNS-poisoned,\n// or compromised), so we never cast its JSON blindly: a malformed response must\n// fail loudly here rather than surface as a NaN balance or feed a garbage value\n// into a downstream consumer's coin selection.\nfunction assertRestUtxo(u: unknown, i: number): asserts u is RestUtxo {\n  const where = `getUtxos: utxo[${i}]`;\n  if (typeof u !== \"object\" || u === null) {\n    throw new Error(`${where} is not an object`);\n  }\n  const o = u as Record<string, unknown>;\n  if (typeof o.txid !== \"string\" || !/^[0-9a-f]{64}$/i.test(o.txid)) {\n    throw new Error(`${where}.txid is not a 32-byte hex string`);\n  }\n  if (!Number.isSafeInteger(o.vout) || (o.vout as number) < 0) {\n    throw new Error(`${where}.vout is not a non-negative integer`);\n  }\n  // A negative, fractional, or out-of-safe-range value can corrupt every sum\n  // and fee/coin-selection decision derived from it.\n  if (!Number.isSafeInteger(o.value) || (o.value as number) < 0) {\n    throw new Error(`${where}.value is not a non-negative safe integer`);\n  }\n  if (\n    typeof o.status !== \"object\" ||\n    o.status === null ||\n    typeof (o.status as Record<string, unknown>).confirmed !== \"boolean\"\n  ) {\n    throw new Error(`${where}.status.confirmed is not a boolean`);\n  }\n}\n\n// The subset of Bitcoin Core's `scantxoutset` result we consume.\ninterface ScantxoutsetResult {\n  success: boolean;\n  height: number;\n  unspents?: Array<{\n    txid: unknown;\n    vout: unknown;\n    amount: unknown; // BTC (float), per Bitcoin Core\n    height?: unknown;\n  }>;\n}\n\n// Bitcoin addresses are alphanumeric (bech32/bech32m) or base58; neither\n// contains the parentheses/commas/whitespace that would let a caller-supplied\n// string break out of the `addr(...)` output descriptor below. Reject anything\n// else loudly rather than forwarding a crafted descriptor to the node.\nfunction assertPlainAddress(address: string): void {\n  if (!/^[a-zA-Z0-9]+$/.test(address)) {\n    throw new Error(`getUtxos: refusing to scan malformed address`);\n  }\n}\n\n// Retrying a busy/timed-out `scantxoutset` rather than surfacing a hard error to\n// the balance UI. The attempt count and backoff curve are the shared policy in\n// src/scan-retry.ts, which the Core-RPC path (scanForUtxos) uses too.\n//\n// Detection differs from that path, though: this transport has no typed error\n// class, so error -8 arrives as text from rpcCall (\"RPC scantxoutset error:\n// bitcoin rpc error -8: Scan already in progress, …\") and the abort at\n// DEFAULT_TIMEOUT_MS as \"request to … timed out …\". Match either.\nfunction isRetryableScanError(err: unknown): boolean {\n  if (!(err instanceof Error)) return false;\n  return /scan already in progress|rpc error -8|\\btimed out\\b/i.test(\n    err.message,\n  );\n}\n\n// ---------------------------------------------------------------------------\n// Esplora/Electrs indexer path (preferred when `network.rpc.esplora` is set)\n// ---------------------------------------------------------------------------\n//\n// An indexer answers an address query from a prebuilt index, so it returns in\n// milliseconds where `scantxoutset` walks the entire UTXO set (~14s on signet)\n// under a node-global lock. It also sees the mempool, so `status.confirmed`\n// carries real information instead of being hardcoded true.\n\n// A transport-level failure is one where the indexer did not deliver a usable\n// answer: DNS/connection error, timeout, or an HTTP status. These are the only\n// conditions that justify falling back to the authoritative JSON-RPC node —\n// a malformed *body* is a correctness problem and must surface loudly, since\n// silently falling back would let a tampered indexer hide behind the node.\nclass EsploraTransportError extends Error {}\n\n// GET the Esplora UTXO list for an address: `/address/:addr/utxo`, which\n// returns exactly the RestUtxo shape (value already in sats).\nasync function getUtxosEsplora(\n  base: string,\n  address: string,\n): Promise<RestUtxo[]> {\n  let res: Response;\n  try {\n    res = await fetchWithTimeout(\n      `${base}/address/${encodeURIComponent(address)}/utxo`,\n      { headers: { accept: \"application/json\" } },\n    );\n  } catch (err) {\n    throw new EsploraTransportError(\n      `esplora getUtxos: ${err instanceof Error ? err.message : String(err)}`,\n    );\n  }\n  if (!res.ok) {\n    const detail = (await res.text().catch(() => \"\")).trim().slice(0, 256);\n    throw new EsploraTransportError(\n      `esplora getUtxos: HTTP ${res.status} ${res.statusText}${\n        detail ? ` — ${detail}` : \"\"\n      }`,\n    );\n  }\n\n  let body: unknown;\n  try {\n    body = await res.json();\n  } catch (err) {\n    // A body that is not JSON at all is a transport/proxy problem (captive\n    // portal, HTML error page), not indexer data — worth falling back.\n    throw new EsploraTransportError(\n      `esplora getUtxos: response was not JSON: ${\n        err instanceof Error ? err.message : String(err)\n      }`,\n    );\n  }\n\n  // Past this point the indexer DID answer, so any shape violation is a real\n  // data problem and must throw rather than fall back. Same trust boundary as\n  // the scantxoutset path: shape and range only, never authenticity.\n  if (!Array.isArray(body)) {\n    throw new Error(\"getUtxos: esplora response is not an array\");\n  }\n  return body.map((u, i) => {\n    assertRestUtxo(u, i);\n    const status = u.status;\n    return {\n      txid: u.txid,\n      vout: u.vout,\n      value: u.value,\n      status: {\n        confirmed: status.confirmed,\n        ...(typeof status.block_height === \"number\"\n          ? { block_height: status.block_height }\n          : {}),\n        ...(typeof status.block_hash === \"string\"\n          ? { block_hash: status.block_hash }\n          : {}),\n        ...(typeof status.block_time === \"number\"\n          ? { block_time: status.block_time }\n          : {}),\n      },\n    };\n  });\n}\n\n// POST a raw transaction hex to the indexer's `/tx` endpoint; it returns the\n// txid as plain text.\nasync function broadcastTxEsplora(\n  base: string,\n  txHex: string,\n): Promise<string> {\n  let res: Response;\n  try {\n    res = await fetchWithTimeout(`${base}/tx`, {\n      method: \"POST\",\n      headers: { \"content-type\": \"text/plain\" },\n      body: txHex,\n    });\n  } catch (err) {\n    throw new EsploraTransportError(\n      `esplora broadcastTx: ${err instanceof Error ? err.message : String(err)}`,\n    );\n  }\n  const text = (await res.text().catch(() => \"\")).trim();\n  if (!res.ok) {\n    // Distinguish \"the node looked at this transaction and said no\" from \"this\n    // endpoint could not process the request at all\".\n    //\n    // 400/422 is bitcoind REJECTING the tx (bad signature, insufficient fee,\n    // double spend) — a real, deterministic answer. Retrying it against the\n    // JSON-RPC node would produce the same rejection, so surface it.\n    //\n    // Every other status (404 route missing on a mis-set esplora base, 405,\n    // 403 policy, 429 rate limit, 5xx) says nothing about the transaction's\n    // validity. Treating those as rejections would report a perfectly good\n    // transaction as invalid and skip the working fallback — so they fall\n    // through to the node instead.\n    if (res.status === 400 || res.status === 422) {\n      throw new Error(\n        `broadcastTx rejected by esplora: HTTP ${res.status}${\n          text ? ` — ${text.slice(0, 512)}` : \"\"\n        }`,\n      );\n    }\n    throw new EsploraTransportError(\n      `esplora broadcastTx: HTTP ${res.status} ${res.statusText}${\n        text ? ` — ${text.slice(0, 256)}` : \"\"\n      }`,\n    );\n  }\n  if (!/^[0-9a-f]{64}$/i.test(text)) {\n    throw new Error(\n      `broadcastTx: esplora did not return a txid (got \"${text.slice(0, 128)}\")`,\n    );\n  }\n  return text;\n}\n\nexport interface GetUtxosOptions {\n  // How many times to retry a transient scantxoutset failure (busy node /\n  // timeout) before giving up. Defaults to SCAN_RETRY_ATTEMPTS. Set to 0 to\n  // disable retries.\n  scanRetries?: number;\n  // Set false to skip the Esplora indexer and force the JSON-RPC\n  // `scantxoutset` path even when `network.rpc.esplora` is configured.\n  // Defaults to true.\n  preferEsplora?: boolean;\n}\n\n/**\n * Fetch the unspent outputs for an address.\n *\n * Two paths, in preference order:\n *\n *   1. `network.rpc.esplora`, when one is configured (signet is) and\n *      `options.preferEsplora !== false`. An indexer answers in ~0.4s, takes no\n *      node-global lock, and sees the MEMPOOL — so unconfirmed outputs come back\n *      with `status.confirmed === false`.\n *   2. The node's `scantxoutset` JSON-RPC (the Tachi daemon is not Esplora),\n *      which is authoritative and the automatic fallback when the indexer is\n *      unreachable. It does NOT see the mempool, so every UTXO it returns is\n *      reported as confirmed.\n *\n * Only a TRANSPORT failure from the indexer falls back. A malformed indexer\n * response throws, so a broken or tampered indexer surfaces rather than hiding\n * behind the node.\n *\n * Because `scantxoutset` holds a node-global lock (see the retry note above), a\n * concurrent scan on the shared gateway can make path 2 transiently fail; the\n * call retries such failures with backoff before throwing. Retries are bounded\n * by `options.scanRetries`.\n *\n * TRUST BOUNDARY: the returned values are only validated for *shape and range*,\n * not *authenticity*. The hosted gateway is trusted to report the correct UTXO\n * set. This is acceptable for the display-only balance path\n * ({@link useTestnetWallet}'s `refreshBalance`), but any caller that uses these\n * UTXOs to BUILD or SIGN a transaction MUST re-verify each input's value and\n * scriptPubKey against its parent transaction first — see `verifyParentOutput`\n * in `src/psbt.ts`, which defends the Core-RPC signing path against exactly this\n * tampering. Do not trust `value` from this function for fee or coin-selection\n * decisions without that check.\n */\nexport async function getUtxos(\n  network: NetworkWithRpc,\n  address: string,\n  options: GetUtxosOptions = {},\n): Promise<RestUtxo[]> {\n  assertPlainAddress(address);\n\n  // Prefer the indexer when one is configured: ~35x faster on signet, no\n  // node-global lock, and real mempool visibility. Only a transport failure\n  // falls through to the authoritative node below.\n  const esplora = network.rpc.esplora;\n  if (esplora && options.preferEsplora !== false) {\n    try {\n      return await getUtxosEsplora(esplora, address);\n    } catch (err) {\n      if (!(err instanceof EsploraTransportError)) throw err;\n      // Indexer unreachable — fall through to scantxoutset.\n    }\n  }\n\n  const maxRetries = options.scanRetries ?? SCAN_RETRY_ATTEMPTS;\n\n  // Retry only the RPC call itself — a transient busy/timeout failure is worth\n  // re-issuing, but a shape/range error from parsing below is deterministic and\n  // must surface immediately.\n  let result: ScantxoutsetResult;\n  for (let attempt = 0; ; attempt++) {\n    try {\n      result = await rpcCall<ScantxoutsetResult>(network, \"scantxoutset\", [\n        \"start\",\n        [{ desc: `addr(${address})` }],\n      ]);\n      break;\n    } catch (err) {\n      if (attempt < maxRetries && isRetryableScanError(err)) {\n        await sleep(scanRetryDelay(attempt));\n        continue;\n      }\n      throw err;\n    }\n  }\n  if (!result || result.success !== true) {\n    throw new Error(\"getUtxos: scantxoutset did not complete successfully\");\n  }\n  const utxos: RestUtxo[] = (result.unspents ?? []).map((u, i) => {\n    // Convert the BTC float amount to integer sats up front so the safe-integer\n    // guard in assertRestUtxo catches any absurd value the node reports.\n    let valueSats: number;\n    try {\n      valueSats = Number(btcToSats(u.amount as number));\n    } catch {\n      throw new Error(`getUtxos: utxo[${i}].amount is not a valid BTC amount`);\n    }\n    const blockHeight =\n      typeof u.height === \"number\" && Number.isSafeInteger(u.height)\n        ? u.height\n        : undefined;\n    const utxo: RestUtxo = {\n      txid: u.txid as string,\n      vout: u.vout as number,\n      value: valueSats,\n      status: {\n        confirmed: true,\n        ...(blockHeight !== undefined ? { block_height: blockHeight } : {}),\n      },\n    };\n    assertRestUtxo(utxo, i);\n    return utxo;\n  });\n  return utxos;\n}\n\nexport interface BroadcastTxOptions {\n  // Set false to skip the Esplora indexer and broadcast via JSON-RPC\n  // `sendrawtransaction` even when `network.rpc.esplora` is configured.\n  // Defaults to true.\n  preferEsplora?: boolean;\n}\n\n/**\n * Broadcast a raw transaction hex and return the txid.\n *\n * Uses the Esplora indexer's `POST /tx` when one is configured, falling back to\n * the node's `sendrawtransaction` JSON-RPC if the indexer is unreachable. Both\n * ultimately hand the transaction to the same bitcoind on the same chain.\n *\n * A REJECTION (bad signature, insufficient fee, double spend) is returned as a\n * hard error from whichever path saw it — it is not retried against the other,\n * since the second node would reject it identically and a spurious retry could\n * mask the real reason.\n *\n * The hosted Tachi daemon accepts `sendrawtransaction` without authentication,\n * so no API key is required.\n */\nexport async function broadcastTx(\n  network: NetworkWithRpc,\n  txHex: string,\n  options: BroadcastTxOptions = {},\n): Promise<string> {\n  const esplora = network.rpc.esplora;\n  if (esplora && options.preferEsplora !== false) {\n    try {\n      return await broadcastTxEsplora(esplora, txHex);\n    } catch (err) {\n      if (!(err instanceof EsploraTransportError)) throw err;\n      // Indexer unreachable — fall through to the node.\n    }\n  }\n  return rpcCall<string>(network, \"sendrawtransaction\", [txHex]);\n}\n","/**\n * BIP-322 \"simple\" signature verification for P2WPKH and P2TR addresses.\n *\n * NOTE: `bitcoinjs-message` only implements the legacy \"Bitcoin Signed Message\"\n * (ECDSA) scheme — it does NOT support BIP-322. Xverse returns BIP-322\n * signatures, so this module implements the BIP-322 *simple*\n * verification manually with bitcoinjs-lib, following the toSpend / toSign\n * virtual-transaction construction from the BIP:\n *\n *   1. message_hash = tagged_hash(\"BIP0322-signed-message\", message)\n *   2. toSpend: a 0-fee tx whose single input commits to message_hash and\n *      whose single output pays the address' scriptPubKey.\n *   3. toSign:  spends toSpend[0] carrying the provided witness, outputs\n *      an OP_RETURN. Its sighash is what the wallet actually signed.\n *\n * Verification then checks the witness signature against that sighash and\n * confirms the key commits to the address.\n */\n\nimport * as ecc from \"@bitcoinerlab/secp256k1\";\nimport * as bitcoin from \"bitcoinjs-lib\";\nimport type { NetworkName } from \"../types.js\";\n\n// Initialise the secp256k1 backend (idempotent across the SDK).\nbitcoin.initEccLib(ecc);\n\nexport interface VerifyResult {\n  valid: boolean;\n  reason?: string;\n  // The network the address was resolved on. Present whenever the address\n  // parsed (regardless of whether signature verification then succeeded), so\n  // callers using a signature as a proof-of-ownership can assert the\n  // address↔network binding. The testnet family (testnet/signet) shares an\n  // identical address encoding and is reported as \"testnet\" when no expected\n  // network was supplied; pass `expectedNetwork` to bind precisely.\n  network?: NetworkName;\n}\n\nconst BIP322_TAG = \"BIP0322-signed-message\";\n\n// tagged_hash(tag, msg) = SHA256(SHA256(tag) || SHA256(tag) || msg)\nfunction taggedHash(tag: string, msg: Uint8Array): Buffer {\n  const tagHash = bitcoin.crypto.sha256(Buffer.from(tag, \"utf8\"));\n  return Buffer.from(\n    bitcoin.crypto.sha256(Buffer.concat([tagHash, tagHash, msg])),\n  );\n}\n\n// Resolve an address to its scriptPubKey along with the network it parsed on.\n// The scriptPubKey is identical across networks (only the HRP/version differs),\n// so without a binding we try each distinct bitcoinjs network in turn. When\n// `expected` is supplied we resolve *only* against that network, so a signature\n// over an address on some other network is rejected rather than silently\n// accepted (see VerifyResult.network).\nfunction getOutputScript(\n  address: string,\n  expected?: NetworkName,\n): { scriptPubKey: Uint8Array; network: NetworkName } | null {\n  // Address decoding is purely about the encoding family (HRP/version bytes),\n  // independent of which networks the registry exposes as selectable — signet\n  // reuses testnet's encoding, so we map each NetworkName straight onto its\n  // bitcoinjs-lib Network object rather than going through getNetwork().\n  const family: Record<NetworkName, bitcoin.networks.Network> = {\n    mainnet: bitcoin.networks.bitcoin,\n    testnet: bitcoin.networks.testnet,\n    signet: bitcoin.networks.testnet,\n    regtest: bitcoin.networks.regtest,\n  };\n  const candidates: { name: NetworkName; network: bitcoin.networks.Network }[] =\n    expected\n      ? [{ name: expected, network: family[expected] }]\n      : [\n          { name: \"mainnet\", network: bitcoin.networks.bitcoin },\n          { name: \"testnet\", network: bitcoin.networks.testnet },\n          { name: \"regtest\", network: bitcoin.networks.regtest },\n        ];\n  for (const { name, network } of candidates) {\n    try {\n      return {\n        scriptPubKey: bitcoin.address.toOutputScript(address, network),\n        network: name,\n      };\n    } catch {\n      // Not valid on this network — try the next.\n    }\n  }\n  return null;\n}\n\nfunction buildToSpend(\n  scriptPubKey: Uint8Array,\n  messageHash: Buffer,\n): bitcoin.Transaction {\n  const tx = new bitcoin.Transaction();\n  tx.version = 0;\n  tx.locktime = 0;\n  // scriptSig = OP_0 PUSH32[message_hash]\n  const scriptSig = bitcoin.script.compile([bitcoin.opcodes.OP_0, messageHash]);\n  // prevout = (0x00 * 32 : 0xffffffff), nSequence = 0\n  tx.addInput(Buffer.alloc(32, 0), 0xffffffff, 0, scriptSig);\n  tx.addOutput(Buffer.from(scriptPubKey), 0n);\n  return tx;\n}\n\nfunction buildToSign(\n  toSpend: bitcoin.Transaction,\n  witness: Uint8Array[],\n): bitcoin.Transaction {\n  const tx = new bitcoin.Transaction();\n  tx.version = 0;\n  tx.locktime = 0;\n  // Spends toSpend[0] with an empty scriptSig and nSequence = 0.\n  tx.addInput(toSpend.getHash(false), 0, 0);\n  // Single OP_RETURN output, value 0.\n  tx.addOutput(bitcoin.script.compile([bitcoin.opcodes.OP_RETURN]), 0n);\n  tx.setWitness(0, witness);\n  return tx;\n}\n\n// Decode a serialized witness stack (compactSize count, then length-prefixed\n// items) as produced by a BIP-322 simple signature.\nfunction parseWitnessStack(buf: Buffer): Uint8Array[] {\n  let offset = 0;\n  const readCompactSize = (): number => {\n    if (offset >= buf.length) throw new Error(\"truncated witness\");\n    const first = buf[offset++];\n    if (first < 0xfd) return first;\n    if (first === 0xfd) {\n      const v = buf.readUInt16LE(offset);\n      offset += 2;\n      return v;\n    }\n    if (first === 0xfe) {\n      const v = buf.readUInt32LE(offset);\n      offset += 4;\n      return v;\n    }\n    throw new Error(\"witness item too large\");\n  };\n\n  // A BIP-322 simple signature (P2WPKH/P2TR) has at most a handful of small\n  // witness items, so cap count and per-item length to reject crafted inputs\n  // that declare huge sizes to force disproportionate work.\n  const MAX_WITNESS_ITEMS = 8;\n  const MAX_WITNESS_ITEM_LEN = 1024;\n\n  const count = readCompactSize();\n  if (count > MAX_WITNESS_ITEMS) throw new Error(\"witness stack too large\");\n  const items: Uint8Array[] = [];\n  for (let i = 0; i < count; i++) {\n    const len = readCompactSize();\n    if (len > MAX_WITNESS_ITEM_LEN) throw new Error(\"witness item too large\");\n    if (offset + len > buf.length) throw new Error(\"truncated witness item\");\n    items.push(buf.subarray(offset, offset + len));\n    offset += len;\n  }\n  return items;\n}\n\nfunction verifyP2wpkh(\n  scriptPubKey: Uint8Array,\n  toSign: bitcoin.Transaction,\n  witness: Uint8Array[],\n): VerifyResult {\n  if (witness.length < 2) {\n    return {\n      valid: false,\n      reason: \"P2WPKH witness must be [signature, pubkey]\",\n    };\n  }\n  const sig = Buffer.from(witness[0]);\n  const pubkey = Buffer.from(witness[1]);\n  const keyhash = scriptPubKey.subarray(2); // 20-byte program\n\n  if (!Buffer.from(bitcoin.crypto.hash160(pubkey)).equals(keyhash)) {\n    return { valid: false, reason: \"public key does not match address\" };\n  }\n\n  const decoded = bitcoin.script.signature.decode(sig);\n  // BIP143 scriptCode for P2WPKH: OP_DUP OP_HASH160 <kh> OP_EQUALVERIFY OP_CHECKSIG\n  const scriptCode = bitcoin.script.compile([\n    bitcoin.opcodes.OP_DUP,\n    bitcoin.opcodes.OP_HASH160,\n    keyhash,\n    bitcoin.opcodes.OP_EQUALVERIFY,\n    bitcoin.opcodes.OP_CHECKSIG,\n  ]);\n  const sighash = toSign.hashForWitnessV0(0, scriptCode, 0n, decoded.hashType);\n  const valid = ecc.verify(sighash, pubkey, decoded.signature);\n  return valid\n    ? { valid: true }\n    : { valid: false, reason: \"signature verification failed\" };\n}\n\nfunction verifyP2tr(\n  scriptPubKey: Uint8Array,\n  toSign: bitcoin.Transaction,\n  witness: Uint8Array[],\n): VerifyResult {\n  if (witness.length < 1) {\n    return { valid: false, reason: \"P2TR witness must contain a signature\" };\n  }\n  let sig = Buffer.from(witness[0]);\n  let hashType = bitcoin.Transaction.SIGHASH_DEFAULT;\n  if (sig.length === 65) {\n    hashType = sig[64];\n    sig = sig.subarray(0, 64);\n  } else if (sig.length !== 64) {\n    return {\n      valid: false,\n      reason: `unexpected schnorr signature length ${sig.length}`,\n    };\n  }\n  const outputKey = scriptPubKey.subarray(2); // 32-byte x-only key\n  const sighash = toSign.hashForWitnessV1(\n    0,\n    [Buffer.from(scriptPubKey)],\n    [0n],\n    hashType,\n  );\n  const valid = ecc.verifySchnorr(sighash, outputKey, sig);\n  return valid\n    ? { valid: true }\n    : { valid: false, reason: \"schnorr signature verification failed\" };\n}\n\n/**\n * Verify a BIP-322 simple signature for a P2WPKH or P2TR address.\n *\n * @param address         the signer's address (P2WPKH `bc1q…` / P2TR `bc1p…`)\n * @param message         the signed message (UTF-8)\n * @param signatureBase64 base64-encoded witness stack (as returned by wallets)\n * @param expectedNetwork when set, the address must parse on this network or\n *                        verification fails — bind this for proof-of-ownership\n *                        use cases so a signature over an address on a\n *                        different network is not silently accepted. The\n *                        resolved network is echoed back on `VerifyResult.network`.\n */\nexport function verifyBip322Signature(\n  address: string,\n  message: string,\n  signatureBase64: string,\n  expectedNetwork?: NetworkName,\n): VerifyResult {\n  try {\n    const resolved = getOutputScript(address, expectedNetwork);\n    if (!resolved) {\n      return {\n        valid: false,\n        reason: expectedNetwork\n          ? `address not valid on expected network ${expectedNetwork}: ${address}`\n          : `unrecognized address: ${address}`,\n      };\n    }\n    const { scriptPubKey, network } = resolved;\n\n    const messageHash = taggedHash(BIP322_TAG, Buffer.from(message, \"utf8\"));\n    const toSpend = buildToSpend(scriptPubKey, messageHash);\n    const witness = parseWitnessStack(Buffer.from(signatureBase64, \"base64\"));\n    const toSign = buildToSign(toSpend, witness);\n\n    // P2WPKH: OP_0 <20-byte keyhash>\n    if (\n      scriptPubKey.length === 22 &&\n      scriptPubKey[0] === 0x00 &&\n      scriptPubKey[1] === 0x14\n    ) {\n      return { ...verifyP2wpkh(scriptPubKey, toSign, witness), network };\n    }\n    // P2TR: OP_1 <32-byte x-only key>\n    if (\n      scriptPubKey.length === 34 &&\n      scriptPubKey[0] === 0x51 &&\n      scriptPubKey[1] === 0x20\n    ) {\n      return { ...verifyP2tr(scriptPubKey, toSign, witness), network };\n    }\n    return {\n      valid: false,\n      reason: \"only P2WPKH and P2TR addresses are supported\",\n      network,\n    };\n  } catch (err) {\n    return {\n      valid: false,\n      reason: err instanceof Error ? err.message : String(err),\n    };\n  }\n}\n","import {\n  FeeRateError,\n  InsufficientFundsError,\n  InvalidAmountError,\n} from \"./errors.js\";\nimport type { AddressType, Utxo } from \"./types.js\";\nimport { SAFE_DUST_THRESHOLD_SATS } from \"./units.js\";\n\nexport interface CoinSelectionInput {\n  utxos: readonly Utxo[];\n  // Target amount in satoshis (excluding fee)\n  amountSats: bigint;\n  // Fee rate in sat/vB. Must be ≥ 1\n  feeRate: number;\n  // Address type used by the wallet's inputs (for vsize estimation)\n  inputAddressType: AddressType;\n  // Address type of the recipient output\n  outputAddressType: AddressType;\n  // Address type of the change output\n  changeAddressType?: AddressType;\n  // If true, send the entire UTXO set to the recipient\n  sweep?: boolean;\n}\n\nexport interface CoinSelectionResult {\n  inputs: Utxo[];\n  feeSats: bigint;\n  changeSats: bigint;\n  outputCount: number;\n  vsize: number;\n}\n\n// Approximate vsize (vB) per input/output script type. p2wpkh only for now.\n// p2wpkh input ≈ 68 vB (witness signature/pubkey are weight-discounted);\n// p2wpkh output = 31 vB.\nconst INPUT_VSIZE: Record<AddressType, number> = {\n  p2wpkh: 68,\n};\n\nconst OUTPUT_VSIZE: Record<AddressType, number> = {\n  p2wpkh: 31,\n};\n\nexport function estimateVsize(\n  inputType: AddressType,\n  outputTypes: readonly AddressType[],\n  nInputs: number,\n): number {\n  // Base tx overhead (version, locktime, in/out counts) = 10 vB, plus the\n  // segwit marker + flag (2 weight units = 0.5 vB).\n  const overhead = 10.5;\n  const inSize = INPUT_VSIZE[inputType] * nInputs;\n  const outSize = outputTypes.reduce((acc, t) => acc + OUTPUT_VSIZE[t], 0);\n  return Math.ceil(overhead + inSize + outSize);\n}\n\nexport function selectCoins(opts: CoinSelectionInput): CoinSelectionResult {\n  const {\n    utxos,\n    amountSats,\n    feeRate,\n    inputAddressType,\n    outputAddressType,\n    changeAddressType = inputAddressType,\n    sweep = false,\n  } = opts;\n\n  if (!Number.isFinite(feeRate) || feeRate < 1) {\n    throw new FeeRateError(\n      `feeRate must be a finite number ≥ 1 sat/vB, got ${feeRate}`,\n    );\n  }\n  if (!sweep && amountSats <= 0n) {\n    throw new InvalidAmountError(`amountSats must be > 0, got ${amountSats}`);\n  }\n  if (!sweep && amountSats < SAFE_DUST_THRESHOLD_SATS) {\n    throw new InvalidAmountError(\n      `amountSats ${amountSats} is below dust threshold ${SAFE_DUST_THRESHOLD_SATS}`,\n    );\n  }\n\n  if (utxos.length === 0) {\n    throw new InsufficientFundsError(0n, sweep ? 1n : amountSats);\n  }\n\n  // Largest-first ordering. Stable sort on (value, txid, vout) so the result is reproducible across runs important for tests and audit.\n  const sorted = [...utxos].sort((a, b) => {\n    if (a.valueSats !== b.valueSats) return a.valueSats > b.valueSats ? -1 : 1;\n    if (a.txid !== b.txid) return a.txid < b.txid ? -1 : 1;\n    return a.vout - b.vout;\n  });\n\n  if (sweep) {\n    return buildSweep(sorted, feeRate, inputAddressType, outputAddressType);\n  }\n\n  const selected: Utxo[] = [];\n  let total = 0n;\n\n  for (const u of sorted) {\n    selected.push(u);\n    total += u.valueSats;\n\n    // Try a \"with change\" tx first.\n    const vsizeWithChange = estimateVsize(\n      inputAddressType,\n      [outputAddressType, changeAddressType],\n      selected.length,\n    );\n    const feeWithChange = BigInt(Math.ceil(vsizeWithChange * feeRate));\n\n    if (total >= amountSats + feeWithChange) {\n      const change = total - amountSats - feeWithChange;\n      if (change >= SAFE_DUST_THRESHOLD_SATS) {\n        return {\n          inputs: selected,\n          feeSats: feeWithChange,\n          changeSats: change,\n          outputCount: 2,\n          vsize: vsizeWithChange,\n        };\n      }\n\n      // Change would be dust try a single-output tx and absorb the dust into the fee.\n      const vsizeNoChange = estimateVsize(\n        inputAddressType,\n        [outputAddressType],\n        selected.length,\n      );\n      const feeNoChange = BigInt(Math.ceil(vsizeNoChange * feeRate));\n      if (total >= amountSats + feeNoChange) {\n        return {\n          inputs: selected,\n          feeSats: total - amountSats,\n          changeSats: 0n,\n          outputCount: 1,\n          vsize: vsizeNoChange,\n        };\n      }\n      // Single-output also doesn't fit — keep adding inputs.\n    }\n  }\n\n  // Exhausted UTXO set without covering amount + fee.\n  const requiredEstimate =\n    amountSats +\n    BigInt(\n      Math.ceil(\n        estimateVsize(\n          inputAddressType,\n          [outputAddressType, changeAddressType],\n          selected.length || 1,\n        ) * feeRate,\n      ),\n    );\n  throw new InsufficientFundsError(total, requiredEstimate);\n}\n\nfunction buildSweep(\n  sorted: readonly Utxo[],\n  feeRate: number,\n  inputAddressType: AddressType,\n  outputAddressType: AddressType,\n): CoinSelectionResult {\n  const inputs = [...sorted];\n  const total = inputs.reduce((acc, u) => acc + u.valueSats, 0n);\n  const vsize = estimateVsize(\n    inputAddressType,\n    [outputAddressType],\n    inputs.length,\n  );\n  const fee = BigInt(Math.ceil(vsize * feeRate));\n  if (total <= fee + SAFE_DUST_THRESHOLD_SATS) {\n    throw new InsufficientFundsError(total, fee + SAFE_DUST_THRESHOLD_SATS);\n  }\n  return {\n    inputs,\n    feeSats: fee,\n    changeSats: 0n,\n    outputCount: 1,\n    vsize,\n  };\n}\n","/**\n * KeystoreProvider — built-in WalletProvider backed by BIP39/BIP32 HD derivation.\n *\n * Wraps `Keystore` so `Wallet` can consume it via the generic `WalletProvider` interface,\n * preserving all Keystore security guarantees (private fields, lock/wipe, safe serialization).\n *\n * Usage:\n *   const keystore = Keystore.fromSeedBytes(seed, network, 'p2wpkh', 0);\n *   const provider = new KeystoreProvider(keystore);\n *   const wallet   = new Wallet({ provider, rpc });\n */\n\nimport type * as bitcoin from \"bitcoinjs-lib\";\n\nimport {\n  type Keystore,\n  buildDescriptor,\n  deriveAddressFromAccountNode,\n} from \"../derivation.js\";\nimport { signPsbt as signPsbtWithKeystore } from \"../psbt.js\";\nimport type {\n  AddressType,\n  DerivedKey,\n  NetworkConfig,\n  SignerInfo,\n  Utxo,\n} from \"../types.js\";\nimport type { WalletProvider } from \"./types.js\";\n\nexport class KeystoreProvider implements WalletProvider {\n  readonly name = \"keystore\";\n\n  // The built-in HD signer is the trusted provider that builds and signs PSBTs\n  // locally, so it explicitly opts in to the internal Wallet.send() flow. All\n  // other providers fail closed unless they set this too (see WalletProvider).\n  readonly supportsInternalSend = true;\n\n  readonly #keystore: Keystore;\n\n  constructor(keystore: Keystore) {\n    this.#keystore = keystore;\n  }\n\n  get network(): NetworkConfig {\n    return this.#keystore.network;\n  }\n\n  get addressType(): AddressType {\n    return this.#keystore.addressType;\n  }\n\n  get account(): number {\n    return this.#keystore.account;\n  }\n\n  get fingerprint(): string {\n    return this.#keystore.fingerprint;\n  }\n\n  get accountPath(): string {\n    return this.#keystore.accountPath;\n  }\n\n  get accountXpub(): string {\n    return this.#keystore.accountXpub;\n  }\n\n  get locked(): boolean {\n    return this.#keystore.locked;\n  }\n\n  // Address derivation\n  deriveReceiveAddresses(count: number): DerivedKey[] {\n    return this.#deriveChain(false, count);\n  }\n\n  deriveChangeAddresses(count: number): DerivedKey[] {\n    return this.#deriveChain(true, count);\n  }\n\n  // Signing\n  signPsbt(psbt: bitcoin.Psbt, inputs: readonly Utxo[]): void {\n    signPsbtWithKeystore({ psbt, inputs, keystore: this.#keystore });\n  }\n\n  // Descriptors\n  buildDescriptor(change: boolean): string {\n    return buildDescriptor(\n      this.#keystore.addressType,\n      this.#keystore.fingerprint,\n      this.#keystore.accountPath,\n      this.#keystore.accountXpub,\n      change,\n    );\n  }\n\n  // Signer info\n  getSignerInfo(): SignerInfo {\n    return {\n      fingerprint: this.#keystore.fingerprint,\n      accountPath: this.#keystore.accountPath,\n      accountXpub: this.#keystore.accountXpub,\n      addressType: this.#keystore.addressType,\n      canSign: !this.#keystore.locked,\n    };\n  }\n\n  lock(): void {\n    this.#keystore.lock();\n  }\n\n  #deriveChain(change: boolean, count: number): DerivedKey[] {\n    const accountNode = this.#keystore.watchOnlyAccountNode();\n    const addresses: DerivedKey[] = [];\n    for (let i = 0; i < count; i++) {\n      addresses.push(\n        deriveAddressFromAccountNode(\n          accountNode,\n          this.#keystore.addressType,\n          this.#keystore.network,\n          this.#keystore.account,\n          change,\n          i,\n        ),\n      );\n    }\n    return addresses;\n  }\n\n  [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n    return `KeystoreProvider(${this.addressType} ${this.accountPath} fp=${this.fingerprint} locked=${this.locked})`;\n  }\n\n  toJSON(): Record<string, unknown> {\n    return {\n      name: this.name,\n      addressType: this.addressType,\n      accountPath: this.accountPath,\n      fingerprint: this.fingerprint,\n      locked: this.locked,\n    };\n  }\n}\n","import * as bip39 from \"bip39\";\n\nimport {\n  Keystore,\n  generateMnemonic,\n  normalizeMnemonic,\n  validateMnemonic as checkMnemonic,\n} from \"./derivation.js\";\nimport { InvalidMnemonicError, WalletError } from \"./errors.js\";\nimport { getNetwork } from \"./network.js\";\nimport { KeystoreProvider } from \"./providers/keystore-provider.js\";\nimport type { WalletProvider } from \"./providers/types.js\";\nimport type { ScanRetryOptions } from \"./rpc/index.js\";\nimport type { RpcClient } from \"./rpc/types.js\";\nimport type { AddressType, SignerInfo, Utxo, WalletBalance } from \"./types.js\";\nimport { Wallet } from \"./wallet.js\";\n\n// Reserved provider names (cannot be used by external providers).\nconst RESERVED_PROVIDER_NAMES = new Set([\"keystore\"]);\n\nexport interface AggregatorConfig {\n  // Network name must match a built-in or custom-registered network\n  network: string;\n  rpc: RpcClient;\n  // Optional BIP39 passphrase (applied once at construction, then discarded)\n  // The passphrase is NOT retained on the aggregator instance.\n  passphrase?: string;\n  // Gap limit propagated to every child Wallet\n  gapLimit?: number;\n  // Maximum number of rescan iterations per sync(). Guards against adversarial\n  // RPC endpoints claiming unbounded activity at the window edge.\n  maxSyncIterations?: number;\n  // Backoff policy for scantxoutset lock contention, propagated to every child\n  // Wallet. Defaults apply when omitted — see scanForUtxos.\n  scanRetry?: ScanRetryOptions;\n}\n\nexport interface AccountSpec {\n  addressType: AddressType;\n  account?: number;\n  // Defaults to \"keystore\" for backward compatibility\n  provider?: string;\n}\n\nexport interface AggregatorInfo {\n  network: string;\n  signers: readonly SignerInfo[];\n  wallets: number;\n}\n\n// Internal retained config (passphrase deliberately excluded).\ninterface RetainedConfig {\n  network: string;\n  rpc: RpcClient;\n  gapLimit?: number;\n  maxSyncIterations?: number;\n  scanRetry?: ScanRetryOptions;\n}\n\n// Private wrapper so `lock()` can zero the seed in-place before dropping the reference.\nclass SeedRef {\n  #value: Uint8Array | null;\n\n  constructor(seed: Uint8Array) {\n    this.#value = seed;\n  }\n\n  get value(): Uint8Array | null {\n    return this.#value;\n  }\n\n  wipe(): void {\n    if (this.#value) {\n      this.#value.fill(0);\n      this.#value = null;\n    }\n  }\n}\n\nexport class WalletAggregator {\n  readonly #config: RetainedConfig;\n  readonly #wallets = new Map<string, Wallet>();\n  #seedRef: SeedRef | null;\n\n  private constructor(config: RetainedConfig, seed: Uint8Array) {\n    this.#config = config;\n    this.#seedRef = new SeedRef(seed);\n  }\n\n  static fromMnemonic(\n    mnemonic: string,\n    config: AggregatorConfig,\n  ): WalletAggregator {\n    const cleaned = normalizeMnemonic(mnemonic);\n    if (!checkMnemonic(cleaned)) {\n      throw new InvalidMnemonicError();\n    }\n    getNetwork(config.network);\n    const seedBuf = bip39.mnemonicToSeedSync(cleaned, config.passphrase ?? \"\");\n    try {\n      // Copy the bytes we need and retain only what's safe to keep.\n      const seedCopy = new Uint8Array(seedBuf);\n      return new WalletAggregator(stripConfig(config), seedCopy);\n    } finally {\n      seedBuf.fill(0);\n    }\n  }\n\n  static fromSeed(\n    seed: Uint8Array,\n    config: AggregatorConfig,\n  ): WalletAggregator {\n    getNetwork(config.network);\n    return new WalletAggregator(stripConfig(config), new Uint8Array(seed));\n  }\n\n  static createNew(\n    config: AggregatorConfig,\n    strength: 128 | 160 | 192 | 224 | 256 = 256,\n  ): { aggregator: WalletAggregator; mnemonic: string } {\n    const mnemonic = generateMnemonic(strength);\n    const aggregator = WalletAggregator.fromMnemonic(mnemonic, config);\n    return { aggregator, mnemonic };\n  }\n\n  get info(): AggregatorInfo {\n    const signers: SignerInfo[] = [];\n    for (const w of this.#wallets.values()) {\n      for (const s of w.signers) signers.push(s);\n    }\n    return {\n      network: this.#config.network,\n      signers,\n      wallets: this.#wallets.size,\n    };\n  }\n\n  get signers(): readonly SignerInfo[] {\n    return this.info.signers;\n  }\n\n  get wallets(): readonly Wallet[] {\n    return [...this.#wallets.values()];\n  }\n\n  get locked(): boolean {\n    return this.#seedRef === null;\n  }\n\n  addAccount(spec: AccountSpec): Wallet {\n    const providerName = spec.provider ?? \"keystore\";\n    if (providerName !== \"keystore\") {\n      throw new WalletError(\n        \"INVALID_ACCOUNT_SPEC\",\n        `addAccount() only supports provider='keystore' — use addProvider() to register '${providerName}'`,\n      );\n    }\n\n    const account = spec.account ?? 0;\n    const key = this.#buildKey(providerName, spec.addressType, account);\n\n    const existing = this.#wallets.get(key);\n    if (existing) return existing;\n\n    if (!this.#seedRef || !this.#seedRef.value) {\n      throw new WalletError(\n        \"AGGREGATOR_LOCKED\",\n        \"Cannot add HD account — aggregator seed has been wiped\",\n      );\n    }\n\n    const networkConfig = getNetwork(this.#config.network);\n    const keystore = Keystore.fromSeedBytes(\n      this.#seedRef.value,\n      networkConfig,\n      spec.addressType,\n      account,\n    );\n    const provider = new KeystoreProvider(keystore);\n    const wallet = new Wallet({\n      provider,\n      rpc: this.#config.rpc,\n      gapLimit: this.#config.gapLimit,\n      maxSyncIterations: this.#config.maxSyncIterations,\n      scanRetry: this.#config.scanRetry,\n    });\n    this.#wallets.set(key, wallet);\n    return wallet;\n  }\n\n  // Register an external WalletProvider (e.g. XverseProvider from the browser\n  // entry, which bridges a connected Xverse extension into the aggregator).\n  // Rejects reserved internal names so a plugin cannot shadow the built-in\n  // keystore slot and redirect HD account creation.\n  addProvider(provider: WalletProvider): Wallet {\n    if (RESERVED_PROVIDER_NAMES.has(provider.name)) {\n      throw new WalletError(\n        \"RESERVED_PROVIDER_NAME\",\n        `Provider name \"${provider.name}\" is reserved for internal use`,\n      );\n    }\n    const key = this.#buildKey(\n      provider.name,\n      provider.addressType,\n      provider.account,\n    );\n    const existing = this.#wallets.get(key);\n    if (existing) return existing;\n\n    const wallet = new Wallet({\n      provider,\n      rpc: this.#config.rpc,\n      gapLimit: this.#config.gapLimit,\n      maxSyncIterations: this.#config.maxSyncIterations,\n      scanRetry: this.#config.scanRetry,\n    });\n    this.#wallets.set(key, wallet);\n    return wallet;\n  }\n\n  getWallet(spec: AccountSpec): Wallet {\n    const providerName = spec.provider ?? \"keystore\";\n    const account = spec.account ?? 0;\n    const key = this.#buildKey(providerName, spec.addressType, account);\n\n    const existing = this.#wallets.get(key);\n    if (existing) return existing;\n\n    if (providerName === \"keystore\") {\n      return this.addAccount({ ...spec, provider: \"keystore\", account });\n    }\n\n    throw new WalletError(\n      \"WALLET_NOT_FOUND\",\n      `No wallet registered for ${key} — call addProvider() first`,\n    );\n  }\n\n  wallet(spec: AccountSpec): Wallet {\n    return this.getWallet(spec);\n  }\n\n  async syncAll(): Promise<void> {\n    await Promise.all([...this.#wallets.values()].map((w) => w.sync()));\n  }\n\n  aggregateBalance(): WalletBalance {\n    let confirmed = 0n;\n    let unconfirmed = 0n;\n    for (const w of this.#wallets.values()) {\n      const b = w.balance;\n      confirmed += b.confirmed;\n      unconfirmed += b.unconfirmed;\n    }\n    return {\n      confirmed,\n      unconfirmed,\n      total: confirmed + unconfirmed,\n    };\n  }\n\n  aggregateUtxos(): Utxo[] {\n    const out: Utxo[] = [];\n    for (const w of this.#wallets.values()) {\n      out.push(...w.utxos);\n    }\n    return out;\n  }\n\n  lock(): void {\n    if (this.#seedRef) {\n      this.#seedRef.wipe();\n      this.#seedRef = null;\n    }\n    for (const w of this.#wallets.values()) {\n      w.lock();\n    }\n  }\n\n  #buildKey(\n    provider: string,\n    addressType: AddressType,\n    account: number,\n  ): string {\n    return `${provider}:${addressType}#${account}`;\n  }\n\n  [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n    return `WalletAggregator(network=${this.#config.network} wallets=${this.#wallets.size} locked=${this.locked})`;\n  }\n\n  toJSON(): Record<string, unknown> {\n    return {\n      network: this.#config.network,\n      locked: this.locked,\n      wallets: [...this.#wallets.keys()],\n    };\n  }\n}\n\n// Retain only safe fields and drop the BIP39 passphrase after seed derivation to avoid lingering in memory\nfunction stripConfig(config: AggregatorConfig): RetainedConfig {\n  return {\n    network: config.network,\n    rpc: config.rpc,\n    gapLimit: config.gapLimit,\n    maxSyncIterations: config.maxSyncIterations,\n    scanRetry: config.scanRetry,\n  };\n}\n","import * as bitcoin from \"bitcoinjs-lib\";\n\nimport type { Keystore } from \"./derivation.js\";\nimport { selectCoins } from \"./coin-selection.js\";\nimport { InvalidAddressError, WalletError } from \"./errors.js\";\nimport { getNetwork, isAddressOnNetwork } from \"./network.js\";\nimport { KeystoreProvider } from \"./providers/keystore-provider.js\";\nimport type { WalletProvider } from \"./providers/types.js\";\nimport { buildPsbt, extractTransaction } from \"./psbt.js\";\nimport {\n  broadcastRawTransaction,\n  scanForUtxos,\n  type ScanRetryOptions,\n} from \"./rpc/index.js\";\nimport type { RpcClient } from \"./rpc/types.js\";\nimport type {\n  AddressType,\n  BroadcastResult,\n  DerivedKey,\n  SendOptions,\n  SignerInfo,\n  Utxo,\n  WalletBalance,\n  WalletInfo,\n} from \"./types.js\";\n\nconst DEFAULT_GAP_LIMIT = 20;\nconst DEFAULT_MAX_SYNC_ITERATIONS = 32;\nconst COINBASE_MATURITY = 100;\n\nexport type WalletState = \"new\" | \"synced\";\n\nexport interface WalletOptions {\n  // Provider handles signing and address derivation\n  provider?: WalletProvider;\n  // Direct keystore path. Internally wrapped in KeystoreProvider.\n  keystore?: Keystore;\n  rpc: RpcClient;\n  // Number of addresses to pre derive per chain\n  gapLimit?: number;\n  // Caps `sync()` rescan iterations to prevent unbounded derivation loops from malicious RPC responses.\n  maxSyncIterations?: number;\n  // Backoff policy for the `scantxoutset` node-global lock contention that\n  // sync() retries through — see scanForUtxos. Defaults apply when omitted;\n  // pass `{ attempts: 1 }` to opt out and handle error -8 yourself.\n  scanRetry?: ScanRetryOptions;\n}\n\nexport class Wallet {\n  readonly #provider: WalletProvider;\n  readonly #rpc: RpcClient;\n  readonly #gapLimit: number;\n  readonly #maxSyncIterations: number;\n  readonly #scanRetry: ScanRetryOptions | undefined;\n\n  // Derivation caches\n  #receive: DerivedKey[] = [];\n  #change: DerivedKey[] = [];\n\n  // scriptPubKey hex → DerivedKey (reverse lookup for scan results)\n  #scriptMap = new Map<string, DerivedKey>();\n\n  // Highest seen used index per chain (-1 if none)\n  #highestUsedReceive = -1;\n  #highestUsedChange = -1;\n\n  // Next-unused pointer per chain\n  #nextUnusedReceive = 0;\n  #nextUnusedChange = 0;\n\n  #utxos: Utxo[] = [];\n  #immature: Utxo[] = [];\n  #state: WalletState = \"new\";\n\n  // Serializes `send()` calls to prevent concurrent UTXO double spend conflicts.\n  #sendChain: Promise<unknown> = Promise.resolve();\n\n  constructor(opts: WalletOptions) {\n    if (opts.provider) {\n      this.#provider = opts.provider;\n    } else if (opts.keystore) {\n      this.#provider = new KeystoreProvider(opts.keystore);\n    } else {\n      throw new WalletError(\n        \"INVALID_WALLET_OPTIONS\",\n        \"Wallet requires either `provider` or `keystore` (deprecated)\",\n      );\n    }\n    this.#rpc = opts.rpc;\n    this.#gapLimit = opts.gapLimit ?? DEFAULT_GAP_LIMIT;\n    this.#maxSyncIterations = sanitizeMaxSyncIterations(opts.maxSyncIterations);\n    this.#scanRetry = opts.scanRetry;\n\n    this.#extendDerivations(this.#gapLimit, this.#gapLimit);\n  }\n\n  get provider(): WalletProvider {\n    return this.#provider;\n  }\n\n  get locked(): boolean {\n    return this.#provider.locked;\n  }\n\n  get state(): WalletState {\n    return this.#state;\n  }\n\n  get receiveAddress(): string {\n    if (!this.#receive[this.#nextUnusedReceive]) {\n      this.#extendDerivations(this.#nextUnusedReceive + 1, 0);\n    }\n    return this.#receive[this.#nextUnusedReceive]!.address;\n  }\n\n  get changeAddress(): string {\n    if (!this.#change[this.#nextUnusedChange]) {\n      this.#extendDerivations(0, this.#nextUnusedChange + 1);\n    }\n    return this.#change[this.#nextUnusedChange]!.address;\n  }\n\n  get balance(): WalletBalance {\n    let confirmed = 0n;\n    let unconfirmed = 0n;\n    for (const u of this.#utxos) {\n      if (u.confirmations > 0) {\n        confirmed += u.valueSats;\n      } else {\n        unconfirmed += u.valueSats;\n      }\n    }\n    return {\n      confirmed,\n      unconfirmed,\n      total: confirmed + unconfirmed,\n    };\n  }\n\n  get utxos(): readonly Utxo[] {\n    return this.#utxos;\n  }\n\n  get immatureUtxos(): readonly Utxo[] {\n    return this.#immature;\n  }\n\n  get signers(): readonly SignerInfo[] {\n    return [this.#provider.getSignerInfo()];\n  }\n\n  get info(): WalletInfo {\n    return {\n      address: this.receiveAddress,\n      balance: this.balance,\n      network: this.#provider.network.name,\n      addressType: this.#provider.addressType,\n      accountPath: this.#provider.accountPath,\n      accountXpub: this.#provider.accountXpub,\n      receiveDescriptor: this.#provider.buildDescriptor(false),\n      changeDescriptor: this.#provider.buildDescriptor(true),\n    };\n  }\n\n  async sync(): Promise<void> {\n    let rescans = 0;\n    while (true) {\n      const descriptors: string[] = [];\n      for (const d of this.#receive) descriptors.push(`addr(${d.address})`);\n      for (const d of this.#change) descriptors.push(`addr(${d.address})`);\n\n      const { utxos: scanned } = await scanForUtxos(this.#rpc, descriptors, {\n        retry: this.#scanRetry,\n      });\n\n      let maxUsedReceive = -1;\n      let maxUsedChange = -1;\n      const confirmed: Utxo[] = [];\n      const immature: Utxo[] = [];\n\n      for (const u of scanned) {\n        const derived = this.#scriptMap.get(u.scriptPubKey);\n        if (!derived) {\n          continue;\n        }\n\n        if (derived.change) {\n          if (derived.index > maxUsedChange) maxUsedChange = derived.index;\n        } else {\n          if (derived.index > maxUsedReceive) maxUsedReceive = derived.index;\n        }\n\n        const utxo: Utxo = {\n          txid: u.txid,\n          vout: u.vout,\n          valueSats: u.valueSats,\n          address: derived.address,\n          scriptPubKey: u.scriptPubKey,\n          height: u.height,\n          confirmations: u.confirmations,\n          coinbase: u.coinbase,\n          derivationPath: derived.path,\n          change: derived.change,\n          addressIndex: derived.index,\n        };\n\n        if (u.coinbase && u.confirmations < COINBASE_MATURITY) {\n          immature.push(utxo);\n        } else {\n          confirmed.push(utxo);\n        }\n      }\n\n      if (maxUsedReceive > this.#highestUsedReceive) {\n        this.#highestUsedReceive = maxUsedReceive;\n      }\n      if (maxUsedChange > this.#highestUsedChange) {\n        this.#highestUsedChange = maxUsedChange;\n      }\n\n      const wantReceive = this.#highestUsedReceive + 1 + this.#gapLimit;\n      const wantChange = this.#highestUsedChange + 1 + this.#gapLimit;\n      const needReceive = wantReceive - this.#receive.length;\n      const needChange = wantChange - this.#change.length;\n\n      if (needReceive > 0 || needChange > 0) {\n        if (rescans >= this.#maxSyncIterations) {\n          throw new WalletError(\n            \"SYNC_LIMIT_EXCEEDED\",\n            `sync() exceeded ${this.#maxSyncIterations} rescan iterations` +\n              `; possible adversarial RPC endpoint or misconfigured gap limit`,\n          );\n        }\n        rescans++;\n        this.#extendDerivations(\n          Math.max(0, needReceive),\n          Math.max(0, needChange),\n        );\n        continue;\n      }\n\n      this.#utxos = confirmed;\n      this.#immature = immature;\n      if (this.#highestUsedReceive + 1 > this.#nextUnusedReceive) {\n        this.#nextUnusedReceive = this.#highestUsedReceive + 1;\n      }\n      if (this.#highestUsedChange + 1 > this.#nextUnusedChange) {\n        this.#nextUnusedChange = this.#highestUsedChange + 1;\n      }\n      this.#state = \"synced\";\n      return;\n    }\n  }\n\n  // Validate destination → auto-sync → coin selection → PSBT build → provider sign → broadcast.\n  // Concurrent callers are serialized: each send() queues behind the previous one\n  // so UTXOs can't be double-selected across an in-flight sync.\n  async send(opts: SendOptions): Promise<BroadcastResult> {\n    const run = async (): Promise<BroadcastResult> => this.#runSend(opts);\n    const task = this.#sendChain.then(run, run);\n    this.#sendChain = task.catch(() => undefined);\n    return task;\n  }\n\n  async #runSend(opts: SendOptions): Promise<BroadcastResult> {\n    // External providers that only sign externally-built PSBTs cannot go\n    // through the internal p2wpkh PSBT builder — doing so would silently\n    // produce a malformed transaction for their (segwit/taproot) script.\n    if (this.#provider.supportsInternalSend !== true) {\n      throw new WalletError(\n        \"INTERNAL_SEND_UNSUPPORTED\",\n        `Provider \"${this.#provider.name}\" is not marked supportsInternalSend=true; ` +\n          `build a PSBT and route it through the provider's external signer ` +\n          `(e.g. prepareForWalletSigning() + the wallet's signPsbt).`,\n      );\n    }\n\n    const networkName = this.#provider.network.name;\n    if (!isAddressOnNetwork(opts.to, networkName)) {\n      throw new InvalidAddressError(\n        opts.to,\n        `not valid on network ${networkName}`,\n      );\n    }\n\n    if (this.#state === \"new\") {\n      await this.sync();\n    }\n\n    const outputAddressType = inferAddressType(opts.to, networkName);\n\n    const selection = selectCoins({\n      utxos: this.#utxos,\n      amountSats: opts.amount,\n      feeRate: opts.feeRate,\n      inputAddressType: this.#provider.addressType,\n      outputAddressType,\n      changeAddressType: this.#provider.addressType,\n    });\n\n    const outputs: { address: string; valueSats: bigint }[] = [\n      { address: opts.to, valueSats: opts.amount },\n    ];\n    const changeAddress = selection.changeSats > 0n ? this.changeAddress : null;\n    const changeIndex = changeAddress !== null ? this.#nextUnusedChange : -1;\n    const changeVout = changeAddress !== null ? outputs.length : -1;\n    if (changeAddress !== null) {\n      outputs.push({\n        address: changeAddress,\n        valueSats: selection.changeSats,\n      });\n    }\n\n    const psbt = await buildPsbt({\n      network: this.#provider.network.network,\n      inputs: selection.inputs,\n      outputs,\n      inputAddressType: this.#provider.addressType,\n      rpc: this.#rpc,\n    });\n\n    await this.#provider.signPsbt(psbt, selection.inputs);\n\n    const { hex, txid } = extractTransaction(psbt);\n    await broadcastRawTransaction(this.#rpc, hex);\n\n    // Rebuild local UTXOs post-send: drop spent inputs and add change as unconfirmed so it’s immediately spendable until next sync().\n    const spent = new Set(selection.inputs.map((u) => `${u.txid}:${u.vout}`));\n    const nextUtxos = this.#utxos.filter(\n      (u) => !spent.has(`${u.txid}:${u.vout}`),\n    );\n    if (changeAddress !== null) {\n      const derived = this.#change[changeIndex]!;\n      nextUtxos.push({\n        txid,\n        vout: changeVout,\n        valueSats: selection.changeSats,\n        address: changeAddress,\n        scriptPubKey: derived.scriptPubKey,\n        height: 0,\n        confirmations: 0,\n        coinbase: false,\n        derivationPath: derived.path,\n        change: true,\n        addressIndex: changeIndex,\n      });\n    }\n    this.#utxos = nextUtxos;\n\n    // Advance the change pointer only after a successful broadcast so\n    // repeated sends don't reuse the same change address (privacy leak).\n    if (changeAddress !== null) {\n      this.#nextUnusedChange += 1;\n      if (!this.#change[this.#nextUnusedChange]) {\n        this.#extendDerivations(\n          0,\n          this.#nextUnusedChange + 1 - this.#change.length,\n        );\n      }\n    }\n\n    return { txid };\n  }\n\n  lock(): void {\n    this.#provider.lock();\n  }\n\n  #extendDerivations(receiveTotalAdd: number, changeTotalAdd: number): void {\n    if (receiveTotalAdd > 0) {\n      const total = this.#receive.length + receiveTotalAdd;\n      const derived = this.#provider.deriveReceiveAddresses(total);\n      this.#receive = derived;\n      for (const d of derived) this.#scriptMap.set(d.scriptPubKey, d);\n    }\n    if (changeTotalAdd > 0) {\n      const total = this.#change.length + changeTotalAdd;\n      const derived = this.#provider.deriveChangeAddresses(total);\n      this.#change = derived;\n      for (const d of derived) this.#scriptMap.set(d.scriptPubKey, d);\n    }\n  }\n\n  [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n    const path = this.#provider.accountPath ?? \"no-derivation\";\n    return `Wallet(provider=${this.#provider.name} ${this.#provider.addressType} ${path} state=${this.#state} locked=${this.locked})`;\n  }\n\n  toJSON(): Record<string, unknown> {\n    return {\n      provider: this.#provider.name,\n      addressType: this.#provider.addressType,\n      accountPath: this.#provider.accountPath,\n      network: this.#provider.network.name,\n      state: this.#state,\n      locked: this.locked,\n      balance: {\n        confirmed: this.balance.confirmed.toString(),\n        unconfirmed: this.balance.unconfirmed.toString(),\n        total: this.balance.total.toString(),\n      },\n    };\n  }\n}\n\n// The option is a security cap: coerce non-finite/negative inputs to the default\n// and refuse to exceed the built-in ceiling so a caller can't weaken the bound.\nfunction sanitizeMaxSyncIterations(value: number | undefined): number {\n  const n = Number(value);\n  const int = Number.isFinite(n) ? Math.floor(n) : DEFAULT_MAX_SYNC_ITERATIONS;\n  return Math.max(0, Math.min(DEFAULT_MAX_SYNC_ITERATIONS, int));\n}\n\n// Infer script type from address and reject non-p2wpkh to prevent unsupported outputs and fee issues\nfunction inferAddressType(address: string, networkName: string): AddressType {\n  const network = getNetwork(networkName).network;\n  let script: Uint8Array;\n  try {\n    script = bitcoin.address.toOutputScript(address, network);\n  } catch {\n    throw new InvalidAddressError(\n      address,\n      `not valid on network ${networkName}`,\n    );\n  }\n  // P2WPKH scriptPubKey: OP_0 <20-byte push> = 0x00 0x14 <20 bytes> (22 bytes).\n  if (script.length === 22 && script[0] === 0x00 && script[1] === 0x14) {\n    return \"p2wpkh\";\n  }\n  throw new InvalidAddressError(\n    address,\n    \"only p2wpkh destination addresses are supported\",\n  );\n}\n"],"mappings":"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","names":["generateMnemonic","validateMnemonic","address","address","sats","bitcoin","generateMnemonic","validateMnemonic","bip39","import_bip32","ecc","bitcoin","sleep","bip32","ecc","tryWipeNode","bitcoin","DEFAULT_TIMEOUT_MS","address","isRetryableScanError","ecc","bitcoin","address","bip39","bitcoin","address","script","validateMnemonic","generateMnemonic"]}