{"version":3,"file":"toRefundInputs-DaxiTty9.cjs","sources":["../src/tbv/core/deposit-terms/depositTermsErrors.ts","../src/tbv/core/deposit-terms/rebuildDepositTermsCore.ts","../src/tbv/core/wots/errors.ts","../src/tbv/core/recovery/recoveryErrors.ts","../src/tbv/core/recovery/deriveHashlocksFromPrePegin.ts","../src/tbv/core/recovery/peginParamsCandidates.ts","../src/tbv/core/recovery/reconstructPeginParams.ts","../src/tbv/core/recovery/toRefundInputs.ts"],"sourcesContent":["/**\n * Typed rejection contract for deposit-terms approval. Providers cannot import\n * this class (no dependency edge between the packages), so the cross-package\n * contract is the error SHAPE on {@link DepositTermsApprover}. Consumers land\n * with the first provider (#2109) and its app error mapping (#2110).\n *\n * @module deposit-terms/depositTermsErrors\n */\n\n/** The `name` value providers must set on envelope rejections (the wire contract). */\nexport const DEPOSIT_TERMS_REJECTED_ERROR_NAME = \"DepositTermsRejectedError\";\n\n/** Why the terms were rejected before approval. */\nexport type DepositTermsRejectionReason = \"device-envelope\";\n\n/** SDK-owned typed rejection thrown when deposit terms fail pre-approval validation. */\nexport class DepositTermsRejectedError extends Error {\n  readonly reason: DepositTermsRejectionReason;\n\n  constructor(\n    message: string,\n    reason: DepositTermsRejectionReason = \"device-envelope\",\n  ) {\n    super(message);\n    this.name = DEPOSIT_TERMS_REJECTED_ERROR_NAME;\n    this.reason = reason;\n  }\n}\n\n/**\n * Guard for app-side error mapping. Matches `instanceof` OR the documented\n * `name` — providers and foreign realms throw structurally-conforming plain\n * errors that `instanceof` cannot see.\n */\nexport function isDepositTermsRejectedError(\n  err: unknown,\n): err is DepositTermsRejectedError {\n  if (err instanceof DepositTermsRejectedError) return true;\n  if (typeof err !== \"object\" || err === null) return false;\n  const shaped = err as { name?: unknown; reason?: unknown };\n  // The documented provider shape REQUIRES the reason; a name-only match is\n  // a contract violation and propagates unnormalized.\n  return (\n    shaped.name === DEPOSIT_TERMS_REJECTED_ERROR_NAME &&\n    shaped.reason === \"device-envelope\"\n  );\n}\n","/**\n * Pure core of the resume-broadcast DepositTerms rebuild (#2220 Part 2).\n *\n * Takes plain chain-derived data (the app orchestrator does the chain reads +\n * sibling discovery) and: (1) asserts sibling completeness against the funded\n * tx's auth-anchor OP_RETURN, (2) recomputes the amount-independent sizing\n * (depositorClaimValue, peginMaxFee, anchor) via WASM, (3) byte-matches each\n * HTLC output's value + scriptPubKey against the funded tx (Gate 1), then (4)\n * projects into DepositTerms. No chain access, no browser state — unit-testable.\n *\n * btc-vault is the protocol source of truth (`compute_min_htlc_value`,\n * `derive_challengers_for`).\n */\n\nimport {\n  computeMinClaimValue,\n  computeMinPeginFee,\n  getPrePeginHtlcConnectorInfo,\n  peginP2aAnchorOutput,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Transaction } from \"bitcoinjs-lib\";\n\nimport { findAuthAnchorOpReturn } from \"../managers/pegin/assertAuthAnchorOpReturn\";\nimport { assertEncodedHtlcOutputsMatch } from \"../primitives/psbt/assertWasmPeginSizing\";\nimport { stripHexPrefix } from \"../primitives/utils/bitcoin\";\nimport { MAX_REASONABLE_PEGIN_VBYTES } from \"../utils/fee/constants\";\nimport { calculateBtcTxHash } from \"../utils/transaction/btcTxHash\";\n\nimport { buildDepositTerms } from \"./buildDepositTerms\";\nimport type { DepositTerms } from \"./depositTerms\";\n\n/** One HTLC in the shared Pre-PegIn tx, ordered by (and contiguous in) htlcVout. */\nexport interface RebuildSibling {\n  /** 32-byte hex hashlock (0x prefix optional), per-vault (feeds the HTLC scriptPubKey). */\n  hashlock: string;\n  /** btc-vault `pegin_amount` for this sibling (satoshis). */\n  amount: bigint;\n}\n\nexport interface RebuildDepositTermsCoreInput {\n  /** Stamped tx-graph version (NOT chain-active). */\n  vaultCoreVersion: number;\n  /** Sibling HTLCs ordered by htlcVout; index === htlcVout (asserted by the app). */\n  siblings: readonly RebuildSibling[];\n  /** Funded Pre-PegIn tx hex. Gate 0 (hash vs prepeginTxid) is SELF-verified below — callers need not pre-verify. */\n  fundedPrePeginTxHex: string;\n\n  // Stamped-version participant data (already resolved + sorted by the app).\n  depositorBtcPubkey: string;\n  vaultProviderBtcPubkey: string;\n  vaultKeeperBtcPubkeys: readonly string[];\n  universalChallengerBtcPubkeys: readonly string[];\n\n  // Version-locked scalars.\n  protocolFeeRate: bigint;\n  minPeginFeeRate: bigint;\n  councilQuorum: number;\n  councilSize: number;\n  timelockPegin: number;\n  timelockAssert: number;\n  timelockRefund: number;\n\n  // Pass-through into DepositTerms.\n  prepeginTxid: string;\n  /** Funded-tx fee (Σin − Σout), computed by the app; the device's `prepegin_max_fee` bound. */\n  prepeginMaxFee: bigint;\n  maxAcceptableCommissionBps: number;\n\n  /** WASM network descriptor for scriptPubKey derivation. */\n  network: Parameters<typeof getPrePeginHtlcConnectorInfo>[0][\"network\"];\n}\n\nexport async function rebuildDepositTermsCore(\n  input: RebuildDepositTermsCoreInput,\n): Promise<DepositTerms> {\n  const siblingCount = input.siblings.length;\n  if (siblingCount === 0) {\n    throw new Error(\n      \"rebuildDepositTermsCore: at least one sibling is required\",\n    );\n  }\n  for (const [i, sibling] of input.siblings.entries()) {\n    if (sibling.amount <= 0n) {\n      throw new Error(\n        `rebuildDepositTermsCore: sibling[${i}] has non-positive on-chain pegin ` +\n          `amount ${sibling.amount}; the chain-read vault record is invalid. Resume refused.`,\n      );\n    }\n  }\n  if (input.prepeginMaxFee <= 0n) {\n    throw new Error(\n      `rebuildDepositTermsCore: prepeginMaxFee must be > 0, got ${input.prepeginMaxFee}`,\n    );\n  }\n\n  // Gate 0, self-verified: everything below trusts these bytes, and a\n  // substituted tx replicating the HTLC outputs would pass Gate 1 with a\n  // different fee/txid.\n  const expectedTxid = stripHexPrefix(input.prepeginTxid).toLowerCase();\n  const actualTxid = stripHexPrefix(\n    calculateBtcTxHash(input.fundedPrePeginTxHex),\n  ).toLowerCase();\n  if (actualTxid !== expectedTxid) {\n    throw new Error(\n      `Funded Pre-PegIn tx hashes to ${actualTxid}, expected ${expectedTxid} ` +\n        `(on-chain prepeginTxid). Resume refused.`,\n    );\n  }\n\n  // Completeness anchor: the single auth-anchor OP_RETURN sits at vout === HTLC\n  // count — the only guard against an indexer-lagged partial sibling set.\n  const found = findAuthAnchorOpReturn(\n    stripHexPrefix(input.fundedPrePeginTxHex),\n  );\n  if (found === undefined) {\n    throw new Error(\n      `Funded Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN ` +\n        `commitment — it either predates auth anchoring or is malformed. The ` +\n        `intent resume path requires the anchor to prove sibling completeness. ` +\n        `Resume refused.`,\n    );\n  }\n  if (found.vout !== siblingCount) {\n    throw new Error(\n      `Auth-anchor OP_RETURN at vout ${found.vout} does not match the ` +\n        `discovered sibling count ${siblingCount}; the discovered sibling set ` +\n        `does not cover this transaction's HTLC outputs (a lagging index can ` +\n        `cause this — retry later). Resume refused.`,\n    );\n  }\n\n  // Amount-independent sizing. Depositor-as-claimer: numLocalChallengers ===\n  // numVks (VP excluded) — btc-vault graph.rs derive_challengers_for.\n  const numVks = input.vaultKeeperBtcPubkeys.length;\n  const numUcs = input.universalChallengerBtcPubkeys.length;\n  const depositorClaimValue = await computeMinClaimValue(\n    input.vaultCoreVersion,\n    numVks,\n    numUcs,\n    input.councilQuorum,\n    input.councilSize,\n    input.protocolFeeRate,\n  );\n  const peginMaxFee = await computeMinPeginFee(\n    input.vaultCoreVersion,\n    numVks,\n    numUcs,\n    input.minPeginFeeRate,\n  );\n  const anchor = await peginP2aAnchorOutput(input.vaultCoreVersion);\n  const anchorValue = anchor?.value ?? 0n;\n\n  // Independent bounds on the WASM outputs (mirrors assertWasmPeginSizing):\n  // Gate 1 only proves the DCV+fee+anchor SUM — these constrain the\n  // decomposition the device is shown.\n  if (depositorClaimValue <= 0n) {\n    throw new Error(\n      `WASM returned non-positive depositorClaimValue ${depositorClaimValue}; ` +\n        `expected > 0. Resume refused.`,\n    );\n  }\n  if (peginMaxFee <= 0n) {\n    throw new Error(\n      `WASM returned non-positive peginMaxFee ${peginMaxFee}; expected > 0. ` +\n        `Resume refused.`,\n    );\n  }\n  // Explicit anchor check: the sum bound alone would let a negative anchor\n  // offset an inflated peginMaxFee (kept local, not inherited from the facade).\n  if (anchorValue < 0n) {\n    throw new Error(\n      `WASM returned negative P2A anchor value ${anchorValue}. Resume refused.`,\n    );\n  }\n  const impliedReserve = peginMaxFee + anchorValue;\n  const maxImpliedReserve = input.minPeginFeeRate * MAX_REASONABLE_PEGIN_VBYTES;\n  if (impliedReserve <= 0n || impliedReserve > maxImpliedReserve) {\n    throw new Error(\n      `WASM implied PegIn reserve ${impliedReserve} sat is outside ` +\n        `(0, ${maxImpliedReserve}] (minPeginFeeRate=${input.minPeginFeeRate} × ` +\n        `${MAX_REASONABLE_PEGIN_VBYTES} vbytes). Resume refused.`,\n    );\n  }\n\n  // Gate 1: per sibling, value = amount + DCV + peginMaxFee + anchor (btc-vault\n  // compute_min_htlc_value) + scriptPubKey from the on-chain hashlock,\n  // byte-matched against outputs 0..N-1.\n  const expectedHtlcValues = input.siblings.map(\n    (s) => s.amount + depositorClaimValue + peginMaxFee + anchorValue,\n  );\n  const expectedHtlcScriptPubKeys = await Promise.all(\n    input.siblings.map(async (s) => {\n      const connector = await getPrePeginHtlcConnectorInfo({\n        txGraphVersion: input.vaultCoreVersion,\n        depositorPubkey: input.depositorBtcPubkey,\n        vaultProviderPubkey: input.vaultProviderBtcPubkey,\n        vaultKeeperPubkeys: [...input.vaultKeeperBtcPubkeys],\n        universalChallengerPubkeys: [...input.universalChallengerBtcPubkeys],\n        hashlock: stripHexPrefix(s.hashlock),\n        timelockRefund: input.timelockRefund,\n        network: input.network,\n      });\n      return connector.scriptPubKey;\n    }),\n  );\n  const fundedOutputs = Transaction.fromHex(\n    stripHexPrefix(input.fundedPrePeginTxHex),\n  ).outs.map((o) => ({ value: o.value, script: o.script }));\n  assertEncodedHtlcOutputsMatch(\n    fundedOutputs,\n    expectedHtlcValues,\n    expectedHtlcScriptPubKeys,\n  );\n\n  return buildDepositTerms({\n    vaultCoreVersion: input.vaultCoreVersion,\n    protocolFeeRate: input.protocolFeeRate,\n    timelockPegin: input.timelockPegin,\n    timelockAssert: input.timelockAssert,\n    timelockRefund: input.timelockRefund,\n    prepeginTxid: input.prepeginTxid,\n    prepeginMaxFee: input.prepeginMaxFee,\n    vaultProviderBtcPubkey: input.vaultProviderBtcPubkey,\n    vaultKeeperBtcPubkeys: input.vaultKeeperBtcPubkeys,\n    universalChallengerBtcPubkeys: input.universalChallengerBtcPubkeys,\n    maxAcceptableCommissionBps: input.maxAcceptableCommissionBps,\n    peginAmounts: input.siblings.map((s) => s.amount),\n    depositorClaimValue,\n    peginMaxFee,\n  });\n}\n","/**\n * Check whether an error from the vault provider indicates that the\n * submitted WOTS public key hash does not match the on-chain\n * commitment. This signals that the wrong wallet is connected (its\n * `deriveContextHash` produces a different vault root and therefore\n * different WOTS keys).\n */\nexport function isWotsMismatchError(error: unknown): boolean {\n  const msg = (\n    error instanceof Error\n      ? error.message\n      : typeof error === \"string\"\n        ? error\n        : \"\"\n  ).toLowerCase();\n\n  return (\n    msg.includes(\"wots\") &&\n    msg.includes(\"hash\") &&\n    msg.includes(\"does not match\")\n  );\n}\n","/**\n * Typed failures for Pre-PegIn parameter recovery (#2203).\n *\n * Split by who can act on them. A root mismatch is user-fixable — wrong\n * wallet, wrong account or wrong network — and must be distinguishable from\n * a search that found nothing, which is ours. Without the split both look\n * identical to the caller.\n *\n * @module recovery/recoveryErrors\n */\n\n/**\n * The re-derived vault root does not match the funded Pre-PegIn's auth-anchor\n * OP_RETURN commitment.\n *\n * The root is bound to the wallet seed, the derivation account AND the\n * network (`derive-context-hash.md` §2.1 folds the connected pubkey and the\n * canonical network name into the HKDF `info`), so all three must match the\n * ones that created the deposit.\n */\nexport class VaultRootMismatchError extends Error {\n  constructor(\n    readonly derivedAuthAnchorHash: string,\n    readonly onChainAuthAnchorHash: string,\n  ) {\n    super(\n      `Re-derived vault root does not match this Pre-PegIn: derived ` +\n        `auth-anchor hash ${derivedAuthAnchorHash}, transaction commits to ` +\n        `${onChainAuthAnchorHash}. Connect the same wallet, on the same ` +\n        `account and the same network, that created the deposit.`,\n    );\n    this.name = \"VaultRootMismatchError\";\n  }\n}\n\n/**\n * The Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN.\n *\n * The anchor sits at `vout === htlcCount`, and it is the only structural\n * signal for how many HTLC outputs the transaction funds. Without it the\n * vault count would have to be guessed, so recovery refuses rather than\n * deriving the wrong number of hashlocks.\n */\nexport class UnanchoredPrePeginError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"UnanchoredPrePeginError\";\n  }\n}\n\n/**\n * No candidate parameter set reproduces the funded Pre-PegIn's HTLC outputs.\n *\n * Either the true parameters are outside the enumerated space — an operator\n * roster that rotated more than once has no chain-reachable historical read —\n * or the transaction is not one of ours.\n */\nexport class PeginParamsNotFoundError extends Error {\n  constructor(\n    readonly candidatesTried: number,\n    /** A bounded sample of per-candidate rejection reasons, for diagnosis. */\n    readonly sampleRejections: readonly string[],\n    /** Versions that could not be read, the likeliest reason for no match. */\n    readonly unresolvedLabels: readonly string[] = [],\n  ) {\n    super(\n      `No candidate parameter set reproduces this Pre-PegIn's HTLC outputs ` +\n        `(${candidatesTried} candidate(s) tried). ` +\n        (unresolvedLabels.length > 0\n          ? `${unresolvedLabels.length} version(s) could not be resolved and ` +\n            `may hold the answer: ${unresolvedLabels.join(\" | \")}. `\n          : \"\") +\n        `Sample rejections: ${sampleRejections.join(\" | \")}`,\n    );\n    this.name = \"PeginParamsNotFoundError\";\n  }\n}\n\n/**\n * More than one candidate reproduces the funded Pre-PegIn. Fail closed.\n *\n * Every survivor byte-matched the SAME funded outputs, so they agree on each\n * HTLC scriptPubKey and on the total value of each output, and would produce\n * the same refund transaction. What they disagree on is the SPLIT of that\n * value into `peginAmount` and reserve, and the version stamps that determine\n * it — neither of which the transaction carries any evidence of.\n */\nexport class PeginParamsAmbiguousError extends Error {\n  constructor(readonly survivorLabels: readonly string[]) {\n    super(\n      `${survivorLabels.length} candidate parameter sets reproduce this ` +\n        `Pre-PegIn's HTLC outputs, so the vault's stamped versions cannot be ` +\n        `determined: ${survivorLabels.join(\" | \")}. Reconstruction refused.`,\n    );\n    this.name = \"PeginParamsAmbiguousError\";\n  }\n}\n\n/**\n * Exactly one candidate matched, but the candidate space was known to be\n * incomplete. Fail closed.\n *\n * Uniqueness only detects a wrong answer when the right answer is ALSO in the\n * space. If the true version could not be read, a different version sharing\n * the same `timelockRefund` and participants matches the transaction just as\n * well — the search subtracts that candidate's reserve and the verifier adds\n * the same reserve back, so it survives — and the sole survivor would be\n * returned with the wrong version stamps and the wrong `peginAmount` split.\n *\n * Resolve the versions below and search again rather than trusting the match.\n */\nexport class PeginParamsIncompleteSpaceError extends Error {\n  constructor(\n    readonly matchedLabel: string,\n    readonly unresolvedLabels: readonly string[],\n  ) {\n    super(\n      `A candidate matched this Pre-PegIn (${matchedLabel}), but ` +\n        `${unresolvedLabels.length} version(s) could not be resolved, so the ` +\n        `search space did not provably contain the true parameters: ` +\n        `${unresolvedLabels.join(\" | \")}. A version sharing the matched ` +\n        `timelockRefund and participants is indistinguishable from the true ` +\n        `one, so the match cannot be trusted. Reconstruction refused.`,\n    );\n    this.name = \"PeginParamsIncompleteSpaceError\";\n  }\n}\n\n/**\n * A WASM sizing call returned a value no valid parameter set can produce.\n *\n * Raised before the value is consumed, and deliberately NOT treated as a\n * candidate rejection: it indicts the binary rather than the candidate, so it\n * escapes the search instead of being counted as one more parameter set that\n * did not match.\n */\nexport class PeginSizingIntegrityError extends Error {\n  constructor(message: string) {\n    super(`${message}. Reconstruction refused.`);\n    this.name = \"PeginSizingIntegrityError\";\n  }\n}\n","/**\n * Re-derive a stranded deposit's per-vault hashlocks from the wallet and the\n * funded Pre-PegIn transaction alone (#2203).\n *\n * An Ethereum reorg that drops the registration takes the vault row with it,\n * so the depositor pubkey, the HTLC vout and the hashlocks are gone. All three\n * are recoverable without a single `vaultId`-keyed read: the depositor pubkey\n * comes from the connected wallet, the vault count from the transaction's\n * auth-anchor OP_RETURN vout, and the hashlocks from the same HKDF pipeline the\n * deposit used.\n *\n * The parameter search that turns these hashlocks back into a refundable\n * template lives in `reconstructPeginParams` and needs no wallet.\n *\n * @module recovery/deriveHashlocksFromPrePegin\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { findAuthAnchorOpReturn } from \"../managers/pegin/assertAuthAnchorOpReturn\";\nimport { expandPerVaultSecrets } from \"../managers/pegin/expandPerVaultSecrets\";\nimport {\n  hexToUint8Array,\n  processPublicKeyToXOnly,\n  stripHexPrefix,\n  uint8ArrayToHex,\n} from \"../primitives/utils/bitcoin\";\nimport {\n  deriveVaultRoot,\n  expandAuthAnchor,\n  parseFundingOutpointsFromTx,\n  type DeriveContextHashCapableWallet,\n} from \"../vault-secrets\";\n\nimport {\n  UnanchoredPrePeginError,\n  VaultRootMismatchError,\n} from \"./recoveryErrors\";\n\nexport interface DeriveHashlocksFromPrePeginInput {\n  /** Any wallet implementing `deriveContextHash` — the depositor's own. */\n  wallet: DeriveContextHashCapableWallet;\n  /**\n   * Depositor BTC public key, read from the CONNECTED WALLET. The reorg\n   * destroyed the row that would normally supply it, and taking it from any\n   * chain read would defeat the recovery.\n   *\n   * Accepted in whatever form the wallet hands back — x-only, 33-byte\n   * compressed or 65-byte uncompressed, `0x` optional — and narrowed to x-only\n   * here. Wallets return the compressed form from `getPublicKey`, so requiring\n   * x-only would make the common case an error.\n   */\n  depositorBtcPubkey: string;\n  /** Funded (broadcast) Pre-PegIn transaction hex, `0x` optional. */\n  fundedPrePeginTxHex: string;\n}\n\nexport interface DeriveHashlocksFromPrePeginResult {\n  /** Number of HTLC outputs the transaction funds, from the anchor's vout. */\n  vaultCount: number;\n  /** 32-byte hex hashlocks (no `0x`), indexed by `htlcVout`. */\n  hashlocks: readonly string[];\n  /** The transaction's auth-anchor commitment, `SHA256(authAnchor)` as hex. */\n  authAnchorHash: string;\n}\n\n/**\n * Derive the per-vault hashlocks committed by a funded Pre-PegIn.\n *\n * Validates the re-derived root against the transaction's auth-anchor\n * OP_RETURN before expanding anything else. That check costs one HKDF call,\n * needs zero protocol parameters, and is what separates \"wrong wallet,\n * account or network\" from \"right wallet, no candidate matched\" — otherwise\n * both surface as a fruitless parameter search.\n *\n * @throws {UnanchoredPrePeginError} If the transaction carries no single,\n *   unambiguous auth-anchor OP_RETURN.\n * @throws {VaultRootMismatchError} If the derived root does not commit to the\n *   transaction's anchor.\n */\nexport async function deriveHashlocksFromPrePegin(\n  input: DeriveHashlocksFromPrePeginInput,\n): Promise<DeriveHashlocksFromPrePeginResult> {\n  const { wallet, depositorBtcPubkey, fundedPrePeginTxHex } = input;\n\n  const cleanTxHex = stripHexPrefix(fundedPrePeginTxHex);\n  const anchor = findAuthAnchorOpReturn(cleanTxHex);\n  if (anchor === undefined) {\n    throw new UnanchoredPrePeginError(\n      `Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN, so the ` +\n        `number of HTLC outputs it funds cannot be determined. Legacy ` +\n        `pre-anchor deposits are not recoverable by this path.`,\n    );\n  }\n  // The anchor sits immediately after the HTLC outputs, so its vout IS the\n  // vault count. At vout 0 it would claim a Pre-PegIn that funds nothing.\n  const vaultCount = anchor.vout;\n  if (vaultCount === 0) {\n    throw new UnanchoredPrePeginError(\n      `Pre-PegIn's auth-anchor OP_RETURN is at vout 0, implying zero HTLC ` +\n        `outputs; there is nothing to recover.`,\n    );\n  }\n\n  const fundingOutpoints = parseFundingOutpointsFromTx(cleanTxHex);\n\n  const root = await deriveVaultRoot(wallet, {\n    // The vault context takes the 32-byte x-only key; a wallet's compressed\n    // key would otherwise fail a byte-length check deep in the encoder with\n    // nothing pointing back at the caller.\n    depositorBtcPubkey: hexToUint8Array(\n      processPublicKeyToXOnly(depositorBtcPubkey),\n    ),\n    fundingOutpoints,\n  });\n\n  // Ordering is load-bearing: `expandPerVaultSecrets` takes ownership of\n  // `root` and zeroes it, so the anchor expansion must run first. On any\n  // throw in this window nothing else will wipe the root, so wipe it here.\n  try {\n    const authAnchorBytes = await expandAuthAnchor(root);\n    let derivedAuthAnchorHash: string;\n    try {\n      derivedAuthAnchorHash = uint8ArrayToHex(sha256(authAnchorBytes));\n    } finally {\n      authAnchorBytes.fill(0);\n    }\n    if (derivedAuthAnchorHash !== anchor.hash) {\n      throw new VaultRootMismatchError(derivedAuthAnchorHash, anchor.hash);\n    }\n  } catch (err) {\n    root.fill(0);\n    throw err;\n  }\n\n  // Shares the deposit-time expansion rather than a hashlock-only variant, so\n  // the two can never drift. Its WOTS output is unused here and dropped with\n  // the result object; refunding spends the timelock leaf, not the preimage.\n  const { hashlocks } = await expandPerVaultSecrets(root, vaultCount);\n\n  return { vaultCount, hashlocks, authAnchorHash: anchor.hash };\n}\n","/**\n * The candidate parameter space `reconstructPeginParams` searches (#2203).\n *\n * A reorg destroys the vault row's version stamps but not the versioned data\n * they point at: `getOffchainParamsByVersion`, `getVaultKeepersByVersion` and\n * `getUniversalChallengersByVersion` are keyed by version, not by `vaultId`,\n * and survive. So the stamps are recoverable by enumeration.\n *\n * Two parameters are deliberately NOT axes here.\n *\n * `vaultCoreVersion` is supplied, not searched. The Pre-PegIn carries no\n * evidence of it: `getPrePeginHtlcConnectorInfo` produces a byte-identical\n * scriptPubKey for v1 and v2, and the version's only other effect on the\n * transaction is the size of the reserve folded into the HTLC value — which\n * the search inverts back out of that same value, so it matches by\n * construction. Enumerating it would guarantee an ambiguous result rather than\n * narrow one. See `__tests__/reconstructPeginParams.test.ts`, which pins the\n * identical-scriptPubKey fact so a future graph version that DOES change the\n * connector fails loudly here.\n *\n * The RFC-006 operation-key epochs are not enumerable at all. Every\n * epoch-keyed read needs `getVaultKeyEpochs(vaultId)` — the destroyed row —\n * and no ABI in this repo exposes an epoch history, a counter, or an event.\n * Only the genesis keys and the operators' current keys are reachable, which\n * is why {@link KeyEpochPolicy} has exactly two values and why they apply to\n * the whole participant set at once: a vault whose participants rotated more\n * than once since creation cannot be reconstructed.\n *\n * @module recovery/peginParamsCandidates\n */\n\nimport type { Address } from \"viem\";\n\n/** One versioned offchain-params snapshot, flattened to what a trial needs. */\nexport interface OffchainParamsCandidate {\n  /** `offchainParamsVersion` stamp this snapshot would restore. */\n  version: number;\n  /** `VersionedOffchainParams.feeRate`. */\n  protocolFeeRate: bigint;\n  minPeginFeeRate: bigint;\n  councilQuorum: number;\n  /** `VersionedOffchainParams.securityCouncilKeys.length`. */\n  councilSize: number;\n  /** `getTimelockPeginByVersion(version)` — not a field on the params struct. */\n  timelockPegin: number;\n  timelockAssert: number;\n  /** `VersionedOffchainParams.tRefund` — the only scalar here that reaches the HTLC scriptPubKey. */\n  timelockRefund: number;\n}\n\n/**\n * One participant key set: a vault provider plus the two rosters at the\n * versions the vault was stamped with.\n *\n * Every key here must be an RFC-006 **operation** key resolved at that\n * participant's own key epoch, and the two roster arrays must be sorted —\n * exactly what `resolveParticipantKeysAtEpochs` produces as\n * `vaultKeeperOperationKeysSorted` / `universalChallengerOperationKeysSorted`.\n * Registration keys are NOT interchangeable: they only coincide with operation\n * keys while nobody has rotated, so passing them yields a wrong script on every\n * candidate and a not-found that wrongly implies the true set was tried.\n *\n * The three epochs are stamped independently by three registries, so a mixed\n * state — the vault provider rotated before this deposit, a challenger after —\n * is ordinary rather than impossible. That is why epochs are resolved per\n * participant from the `PegInSubmitted` log rather than chosen as one\n * all-genesis or all-current policy.\n */\nexport interface ParticipantKeySetCandidate {\n  vaultProvider: Address;\n  /** x-only operation-key hex (no `0x`) at the vault's `vpKeyEpoch`. */\n  vaultProviderBtcPubkey: string;\n  appVaultKeepersVersion: number;\n  /** Sorted operation keys at the vault's `appKeeperKeyEpoch`. */\n  vaultKeeperBtcPubkeys: readonly string[];\n  universalChallengersVersion: number;\n  /** Sorted operation keys at the vault's `ucKeyEpoch`. */\n  universalChallengerBtcPubkeys: readonly string[];\n}\n\n/** A fully-determined parameter set to trial against the funded Pre-PegIn. */\nexport interface PeginParamsCandidate {\n  /**\n   * Stamped tx-graph version (NOT the chain-active one). Carried so the result\n   * describes itself, but constant across a candidate space — see the module\n   * note on why it cannot be searched.\n   */\n  vaultCoreVersion: number;\n  offchainParams: OffchainParamsCandidate;\n  participants: ParticipantKeySetCandidate;\n}\n\nexport interface BuildPeginParamsCandidatesInput {\n  /**\n   * The tx-graph version the stranded deposit was built with. A scalar, not a\n   * list: the transaction cannot discriminate it, so this is taken on trust.\n   * Read it from the orphaned `PegInSubmitted` log — `activeVaultCoreVersion()`\n   * is the current version and is wrong for any deposit that predates a bump.\n   */\n  vaultCoreVersion: number;\n  offchainParams: readonly OffchainParamsCandidate[];\n  participantKeySets: readonly ParticipantKeySetCandidate[];\n}\n\n/**\n * Expand the two searchable axes into the flat candidate list\n * `reconstructPeginParams` trials.\n *\n * With the parameters read from the `PegInSubmitted` log this is called with\n * one entry per axis and produces a single candidate to verify. The\n * multi-element form is the fallback search.\n */\nexport function buildPeginParamsCandidates(\n  input: BuildPeginParamsCandidatesInput,\n): PeginParamsCandidate[] {\n  const { vaultCoreVersion, offchainParams, participantKeySets } = input;\n  if (!Number.isInteger(vaultCoreVersion) || vaultCoreVersion < 1) {\n    throw new Error(\n      `buildPeginParamsCandidates: vaultCoreVersion must be a positive integer, got ${vaultCoreVersion}`,\n    );\n  }\n  if (offchainParams.length === 0) {\n    throw new Error(\n      \"buildPeginParamsCandidates: at least one offchain-params version is required\",\n    );\n  }\n  if (participantKeySets.length === 0) {\n    throw new Error(\n      \"buildPeginParamsCandidates: at least one participant key set is required\",\n    );\n  }\n\n  const candidates: PeginParamsCandidate[] = [];\n  for (const params of offchainParams) {\n    for (const participants of participantKeySets) {\n      candidates.push({\n        vaultCoreVersion,\n        offchainParams: params,\n        participants,\n      });\n    }\n  }\n  return candidates;\n}\n\n/** Which enumeration a version belongs to. */\nexport type CandidateAxis =\n  | \"offchainParams\"\n  | \"vaultKeepers\"\n  | \"universalChallengers\";\n\n/**\n * A version the caller enumerated over but could not resolve into candidate\n * data — dropped by `fetchAllOffchainParams`'s validation, or reported to a\n * roster loop's `onSkippedVersion` observer.\n *\n * Recorded rather than ignored because an unresolved version is UNRESOLVABLE,\n * not absent: it may be the very version that stamped the stranded vault, and\n * a search space missing its answer can still return a confident look-alike.\n */\nexport interface UnresolvedVersion {\n  axis: CandidateAxis;\n  version: number;\n  reason: string;\n}\n\n/** Compact identity of an unresolved version, for error messages. */\nexport function describeUnresolvedVersion(\n  unresolved: UnresolvedVersion,\n): string {\n  return `${unresolved.axis} v${unresolved.version} (${unresolved.reason})`;\n}\n\n/** Compact identity of a candidate, for error messages and result labels. */\nexport function describePeginParamsCandidate(\n  candidate: PeginParamsCandidate,\n): string {\n  const { participants } = candidate;\n  return (\n    `core=${candidate.vaultCoreVersion} ` +\n    `offchain=${candidate.offchainParams.version} ` +\n    `keepers=${participants.appVaultKeepersVersion} ` +\n    `challengers=${participants.universalChallengersVersion} ` +\n    `vp=${participants.vaultProvider}`\n  );\n}\n","/**\n * Recover a stranded deposit's destroyed protocol parameters by trialling an\n * enumerated candidate space against the funded Pre-PegIn transaction (#2203).\n *\n * This is a candidate enumerator plus a loop over an EXISTING verifier.\n * `rebuildDepositTermsCore` already answers \"do these parameters and this\n * funded transaction agree?\" — it rebuilds every HTLC scriptPubKey through the\n * WASM oracle and byte-matches script and value against the transaction, from\n * plain inputs with no chain access. Recovery reuses it verbatim so there is\n * exactly one implementation of that judgement in the codebase.\n *\n * No wallet, no `vaultId`, no browser: every input is either supplied by the\n * caller or read off the transaction. Hashlocks come from\n * `deriveHashlocksFromPrePegin`.\n *\n * @module recovery/reconstructPeginParams\n */\n\nimport {\n  computeMinClaimValue,\n  computeMinPeginFee,\n  peginP2aAnchorOutput,\n  type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Transaction } from \"bitcoinjs-lib\";\n\nimport type { DepositTerms } from \"../deposit-terms/depositTerms\";\nimport { rebuildDepositTermsCore } from \"../deposit-terms/rebuildDepositTermsCore\";\nimport { findAuthAnchorOpReturn } from \"../managers/pegin/assertAuthAnchorOpReturn\";\nimport { HtlcOutputMismatchError } from \"../primitives/psbt/assertWasmPeginSizing\";\nimport {\n  processPublicKeyToXOnly,\n  stripHexPrefix,\n} from \"../primitives/utils/bitcoin\";\nimport { calculateBtcTxHash } from \"../utils/transaction/btcTxHash\";\n\nimport {\n  describePeginParamsCandidate,\n  describeUnresolvedVersion,\n  type PeginParamsCandidate,\n  type UnresolvedVersion,\n} from \"./peginParamsCandidates\";\nimport {\n  PeginParamsAmbiguousError,\n  PeginParamsIncompleteSpaceError,\n  PeginParamsNotFoundError,\n  PeginSizingIntegrityError,\n  UnanchoredPrePeginError,\n} from \"./recoveryErrors\";\n\n/**\n * How many per-candidate reasons an error message carries, for rejections and\n * for unevaluated candidates alike. The full list is one line per candidate and\n * runs to hundreds; a handful is enough to tell \"wrong transaction\" from\n * \"roster not enumerated\". Only the message is capped — the counts that drive\n * the fail-closed decisions stay exact.\n */\nconst MAX_REPORTED_REJECTIONS = 5;\n\nexport interface ReconstructPeginParamsInput {\n  /** Hashlocks indexed by `htlcVout`, from `deriveHashlocksFromPrePegin`. */\n  hashlocks: readonly string[];\n  /** Funded (broadcast) Pre-PegIn transaction hex, `0x` optional. */\n  fundedPrePeginTxHex: string;\n  /** Depositor x-only BTC pubkey hex, from the connected wallet. */\n  depositorBtcPubkey: string;\n  /**\n   * Funded-transaction fee, `Σin − Σout`. Not derivable from the transaction\n   * alone — the input values live in the funding UTXOs — but those are\n   * Bitcoin-keyed reads, which a reorg on Ethereum leaves intact.\n   */\n  prepeginMaxFee: bigint;\n  /**\n   * Commission ceiling projected into the returned {@link DepositTerms}. Not a\n   * search axis: it never reaches the HTLC scriptPubKey or value, so the\n   * transaction carries no evidence of it and the caller must supply the bound\n   * it is willing to accept.\n   */\n  maxAcceptableCommissionBps: number;\n  network: Network;\n  /** The space to search, from `buildPeginParamsCandidates`. */\n  candidates: readonly PeginParamsCandidate[];\n  /**\n   * Versions the caller enumerated over but could not resolve. Required, and\n   * `[]` is the explicit claim that the enumeration was complete — so a caller\n   * cannot arrive at a trusted answer by forgetting to mention its gaps.\n   *\n   * A non-empty list turns a sole match into a\n   * {@link PeginParamsIncompleteSpaceError}: uniqueness only rules out a wrong\n   * answer when the right answer was in the space to begin with.\n   */\n  unresolvedVersions: readonly UnresolvedVersion[];\n}\n\nexport interface ReconstructPeginParamsResult {\n  /** The single candidate whose rebuild matched the funded transaction. */\n  candidate: PeginParamsCandidate;\n  /**\n   * Terms projected from the matched candidate.\n   *\n   * The transaction pins the participant keys, `timelockRefund`, and each\n   * HTLC's scriptPubKey and total value. It does NOT pin how that value splits\n   * into `peginAmount`, `depositorClaimValue` and `peginMaxFee` — that split\n   * follows from the matched candidate's fee-side parameters, which the\n   * transaction carries no evidence of.\n   */\n  terms: DepositTerms;\n  /**\n   * Per-vault `peginAmount`, inverted from the observed HTLC output values.\n   * Only as sound as the matched candidate's reserve — see {@link terms}.\n   */\n  peginAmounts: readonly bigint[];\n  /** The transaction's `SHA256(authAnchor)` commitment, for the refund rebuild. */\n  authAnchorHash: string;\n  /** Size of the space actually trialled, for the recovery record. */\n  candidatesTried: number;\n  /**\n   * Every candidate that matched and projected identical terms.\n   *\n   * More than one is normal rather than suspicious: candidates differing only\n   * in fields the transaction cannot express — version labels whose\n   * script- and value-relevant content is the same — are indistinguishable by\n   * construction and describe the same deposit. They are reported rather than\n   * refused; refusal is reserved for survivors whose terms actually differ.\n   */\n  matchedCandidates: readonly PeginParamsCandidate[];\n}\n\n/**\n * Canonical form of a match's observable content, for equality only.\n *\n * Two survivors agreeing here produce the same refund and the same reported\n * amounts, so the difference between them is a label with no consequence.\n */\nfunction matchFingerprint(\n  terms: DepositTerms,\n  peginAmounts: readonly bigint[],\n): string {\n  return JSON.stringify({ terms, peginAmounts }, (_key, value) =>\n    typeof value === \"bigint\" ? `${value}` : value,\n  );\n}\n\n/** Amount-independent per-HTLC reserve, recomputed exactly as the verifier does. */\ninterface PeginSizing {\n  depositorClaimValue: bigint;\n  peginMaxFee: bigint;\n  p2aAnchorValue: bigint;\n}\n\n/** Identity of the inputs that determine a candidate's reserve, for memoising it. */\nfunction sizingCacheKey(candidate: PeginParamsCandidate): string {\n  const { offchainParams: params, participants } = candidate;\n  return [\n    candidate.vaultCoreVersion,\n    participants.vaultKeeperBtcPubkeys.length,\n    participants.universalChallengerBtcPubkeys.length,\n    params.councilQuorum,\n    params.councilSize,\n    params.protocolFeeRate,\n    params.minPeginFeeRate,\n  ].join(\"|\");\n}\n\n/**\n * Compute the amount-independent reserve for one candidate, asserting the WASM\n * outputs before they are consumed (CLAUDE.md critical path 1).\n *\n * Only binary-integrity invariants are asserted here — a claim value or fee of\n * zero, or a negative anchor, is impossible for ANY valid parameter set, so it\n * indicts the binary rather than the candidate and must escape the search loop\n * instead of being counted as a rejection. The plausibility band on the implied\n * reserve is deliberately NOT duplicated: it depends on the candidate's own\n * `minPeginFeeRate`, so a candidate can legitimately fail it, and the verifier\n * applies it where it belongs — as a candidate filter.\n *\n * An absent anchor reads as `0n` because the facade returns `null` for graph\n * versions whose PegIn carries no anchor and never a zero-valued placeholder,\n * which is the same reading `rebuildDepositTermsCore` takes.\n */\nasync function computePeginSizing(\n  candidate: PeginParamsCandidate,\n): Promise<PeginSizing> {\n  const { offchainParams: params, participants } = candidate;\n  // Depositor-as-claimer: the local-challenger count is the keeper count\n  // (the vault provider is excluded) — btc-vault graph.rs derive_challengers_for.\n  const numVks = participants.vaultKeeperBtcPubkeys.length;\n  const numUcs = participants.universalChallengerBtcPubkeys.length;\n  const [depositorClaimValue, peginMaxFee, anchorOutput] = await Promise.all([\n    computeMinClaimValue(\n      candidate.vaultCoreVersion,\n      numVks,\n      numUcs,\n      params.councilQuorum,\n      params.councilSize,\n      params.protocolFeeRate,\n    ),\n    computeMinPeginFee(\n      candidate.vaultCoreVersion,\n      numVks,\n      numUcs,\n      params.minPeginFeeRate,\n    ),\n    peginP2aAnchorOutput(candidate.vaultCoreVersion),\n  ]);\n  const p2aAnchorValue = anchorOutput?.value ?? 0n;\n\n  if (depositorClaimValue <= 0n) {\n    throw new PeginSizingIntegrityError(\n      `WASM returned non-positive depositorClaimValue ${depositorClaimValue} for graph version ${candidate.vaultCoreVersion}`,\n    );\n  }\n  if (peginMaxFee <= 0n) {\n    throw new PeginSizingIntegrityError(\n      `WASM returned non-positive peginMaxFee ${peginMaxFee} for graph version ${candidate.vaultCoreVersion}`,\n    );\n  }\n  if (p2aAnchorValue < 0n) {\n    throw new PeginSizingIntegrityError(\n      `WASM returned negative P2A anchor value ${p2aAnchorValue} for graph version ${candidate.vaultCoreVersion}`,\n    );\n  }\n\n  return { depositorClaimValue, peginMaxFee, p2aAnchorValue };\n}\n\n/**\n * Search the candidate space for the parameter set that reproduces the funded\n * Pre-PegIn, and project it back into {@link DepositTerms}.\n *\n * Per candidate: invert each vault's `peginAmount` from the observed HTLC\n * output value via the protocol identity `htlcValue = peginAmount +\n * depositorClaimValue + peginMaxFee + p2aAnchorValue`, then hand the result to\n * `rebuildDepositTermsCore`, which independently recomputes that same sizing\n * and byte-matches both the value and the scriptPubKey of every HTLC output.\n *\n * Because the amount is inverted from the value it is compared against, the\n * VALUE check cannot discriminate between candidates: it holds for any\n * candidate whose reserve leaves a positive amount. The scriptPubKey does all\n * the discriminating, and `getPrePeginHtlcConnectorInfo` accepts exactly one\n * offchain-params scalar — `timelockRefund`. So two offchain versions sharing\n * a `timelockRefund` are indistinguishable however much their fee rates or\n * council parameters differ, and that is precisely the ambiguity this function\n * refuses to guess through. The value check is still run, by the verifier, as\n * the bound that stops a candidate whose reserve exceeds the funded output.\n *\n * Every candidate is trialled; the loop does not stop at the first match,\n * because detecting ambiguity is the point. Matches are then COMPARED rather\n * than counted — several candidates matching is the ordinary case whenever\n * their differences cannot reach the transaction, and refusing on a count\n * alone would reject a deposit whose refund is fully determined.\n *\n * A candidate is only rejected on a Gate-1 byte mismatch, which is the\n * transaction positively disagreeing with it. Any other failure means the\n * candidate was never really evaluated, so it is recorded as unresolved and\n * feeds the same fail-closed path as a version that could not be read —\n * otherwise an incidental error on the TRUE candidate would remove it silently\n * and hand back a look-alike as a trusted unique answer.\n *\n * @throws {UnanchoredPrePeginError} If the transaction carries no single,\n *   unambiguous auth-anchor OP_RETURN.\n * @throws {PeginParamsNotFoundError} If no candidate matched.\n * @throws {PeginParamsAmbiguousError} If matches disagree on the projected terms.\n * @throws {PeginParamsIncompleteSpaceError} If a match is found but the space\n *   was known to be incomplete, or a candidate failed to evaluate.\n */\nexport async function reconstructPeginParams(\n  input: ReconstructPeginParamsInput,\n): Promise<ReconstructPeginParamsResult> {\n  const {\n    hashlocks,\n    fundedPrePeginTxHex,\n    depositorBtcPubkey,\n    prepeginMaxFee,\n    maxAcceptableCommissionBps,\n    network,\n    candidates,\n    unresolvedVersions,\n  } = input;\n\n  if (hashlocks.length === 0) {\n    throw new Error(\n      \"reconstructPeginParams: at least one hashlock is required\",\n    );\n  }\n  if (candidates.length === 0) {\n    throw new Error(\"reconstructPeginParams: candidate space is empty\");\n  }\n\n  // The verifier compares this against WASM-built scripts and does not\n  // normalise, while the derivation half accepts a `0x` prefix. Passing one\n  // wallet string to both must not make step 1 pass and step 2 fail every\n  // candidate, which would present as \"no parameters found\".\n  const normalizedDepositorBtcPubkey =\n    processPublicKeyToXOnly(depositorBtcPubkey);\n\n  const cleanTxHex = stripHexPrefix(fundedPrePeginTxHex);\n  const anchor = findAuthAnchorOpReturn(cleanTxHex);\n  if (anchor === undefined) {\n    throw new UnanchoredPrePeginError(\n      `Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN; the ` +\n        `sibling set cannot be proven complete. Reconstruction refused.`,\n    );\n  }\n  // The verifier re-checks this, but catching it here attributes the failure\n  // to the hashlock set rather than to every candidate in turn.\n  if (anchor.vout !== hashlocks.length) {\n    throw new Error(\n      `reconstructPeginParams: ${hashlocks.length} hashlock(s) supplied but ` +\n        `the auth-anchor OP_RETURN sits at vout ${anchor.vout}, so the ` +\n        `transaction funds ${anchor.vout} HTLC output(s). Reconstruction refused.`,\n    );\n  }\n\n  const outputs = Transaction.fromHex(cleanTxHex).outs;\n  const observedHtlcValues = hashlocks.map((_, i) => BigInt(outputs[i].value));\n  const prepeginTxid = stripHexPrefix(\n    calculateBtcTxHash(cleanTxHex),\n  ).toLowerCase();\n\n  const sizingCache = new Map<string, PeginSizing>();\n  const survivors: {\n    candidate: PeginParamsCandidate;\n    terms: DepositTerms;\n    peginAmounts: bigint[];\n    fingerprint: string;\n  }[] = [];\n  const rejections: string[] = [];\n  // Count drives the fail-closed decision and must stay exact; only the labels\n  // that reach the error message are capped, since in the fallback search every\n  // candidate can land here and each entry embeds a full error message.\n  const unevaluatedLabels: string[] = [];\n  let unevaluatedCount = 0;\n\n  for (const candidate of candidates) {\n    try {\n      const cacheKey = sizingCacheKey(candidate);\n      let sizing = sizingCache.get(cacheKey);\n      if (sizing === undefined) {\n        sizing = await computePeginSizing(candidate);\n        sizingCache.set(cacheKey, sizing);\n      }\n      const reserve =\n        sizing.depositorClaimValue + sizing.peginMaxFee + sizing.p2aAnchorValue;\n      const peginAmounts = observedHtlcValues.map((value) => value - reserve);\n      // A reserve larger than the funded output is the transaction positively\n      // disagreeing with this candidate — the value bound doing the one piece\n      // of discriminating it can. The verifier would reject it too, but with a\n      // generic error that would be misread as \"never evaluated\" and would\n      // pollute the space with phantom gaps.\n      const shortIndex = peginAmounts.findIndex((amount) => amount <= 0n);\n      if (shortIndex !== -1) {\n        throw new HtlcOutputMismatchError(\n          `HTLC output[${shortIndex}] value ${observedHtlcValues[shortIndex]} ` +\n            `is not above this candidate's reserve ${reserve}, so it implies a ` +\n            `non-positive pegin amount ${peginAmounts[shortIndex]}.`,\n        );\n      }\n\n      const { offchainParams: params, participants } = candidate;\n      const terms = await rebuildDepositTermsCore({\n        vaultCoreVersion: candidate.vaultCoreVersion,\n        siblings: hashlocks.map((hashlock, i) => ({\n          hashlock,\n          amount: peginAmounts[i],\n        })),\n        fundedPrePeginTxHex: cleanTxHex,\n        depositorBtcPubkey: normalizedDepositorBtcPubkey,\n        vaultProviderBtcPubkey: participants.vaultProviderBtcPubkey,\n        vaultKeeperBtcPubkeys: participants.vaultKeeperBtcPubkeys,\n        universalChallengerBtcPubkeys:\n          participants.universalChallengerBtcPubkeys,\n        protocolFeeRate: params.protocolFeeRate,\n        minPeginFeeRate: params.minPeginFeeRate,\n        councilQuorum: params.councilQuorum,\n        councilSize: params.councilSize,\n        timelockPegin: params.timelockPegin,\n        timelockAssert: params.timelockAssert,\n        timelockRefund: params.timelockRefund,\n        prepeginTxid,\n        prepeginMaxFee,\n        maxAcceptableCommissionBps,\n        network,\n      });\n\n      survivors.push({\n        candidate,\n        terms,\n        peginAmounts,\n        fingerprint: matchFingerprint(terms, peginAmounts),\n      });\n    } catch (err) {\n      // A malformed WASM sizing output is not a property of the candidate, so\n      // counting it as a rejection would bury a broken binary under \"no\n      // candidate matched\". Let it out.\n      if (err instanceof PeginSizingIntegrityError) {\n        throw err;\n      }\n      const label = describePeginParamsCandidate(candidate);\n      const reason = err instanceof Error ? err.message : String(err);\n      if (err instanceof HtlcOutputMismatchError) {\n        // The transaction positively disagrees with this candidate — the\n        // expected outcome for all but one, so it cannot propagate. Recorded,\n        // and a sample reaches the not-found error to keep it diagnosable.\n        if (rejections.length < MAX_REPORTED_REJECTIONS) {\n          rejections.push(`[${label}] ${reason}`);\n        }\n      } else {\n        // Anything else says nothing about the transaction: this candidate was\n        // never actually evaluated. Treating it as a rejection would let an\n        // incidental failure on the true candidate hand back a look-alike.\n        unevaluatedCount++;\n        if (unevaluatedLabels.length < MAX_REPORTED_REJECTIONS) {\n          unevaluatedLabels.push(`${label} (${reason})`);\n        }\n      }\n    }\n  }\n\n  // A candidate that could not be evaluated is a hole in the space in exactly\n  // the same way an unreadable version is, so the two are reported together.\n  const gapCount = unresolvedVersions.length + unevaluatedCount;\n  const gaps = [\n    ...unresolvedVersions.map(describeUnresolvedVersion),\n    ...unevaluatedLabels,\n  ];\n\n  if (survivors.length === 0) {\n    throw new PeginParamsNotFoundError(candidates.length, rejections, gaps);\n  }\n\n  // Compare, do not count. Survivors all byte-matched the same funded outputs,\n  // so they already agree on every HTLC scriptPubKey and total value; if they\n  // also project identical terms there is nothing to choose between them and\n  // nothing is at stake in choosing.\n  const distinct = new Set(survivors.map((s) => s.fingerprint));\n  if (distinct.size > 1) {\n    throw new PeginParamsAmbiguousError(\n      survivors.map((s) => describePeginParamsCandidate(s.candidate)),\n    );\n  }\n\n  // Reported after ambiguity: disagreeing survivors are the more specific\n  // diagnosis, and that error already names them.\n  if (gapCount > 0) {\n    throw new PeginParamsIncompleteSpaceError(\n      describePeginParamsCandidate(survivors[0].candidate),\n      gaps,\n    );\n  }\n\n  return {\n    candidate: survivors[0].candidate,\n    terms: survivors[0].terms,\n    peginAmounts: survivors[0].peginAmounts,\n    authAnchorHash: anchor.hash,\n    candidatesTried: candidates.length,\n    matchedCandidates: survivors.map((s) => s.candidate),\n  };\n}\n","/**\n * Close the loop from a verified reconstruction to the ordinary refund path\n * (#2203).\n *\n * `buildAndBroadcastRefund` takes its two reads — the vault row and the\n * version-pinned Pre-PegIn context — as injected callbacks rather than\n * performing them itself. That is the whole seam recovery needs: a stranded\n * deposit has no row to read, but it does have a reconstruction that was\n * byte-verified against the funded transaction, and those are exactly the\n * fields the callbacks are expected to return.\n *\n * So recovery does not need a parallel refund implementation, and must not\n * have one. It supplies the same shapes from a different source and reuses the\n * orchestrator verbatim, which keeps the refund-fee cap, the abort checks, the\n * `htlcVout` contiguity invariant and the bitcoind error classification in one\n * place for both paths.\n *\n * @module recovery/toRefundInputs\n */\n\nimport type { Network } from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport type { Address, Hex } from \"viem\";\n\nimport { ensureHexPrefix } from \"../primitives/utils/bitcoin\";\nimport type {\n  RefundPrePeginContext,\n  VaultRefundData,\n} from \"../services/refund/buildAndBroadcastRefund\";\n\nimport type { ReconstructPeginParamsResult } from \"./reconstructPeginParams\";\n\nexport interface ToRefundInputsOptions {\n  /**\n   * Which sibling of the Pre-PegIn to refund, as an index into the\n   * reconstruction's hashlocks and amounts. Equal to the vault's `htlcVout`\n   * by construction — `PeginManager` asserts `perVault[i].htlcVout === i`.\n   */\n  htlcVout: number;\n  /**\n   * Depositor BTC pubkey, the same value the reconstruction was run with.\n   * Passed through rather than re-derived so the refund is built against the\n   * key that was actually verified.\n   *\n   * Deliberately NOT narrowed to x-only here. `VaultRefundData.depositorBtcPubkey`\n   * accepts \"32 or 33 bytes of hex\", and `buildAndBroadcastRefund` narrows it\n   * with `processPublicKeyToXOnly` before it reaches the PSBT builder — so a\n   * wallet's compressed key flows through unchanged, which is what wallets\n   * actually return. Narrowing early would discard the parity byte the\n   * orchestrator's own validation accepts.\n   */\n  depositorBtcPubkey: string;\n  /**\n   * The vault provider's application entry point. Not recoverable from the\n   * Bitcoin transaction and not part of the verified parameter set — it is a\n   * field of the vault-provider registry row, which is address-keyed and\n   * survives the reorg untouched.\n   */\n  applicationEntryPoint: Address;\n  /** Funded Pre-PegIn transaction hex, `0x` optional. */\n  fundedPrePeginTxHex: string;\n  /** Hashlocks indexed by `htlcVout`, as passed to the reconstruction. */\n  hashlocks: readonly string[];\n  /**\n   * The Bitcoin network the reconstruction was verified against. An input to\n   * the search rather than an output of it, so it is restated here; passing a\n   * different one would build the refund against a different script tree than\n   * the one that was proven to match.\n   */\n  network: Network;\n}\n\nexport interface RefundInputsFromRecovery {\n  vault: VaultRefundData;\n  context: RefundPrePeginContext;\n}\n\n/**\n * Project a verified reconstruction into the two shapes\n * `buildAndBroadcastRefund` injects.\n *\n * Every value here comes from a parameter set that has already been\n * byte-matched against the funded transaction's HTLC outputs, so this is a\n * projection and not a second validation pass. The orchestrator re-checks the\n * parts it owns regardless.\n *\n * @throws If `htlcVout` does not index the reconstructed batch, or the\n *   hashlock vector disagrees with the reconstructed amounts.\n */\nexport function toRefundInputs(\n  result: ReconstructPeginParamsResult,\n  options: ToRefundInputsOptions,\n): RefundInputsFromRecovery {\n  const {\n    htlcVout,\n    depositorBtcPubkey,\n    applicationEntryPoint,\n    fundedPrePeginTxHex,\n    hashlocks,\n    network,\n  } = options;\n\n  const { candidate, peginAmounts } = result;\n  const { offchainParams, participants } = candidate;\n\n  if (hashlocks.length !== peginAmounts.length) {\n    throw new Error(\n      `toRefundInputs: ${hashlocks.length} hashlock(s) but ` +\n        `${peginAmounts.length} reconstructed amount(s); the reconstruction ` +\n        `and the hashlock vector describe different transactions.`,\n    );\n  }\n  if (\n    !Number.isInteger(htlcVout) ||\n    htlcVout < 0 ||\n    htlcVout >= peginAmounts.length\n  ) {\n    throw new Error(\n      `toRefundInputs: htlcVout ${htlcVout} is outside the reconstructed ` +\n        `batch of ${peginAmounts.length} vault(s).`,\n    );\n  }\n\n  // The orchestrator requires the complete vout-ordered batch, not just the\n  // target: its anchor check is fail-closed, so refunding one sibling of a\n  // multi-vault Pre-PegIn without the others is rejected outright.\n  const batch = peginAmounts.map((amount, index) => ({\n    hashlock: ensureHexPrefix(hashlocks[index]),\n    amount,\n    htlcVout: index,\n  }));\n\n  const vault: VaultRefundData = {\n    vaultCoreVersion: candidate.vaultCoreVersion,\n    hashlock: batch[htlcVout].hashlock as Hex,\n    htlcVout,\n    offchainParamsVersion: offchainParams.version,\n    appVaultKeepersVersion: participants.appVaultKeepersVersion,\n    universalChallengersVersion: participants.universalChallengersVersion,\n    vaultProvider: participants.vaultProvider,\n    applicationEntryPoint,\n    amount: peginAmounts[htlcVout],\n    unsignedPrePeginTxHex: fundedPrePeginTxHex,\n    depositorBtcPubkey,\n    batch,\n  };\n\n  const context: RefundPrePeginContext = {\n    vaultProviderPubkey: participants.vaultProviderBtcPubkey,\n    vaultKeeperPubkeys: participants.vaultKeeperBtcPubkeys,\n    universalChallengerPubkeys: participants.universalChallengerBtcPubkeys,\n    timelockRefund: offchainParams.timelockRefund,\n    feeRate: offchainParams.protocolFeeRate,\n    minPeginFeeRate: offchainParams.minPeginFeeRate,\n    // Depositor-as-claimer: the local-challenger count is the keeper count,\n    // the vault provider excluded — btc-vault graph.rs derive_challengers.\n    numLocalChallengers: participants.vaultKeeperBtcPubkeys.length,\n    councilQuorum: offchainParams.councilQuorum,\n    councilSize: offchainParams.councilSize,\n    network,\n  };\n\n  return { vault, context };\n}\n"],"names":["DEPOSIT_TERMS_REJECTED_ERROR_NAME","DepositTermsRejectedError","message","reason","__publicField","isDepositTermsRejectedError","err","shaped","rebuildDepositTermsCore","input","siblingCount","i","sibling","expectedTxid","stripHexPrefix","actualTxid","calculateBtcTxHash","found","findAuthAnchorOpReturn","numVks","numUcs","depositorClaimValue","computeMinClaimValue","peginMaxFee","computeMinPeginFee","anchor","peginP2aAnchorOutput","anchorValue","impliedReserve","maxImpliedReserve","MAX_REASONABLE_PEGIN_VBYTES","expectedHtlcValues","s","expectedHtlcScriptPubKeys","getPrePeginHtlcConnectorInfo","fundedOutputs","Transaction","assertEncodedHtlcOutputsMatch","buildDepositTerms","isWotsMismatchError","error","msg","VaultRootMismatchError","derivedAuthAnchorHash","onChainAuthAnchorHash","UnanchoredPrePeginError","PeginParamsNotFoundError","candidatesTried","sampleRejections","unresolvedLabels","PeginParamsAmbiguousError","survivorLabels","PeginParamsIncompleteSpaceError","matchedLabel","PeginSizingIntegrityError","deriveHashlocksFromPrePegin","wallet","depositorBtcPubkey","fundedPrePeginTxHex","cleanTxHex","vaultCount","fundingOutpoints","parseFundingOutpointsFromTx","root","deriveVaultRoot","hexToUint8Array","processPublicKeyToXOnly","authAnchorBytes","expandAuthAnchor","uint8ArrayToHex","sha256","hashlocks","expandPerVaultSecrets","buildPeginParamsCandidates","vaultCoreVersion","offchainParams","participantKeySets","candidates","params","participants","describeUnresolvedVersion","unresolved","describePeginParamsCandidate","candidate","MAX_REPORTED_REJECTIONS","matchFingerprint","terms","peginAmounts","_key","value","sizingCacheKey","computePeginSizing","anchorOutput","p2aAnchorValue","reconstructPeginParams","prepeginMaxFee","maxAcceptableCommissionBps","network","unresolvedVersions","normalizedDepositorBtcPubkey","outputs","observedHtlcValues","_","prepeginTxid","sizingCache","survivors","rejections","unevaluatedLabels","unevaluatedCount","cacheKey","sizing","reserve","shortIndex","amount","HtlcOutputMismatchError","hashlock","label","gapCount","gaps","toRefundInputs","result","options","htlcVout","applicationEntryPoint","batch","index","ensureHexPrefix","vault","context"],"mappings":"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"}