{"version":3,"file":"PeginManager-VM-jifLt.cjs","sources":["../../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/_u64.js","../src/tbv/core/deposit-terms/buildDepositTerms.ts","../src/tbv/core/deposit-terms/commissionCeiling.ts","../src/tbv/core/managers/pegin/normalizeWalletInputs.ts","../src/tbv/core/deposit-terms/prePeginApproval.ts","../../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/legacy.js","../../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/sha3.js","../src/tbv/core/wots/blockDerivation.ts","../src/tbv/core/managers/pegin/expandPerVaultSecrets.ts","../src/tbv/core/managers/pegin/verifyPopWitness.ts","../src/tbv/core/managers/PeginManager.ts"],"sourcesContent":["/**\n * Internal helpers for u64. BigUint64Array is too slow as per 2025, so we implement it using Uint32Array.\n * @todo re-check https://issues.chromium.org/issues/42212588\n * @module\n */\nconst U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);\nconst _32n = /* @__PURE__ */ BigInt(32);\nfunction fromBig(n, le = false) {\n    if (le)\n        return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };\n    return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };\n}\nfunction split(lst, le = false) {\n    const len = lst.length;\n    let Ah = new Uint32Array(len);\n    let Al = new Uint32Array(len);\n    for (let i = 0; i < len; i++) {\n        const { h, l } = fromBig(lst[i], le);\n        [Ah[i], Al[i]] = [h, l];\n    }\n    return [Ah, Al];\n}\nconst toBig = (h, l) => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);\n// for Shift in [0, 32)\nconst shrSH = (h, _l, s) => h >>> s;\nconst shrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in [1, 32)\nconst rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s));\nconst rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32));\nconst rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s));\n// Right rotate for shift===32 (just swaps l&h)\nconst rotr32H = (_h, l) => l;\nconst rotr32L = (h, _l) => h;\n// Left rotate for Shift in [1, 32)\nconst rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s));\nconst rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s));\n// Left rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s));\nconst rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s));\n// JS uses 32-bit signed integers for bitwise operations which means we cannot\n// simple take carry out of low bit sum by shift, we need to use division.\nfunction add(Ah, Al, Bh, Bl) {\n    const l = (Al >>> 0) + (Bl >>> 0);\n    return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };\n}\n// Addition with more than 2 elements\nconst add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);\nconst add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;\nconst add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);\nconst add4H = (low, Ah, Bh, Ch, Dh) => (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;\nconst add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);\nconst add5H = (low, Ah, Bh, Ch, Dh, Eh) => (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;\n// prettier-ignore\nexport { add, add3H, add3L, add4H, add4L, add5H, add5L, fromBig, rotlBH, rotlBL, rotlSH, rotlSL, rotr32H, rotr32L, rotrBH, rotrBL, rotrSH, rotrSL, shrSH, shrSL, split, toBig };\n// prettier-ignore\nconst u64 = {\n    fromBig, split, toBig,\n    shrSH, shrSL,\n    rotrSH, rotrSL, rotrBH, rotrBL,\n    rotr32H, rotr32L,\n    rotlSH, rotlSL, rotlBH, rotlBL,\n    add, add3L, add3H, add4L, add4H, add5H, add5L,\n};\nexport default u64;\n//# sourceMappingURL=_u64.js.map","import {\n  BPS_DENOMINATOR,\n  MAX_VP_COMMISSION_BPS_EXCLUSIVE,\n} from \"../primitives/psbt/constants\";\n\nimport type {\n  BuildDepositTermsInputs,\n  DepositTerms,\n  DepositTermsVaultGroup,\n} from \"./depositTerms\";\n\nconst TXID_HEX_LENGTH = 64;\n\n/**\n * Project already-validated pegin inputs into protocol-level deposit terms.\n * Not a second validator: keys arrive canonical and sorted from on-chain\n * validation, and non-negative sizing is already asserted by WASM output checks.\n */\nexport function buildDepositTerms(\n  inputs: BuildDepositTermsInputs,\n): DepositTerms {\n  const txid = inputs.prepeginTxid.toLowerCase();\n  if (!/^[0-9a-f]+$/.test(txid) || txid.length !== TXID_HEX_LENGTH) {\n    throw new Error(\n      `buildDepositTerms: prepeginTxid must be 64 hex chars, got \"${inputs.prepeginTxid}\"`,\n    );\n  }\n  if (inputs.peginAmounts.length === 0) {\n    throw new Error(\"buildDepositTerms: at least one pegin amount is required\");\n  }\n  // Device-envelope validation is a PROVIDER obligation inside\n  // approveDepositTerms (DepositTermsApprover contract; adapter lands at #2109).\n  if (\n    inputs.timelockPegin <= 0 ||\n    inputs.timelockAssert <= 0 ||\n    inputs.timelockRefund <= 0\n  ) {\n    throw new Error(\"buildDepositTerms: timelocks must be positive\");\n  }\n  // Same bound payout.ts enforces before broadcast; catching drift here keeps\n  // the projected commissionFee ceiling meaningful.\n  if (\n    !Number.isInteger(inputs.maxAcceptableCommissionBps) ||\n    inputs.maxAcceptableCommissionBps < 0 ||\n    inputs.maxAcceptableCommissionBps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n  ) {\n    throw new Error(\n      `buildDepositTerms: maxAcceptableCommissionBps must be an integer in ` +\n        `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${inputs.maxAcceptableCommissionBps}`,\n    );\n  }\n\n  const bpsDenominator = BigInt(BPS_DENOMINATOR);\n  const vaults: DepositTermsVaultGroup[] = inputs.peginAmounts.map(\n    (peginAmount, index) => ({\n      htlcVout: index,\n      vaultProviderBtcPubkey: inputs.vaultProviderBtcPubkey,\n      peginAmount,\n      // Ceiling, not quote: floor(peginAmount * maxAcceptableBps / 10_000) —\n      // the same bound the registration calldata enforces on-chain, so any\n      // stamped commission the contract admits stays under it (firmware\n      // >= c8db53e checks the payout commission output <= this value).\n      commissionFee:\n        (peginAmount * BigInt(inputs.maxAcceptableCommissionBps)) /\n        bpsDenominator,\n      depositorClaimValue: inputs.depositorClaimValue,\n      peginMaxFee: inputs.peginMaxFee,\n    }),\n  );\n\n  return {\n    vaultCoreVersion: inputs.vaultCoreVersion,\n    protocolFeeRate: inputs.protocolFeeRate,\n    timelockPegin: inputs.timelockPegin,\n    timelockAssert: inputs.timelockAssert,\n    timelockRefund: inputs.timelockRefund,\n    prepeginTxid: txid,\n    prepeginMaxFee: inputs.prepeginMaxFee,\n    vaultKeeperBtcPubkeys: [...inputs.vaultKeeperBtcPubkeys],\n    universalChallengerBtcPubkeys: [...inputs.universalChallengerBtcPubkeys],\n    vaults,\n  };\n}\n","/**\n * The depositor's commission ceiling (`maxAcceptableCommissionBps`) policy:\n * quoted VP commission + drift headroom, capped below the contract's\n * exclusive bound. Shared by the fresh path (`PeginManager`) and the\n * resume-rebuild path so both compute the same ceiling.\n *\n * @module deposit-terms/commissionCeiling\n */\n\n/*\n * Commission-check map (each guards a DIFFERENT boundary — do not consolidate):\n *  1. assertVpCommissionInProtocolRange (vault app, vaultPayoutSignatureService)\n *     — chain-read trust boundary; mirrors VPKeyRegistryLogic.sol bounds.\n *  2. capMaxAcceptableCommissionBps (here) — depositor quote → ceiling policy;\n *     mirrors PeginLogic.sol's strict > check via the +25bps headroom.\n *  3. buildDepositTerms range check — public-API precondition on the projection\n *     that mints the device-enforced commissionFee.\n *  4. payout.ts commission cap — the VP-built tx's output value vs bps at the\n *     signing site (CLAUDE.md Critical Path #3).\n *  5. envelope.ts dust/cross-field gates (ledger-vault-signer) — firmware-only\n *     constants, pre-device-I/O (Critical Path #7).\n */\n\nimport { MAX_VP_COMMISSION_BPS_EXCLUSIVE } from \"../primitives/psbt/constants\";\n\n/**\n * Headroom (in basis points) added to the current VP commission to compute\n * `maxAcceptableCommissionBps` at submit time. Lets the VP raise its\n * commission by up to this amount between read and submit without forcing\n * a re-quote. Capped by {@link MAX_ACCEPTABLE_COMMISSION_BPS_CAP}.\n *\n * Contract check is strict `>` (PeginLogic.sol `VaultProviderCommissionExceeded`\n * revert), so +25 allows up\n * to +25 bps of drift.\n */\nexport const COMMISSION_BPS_HEADROOM = 25;\n\n/**\n * Hard ceiling for `maxAcceptableCommissionBps`. The contract enforces\n * `commissionBps < 10000`, so any value at/above that is unreachable;\n * `9999` is the maximum useful cap.\n */\nexport const MAX_ACCEPTABLE_COMMISSION_BPS_CAP = 9999;\n\n/**\n * The commission ceiling submitted as registration calldata and mirrored\n * into `DepositTerms.commissionFee`: quoted + drift headroom, capped.\n * Single source for both consumers — feed it the SAME quoted bps at prepare\n * and register time so device-accept stays coextensive with contract-accept.\n */\nexport function capMaxAcceptableCommissionBps(bps: number): number {\n  // Validate the raw quote before headroom shifts its domain — a negative\n  // quote must throw here, not become a small \"legal\" ceiling.\n  // Reject an out-of-range quote outright — clamping it to 9999 would turn a\n  // bad read into a 99.99% ceiling, the exact failure the cap exists to stop.\n  if (\n    !Number.isInteger(bps) ||\n    bps < 0 ||\n    bps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n  ) {\n    throw new Error(\n      `Quoted commissionBps must be an integer in ` +\n        `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${bps}`,\n    );\n  }\n  return Math.min(\n    bps + COMMISSION_BPS_HEADROOM,\n    MAX_ACCEPTABLE_COMMISSION_BPS_CAP,\n  );\n}\n","/**\n * Normalizers for wallet-returned values consumed by the Pre-PegIn flow.\n *\n * @module managers/pegin/normalizeWalletInputs\n */\n\nimport { Buffer } from \"buffer\";\nimport type { Hex } from \"viem\";\n\nimport { processPublicKeyToXOnly } from \"../../primitives/utils/bitcoin\";\n\nconst HEX_SIGNATURE_REGEX = /^0x[0-9a-f]+$/i;\nconst UNPREFIXED_HEX_SIGNATURE_REGEX = /^[0-9a-f]+$/i;\nconst BASE64_SIGNATURE_REGEX = /^[A-Za-z0-9+/]+={0,2}$/;\n\n/**\n * Normalize a wallet-returned BTC public key to the canonical x-only\n * 64-char lowercase hex form (no 0x prefix).\n *\n * Throws on empty/non-string input. Idempotent on x-only input.\n */\nexport function normalizeXOnlyPubkey(raw: unknown): string {\n  if (typeof raw !== \"string\" || raw.length === 0) {\n    throw new Error(\"BTC wallet returned empty public key\");\n  }\n  // Lowercase so case-sensitive equality checks downstream don't fail\n  // on uppercase wallet output (processPublicKeyToXOnly passes a 64-char\n  // input through unchanged).\n  return processPublicKeyToXOnly(raw).toLowerCase();\n}\n\n/**\n * Normalize a wallet-returned BIP-322 signature into 0x-prefixed hex.\n *\n * Accepts:\n *  - 0x-prefixed lowercase/uppercase hex\n *  - unprefixed hex (wins over base64 when input is pure `[0-9a-fA-F]+`)\n *  - canonical standard base64 (`[A-Za-z0-9+/]` with `=` padding to a\n *    multiple of 4 and no non-canonical encodings)\n *\n * Rejects URL-safe base64 (`-`/`_`) and base64 without padding. Wallets\n * known to return BIP-322 signatures (Keystone, UniSat, OKX, OneKey,\n * Unisat) all use standard base64; URL-safe is an explicit non-goal.\n */\nexport function normalizePopSignature(raw: unknown): Hex {\n  if (typeof raw !== \"string\" || raw.length === 0) {\n    throw new Error(\"BTC wallet returned empty BIP-322 signature\");\n  }\n\n  if (raw.startsWith(\"0x\") || raw.startsWith(\"0X\")) {\n    if (\n      !HEX_SIGNATURE_REGEX.test(raw) ||\n      raw.length < 4 ||\n      raw.length % 2 !== 0\n    ) {\n      throw new Error(\"BTC wallet returned malformed hex BIP-322 signature\");\n    }\n    return raw.toLowerCase() as Hex;\n  }\n\n  // Prefer hex when the input could be either: every hex char is also a\n  // valid base64 char, so the base64 branch alone would silently misdecode\n  // a wallet returning \"deadbeef\" instead of \"0xdeadbeef\".\n  if (UNPREFIXED_HEX_SIGNATURE_REGEX.test(raw)) {\n    if (raw.length % 2 !== 0) {\n      throw new Error(\"BTC wallet returned malformed hex BIP-322 signature\");\n    }\n    return `0x${raw.toLowerCase()}` as Hex;\n  }\n\n  if (!BASE64_SIGNATURE_REGEX.test(raw) || raw.length % 4 !== 0) {\n    throw new Error(\"BTC wallet returned malformed base64 BIP-322 signature\");\n  }\n  const bytes = Buffer.from(raw, \"base64\");\n  // Round-trip to reject non-canonical base64 (e.g. \"AB==\" decodes but\n  // re-encodes to \"AA==\").\n  if (bytes.length === 0 || bytes.toString(\"base64\") !== raw) {\n    throw new Error(\"BTC wallet returned malformed base64 BIP-322 signature\");\n  }\n  return `0x${bytes.toString(\"hex\")}` as Hex;\n}\n","/**\n * The Pre-PegIn approval ceremony for intent-based signing wallets.\n *\n * A shared helper because there are two Pre-PegIn broadcast paths — the SDK's\n * {@link PeginManager.signAndBroadcast} and the vault app's own\n * `broadcastPrePeginTransaction` (a near-duplicate). Both must run the exact\n * same derive → approve sequence immediately before `signPsbt`, or the two\n * copies drift on a signing-critical path.\n *\n * The device signs a Pre-PegIn only from `INTENT_LOADED`, and only if the\n * approved intent's `prepegin_txid` matches this tx and its fee is within the\n * approved `prepegin_max_fee`. So an approval-capable wallet must be shown the\n * terms (and derive the context root that gates the intent) before it signs.\n *\n * @module deposit-terms/prePeginApproval\n */\n\nimport { Transaction } from \"bitcoinjs-lib\";\n\nimport { normalizeXOnlyPubkey } from \"../managers/pegin/normalizeWalletInputs\";\nimport { hexToUint8Array } from \"../primitives/utils/bitcoin\";\nimport { deriveVaultRoot, parseFundingOutpointsFromTx } from \"../vault-secrets\";\nimport type { DepositTerms } from \"./depositTerms\";\n\n/**\n * Minimal structural wallet for the Pre-PegIn ceremony. Mirrors\n * `DeriveContextHashCapableWallet` so an app-side wrapper object qualifies\n * without implementing all of `BitcoinWallet`. All methods are optional so\n * the capability probe below can run on any wallet.\n */\nexport interface PrePeginApprovalWallet {\n  deriveContextHash?(appName: string, context: string): Promise<string>;\n  approveDepositTerms?(terms: DepositTerms): Promise<void>;\n  holdsApprovedDepositTerms?(terms: DepositTerms): Promise<boolean>;\n  validateDepositTerms?(terms: DepositTerms): Promise<void>;\n}\n\nexport interface EnsurePrePeginTermsApprovalParams {\n  wallet: PrePeginApprovalWallet;\n  /** The approved terms — required for approval-capable wallets, ignored (but still txid-checked) otherwise. */\n  depositTerms: DepositTerms | undefined;\n  /** Funded Pre-PegIn tx hex (0x optional): the funding outpoints AND the txid the terms must match. */\n  fundedPrePeginTxHex: string;\n  /** x-only depositor pubkey (64 hex, 0x optional) — the identity the PSBT is signed with. */\n  depositorBtcPubkey: string;\n}\n\n/**\n * Run the derive → approve ceremony (or a no-op) before a Pre-PegIn signature.\n *\n * - Non-approval wallets: no-op, after asserting the terms (if any) match the tx.\n * - Approval-capable wallets: require terms, assert they match this tx's txid,\n *   derive the vault root over the tx's funding outpoints, then approve.\n *\n * Skip fast-path: when `holdsApprovedDepositTerms` reports the byte-equal\n * intent still live, the ceremony is skipped — it survives everything the\n * flow does in between (PoP/PegIn signing spend separate device state;\n * app-babylon-vault `sign_psbt_validate.c` @ 73a57c50). A stale true fails\n * closed at the signature; the retry then re-runs the full ceremony.\n *\n * Otherwise always derives first — the host cannot read device state, so\n * this path never approves-only.\n *\n * @throws If approval-capable but no terms are provided, or the provided terms\n *   are for a different transaction.\n */\nexport async function ensurePrePeginTermsApproval(\n  params: EnsurePrePeginTermsApprovalParams,\n): Promise<void> {\n  const { wallet, depositTerms, fundedPrePeginTxHex, depositorBtcPubkey } =\n    params;\n  // Gate on typeof (the seam's supportsDepositApproval convention) so a spread\n  // non-function value is treated as absent rather than reaching the approve\n  // call and throwing a raw TypeError. Also narrows it to a function below.\n  const approveDepositTerms =\n    typeof wallet.approveDepositTerms === \"function\"\n      ? wallet.approveDepositTerms\n      : undefined;\n\n  // Nothing to do — not an approval wallet and no terms to validate — so skip\n  // parsing the tx entirely.\n  if (!approveDepositTerms && !depositTerms) {\n    return;\n  }\n\n  const cleanHex = fundedPrePeginTxHex.startsWith(\"0x\")\n    ? fundedPrePeginTxHex.slice(2)\n    : fundedPrePeginTxHex;\n  const tx = Transaction.fromHex(cleanHex);\n  const txid = tx.getId();\n\n  // Whatever the wallet, if terms were supplied they must be for THIS tx.\n  // Complements runDepositorPresignFlow's assertDepositTermsMatchSigningContext,\n  // which checks the graph scalars and rosters but never the txid.\n  if (\n    depositTerms &&\n    depositTerms.prepeginTxid.replace(/^0x/, \"\").toLowerCase() !== txid\n  ) {\n    throw new Error(\n      `Deposit terms do not match the transaction being broadcast: terms are for ` +\n        `prepeginTxid ${depositTerms.prepeginTxid}, but this transaction is ${txid}.`,\n    );\n  }\n\n  if (!approveDepositTerms) {\n    return;\n  }\n\n  if (!depositTerms) {\n    throw new Error(\n      \"This wallet requires approved deposit terms before signing the Pre-PegIn transaction, \" +\n        \"but none were provided. Pass PreparePeginResult.depositTerms (fresh flows) or a resume rebuild.\",\n    );\n  }\n\n  if (typeof wallet.deriveContextHash !== \"function\") {\n    throw new Error(\n      \"A deposit-approval wallet must also implement deriveContextHash, but this one does not.\",\n    );\n  }\n\n  // Fast path: the preparePegin intent is still live — re-deriving would only\n  // wipe it and force a second ceremony. Stale answers fail closed at the sig.\n  if (typeof wallet.holdsApprovedDepositTerms === \"function\") {\n    let holdsApproval = false;\n    try {\n      holdsApproval = await wallet.holdsApprovedDepositTerms(depositTerms);\n    } catch {\n      // The seam forbids the probe to throw; a violating provider falls back\n      // to the full ceremony rather than aborting the broadcast.\n    }\n    if (holdsApproval) {\n      return;\n    }\n  }\n\n  // #2110 T4: envelope violations fail here, before the derive costs a\n  // physical approval. Validate-only per DepositTermsApprover — no device I/O.\n  if (typeof wallet.validateDepositTerms === \"function\") {\n    await wallet.validateDepositTerms(depositTerms);\n  }\n\n  // Same funding outpoints preparePegin derived over, via the shared\n  // golden-tested parser (display order; also rejects an input-less tx).\n  const fundingOutpoints = parseFundingOutpointsFromTx(fundedPrePeginTxHex);\n\n  const root = await deriveVaultRoot(\n    { deriveContextHash: wallet.deriveContextHash.bind(wallet) },\n    {\n      depositorBtcPubkey: hexToUint8Array(\n        normalizeXOnlyPubkey(depositorBtcPubkey),\n      ),\n      fundingOutpoints,\n    },\n  );\n  // The derive gates the intent on-device; the broadcast path needs no\n  // secrets, so wipe the returned root immediately.\n  root.fill(0);\n\n  // .call keeps `this` for providers that implement the seam as a prototype\n  // method rather than a bound/arrow field.\n  await approveDepositTerms.call(wallet, depositTerms);\n}\n","/**\n\nSHA1 (RFC 3174), MD5 (RFC 1321) and RIPEMD160 (RFC 2286) legacy, weak hash functions.\nDon't use them in a new protocol. What \"weak\" means:\n\n- Collisions can be made with 2^18 effort in MD5, 2^60 in SHA1, 2^80 in RIPEMD160.\n- No practical pre-image attacks (only theoretical, 2^123.4)\n- HMAC seems kinda ok: https://www.rfc-editor.org/rfc/rfc6151\n * @module\n */\nimport { Chi, HashMD, Maj } from \"./_md.js\";\nimport { clean, createHasher, rotl } from \"./utils.js\";\n/** Initial SHA1 state */\nconst SHA1_IV = /* @__PURE__ */ Uint32Array.from([\n    0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0,\n]);\n// Reusable temporary buffer\nconst SHA1_W = /* @__PURE__ */ new Uint32Array(80);\n/** Internal SHA1 legacy hash class. */\nexport class _SHA1 extends HashMD {\n    A = SHA1_IV[0] | 0;\n    B = SHA1_IV[1] | 0;\n    C = SHA1_IV[2] | 0;\n    D = SHA1_IV[3] | 0;\n    E = SHA1_IV[4] | 0;\n    constructor() {\n        super(64, 20, 8, false);\n    }\n    get() {\n        const { A, B, C, D, E } = this;\n        return [A, B, C, D, E];\n    }\n    set(A, B, C, D, E) {\n        this.A = A | 0;\n        this.B = B | 0;\n        this.C = C | 0;\n        this.D = D | 0;\n        this.E = E | 0;\n    }\n    process(view, offset) {\n        for (let i = 0; i < 16; i++, offset += 4)\n            SHA1_W[i] = view.getUint32(offset, false);\n        for (let i = 16; i < 80; i++)\n            SHA1_W[i] = rotl(SHA1_W[i - 3] ^ SHA1_W[i - 8] ^ SHA1_W[i - 14] ^ SHA1_W[i - 16], 1);\n        // Compression function main loop, 80 rounds\n        let { A, B, C, D, E } = this;\n        for (let i = 0; i < 80; i++) {\n            let F, K;\n            if (i < 20) {\n                F = Chi(B, C, D);\n                K = 0x5a827999;\n            }\n            else if (i < 40) {\n                F = B ^ C ^ D;\n                K = 0x6ed9eba1;\n            }\n            else if (i < 60) {\n                F = Maj(B, C, D);\n                K = 0x8f1bbcdc;\n            }\n            else {\n                F = B ^ C ^ D;\n                K = 0xca62c1d6;\n            }\n            const T = (rotl(A, 5) + F + E + K + SHA1_W[i]) | 0;\n            E = D;\n            D = C;\n            C = rotl(B, 30);\n            B = A;\n            A = T;\n        }\n        // Add the compressed chunk to the current hash value\n        A = (A + this.A) | 0;\n        B = (B + this.B) | 0;\n        C = (C + this.C) | 0;\n        D = (D + this.D) | 0;\n        E = (E + this.E) | 0;\n        this.set(A, B, C, D, E);\n    }\n    roundClean() {\n        clean(SHA1_W);\n    }\n    destroy() {\n        this.set(0, 0, 0, 0, 0);\n        clean(this.buffer);\n    }\n}\n/** SHA1 (RFC 3174) legacy hash function. It was cryptographically broken. */\nexport const sha1 = /* @__PURE__ */ createHasher(() => new _SHA1());\n/** Per-round constants */\nconst p32 = /* @__PURE__ */ Math.pow(2, 32);\nconst K = /* @__PURE__ */ Array.from({ length: 64 }, (_, i) => Math.floor(p32 * Math.abs(Math.sin(i + 1))));\n/** md5 initial state: same as sha1, but 4 u32 instead of 5. */\nconst MD5_IV = /* @__PURE__ */ SHA1_IV.slice(0, 4);\n// Reusable temporary buffer\nconst MD5_W = /* @__PURE__ */ new Uint32Array(16);\n/** Internal MD5 legacy hash class. */\nexport class _MD5 extends HashMD {\n    A = MD5_IV[0] | 0;\n    B = MD5_IV[1] | 0;\n    C = MD5_IV[2] | 0;\n    D = MD5_IV[3] | 0;\n    constructor() {\n        super(64, 16, 8, true);\n    }\n    get() {\n        const { A, B, C, D } = this;\n        return [A, B, C, D];\n    }\n    set(A, B, C, D) {\n        this.A = A | 0;\n        this.B = B | 0;\n        this.C = C | 0;\n        this.D = D | 0;\n    }\n    process(view, offset) {\n        for (let i = 0; i < 16; i++, offset += 4)\n            MD5_W[i] = view.getUint32(offset, true);\n        // Compression function main loop, 64 rounds\n        let { A, B, C, D } = this;\n        for (let i = 0; i < 64; i++) {\n            let F, g, s;\n            if (i < 16) {\n                F = Chi(B, C, D);\n                g = i;\n                s = [7, 12, 17, 22];\n            }\n            else if (i < 32) {\n                F = Chi(D, B, C);\n                g = (5 * i + 1) % 16;\n                s = [5, 9, 14, 20];\n            }\n            else if (i < 48) {\n                F = B ^ C ^ D;\n                g = (3 * i + 5) % 16;\n                s = [4, 11, 16, 23];\n            }\n            else {\n                F = C ^ (B | ~D);\n                g = (7 * i) % 16;\n                s = [6, 10, 15, 21];\n            }\n            F = F + A + K[i] + MD5_W[g];\n            A = D;\n            D = C;\n            C = B;\n            B = B + rotl(F, s[i % 4]);\n        }\n        // Add the compressed chunk to the current hash value\n        A = (A + this.A) | 0;\n        B = (B + this.B) | 0;\n        C = (C + this.C) | 0;\n        D = (D + this.D) | 0;\n        this.set(A, B, C, D);\n    }\n    roundClean() {\n        clean(MD5_W);\n    }\n    destroy() {\n        this.set(0, 0, 0, 0);\n        clean(this.buffer);\n    }\n}\n/**\n * MD5 (RFC 1321) legacy hash function. It was cryptographically broken.\n * MD5 architecture is similar to SHA1, with some differences:\n * - Reduced output length: 16 bytes (128 bit) instead of 20\n * - 64 rounds, instead of 80\n * - Little-endian: could be faster, but will require more code\n * - Non-linear index selection: huge speed-up for unroll\n * - Per round constants: more memory accesses, additional speed-up for unroll\n */\nexport const md5 = /* @__PURE__ */ createHasher(() => new _MD5());\n// RIPEMD-160\nconst Rho160 = /* @__PURE__ */ Uint8Array.from([\n    7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,\n]);\nconst Id160 = /* @__PURE__ */ (() => Uint8Array.from(new Array(16).fill(0).map((_, i) => i)))();\nconst Pi160 = /* @__PURE__ */ (() => Id160.map((i) => (9 * i + 5) % 16))();\nconst idxLR = /* @__PURE__ */ (() => {\n    const L = [Id160];\n    const R = [Pi160];\n    const res = [L, R];\n    for (let i = 0; i < 4; i++)\n        for (let j of res)\n            j.push(j[i].map((k) => Rho160[k]));\n    return res;\n})();\nconst idxL = /* @__PURE__ */ (() => idxLR[0])();\nconst idxR = /* @__PURE__ */ (() => idxLR[1])();\n// const [idxL, idxR] = idxLR;\nconst shifts160 = /* @__PURE__ */ [\n    [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],\n    [12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],\n    [13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],\n    [14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],\n    [15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5],\n].map((i) => Uint8Array.from(i));\nconst shiftsL160 = /* @__PURE__ */ idxL.map((idx, i) => idx.map((j) => shifts160[i][j]));\nconst shiftsR160 = /* @__PURE__ */ idxR.map((idx, i) => idx.map((j) => shifts160[i][j]));\nconst Kl160 = /* @__PURE__ */ Uint32Array.from([\n    0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e,\n]);\nconst Kr160 = /* @__PURE__ */ Uint32Array.from([\n    0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000,\n]);\n// It's called f() in spec.\nfunction ripemd_f(group, x, y, z) {\n    if (group === 0)\n        return x ^ y ^ z;\n    if (group === 1)\n        return (x & y) | (~x & z);\n    if (group === 2)\n        return (x | ~y) ^ z;\n    if (group === 3)\n        return (x & z) | (y & ~z);\n    return x ^ (y | ~z);\n}\n// Reusable temporary buffer\nconst BUF_160 = /* @__PURE__ */ new Uint32Array(16);\nexport class _RIPEMD160 extends HashMD {\n    h0 = 0x67452301 | 0;\n    h1 = 0xefcdab89 | 0;\n    h2 = 0x98badcfe | 0;\n    h3 = 0x10325476 | 0;\n    h4 = 0xc3d2e1f0 | 0;\n    constructor() {\n        super(64, 20, 8, true);\n    }\n    get() {\n        const { h0, h1, h2, h3, h4 } = this;\n        return [h0, h1, h2, h3, h4];\n    }\n    set(h0, h1, h2, h3, h4) {\n        this.h0 = h0 | 0;\n        this.h1 = h1 | 0;\n        this.h2 = h2 | 0;\n        this.h3 = h3 | 0;\n        this.h4 = h4 | 0;\n    }\n    process(view, offset) {\n        for (let i = 0; i < 16; i++, offset += 4)\n            BUF_160[i] = view.getUint32(offset, true);\n        // prettier-ignore\n        let al = this.h0 | 0, ar = al, bl = this.h1 | 0, br = bl, cl = this.h2 | 0, cr = cl, dl = this.h3 | 0, dr = dl, el = this.h4 | 0, er = el;\n        // Instead of iterating 0 to 80, we split it into 5 groups\n        // And use the groups in constants, functions, etc. Much simpler\n        for (let group = 0; group < 5; group++) {\n            const rGroup = 4 - group;\n            const hbl = Kl160[group], hbr = Kr160[group]; // prettier-ignore\n            const rl = idxL[group], rr = idxR[group]; // prettier-ignore\n            const sl = shiftsL160[group], sr = shiftsR160[group]; // prettier-ignore\n            for (let i = 0; i < 16; i++) {\n                const tl = (rotl(al + ripemd_f(group, bl, cl, dl) + BUF_160[rl[i]] + hbl, sl[i]) + el) | 0;\n                al = el, el = dl, dl = rotl(cl, 10) | 0, cl = bl, bl = tl; // prettier-ignore\n            }\n            // 2 loops are 10% faster\n            for (let i = 0; i < 16; i++) {\n                const tr = (rotl(ar + ripemd_f(rGroup, br, cr, dr) + BUF_160[rr[i]] + hbr, sr[i]) + er) | 0;\n                ar = er, er = dr, dr = rotl(cr, 10) | 0, cr = br, br = tr; // prettier-ignore\n            }\n        }\n        // Add the compressed chunk to the current hash value\n        this.set((this.h1 + cl + dr) | 0, (this.h2 + dl + er) | 0, (this.h3 + el + ar) | 0, (this.h4 + al + br) | 0, (this.h0 + bl + cr) | 0);\n    }\n    roundClean() {\n        clean(BUF_160);\n    }\n    destroy() {\n        this.destroyed = true;\n        clean(this.buffer);\n        this.set(0, 0, 0, 0, 0);\n    }\n}\n/**\n * RIPEMD-160 - a legacy hash function from 1990s.\n * * https://homes.esat.kuleuven.be/~bosselae/ripemd160.html\n * * https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf\n */\nexport const ripemd160 = /* @__PURE__ */ createHasher(() => new _RIPEMD160());\n//# sourceMappingURL=legacy.js.map","/**\n * SHA3 (keccak) hash function, based on a new \"Sponge function\" design.\n * Different from older hashes, the internal state is bigger than output size.\n *\n * Check out [FIPS-202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf),\n * [Website](https://keccak.team/keccak.html),\n * [the differences between SHA-3 and Keccak](https://crypto.stackexchange.com/questions/15727/what-are-the-key-differences-between-the-draft-sha-3-standard-and-the-keccak-sub).\n *\n * Check out `sha3-addons` module for cSHAKE, k12, and others.\n * @module\n */\nimport { rotlBH, rotlBL, rotlSH, rotlSL, split } from \"./_u64.js\";\n// prettier-ignore\nimport { abytes, aexists, anumber, aoutput, clean, createHasher, oidNist, swap32IfBE, u32 } from \"./utils.js\";\n// No __PURE__ annotations in sha3 header:\n// EVERYTHING is in fact used on every export.\n// Various per round constants calculations\nconst _0n = BigInt(0);\nconst _1n = BigInt(1);\nconst _2n = BigInt(2);\nconst _7n = BigInt(7);\nconst _256n = BigInt(256);\nconst _0x71n = BigInt(0x71);\nconst SHA3_PI = [];\nconst SHA3_ROTL = [];\nconst _SHA3_IOTA = []; // no pure annotation: var is always used\nfor (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {\n    // Pi\n    [x, y] = [y, (2 * x + 3 * y) % 5];\n    SHA3_PI.push(2 * (5 * y + x));\n    // Rotational\n    SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);\n    // Iota\n    let t = _0n;\n    for (let j = 0; j < 7; j++) {\n        R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n;\n        if (R & _2n)\n            t ^= _1n << ((_1n << BigInt(j)) - _1n);\n    }\n    _SHA3_IOTA.push(t);\n}\nconst IOTAS = split(_SHA3_IOTA, true);\nconst SHA3_IOTA_H = IOTAS[0];\nconst SHA3_IOTA_L = IOTAS[1];\n// Left rotation (without 0, 32, 64)\nconst rotlH = (h, l, s) => (s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s));\nconst rotlL = (h, l, s) => (s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s));\n/** `keccakf1600` internal function, additionally allows to adjust round count. */\nexport function keccakP(s, rounds = 24) {\n    const B = new Uint32Array(5 * 2);\n    // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)\n    for (let round = 24 - rounds; round < 24; round++) {\n        // Theta θ\n        for (let x = 0; x < 10; x++)\n            B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];\n        for (let x = 0; x < 10; x += 2) {\n            const idx1 = (x + 8) % 10;\n            const idx0 = (x + 2) % 10;\n            const B0 = B[idx0];\n            const B1 = B[idx0 + 1];\n            const Th = rotlH(B0, B1, 1) ^ B[idx1];\n            const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];\n            for (let y = 0; y < 50; y += 10) {\n                s[x + y] ^= Th;\n                s[x + y + 1] ^= Tl;\n            }\n        }\n        // Rho (ρ) and Pi (π)\n        let curH = s[2];\n        let curL = s[3];\n        for (let t = 0; t < 24; t++) {\n            const shift = SHA3_ROTL[t];\n            const Th = rotlH(curH, curL, shift);\n            const Tl = rotlL(curH, curL, shift);\n            const PI = SHA3_PI[t];\n            curH = s[PI];\n            curL = s[PI + 1];\n            s[PI] = Th;\n            s[PI + 1] = Tl;\n        }\n        // Chi (χ)\n        for (let y = 0; y < 50; y += 10) {\n            for (let x = 0; x < 10; x++)\n                B[x] = s[y + x];\n            for (let x = 0; x < 10; x++)\n                s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];\n        }\n        // Iota (ι)\n        s[0] ^= SHA3_IOTA_H[round];\n        s[1] ^= SHA3_IOTA_L[round];\n    }\n    clean(B);\n}\n/** Keccak sponge function. */\nexport class Keccak {\n    state;\n    pos = 0;\n    posOut = 0;\n    finished = false;\n    state32;\n    destroyed = false;\n    blockLen;\n    suffix;\n    outputLen;\n    enableXOF = false;\n    rounds;\n    // NOTE: we accept arguments in bytes instead of bits here.\n    constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {\n        this.blockLen = blockLen;\n        this.suffix = suffix;\n        this.outputLen = outputLen;\n        this.enableXOF = enableXOF;\n        this.rounds = rounds;\n        // Can be passed from user as dkLen\n        anumber(outputLen, 'outputLen');\n        // 1600 = 5x5 matrix of 64bit.  1600 bits === 200 bytes\n        // 0 < blockLen < 200\n        if (!(0 < blockLen && blockLen < 200))\n            throw new Error('only keccak-f1600 function is supported');\n        this.state = new Uint8Array(200);\n        this.state32 = u32(this.state);\n    }\n    clone() {\n        return this._cloneInto();\n    }\n    keccak() {\n        swap32IfBE(this.state32);\n        keccakP(this.state32, this.rounds);\n        swap32IfBE(this.state32);\n        this.posOut = 0;\n        this.pos = 0;\n    }\n    update(data) {\n        aexists(this);\n        abytes(data);\n        const { blockLen, state } = this;\n        const len = data.length;\n        for (let pos = 0; pos < len;) {\n            const take = Math.min(blockLen - this.pos, len - pos);\n            for (let i = 0; i < take; i++)\n                state[this.pos++] ^= data[pos++];\n            if (this.pos === blockLen)\n                this.keccak();\n        }\n        return this;\n    }\n    finish() {\n        if (this.finished)\n            return;\n        this.finished = true;\n        const { state, suffix, pos, blockLen } = this;\n        // Do the padding\n        state[pos] ^= suffix;\n        if ((suffix & 0x80) !== 0 && pos === blockLen - 1)\n            this.keccak();\n        state[blockLen - 1] ^= 0x80;\n        this.keccak();\n    }\n    writeInto(out) {\n        aexists(this, false);\n        abytes(out);\n        this.finish();\n        const bufferOut = this.state;\n        const { blockLen } = this;\n        for (let pos = 0, len = out.length; pos < len;) {\n            if (this.posOut >= blockLen)\n                this.keccak();\n            const take = Math.min(blockLen - this.posOut, len - pos);\n            out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);\n            this.posOut += take;\n            pos += take;\n        }\n        return out;\n    }\n    xofInto(out) {\n        // Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF\n        if (!this.enableXOF)\n            throw new Error('XOF is not possible for this instance');\n        return this.writeInto(out);\n    }\n    xof(bytes) {\n        anumber(bytes);\n        return this.xofInto(new Uint8Array(bytes));\n    }\n    digestInto(out) {\n        aoutput(out, this);\n        if (this.finished)\n            throw new Error('digest() was already called');\n        this.writeInto(out);\n        this.destroy();\n        return out;\n    }\n    digest() {\n        return this.digestInto(new Uint8Array(this.outputLen));\n    }\n    destroy() {\n        this.destroyed = true;\n        clean(this.state);\n    }\n    _cloneInto(to) {\n        const { blockLen, suffix, outputLen, rounds, enableXOF } = this;\n        to ||= new Keccak(blockLen, suffix, outputLen, enableXOF, rounds);\n        to.state32.set(this.state32);\n        to.pos = this.pos;\n        to.posOut = this.posOut;\n        to.finished = this.finished;\n        to.rounds = rounds;\n        // Suffix can change in cSHAKE\n        to.suffix = suffix;\n        to.outputLen = outputLen;\n        to.enableXOF = enableXOF;\n        to.destroyed = this.destroyed;\n        return to;\n    }\n}\nconst genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);\n/** SHA3-224 hash function. */\nexport const sha3_224 = /* @__PURE__ */ genKeccak(0x06, 144, 28, \n/* @__PURE__ */ oidNist(0x07));\n/** SHA3-256 hash function. Different from keccak-256. */\nexport const sha3_256 = /* @__PURE__ */ genKeccak(0x06, 136, 32, \n/* @__PURE__ */ oidNist(0x08));\n/** SHA3-384 hash function. */\nexport const sha3_384 = /* @__PURE__ */ genKeccak(0x06, 104, 48, \n/* @__PURE__ */ oidNist(0x09));\n/** SHA3-512 hash function. */\nexport const sha3_512 = /* @__PURE__ */ genKeccak(0x06, 72, 64, \n/* @__PURE__ */ oidNist(0x0a));\n/** keccak-224 hash function. */\nexport const keccak_224 = /* @__PURE__ */ genKeccak(0x01, 144, 28);\n/** keccak-256 hash function. Different from SHA3-256. */\nexport const keccak_256 = /* @__PURE__ */ genKeccak(0x01, 136, 32);\n/** keccak-384 hash function. */\nexport const keccak_384 = /* @__PURE__ */ genKeccak(0x01, 104, 48);\n/** keccak-512 hash function. */\nexport const keccak_512 = /* @__PURE__ */ genKeccak(0x01, 72, 64);\nconst genShake = (suffix, blockLen, outputLen, info = {}) => createHasher((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === undefined ? outputLen : opts.dkLen, true), info);\n/** SHAKE128 XOF with 128-bit security. */\nexport const shake128 = \n/* @__PURE__ */\ngenShake(0x1f, 168, 16, /* @__PURE__ */ oidNist(0x0b));\n/** SHAKE256 XOF with 256-bit security. */\nexport const shake256 = \n/* @__PURE__ */\ngenShake(0x1f, 136, 32, /* @__PURE__ */ oidNist(0x0c));\n/** SHAKE128 XOF with 256-bit output (NIST version). */\nexport const shake128_32 = \n/* @__PURE__ */\ngenShake(0x1f, 168, 32, /* @__PURE__ */ oidNist(0x0b));\n/** SHAKE256 XOF with 512-bit output (NIST version). */\nexport const shake256_64 = \n/* @__PURE__ */\ngenShake(0x1f, 136, 64, /* @__PURE__ */ oidNist(0x0c));\n//# sourceMappingURL=sha3.js.map","/**\n * WOTS Block Key Derivation\n *\n * Derives deterministic WOTS (Winternitz One-Time Signature) block public\n * keys from a per-vault 64-byte seed, matching the Rust `babe::wots`\n * chain logic.\n *\n * Callers obtain the seed from `expandWotsSeed(root, htlcVout)` in the\n * vault-secrets module, where\n * `root = await deriveVaultRoot(wallet, vaultContextInput)`. Per-vault\n * uniqueness is already encoded in the seed via `htlcVout`, so this\n * module only handles the chain derivation — no further key splitting\n * by `(vaultId, depositorPk, appContract)` is needed.\n *\n * @module wots/blockDerivation\n */\n\nimport { ripemd160 } from \"@noble/hashes/legacy.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { keccak_256 } from \"@noble/hashes/sha3.js\";\nimport type { Hex } from \"viem\";\n\nimport type {\n  WotsBlockPublicKey,\n  WotsConfig,\n} from \"../clients/vault-provider/types\";\n\n// ---------------------------------------------------------------------------\n// Constants — must match btc-vault / babe::wots\n// ---------------------------------------------------------------------------\n\n/** Required size of the per-vault WOTS seed in bytes. */\nconst WOTS_SEED_SIZE = 64;\n\n/** Hash160 output size in bytes (= RIPEMD-160(SHA-256(x))). */\nconst CHAIN_ELEMENT_SIZE = 20;\n\n/** Bits per WOTS digit. Matches `babe::WOTS_DIGIT_BITS`. */\nconst WOTS_DIGIT_BITS = 4;\n\n/** Number of checksum digits in canonical WOTS ordering. */\nconst WOTS_CHECKSUM_DIGITS = 2;\n\n/** Digit index for the checksum minor chain (canonical ordering). */\nconst CHECKSUM_MINOR_DIGIT_INDEX = 0;\n\n/** Digit index for the checksum major chain (canonical ordering). */\nconst CHECKSUM_MAJOR_DIGIT_INDEX = 1;\n\n/**\n * Message digit counts per assert block.\n * Matches `btc_vault::ASSERT_WOTS_BLOCK_DIGIT_COUNTS`.\n */\nconst ASSERT_WOTS_BLOCK_DIGIT_COUNTS: readonly number[] = [64, 64];\n\n// ---------------------------------------------------------------------------\n// Cryptographic primitives\n// ---------------------------------------------------------------------------\n\nconst toHex = (bytes: Uint8Array) =>\n  Array.from(bytes)\n    .map((b) => b.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n\nfunction hash160(data: Uint8Array): Uint8Array {\n  return ripemd160(sha256(data));\n}\n\n// ---------------------------------------------------------------------------\n// WOTS chain derivation — mirrors Rust babe::wots\n// ---------------------------------------------------------------------------\n\nfunction maxDigitValue(d: number): number {\n  return (1 << d) - 1;\n}\n\nfunction defaultChecksumRadix(wMax: number): number {\n  let radix = 1;\n  while (radix * radix < wMax + 1) radix++;\n  return Math.max(radix, 2);\n}\n\nfunction createWotsConfig(n: number): WotsConfig {\n  const d = WOTS_DIGIT_BITS;\n  const wMax = n * maxDigitValue(d);\n  return { d, n, checksum_radix: defaultChecksumRadix(wMax) };\n}\n\n/**\n * Derive the starting chain value for a given digit index.\n * Matches Rust `chain_start_for_digit(seed, digit_index)`:\n *   hash160(seed || varint_le(digit_index))\n */\nfunction chainStartForDigit(seed: Uint8Array, digitIndex: number): Uint8Array {\n  const suffixBytes: number[] = [];\n  let idx = digitIndex;\n  while (idx > 0) {\n    suffixBytes.push(idx & 0xff);\n    idx >>>= 8;\n  }\n  const preimage = new Uint8Array(seed.length + suffixBytes.length);\n  preimage.set(seed);\n  for (let i = 0; i < suffixBytes.length; i++) {\n    preimage[seed.length + i] = suffixBytes[i];\n  }\n  return hash160(preimage);\n}\n\n/**\n * Compute the terminal value of a Hash160 chain of given length.\n * Matches Rust `compute_chain(seed, len)` — returns chain[len].\n */\nfunction computeChainTerminal(start: Uint8Array, steps: number): Uint8Array {\n  let current = start;\n  for (let i = 0; i < steps; i++) {\n    current = hash160(current);\n  }\n  return current;\n}\n\n// ---------------------------------------------------------------------------\n// Per-block public key derivation\n// ---------------------------------------------------------------------------\n\nfunction deriveBlockPublicKey(\n  blockSeed: Uint8Array,\n  config: WotsConfig,\n): WotsBlockPublicKey {\n  const k = maxDigitValue(config.d);\n  const checksumMinorMax = config.checksum_radix - 1;\n  const checksumMajorMax = Math.floor((config.n * k) / config.checksum_radix);\n\n  const messageTerminals: number[][] = [];\n  for (let digit = 0; digit < config.n; digit++) {\n    const start = chainStartForDigit(blockSeed, digit + WOTS_CHECKSUM_DIGITS);\n    const terminal = computeChainTerminal(start, k);\n    messageTerminals.push(Array.from(terminal));\n  }\n\n  const checksumMinorStart = chainStartForDigit(\n    blockSeed,\n    CHECKSUM_MINOR_DIGIT_INDEX,\n  );\n  const checksumMinorTerminal = computeChainTerminal(\n    checksumMinorStart,\n    checksumMinorMax,\n  );\n\n  const checksumMajorStart = chainStartForDigit(\n    blockSeed,\n    CHECKSUM_MAJOR_DIGIT_INDEX,\n  );\n  const checksumMajorTerminal = computeChainTerminal(\n    checksumMajorStart,\n    checksumMajorMax,\n  );\n\n  return {\n    config,\n    message_terminals: messageTerminals,\n    checksum_major_terminal: Array.from(checksumMajorTerminal),\n    checksum_minor_terminal: Array.from(checksumMinorTerminal),\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Derive deterministic WOTS block public keys from a per-vault 64-byte seed.\n *\n * The seed must come from `expandWotsSeed(root, htlcVout)` (vault-secrets\n * module). Per-vault uniqueness is encoded in `htlcVout`; this function\n * only handles the chain derivation. Per-block 20-byte seeds are derived\n * as `hash160(seed || blockIdx)` and fed into the standard Rust\n * `babe::wots` chain logic.\n *\n * The seed is zeroed in the `finally` block.\n *\n * @stability frozen — on-chain-binding. Per-block seed derivation,\n * chain length, checksum-digit ordering, and terminal byte layout\n * must match Rust `babe::wots` byte-for-byte. Any divergence rotates\n * `depositorWotsPkHash` and breaks resume + on-chain verification\n * for every existing vault.\n *\n * @param seed - 64-byte per-vault seed.\n * @returns Array of 2 WOTS block public keys.\n * @throws If `seed.length !== 64`.\n */\nexport async function deriveWotsBlocksFromSeed(\n  seed: Uint8Array,\n): Promise<WotsBlockPublicKey[]> {\n  // try/finally wraps the size check so the seed buffer is zeroed on\n  // every exit path, including malformed-input rejection.\n  try {\n    if (seed.length !== WOTS_SEED_SIZE) {\n      throw new Error(\n        `WOTS seed must be exactly ${WOTS_SEED_SIZE} bytes, got ${seed.length}`,\n      );\n    }\n\n    const blocks: WotsBlockPublicKey[] = [];\n\n    for (\n      let blockIdx = 0;\n      blockIdx < ASSERT_WOTS_BLOCK_DIGIT_COUNTS.length;\n      blockIdx++\n    ) {\n      const n = ASSERT_WOTS_BLOCK_DIGIT_COUNTS[blockIdx];\n      const config = createWotsConfig(n);\n\n      // Per-block 20-byte seed: hash160(seed || blockIdx)\n      const blockSeedInput = new Uint8Array(seed.length + 1);\n      blockSeedInput.set(seed);\n      blockSeedInput[seed.length] = blockIdx;\n      const blockSeed = hash160(blockSeedInput);\n\n      try {\n        const block = deriveBlockPublicKey(blockSeed, config);\n\n        if (block.config.d !== WOTS_DIGIT_BITS) {\n          throw new Error(\n            `Block ${blockIdx}: expected d=${WOTS_DIGIT_BITS}, got d=${block.config.d}`,\n          );\n        }\n        if (block.config.n !== n) {\n          throw new Error(\n            `Block ${blockIdx}: expected n=${n}, got n=${block.config.n}`,\n          );\n        }\n        if (block.message_terminals.length !== n) {\n          throw new Error(\n            `Block ${blockIdx}: expected ${n} message terminals, got ${block.message_terminals.length}`,\n          );\n        }\n        for (let t = 0; t < block.message_terminals.length; t++) {\n          if (block.message_terminals[t].length !== CHAIN_ELEMENT_SIZE) {\n            throw new Error(\n              `Block ${blockIdx} terminal ${t}: expected ${CHAIN_ELEMENT_SIZE} bytes, got ${block.message_terminals[t].length}`,\n            );\n          }\n        }\n        if (block.checksum_minor_terminal.length !== CHAIN_ELEMENT_SIZE) {\n          throw new Error(\n            `Block ${blockIdx} checksum_minor: expected ${CHAIN_ELEMENT_SIZE} bytes`,\n          );\n        }\n        if (block.checksum_major_terminal.length !== CHAIN_ELEMENT_SIZE) {\n          throw new Error(\n            `Block ${blockIdx} checksum_major: expected ${CHAIN_ELEMENT_SIZE} bytes`,\n          );\n        }\n\n        blocks.push(block);\n      } finally {\n        blockSeedInput.fill(0);\n        blockSeed.fill(0);\n      }\n    }\n\n    if (blocks.length !== ASSERT_WOTS_BLOCK_DIGIT_COUNTS.length) {\n      throw new Error(\n        `Expected ${ASSERT_WOTS_BLOCK_DIGIT_COUNTS.length} blocks, got ${blocks.length}`,\n      );\n    }\n\n    return blocks;\n  } finally {\n    seed.fill(0);\n  }\n}\n\n/** Validate a single chain terminal: correct length and all bytes in [0, 255]. */\nfunction validateTerminal(\n  terminal: number[],\n  blockIdx: number,\n  label: string,\n): void {\n  if (terminal.length !== CHAIN_ELEMENT_SIZE) {\n    throw new Error(\n      `Block ${blockIdx} ${label}: expected ${CHAIN_ELEMENT_SIZE} bytes, got ${terminal.length}`,\n    );\n  }\n  for (let j = 0; j < terminal.length; j++) {\n    const b = terminal[j];\n    if (!Number.isInteger(b) || b < 0 || b > 255) {\n      throw new Error(\n        `Block ${blockIdx} ${label}[${j}]: invalid byte value ${b}`,\n      );\n    }\n  }\n}\n\n/**\n * Compute the keccak256 hash of WOTS block public keys.\n *\n * Matches Rust `btc_vault::wots_public_keys_keccak256`: for each block,\n * chain tips are concatenated in canonical order\n * `[checksum_minor, checksum_major, message_terminals...]`, then all\n * blocks are concatenated and hashed.\n *\n * The result is committed on-chain as `depositorWotsPkHash` so the vault\n * provider can verify submitted WOTS public keys.\n *\n * @stability frozen — on-chain-binding. Concatenation order of chain\n * tips and the keccak256 input layout MUST match Rust\n * `btc_vault::wots_public_keys_keccak256` byte-for-byte. Any change\n * rotates the on-chain commitment and breaks every existing vault.\n */\nexport function computeWotsBlockPublicKeysHash(\n  publicKeys: WotsBlockPublicKey[],\n): Hex {\n  if (publicKeys.length === 0) {\n    throw new Error(\"Public keys array must not be empty\");\n  }\n\n  for (let i = 0; i < publicKeys.length; i++) {\n    const pk = publicKeys[i];\n    validateTerminal(pk.checksum_minor_terminal, i, \"checksum_minor_terminal\");\n    validateTerminal(pk.checksum_major_terminal, i, \"checksum_major_terminal\");\n    for (let t = 0; t < pk.message_terminals.length; t++) {\n      validateTerminal(pk.message_terminals[t], i, `message_terminal[${t}]`);\n    }\n  }\n\n  let totalTips = 0;\n  for (const pk of publicKeys) {\n    totalTips += WOTS_CHECKSUM_DIGITS + pk.message_terminals.length;\n  }\n\n  const buffer = new Uint8Array(totalTips * CHAIN_ELEMENT_SIZE);\n  let offset = 0;\n\n  for (const pk of publicKeys) {\n    buffer.set(pk.checksum_minor_terminal, offset);\n    offset += CHAIN_ELEMENT_SIZE;\n    buffer.set(pk.checksum_major_terminal, offset);\n    offset += CHAIN_ELEMENT_SIZE;\n    for (const terminal of pk.message_terminals) {\n      buffer.set(terminal, offset);\n      offset += CHAIN_ELEMENT_SIZE;\n    }\n  }\n\n  const digest = keccak_256(buffer);\n  return `0x${toHex(digest)}`;\n}\n","/**\n * Per-vault HKDF expansion of WOTS keys + HTLC preimages from the\n * wallet root.\n *\n * @module managers/pegin/expandPerVaultSecrets\n */\n\nimport type { Hex } from \"viem\";\n\nimport type { WotsBlockPublicKey } from \"../../clients/vault-provider/types\";\nimport {\n  ensureHexPrefix,\n  uint8ArrayToHex,\n} from \"../../primitives/utils/bitcoin\";\nimport { computeHashlock } from \"../../services\";\nimport { expandHashlockSecret, expandWotsSeed } from \"../../vault-secrets\";\nimport {\n  computeWotsBlockPublicKeysHash,\n  deriveWotsBlocksFromSeed,\n} from \"../../wots\";\n\n/**\n * Result of {@link expandPerVaultSecrets}.\n */\nexport interface PerVaultExpansionResult {\n  perVaultWotsKeys: WotsBlockPublicKey[][];\n  /** Keccak256 of WOTS keys, ready as `depositorWotsPkHash` (0x-prefixed). */\n  wotsPkHashes: Hex[];\n  /** HTLC preimage hex per vault (no 0x prefix). */\n  htlcSecretHexes: string[];\n  /** SHA-256 of each HTLC preimage as 64-char hex (no 0x prefix). */\n  hashlocks: string[];\n}\n\n/**\n * Derive per-vault WOTS keys + HTLC preimages from the wallet root.\n *\n * Takes ownership of `root`: zeros the buffer (and per-vault secret\n * buffers) before returning, regardless of how the caller exits.\n *\n * @param root        32-byte wallet-derived root from `deriveVaultRoot`.\n * @param vaultCount  Number of vaults (= length of `amounts`).\n */\nexport async function expandPerVaultSecrets(\n  root: Uint8Array,\n  vaultCount: number,\n): Promise<PerVaultExpansionResult> {\n  const perVaultWotsKeys: WotsBlockPublicKey[][] = [];\n  const wotsPkHashes: Hex[] = [];\n  const htlcSecretHexes: string[] = [];\n  const hashlocks: string[] = [];\n\n  try {\n    for (let i = 0; i < vaultCount; i++) {\n      const wotsSeed = await expandWotsSeed(root, i);\n      try {\n        const wotsPublicKeys = await deriveWotsBlocksFromSeed(wotsSeed);\n        perVaultWotsKeys.push(wotsPublicKeys);\n        wotsPkHashes.push(computeWotsBlockPublicKeysHash(wotsPublicKeys));\n      } finally {\n        wotsSeed.fill(0);\n      }\n\n      const secretBytes = await expandHashlockSecret(root, i);\n      try {\n        const secretHex = uint8ArrayToHex(secretBytes);\n        htlcSecretHexes.push(secretHex);\n        hashlocks.push(computeHashlock(ensureHexPrefix(secretHex)).slice(2));\n      } finally {\n        secretBytes.fill(0);\n      }\n    }\n  } finally {\n    root.fill(0);\n  }\n\n  return { perVaultWotsKeys, wotsPkHashes, htlcSecretHexes, hashlocks };\n}\n","/**\n * Host-side check of the BIP-322 proof-of-possession witness a wallet returns,\n * before it is committed to the Ethereum registration.\n *\n * vaultd verifies the PoP off-chain from the consensus-encoded witness\n * (`btc-vault crates/btc-signer/src/message.rs:94-145`): one item ⇒ P2TR\n * key-path Schnorr over the BIP-86 tweaked key, two items ⇒ P2WPKH, anything\n * else ⇒ `UnsupportedWitnessFormat`. A bad PoP is a PERMANENT ingestion\n * failure (`InvalidDepositorPop`), so catching it here saves a registration.\n * No wallet test (hardware or software) proves a returned PoP validates —\n * this is the first place anything checks it.\n *\n * P2TR is verified with the package's existing BIP-322 verifier (64-byte\n * SIGHASH_DEFAULT or 65-byte SIGHASH_ALL, matching what the `bip322` crate\n * 0.0.10 accepts in `verify.rs:213-236`). P2WPKH mirrors the 2-item arm of\n * `message.rs:107-133`: parse the compressed pubkey, require its x-only\n * form to equal the depositor key, then BIP-322-verify the witness against\n * that pubkey's P2WPKH address.\n *\n * @module managers/pegin/verifyPopWitness\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { Buffer } from \"buffer\";\nimport type { Hex } from \"viem\";\nimport { decodeWitnessStack } from \"../../utils/witness/witnessStack\";\n\nimport {\n  P2WPKH_ENCODED_SIG_MAX,\n  P2WPKH_ENCODED_SIG_MIN,\n  verifyBip322P2wpkhSimple,\n  verifyBip322Simple,\n} from \"../../clients/vault-provider/auth/bip322Verify\";\n\nconst P2TR_WITNESS_ITEMS = 1;\nconst P2WPKH_WITNESS_ITEMS = 2;\n/** SEC1 compressed pubkey: 0x02/0x03 prefix + 32-byte x coordinate. */\nconst COMPRESSED_PUBKEY_BYTES = 33;\n/** SEC1 prefix bytes: 0x02 even Y, 0x03 odd Y; the x coordinate follows. */\nconst SEC1_EVEN_Y_PREFIX = 0x02;\nconst SEC1_ODD_Y_PREFIX = 0x03;\nconst SEC1_PREFIX_BYTES = 1;\nconst SCHNORR_SIG_BYTES = 64;\n/** BIP-341 hash types: 0x00 default (64-byte sig), 0x01 ALL (65-byte sig with trailing type byte). */\nconst SIGHASH_DEFAULT = 0x00;\nconst SIGHASH_ALL = 0x01;\n\nconst X_ONLY_PUBKEY_HEX = /^[0-9a-f]{64}$/i;\n/** `normalizePopSignature` hands us 0x-prefixed lowercase hex; hold it to that. */\nconst WITNESS_BODY_HEX = /^(?:[0-9a-f]{2})+$/;\n\nexport type PopWitnessVerdict =\n  | { readonly kind: \"p2tr-verified\" }\n  | { readonly kind: \"p2wpkh-verified\" };\n\nfunction decodeWitnessItems(witnessHex: Hex): Uint8Array[] {\n  const body = witnessHex.slice(2);\n  // Buffer.from(_, \"hex\") stops silently at the first invalid character.\n  if (!WITNESS_BODY_HEX.test(body)) {\n    throw new Error(\n      \"proof of possession witness is not even-length lowercase hex\",\n    );\n  }\n  return decodeWitnessStack(\n    Uint8Array.from(Buffer.from(body, \"hex\")),\n    \"proof of possession witness\",\n  );\n}\n\n/**\n * Decode a consensus-encoded PoP witness and verify it against the\n * depositor's key: Schnorr for the P2TR shape, ECDSA over the BIP-322\n * P2WPKH virtual transaction for the two-item shape.\n *\n * @param messageBytes     - Bytes of the PoP message that was signed.\n * @param depositorXOnlyHex - Depositor x-only pubkey, bare 64-char hex\n *                            (enforced, not assumed).\n * @param witnessHex       - 0x-prefixed consensus-encoded witness.\n * @throws If the witness is malformed, has an unsupported item count, the\n *         depositor key is not bare x-only hex, the witness pubkey is not\n *         the depositor's, or the signature does not verify.\n */\nexport function verifyPopWitness(\n  messageBytes: Uint8Array,\n  depositorXOnlyHex: string,\n  witnessHex: Hex,\n): PopWitnessVerdict {\n  const items = decodeWitnessItems(witnessHex);\n\n  if (items.length === P2TR_WITNESS_ITEMS) {\n    const [item] = items;\n    // vaultd (bip322 crate `verify.rs:213-236`) accepts 64 bytes = SIGHASH_DEFAULT,\n    // or 65 bytes ending in 0x01 = SIGHASH_ALL; mirror exactly that, nothing looser.\n    let signature: Uint8Array;\n    let hashType: number;\n    if (item.length === SCHNORR_SIG_BYTES) {\n      signature = item;\n      hashType = SIGHASH_DEFAULT;\n    } else if (\n      item.length === SCHNORR_SIG_BYTES + 1 &&\n      item[SCHNORR_SIG_BYTES] === SIGHASH_ALL\n    ) {\n      signature = item.subarray(0, SCHNORR_SIG_BYTES);\n      hashType = SIGHASH_ALL;\n    } else {\n      throw new Error(\n        \"proof of possession witness item must be a 64-byte Schnorr signature \" +\n          \"(or 65 bytes ending in 0x01)\",\n      );\n    }\n\n    // Guard the caller contract: a prefixed or short key would decode to the\n    // wrong bytes and surface as \"does not verify\", hiding the real fault.\n    if (!X_ONLY_PUBKEY_HEX.test(depositorXOnlyHex)) {\n      throw new Error(\n        `depositor public key must be bare 64-char x-only hex, got \"${depositorXOnlyHex}\"`,\n      );\n    }\n    const xOnly = Uint8Array.from(Buffer.from(depositorXOnlyHex, \"hex\"));\n    if (!verifyBip322Simple(messageBytes, xOnly, signature, hashType)) {\n      throw new Error(\n        \"proof of possession signature does not verify against the depositor key\",\n      );\n    }\n    return { kind: \"p2tr-verified\" };\n  }\n\n  if (items.length === P2WPKH_WITNESS_ITEMS) {\n    if (!X_ONLY_PUBKEY_HEX.test(depositorXOnlyHex)) {\n      throw new Error(\n        `depositor public key must be bare 64-char x-only hex, got \"${depositorXOnlyHex}\"`,\n      );\n    }\n    const [encodedSignature, pubkey] = items;\n    if (\n      pubkey.length !== COMPRESSED_PUBKEY_BYTES ||\n      (pubkey[0] !== SEC1_EVEN_Y_PREFIX && pubkey[0] !== SEC1_ODD_Y_PREFIX)\n    ) {\n      throw new Error(\n        `proof of possession P2WPKH witness item 1 is not a compressed public key ` +\n          `(${pubkey.length} bytes, prefix 0x${pubkey[0]?.toString(16) ?? \"none\"})`,\n      );\n    }\n    // Full curve-point parse, as vaultd's CompressedPublicKey::from_slice\n    // (message.rs:111-116) — before the key compare, matching its order.\n    if (!ecc.isPointCompressed(pubkey)) {\n      throw new Error(\n        \"proof of possession P2WPKH witness pubkey is not a valid secp256k1 point\",\n      );\n    }\n    // Pubkey compare (message.rs:117-123, WitnessPubkeyMismatch): witness\n    // item 1 must be the depositor's compressed key — a wrong-account\n    // signature fails HERE, not as a generic invalid signature.\n    const witnessXOnlyHex = Buffer.from(\n      pubkey.subarray(SEC1_PREFIX_BYTES),\n    ).toString(\"hex\");\n    if (witnessXOnlyHex !== depositorXOnlyHex.toLowerCase()) {\n      throw new Error(\n        `proof of possession witness pubkey does not match the depositor key: ` +\n          `witness carries ${witnessXOnlyHex}, expected ${depositorXOnlyHex}`,\n      );\n    }\n    // vaultd only ingests 71/72-byte DER+sighash signatures (bip322 crate\n    // 0.0.10 verify.rs:140-154); RFC-6979 wallets re-sign identically on\n    // retry, so name the real cause instead of a wrong-key diagnosis.\n    if (\n      encodedSignature.length < P2WPKH_ENCODED_SIG_MIN ||\n      encodedSignature.length > P2WPKH_ENCODED_SIG_MAX\n    ) {\n      throw new Error(\n        `proof of possession signature is ${encodedSignature.length} bytes; ` +\n          `vault ingestion accepts only 71/72-byte DER signatures with a ` +\n          `sighash byte — try a different account or a Taproot address`,\n      );\n    }\n    // The trailing byte is the sighash type (bitcoinjs script_signature.js\n    // decode reads it) and the verifier accepts SIGHASH_ALL only — surface it.\n    if (encodedSignature[encodedSignature.length - 1] !== SIGHASH_ALL) {\n      throw new Error(\n        `proof of possession P2WPKH signature must end in a SIGHASH_ALL ` +\n          `(0x01) byte, got 0x${encodedSignature[\n            encodedSignature.length - 1\n          ].toString(16)}`,\n      );\n    }\n    // BIP-322 simple verification against the P2WPKH address of the witness\n    // pubkey (message.rs:125-133; network affects only bech32 encoding).\n    if (!verifyBip322P2wpkhSimple(messageBytes, pubkey, encodedSignature)) {\n      throw new Error(\n        \"proof of possession signature does not verify against the depositor key\",\n      );\n    }\n    return { kind: \"p2wpkh-verified\" };\n  }\n\n  throw new Error(\n    `proof of possession witness has ${items.length} items; expected 1 (P2TR) or 2 (P2WPKH)`,\n  );\n}\n","/**\n * Peg-in Manager - Wallet Orchestration for Peg-in Operations\n *\n * This module provides the PeginManager class that orchestrates the complete\n * peg-in flow using SDK primitives, utilities, and wallet interfaces.\n *\n * @remarks\n * PeginManager handles the peg-in flow:\n * 1. **preparePegin()** - Build Pre-PegIn HTLC, fund it, sign PegIn input\n * 2. **signProofOfPossession()** - Sign BIP-322 PoP (one per deposit session)\n * 3. **registerPeginOnChain()** - Submit to Ethereum contract with PoP\n * 4. **signAndBroadcast()** - Sign and broadcast Pre-PegIn tx to Bitcoin network\n * 5. *(Use {@link PayoutManager} for payout authorization signing)*\n *\n * @see {@link PayoutManager} - For Step 5: sign payout transactions\n * @see {@link buildPrePeginPsbt} - Lower-level primitive used internally\n *\n * @module managers/PeginManager\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport * as bitcoin from \"bitcoinjs-lib\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport {\n  encodeFunctionData,\n  isAddressEqual,\n  zeroAddress,\n  type Address,\n  type Chain,\n  type Hex,\n  type PublicClient,\n  type WalletClient,\n} from \"viem\";\nimport {\n  assertAuthAnchorOpReturn,\n  expandPerVaultSecrets,\n  normalizePopSignature,\n  normalizeXOnlyPubkey,\n  signPsbtsWithFallback,\n  verifyPopWitness,\n} from \"./pegin\";\n\nimport type {\n  BitcoinWallet,\n  Hash,\n  SignPsbtOptions,\n} from \"../../../shared/wallets\";\nimport { ViemVaultRegistryReader } from \"../clients/eth\";\nimport { getUtxoInfo, pushTx, type UtxoInfo } from \"../clients/mempool\";\nimport type { WotsBlockPublicKey } from \"../clients/vault-provider/types\";\nimport { BTCVaultRegistryABI, handleContractError } from \"../contracts\";\nimport {\n  buildDepositTerms,\n  capMaxAcceptableCommissionBps,\n  COMMISSION_BPS_HEADROOM,\n  ensurePrePeginTermsApproval,\n  MAX_ACCEPTABLE_COMMISSION_BPS_CAP,\n  requireChangeAddress,\n  supportsDepositApproval,\n  type DepositTerms,\n} from \"../deposit-terms\";\nimport {\n  assertPsbtUnsignedTxMatches,\n  assertReturnedKeyPathSignatures,\n  assertScriptPathSchnorrSignature,\n  buildPeginInputPsbt,\n  buildPeginTxFromFundedPrePegin,\n  buildPrePeginPsbt,\n  deriveVaultId,\n  extractPeginInputSignature,\n  finalizePeginInputPsbt,\n  type Network,\n  type PrePeginParams,\n} from \"../primitives\";\nimport {\n  ensureHexPrefix,\n  hexToUint8Array,\n  isAddressFromPublicKey,\n  stripHexPrefix,\n  uint8ArrayToHex,\n  X_ONLY_PUBKEY_HEX_LEN,\n} from \"../primitives/utils/bitcoin\";\nimport {\n  calculateBtcTxHash,\n  fundPeginTransaction,\n  getNetwork,\n  getPsbtInputFields,\n  MAX_REASONABLE_FEE_SATS,\n  peginOutputCount,\n  selectUtxosForPegin,\n  waitForTransactionReceiptSmartAware,\n  type UTXO,\n} from \"../utils\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\nimport {\n  deriveVaultRoot,\n  expandAuthAnchor,\n  type FundingOutpoint,\n} from \"../vault-secrets\";\n\n/** Referral code sent with pegin registration — 0 means no referral. */\nconst NO_REFERRAL_CODE = 0;\n\n/**\n * 32-byte zero hex used as a placeholder during the sizing pass for any\n * value whose content does not affect output sizes — currently the\n * per-vault hashlocks and the auth-anchor commitment. The commit pass\n * substitutes real values; UTXO selection and fees match because all\n * four (placeholder hashlock, real SHA256(secret), placeholder anchor,\n * real SHA256(authAnchor)) are 32-byte pushes. Substitution invariance\n * is pinned in `pegin.test.ts`.\n *\n * Scope: only used inside `prepareSizing` where the BYTE CONTENT of an\n * OP_RETURN/hashlock push actually goes into a (throwaway) PSBT.\n * `peginOutputCount` takes a boolean — callers outside this file that\n * just need an output count must not import a placeholder string.\n */\nconst SIZING_PASS_PLACEHOLDER_BYTES32_HEX = \"00\".repeat(32);\n\n/**\n * Placeholder `prepeginTxid` for the provisional deposit terms validated\n * before the derive (#2110 T4) — the real txid exists only post-derive, and\n * the terms carrying this value are validate-only: they never reach a device\n * (the envelope gate reads no txid; see ledger-vault-signer `envelope.ts`).\n */\nconst PROVISIONAL_TERMS_PLACEHOLDER_TXID_HEX = \"00\".repeat(32);\n\n/**\n * Sizing-pass output. The WASM-computed `depositorClaimValue` / `minPeginFee`\n * feed the provisional (validate-only) deposit terms; the commit pass asserts\n * it reproduces them before building the terms the wallet approves.\n */\ninterface PeginSizing {\n  selectedUTXOs: UTXO[];\n  fee: bigint;\n  changeAmount: bigint;\n  depositorClaimValue: bigint;\n  minPeginFee: bigint;\n}\n\n/**\n * Configuration for the PeginManager.\n */\nexport interface PeginManagerConfig {\n  /**\n   * Bitcoin network to use for transactions.\n   */\n  btcNetwork: Network;\n\n  /**\n   * Bitcoin wallet for signing peg-in transactions.\n   */\n  btcWallet: BitcoinWallet;\n\n  /**\n   * Ethereum wallet for registering peg-in on-chain.\n   * Uses viem's WalletClient directly for proper gas estimation.\n   */\n  ethWallet: WalletClient;\n\n  /**\n   * Ethereum chain configuration.\n   * Required for proper gas estimation in contract calls.\n   */\n  ethChain: Chain;\n\n  /**\n   * Public client used for read calls (`readContract`, `estimateGas`,\n   * `waitForTransactionReceipt`). Pass a client configured with the\n   * caller's RPC URL so reads hit the same endpoint as the rest of the\n   * application instead of viem's stock chain default.\n   */\n  publicClient: PublicClient;\n\n  /**\n   * Vault contract addresses.\n   */\n  vaultContracts: {\n    /**\n     * BTCVaultRegistry contract address on Ethereum.\n     */\n    btcVaultRegistry: Address;\n  };\n\n  /**\n   * Mempool API URL for fetching UTXO data and broadcasting transactions.\n   * Use MEMPOOL_API_URLS constant for standard mempool.space URLs, or provide\n   * a custom URL if running your own mempool instance.\n   */\n  mempoolApiUrl: string;\n}\n\n/**\n * Parameters for the pegin flow (pre-pegin + pegin transactions).\n */\nexport interface PreparePeginParams {\n  /**\n   * Vault core (tx-graph) version to build — the contract's\n   * `ProtocolParams.activeVaultCoreVersion()` at build time. Stamped onto\n   * the vault at registration; every Pre-PegIn/PegIn artifact this manager\n   * constructs derives from this graph version.\n   */\n  vaultCoreVersion: number;\n\n  /**\n   * Amounts to peg in per HTLC (in satoshis).\n   * Must have the same length as `hashlocks`.\n   * For single deposits, pass a single-element array.\n   */\n  amounts: readonly bigint[];\n\n  /**\n   * Vault provider's BTC public key (x-only, 64-char hex).\n   * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n   */\n  vaultProviderBtcPubkey: string;\n\n  /**\n   * VP commission quoted for this deposit (bps). Capped to the approval\n   * ceiling before it sizes the terms' commissionFee, so the user approves\n   * the most the VP can take — not the quote.\n   */\n  commissionBps: number;\n\n  /**\n   * Vault keeper BTC public keys (x-only, 64-char hex).\n   * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n   */\n  vaultKeeperBtcPubkeys: readonly string[];\n\n  /**\n   * Universal challenger BTC public keys (x-only, 64-char hex).\n   * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n   */\n  universalChallengerBtcPubkeys: readonly string[];\n\n  /**\n   * CSV timelock in blocks for the PegIn vault output.\n   */\n  timelockPegin: number;\n  /**\n   * btc-vault `timelock_assert` (t2) — the Assert:0 payout-leaf CSV. Carried\n   * into DepositTerms as its own field. Production collapses the two: the SDK\n   * derives timelockPegin from the same on-chain timelockAssert\n   * (`protocol-params-reader.ts` deriveTimelockPegin), mirroring vaultd\n   * (`pegin_validation.rs`). The terms never assume that identity.\n   */\n  timelockAssert: number;\n\n  /**\n   * CSV timelock in blocks for the Pre-PegIn HTLC refund path.\n   */\n  timelockRefund: number;\n\n  /**\n   * TX-graph fee rate in sat/vB from the contract offchain params.\n   * Used by WASM to size the depositor claim value (graph transactions).\n   */\n  protocolFeeRate: bigint;\n\n  /**\n   * Minimum PegIn fee rate in sat/vB from the contract offchain params.\n   * Used by WASM to size the PegIn transaction fee.\n   */\n  minPeginFeeRate: bigint;\n\n  /**\n   * Mempool fee rate in sat/vB for funding the Pre-PegIn transaction.\n   * Used for UTXO selection and change calculation.\n   */\n  mempoolFeeRate: number;\n\n  /**\n   * M in M-of-N council multisig (from contract params).\n   */\n  councilQuorum: number;\n\n  /**\n   * N in M-of-N council multisig (from contract params).\n   */\n  councilSize: number;\n\n  /**\n   * Available UTXOs from the depositor's wallet for funding the Pre-PegIn transaction.\n   */\n  availableUTXOs: readonly UTXO[];\n\n  /**\n   * Bitcoin address for receiving change from the Pre-PegIn transaction.\n   */\n  changeAddress: string;\n}\n\n/**\n * Result of preparing a pegin.\n */\n/** Per-vault PegIn data derived from a shared Pre-PegIn transaction */\nexport interface PerVaultPeginData {\n  /** Index of the HTLC output in the Pre-PegIn transaction (0, 1, 2, ...) */\n  htlcVout: number;\n  /** HTLC output value in satoshis */\n  htlcValue: bigint;\n  /** Depositor-signed PegIn transaction hex (for contract registration) */\n  peginTxHex: string;\n  /** PegIn transaction ID */\n  peginTxid: string;\n  /** Depositor's Schnorr signature over PegIn input (HTLC leaf 0) */\n  peginInputSignature: string;\n  /** Vault output scriptPubKey hex */\n  vaultScriptPubKey: string;\n}\n\n/**\n * Broadcast-ready transaction output of {@link PeginManager.preparePegin}.\n * Safe to log / persist — contains no sensitive material.\n */\nexport interface PreparePeginTransaction {\n  /**\n   * Funded, pre-witness Pre-PegIn tx hex. Pass this for register calls'\n   * `unsignedPrePeginTx` — despite the contract-side name, the registry\n   * stores the funded form so indexers can rebuild refund PSBTs.\n   */\n  fundedPrePeginTxHex: string;\n  /** Funded Pre-PegIn transaction ID */\n  prePeginTxid: string;\n  /** Per-vault PegIn data — one entry per amount */\n  perVault: PerVaultPeginData[];\n  /** UTXOs selected to fund the Pre-PegIn transaction */\n  selectedUTXOs: UTXO[];\n  /** Transaction fee in satoshis */\n  fee: bigint;\n  /** Change amount in satoshis (if any) */\n  changeAmount: bigint;\n}\n\n/**\n * Sensitive material derived from the wallet root. Do not log; do not\n * persist beyond the activation flow. Strings are immutable in JS, so\n * lifetime is GC-only — secrets stay live until the result is dropped.\n */\nexport interface PreparePeginDerivedSecrets {\n  /** Per-vault WOTS block public keys (one array per vault). */\n  perVaultWotsKeys: WotsBlockPublicKey[][];\n  /** Per-vault keccak256 of WOTS keys, ready as `depositorWotsPkHash`. */\n  wotsPkHashes: Hex[];\n  /**\n   * Per-vault HTLC preimage hex (no 0x prefix). Re-derivable any time\n   * via `expandHashlockSecret(root, htlcVout)`; not persisted.\n   */\n  htlcSecretHexes: string[];\n  /**\n   * Raw 32-byte auth-anchor preimage as 64-char lowercase hex (no `0x`).\n   * Sent to the VP via `auth_createDepositorToken` to obtain a bearer\n   * token; the VP validates `SHA256(authAnchorHex) === OP_RETURN_PUSH32`\n   * in the broadcast Pre-PegIn. Reveal is intentional: once exposed\n   * the anchor is public, but its scope is bound to a single\n   * `peginTxid`. Domain-separated from `htlcSecretHexes` and\n   * `perVaultWotsKeys` via the HKDF `info` label, so revealing it does\n   * not weaken the other derived secrets.\n   */\n  authAnchorHex: string;\n}\n\nexport interface PreparePeginResult {\n  /** Broadcast-ready Pre-PegIn + per-vault PegIn txs. Safe to log. */\n  transaction: PreparePeginTransaction;\n  /**\n   * x-only depositor pubkey snapshot used end-to-end across sizing,\n   * vault-root derivation, and PSBT signing. Safe to persist; not\n   * sensitive. Reusing this snapshot downstream guarantees that\n   * derived secrets and signed PSBTs reference the same identity.\n   */\n  depositorBtcPubkey: string;\n  /** Sensitive derived material — see {@link PreparePeginDerivedSecrets}. */\n  derivedSecrets: PreparePeginDerivedSecrets;\n  /**\n   * Protocol-level deposit terms for this Pre-PegIn. Always built, regardless\n   * of wallet capability — {@link supportsDepositApproval} wallets get it via\n   * `approveDepositTerms` before PegIn signing; others just get it back for\n   * reference.\n   */\n  depositTerms: DepositTerms;\n}\n\n/**\n * Parameters for signing and broadcasting a transaction.\n */\nexport interface SignAndBroadcastParams {\n  /**\n   * Funded Pre-PegIn transaction hex from preparePegin().\n   */\n  fundedPrePeginTxHex: string;\n\n  /**\n   * Depositor's BTC public key (x-only, 64-char hex).\n   * Can be provided with or without \"0x\" prefix.\n   * Required for Taproot signing.\n   */\n  depositorBtcPubkey: string;\n\n  /**\n   * Optional pre-fetched prevout data for inputs not yet in the mempool.\n   * Key format: \"txid:vout\" (e.g. \"abc123...def:0\").\n   * When provided, matching inputs skip the mempool API fetch.\n   * Useful for split transactions where outputs are unconfirmed.\n   */\n  localPrevouts?: Record<string, { scriptPubKey: string; value: number }>;\n\n  /**\n   * Approved deposit terms. REQUIRED when `config.btcWallet` supports deposit\n   * approval (`supportsDepositApproval`) — the device signs the Pre-PegIn only\n   * from an approved intent matching this tx. Pass `PreparePeginResult.\n   * depositTerms` for fresh flows, or a resume rebuild. For non-approval\n   * wallets it is ignored, but still validated against the tx's txid if given.\n   */\n  depositTerms?: DepositTerms;\n}\n\n/**\n * BIP-322 BTC Proof-of-Possession binding a depositor's BTC key to their\n * Ethereum account. Produced by {@link PeginManager.signProofOfPossession}\n * and reusable across every register call in the same session — the\n * embedded identities are re-checked at register time.\n */\nexport interface PopSignature {\n  /** BIP-322 signature over the PoP message (0x-prefixed hex). */\n  btcPopSignature: Hex;\n  /** Ethereum address the PoP was signed for. */\n  depositorEthAddress: Address;\n  /** BTC x-only public key (64-char hex, no 0x prefix). */\n  depositorBtcPubkey: string;\n}\n\n/**\n * Parameters for registering a peg-in on Ethereum.\n */\nexport interface RegisterPeginParams {\n  /**\n   * Funded, pre-witness Pre-PegIn tx hex — pass\n   * {@link PreparePeginTransaction.fundedPrePeginTxHex} from\n   * {@link PreparePeginResult.transaction}. The contract-side parameter\n   * is named `unsignedPrePeginTx` but it stores the funded form.\n   */\n  unsignedPrePeginTx: string;\n\n  /**\n   * Depositor-signed PegIn transaction hex (submitted to contract; vault ID derived from this).\n   */\n  depositorSignedPeginTx: string;\n\n  /**\n   * Vault provider's Ethereum address.\n   */\n  vaultProvider: Address;\n\n  /**\n   * SHA256 hashlock for HTLC activation (bytes32 hex with 0x prefix).\n   */\n  hashlock: Hex;\n\n  /**\n   * Depositor's BTC payout address (e.g. bc1p..., bc1q...).\n   * Converted to scriptPubKey internally via bitcoinjs-lib.\n   *\n   * If omitted, defaults to the connected BTC wallet's address\n   * via `btcWallet.getAddress()`.\n   */\n  depositorPayoutBtcAddress?: string;\n\n  /** Keccak256 hash of the depositor's WOTS public key (bytes32) */\n  depositorWotsPkHash: Hex;\n\n  /** Proof of possession from {@link PeginManager.signProofOfPossession}. */\n  popSignature: PopSignature;\n\n  /**\n   * Zero-based index of the HTLC output in the Pre-PegIn transaction that\n   * this PegIn spends. In a batch Pre-PegIn with N HTLC outputs, each vault\n   * registration references a different htlcVout (0..N-1).\n   */\n  htlcVout: number;\n\n  /**\n   * Bounds the registration's maxAcceptableCommissionBps (#1691). REQUIRED\n   * when the wallet approved terms — the ceiling must anchor to the approved\n   * quote. Optional otherwise; falls back to chain-current.\n   */\n  quotedCommissionBps?: number;\n}\n\n/**\n * Result of registering a peg-in on Ethereum.\n */\nexport interface RegisterPeginResult {\n  /**\n   * Ethereum transaction hash for the peg-in registration.\n   */\n  ethTxHash: Hash;\n\n  /**\n   * Derived vault ID: keccak256(abi.encode(peginTxHash, depositor)).\n   * Used for contract reads/writes and indexer queries.\n   */\n  vaultId: Hex;\n\n  /**\n   * Raw Bitcoin pegin transaction hash (double-SHA256 of the signed pegin tx).\n   * Used for VP RPC operations which key on the BTC transaction ID.\n   */\n  peginTxHash: Hex;\n}\n\n/**\n * Single request in a batch pegin registration.\n * All requests in a batch share the same vault provider, depositor BTC\n * pubkey, and Pre-PegIn transaction.\n */\nexport interface BatchPeginRequestItem {\n  /** Signed PegIn tx hex for this vault */\n  depositorSignedPeginTx: string;\n  /** SHA256 hashlock for HTLC activation (bytes32 hex) */\n  hashlock: Hex;\n  /** Zero-based HTLC output index in the Pre-PegIn tx (unique per request) */\n  htlcVout: number;\n  /** Depositor's BTC payout address (required — funds are sent here on payout) */\n  depositorPayoutBtcAddress: string;\n  /** Keccak256 hash of the depositor's WOTS public key (bytes32) */\n  depositorWotsPkHash: Hex;\n}\n\n/**\n * Parameters for registerPeginBatchOnChain.\n */\nexport interface RegisterPeginBatchParams {\n  /** Vault provider address (shared across all vaults in batch) */\n  vaultProvider: Address;\n  /**\n   * Funded, pre-witness Pre-PegIn tx hex — shared across every request in\n   * the batch. See {@link RegisterPeginParams.unsignedPrePeginTx}.\n   */\n  unsignedPrePeginTx: string;\n  /** Individual pegin requests (one per vault) */\n  requests: BatchPeginRequestItem[];\n  /** Proof of possession from {@link PeginManager.signProofOfPossession}. */\n  popSignature: PopSignature;\n  /** See {@link RegisterPeginParams.quotedCommissionBps}. */\n  quotedCommissionBps?: number;\n}\n\n/**\n * Per-vault result from a batch pegin registration.\n */\nexport interface BatchPeginResultItem {\n  /** Derived vault ID: keccak256(abi.encode(peginTxHash, depositor)) */\n  vaultId: Hex;\n  /** Raw BTC pegin transaction hash */\n  peginTxHash: Hex;\n}\n\n/**\n * Result of registering a batch of pegins on Ethereum in a single transaction.\n */\nexport interface RegisterPeginBatchResult {\n  /** Ethereum transaction hash */\n  ethTxHash: Hex;\n  /** Per-vault results (same order as input requests) */\n  vaults: BatchPeginResultItem[];\n}\n\n/**\n * Detect a P2WPKH (Native SegWit) bech32 address for the configured network,\n * used purely for diagnostic routing. Distinguishes P2WPKH (witness v0,\n * 20-byte program) from P2WSH (v0, 32-byte program) and any other bech32\n * shape, so the specific \"use a P2TR\" error fires only when the user\n * actually has a P2WPKH address.\n */\nfunction isP2wpkhAddressForNetwork(address: string, network: Network): boolean {\n  const expectedHrp: Record<Network, string> = {\n    bitcoin: \"bc\",\n    testnet: \"tb\",\n    signet: \"tb\",\n    regtest: \"bcrt\",\n  };\n  try {\n    const decoded = bitcoin.address.fromBech32(address);\n    return (\n      decoded.prefix === expectedHrp[network] &&\n      decoded.version === 0 &&\n      decoded.data.length === 20\n    );\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Resolve prevout data for a transaction input.\n * Checks localPrevouts first; falls back to mempool API.\n */\nfunction resolveUtxoInfo(\n  txid: string,\n  vout: number,\n  localPrevouts:\n    | Record<string, { scriptPubKey: string; value: number }>\n    | undefined,\n  apiUrl: string,\n): Promise<UtxoInfo> {\n  const local = localPrevouts?.[`${txid}:${vout}`];\n  if (local) {\n    return Promise.resolve({\n      txid,\n      vout,\n      value: local.value,\n      scriptPubKey: local.scriptPubKey,\n    });\n  }\n  return getUtxoInfo(txid, vout, apiUrl);\n}\n\n/**\n * Manager for orchestrating peg-in operations.\n *\n * This manager provides a high-level API for creating peg-in transactions\n * by coordinating between SDK primitives, utilities, and wallet interfaces.\n *\n * @remarks\n * The complete peg-in flow consists of 5 steps:\n *\n * | Step | Method | Description |\n * |------|--------|-------------|\n * | 1 | {@link preparePegin} | Build Pre-PegIn HTLC, fund it, sign PegIn input |\n * | 2 | {@link signProofOfPossession} | Sign BIP-322 PoP (one per deposit session) |\n * | 3 | {@link registerPeginOnChain} | Submit to Ethereum contract |\n * | 4 | {@link signAndBroadcast} | Sign and broadcast Pre-PegIn tx to Bitcoin network |\n * | 5 | {@link PayoutManager} | Sign BOTH payout authorizations |\n *\n * **Important:** Step 5 uses {@link PayoutManager}, not this class. After\n * step 4, the vault provider observes the broadcast Pre-PegIn and prepares\n * 3 transactions per claimer:\n * - `claim_tx` - Claim transaction\n * - `assert_tx` - Assert transaction\n * - `payout_tx` - Payout transaction\n *\n * You must sign the Payout transaction for each claimer:\n * - {@link PayoutManager.signPayoutTransaction} - uses assert_tx as input reference\n *\n * Submit all signatures to the vault provider to drive the contract to\n * `VERIFIED` (and then activate by revealing the HTLC secret, which is a\n * services-layer step outside this manager).\n *\n * @see {@link PayoutManager} - Required for Step 5 (payout authorization)\n * @see {@link buildPrePeginPsbt} - Lower-level primitive for custom implementations\n * @see {@link https://github.com/babylonlabs-io/babylon-toolkit/blob/main/packages/babylon-ts-sdk/docs/quickstart/managers.md | Managers Quickstart}\n */\n/**\n * Maximum time (ms) to wait for a transaction receipt before timing out.\n * Matches the prior vault-service polling timeout so users see a clear error\n * instead of an indefinite hang when a transaction is dropped from the mempool.\n */\nconst RECEIPT_TIMEOUT_MS = 120_000;\n\nexport class PeginManager {\n  private readonly config: PeginManagerConfig;\n\n  /**\n   * Creates a new PeginManager instance.\n   *\n   * @param config - Manager configuration including wallets and contract addresses\n   */\n  constructor(config: PeginManagerConfig) {\n    this.config = config;\n  }\n\n  /**\n   * Prepare a peg-in: sizing pass → vault-root derivation (one wallet\n   * popup) → per-vault WOTS / hashlock derivation → commit pass with\n   * PSBT signing (signPsbt for a single vault, one batch popup for a\n   * split). Returns broadcast-ready txs, the pubkey snapshot, and the\n   * sensitive derived material.\n   *\n   * @throws If the wallet rejects, insufficient funds, or an internal\n   *         invariant violation.\n   */\n  async preparePegin(params: PreparePeginParams): Promise<PreparePeginResult> {\n    if (params.amounts.length === 0) {\n      throw new Error(\"amounts must contain at least one entry\");\n    }\n\n    // Raw form for `signInputs[].publicKey` (UniSat/OKX/OneKey reject\n    // x-only); x-only form for protocol/HTLC use. One snapshot binds\n    // sizing, root derivation, and PSBT signing to one identity.\n    const depositorBtcPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n    const depositorBtcPubkey = normalizeXOnlyPubkey(depositorBtcPubkeyRaw);\n\n    // Pre-PegIn change pays back to the depositor. The wallet will sign\n    // whatever output the PSBT carries; nothing downstream proves the\n    // change address belongs to the signing key, so a state-race / stale\n    // FE / hostile adapter that puts an attacker-controlled address here\n    // would drain the change after signing. Bind once at entry — against the\n    // wallet's own change branch when it has one, else the pubkey snapshot.\n    if (supportsDepositApproval(this.config.btcWallet)) {\n      // Approval (policy) wallets own their change branch: the device accepts a\n      // change output only on `.../1/i`, which is not derivable from the receive\n      // key. Any other change address fails mid-ceremony on the device, so this\n      // gate closes that window before any approval screen (the only device\n      // traffic it costs is the silent policy-context read).\n      const walletChange = (\n        await requireChangeAddress(this.config.btcWallet)\n      ).trim();\n      if (params.changeAddress.trim() !== walletChange) {\n        throw new Error(\n          `Pre-PegIn changeAddress \"${params.changeAddress}\" is not the approval wallet's change address ` +\n            `(\"${walletChange}\"). Refusing to build a tx the signing device would reject.`,\n        );\n      }\n    } else if (\n      !isAddressFromPublicKey(\n        params.changeAddress,\n        depositorBtcPubkeyRaw,\n        this.config.btcNetwork,\n      )\n    ) {\n      throw new Error(\n        `Pre-PegIn changeAddress \"${params.changeAddress}\" is not derived ` +\n          `from the connected wallet's public key. Refusing to build a tx ` +\n          `that would send change to an address the signing key doesn't control.`,\n      );\n    }\n\n    // Sizing pass uses a placeholder for the auth-anchor hash because\n    // the wallet popup that produces the real anchor hasn't run yet.\n    // The OP_RETURN's byte length is invariant under content swap, so\n    // UTXO selection and fees match the commit pass.\n    const sizing = await this.prepareSizing(depositorBtcPubkey, params);\n\n    // #2110 T4: an envelope violation must fail HERE, before the derive costs\n    // a physical device approval. Validate-only by contract — no device I/O.\n    if (supportsDepositApproval(this.config.btcWallet)) {\n      const { validateDepositTerms } = this.config.btcWallet;\n      if (typeof validateDepositTerms === \"function\") {\n        await validateDepositTerms.call(\n          this.config.btcWallet,\n          this.buildPeginDepositTerms({\n            params,\n            prepeginTxid: PROVISIONAL_TERMS_PLACEHOLDER_TXID_HEX,\n            prepeginMaxFee: sizing.fee,\n            depositorClaimValue: sizing.depositorClaimValue,\n            peginMaxFee: sizing.minPeginFee,\n          }),\n        );\n      }\n    }\n\n    const fundingOutpoints: FundingOutpoint[] = sizing.selectedUTXOs.map(\n      (u) => ({\n        txid: hexToUint8Array(u.txid),\n        vout: u.vout,\n      }),\n    );\n    const root = await deriveVaultRoot(this.config.btcWallet, {\n      depositorBtcPubkey: hexToUint8Array(depositorBtcPubkey),\n      fundingOutpoints,\n    });\n\n    // Take ownership of the auth anchor before per-vault expansion (which\n    // zeros `root`). Convert to hex immediately, then zero the buffer.\n    // `authAnchorHex` is a JS string — immutable, GC-only — and lives\n    // until the result is dropped. If anything in this window throws,\n    // `expandPerVaultSecrets` won't run to zero `root`, so we wipe it\n    // here on the throw path.\n    let authAnchorHex: string;\n    let authAnchorHash: string;\n    try {\n      const authAnchorBytes = await expandAuthAnchor(root);\n      try {\n        authAnchorHex = uint8ArrayToHex(authAnchorBytes);\n        authAnchorHash = uint8ArrayToHex(sha256(authAnchorBytes));\n      } finally {\n        authAnchorBytes.fill(0);\n      }\n    } catch (err) {\n      root.fill(0);\n      throw err;\n    }\n\n    const derived = await expandPerVaultSecrets(root, params.amounts.length);\n    const { perVaultWotsKeys, wotsPkHashes, htlcSecretHexes, hashlocks } =\n      derived;\n\n    const commit = await this.preparePeginCommit({\n      depositorBtcPubkeyRaw,\n      depositorBtcPubkey,\n      hashlocks,\n      authAnchorHash,\n      sizing,\n      params,\n    });\n\n    // Downstream consumers look up per-vault secrets by index; pin the\n    // contract so a future WASM output-ordering change fails loud.\n    for (let i = 0; i < commit.perVault.length; i++) {\n      if (commit.perVault[i].htlcVout !== i) {\n        throw new Error(\n          `Internal invariant violation: htlcVout/index mismatch at vault ${i} ` +\n            `(expected ${i}, got ${commit.perVault[i].htlcVout})`,\n        );\n      }\n    }\n\n    // Structural guarantee that the broadcast tx actually carries the\n    // OP_RETURN we'll later reveal a preimage for. Without this assertion\n    // a malicious WASM build could emit no OP_RETURN, the VP would still\n    // issue a token (if mis-configured) on a tx with no on-chain\n    // commitment, and the auth flow would degrade to a pure shared\n    // secret. Fail closed.\n    assertAuthAnchorOpReturn(\n      commit.fundedPrePeginTxHex,\n      params.amounts.length,\n      authAnchorHash,\n    );\n\n    const { depositTerms, ...commitTransaction } = commit;\n\n    return {\n      transaction: {\n        ...commitTransaction,\n        selectedUTXOs: sizing.selectedUTXOs,\n        fee: sizing.fee,\n        changeAmount: sizing.changeAmount,\n      },\n      depositorBtcPubkey,\n      derivedSecrets: {\n        perVaultWotsKeys,\n        wotsPkHashes,\n        htlcSecretHexes,\n        authAnchorHex,\n      },\n      depositTerms,\n    };\n  }\n\n  /**\n   * Build unfunded Pre-PegIn + select UTXOs. No PSBT signing.\n   *\n   * Returns the full selection result (UTXOs, fee, changeAmount) so the\n   * commit pass funds the broadcast tx with the exact same set used to\n   * build the vault-context funding-outpoints commitment. Re-running\n   * `selectUtxosForPegin` in the commit pass would be deterministic given\n   * the same inputs, but threading the result through guarantees the\n   * domain separator structurally matches the funded tx inputs.\n   *\n   * Sizing runs before the wallet popup, so neither the real per-vault\n   * hashlocks nor the real `authAnchorHash` are known yet. Both slots\n   * are filled with a 32-byte placeholder; the commit pass swaps in the\n   * real values. Output budget is identical (32-byte push regardless of\n   * content), so UTXO selection is invariant under substitution.\n   */\n  private async prepareSizing(\n    depositorBtcPubkey: string,\n    params: PreparePeginParams,\n  ): Promise<PeginSizing> {\n    const placeholderHashlocks = params.amounts.map(\n      () => SIZING_PASS_PLACEHOLDER_BYTES32_HEX,\n    );\n    const numLocalChallengers = params.vaultKeeperBtcPubkeys.length;\n\n    const prePegin = await buildPrePeginPsbt({\n      vaultCoreVersion: params.vaultCoreVersion,\n      depositorPubkey: depositorBtcPubkey,\n      vaultProviderPubkey: stripHexPrefix(params.vaultProviderBtcPubkey),\n      vaultKeeperPubkeys: params.vaultKeeperBtcPubkeys.map(stripHexPrefix),\n      universalChallengerPubkeys:\n        params.universalChallengerBtcPubkeys.map(stripHexPrefix),\n      hashlocks: placeholderHashlocks,\n      timelockRefund: params.timelockRefund,\n      pegInAmounts: params.amounts,\n      feeRate: params.protocolFeeRate,\n      minPeginFeeRate: params.minPeginFeeRate,\n      numLocalChallengers,\n      councilQuorum: params.councilQuorum,\n      councilSize: params.councilSize,\n      network: this.config.btcNetwork,\n      authAnchorHash: SIZING_PASS_PLACEHOLDER_BYTES32_HEX,\n    });\n\n    const selection = selectUtxosForPegin(\n      [...params.availableUTXOs],\n      prePegin.totalOutputValue,\n      params.mempoolFeeRate,\n      peginOutputCount(prePegin.htlcValues.length, true),\n    );\n\n    return {\n      selectedUTXOs: selection.selectedUTXOs,\n      fee: selection.fee,\n      changeAmount: selection.changeAmount,\n      depositorClaimValue: prePegin.depositorClaimValue,\n      minPeginFee: prePegin.minPeginFee,\n    };\n  }\n\n  /**\n   * One projection for both the provisional (pre-derive, placeholder-txid)\n   * terms and the final approved terms, so the fields the pre-check validated\n   * cannot drift from the fields the device later displays (#2110 T4).\n   */\n  private buildPeginDepositTerms(args: {\n    params: PreparePeginParams;\n    prepeginTxid: string;\n    prepeginMaxFee: bigint;\n    depositorClaimValue: bigint;\n    peginMaxFee: bigint;\n  }): DepositTerms {\n    const { params } = args;\n    return buildDepositTerms({\n      vaultCoreVersion: params.vaultCoreVersion,\n      protocolFeeRate: params.protocolFeeRate,\n      timelockPegin: params.timelockPegin,\n      timelockAssert: params.timelockAssert,\n      timelockRefund: params.timelockRefund,\n      prepeginTxid: args.prepeginTxid,\n      prepeginMaxFee: args.prepeginMaxFee,\n      vaultProviderBtcPubkey: stripHexPrefix(params.vaultProviderBtcPubkey),\n      vaultKeeperBtcPubkeys: params.vaultKeeperBtcPubkeys.map(stripHexPrefix),\n      universalChallengerBtcPubkeys:\n        params.universalChallengerBtcPubkeys.map(stripHexPrefix),\n      maxAcceptableCommissionBps: capMaxAcceptableCommissionBps(\n        params.commissionBps,\n      ),\n      peginAmounts: params.amounts,\n      depositorClaimValue: args.depositorClaimValue,\n      peginMaxFee: args.peginMaxFee,\n    });\n  }\n\n  /** Build PegIn txs and batch-sign their inputs with real hashlocks. */\n  private async preparePeginCommit(args: {\n    depositorBtcPubkeyRaw: string;\n    depositorBtcPubkey: string;\n    hashlocks: readonly string[];\n    authAnchorHash: string;\n    sizing: PeginSizing;\n    params: PreparePeginParams;\n  }): Promise<{\n    fundedPrePeginTxHex: string;\n    prePeginTxid: string;\n    perVault: PerVaultPeginData[];\n    depositTerms: DepositTerms;\n  }> {\n    const {\n      depositorBtcPubkeyRaw,\n      depositorBtcPubkey,\n      hashlocks,\n      authAnchorHash,\n      sizing,\n      params,\n    } = args;\n\n    // Refuse to build the broadcast tx if the orchestrator forgot to\n    // substitute real values for the sizing-pass placeholder. A\n    // placeholder-zero hashlock would produce an HTLC that no real\n    // preimage can spend; a placeholder-zero auth anchor would let\n    // the depositor reveal a known-public preimage to the VP. Fail\n    // before signing, not after broadcast.\n    const placeholderLower = SIZING_PASS_PLACEHOLDER_BYTES32_HEX.toLowerCase();\n    for (let i = 0; i < hashlocks.length; i++) {\n      if (hashlocks[i].toLowerCase() === placeholderLower) {\n        throw new Error(\n          `preparePeginCommit refusing to build with sizing-pass placeholder ` +\n            `hashlock at vault ${i} — internal substitution bug`,\n        );\n      }\n    }\n    if (authAnchorHash.toLowerCase() === placeholderLower) {\n      throw new Error(\n        `preparePeginCommit refusing to build with sizing-pass placeholder ` +\n          `auth-anchor hash — internal substitution bug`,\n      );\n    }\n\n    const vaultProviderBtcPubkey = stripHexPrefix(\n      params.vaultProviderBtcPubkey,\n    );\n    const vaultKeeperBtcPubkeys =\n      params.vaultKeeperBtcPubkeys.map(stripHexPrefix);\n    const universalChallengerBtcPubkeys =\n      params.universalChallengerBtcPubkeys.map(stripHexPrefix);\n    const numLocalChallengers = vaultKeeperBtcPubkeys.length;\n\n    const prePeginParams: PrePeginParams = {\n      vaultCoreVersion: params.vaultCoreVersion,\n      depositorPubkey: depositorBtcPubkey,\n      vaultProviderPubkey: vaultProviderBtcPubkey,\n      vaultKeeperPubkeys: vaultKeeperBtcPubkeys,\n      universalChallengerPubkeys: universalChallengerBtcPubkeys,\n      hashlocks,\n      timelockRefund: params.timelockRefund,\n      pegInAmounts: params.amounts,\n      feeRate: params.protocolFeeRate,\n      minPeginFeeRate: params.minPeginFeeRate,\n      numLocalChallengers,\n      councilQuorum: params.councilQuorum,\n      councilSize: params.councilSize,\n      network: this.config.btcNetwork,\n      authAnchorHash,\n    };\n\n    const prePeginResult = await buildPrePeginPsbt(prePeginParams);\n\n    // The pre-derive check (#2110 T4) validated the sizing-build values; the\n    // wallet approves these commit-build ones — assert agreement, not assume.\n    if (\n      prePeginResult.depositorClaimValue !== sizing.depositorClaimValue ||\n      prePeginResult.minPeginFee !== sizing.minPeginFee\n    ) {\n      throw new Error(\n        `Pre-PegIn sizing/commit divergence: depositorClaimValue ` +\n          `${sizing.depositorClaimValue} -> ${prePeginResult.depositorClaimValue}, ` +\n          `minPeginFee ${sizing.minPeginFee} -> ${prePeginResult.minPeginFee}. ` +\n          `The provisional deposit terms validated before derivation would not ` +\n          `match the terms sent for approval; refusing to continue.`,\n      );\n    }\n\n    const network = getNetwork(this.config.btcNetwork);\n    const fundedPrePeginTxHex = fundPeginTransaction({\n      unfundedTxHex: prePeginResult.psbtHex,\n      selectedUTXOs: sizing.selectedUTXOs,\n      changeAddress: params.changeAddress,\n      changeAmount: sizing.changeAmount,\n      network,\n    });\n\n    // sizing.fee ships in the deposit terms as a hardware signing bound\n    // (prepeginMaxFee) — assert the funded tx actually pays it before the\n    // bound leaves this method.\n    const fundedFee =\n      sizing.selectedUTXOs.reduce((sum, u) => sum + BigInt(u.value), 0n) -\n      prePeginResult.totalOutputValue -\n      sizing.changeAmount;\n    if (fundedFee !== sizing.fee) {\n      throw new Error(\n        `Pre-PegIn funded fee ${fundedFee} does not match the sizing-pass fee ` +\n          `${sizing.fee}; refusing to publish a deposit-terms fee bound the ` +\n          `funded transaction does not pay.`,\n      );\n    }\n\n    const prePeginTxid = stripHexPrefix(\n      calculateBtcTxHash(fundedPrePeginTxHex),\n    );\n\n    // Build the per-vault PegIn txs before deposit-terms approval so the real\n    // htlcVout bind-check inside buildPeginTxFromFundedPrePegin runs before\n    // the depositor approves on a hardware wallet, not after.\n    const peginTxResults: Array<{\n      txHex: string;\n      txid: string;\n      vaultScriptPubKey: string;\n    }> = [];\n    const psbtsToSign: string[] = [];\n    const signOptions: SignPsbtOptions[] = [];\n\n    for (let i = 0; i < hashlocks.length; i++) {\n      const peginTxResult = await buildPeginTxFromFundedPrePegin({\n        prePeginParams,\n        timelockPegin: params.timelockPegin,\n        fundedPrePeginTxHex,\n        htlcVout: i,\n      });\n\n      const peginInputPsbtResult = await buildPeginInputPsbt({\n        vaultCoreVersion: params.vaultCoreVersion,\n        peginTxHex: peginTxResult.txHex,\n        fundedPrePeginTxHex,\n        depositorPubkey: depositorBtcPubkey,\n        vaultProviderPubkey: vaultProviderBtcPubkey,\n        vaultKeeperPubkeys: vaultKeeperBtcPubkeys,\n        universalChallengerPubkeys: universalChallengerBtcPubkeys,\n        hashlock: hashlocks[i],\n        timelockRefund: params.timelockRefund,\n        network: this.config.btcNetwork,\n      });\n\n      peginTxResults.push(peginTxResult);\n      psbtsToSign.push(peginInputPsbtResult.psbtHex);\n      signOptions.push(\n        createTaprootScriptPathSignOptions(depositorBtcPubkeyRaw, 1),\n      );\n    }\n\n    // Always build the deposit terms so callers get them back regardless of\n    // wallet capability; only approval-capable wallets need the call below.\n    // peginMaxFee reuses assertWasmPeginSizing's already-asserted minPeginFee\n    // (via prePeginResult) instead of recomputing it.\n    const depositTerms = this.buildPeginDepositTerms({\n      params,\n      prepeginTxid: prePeginTxid,\n      prepeginMaxFee: sizing.fee,\n      depositorClaimValue: prePeginResult.depositorClaimValue,\n      peginMaxFee: prePeginResult.minPeginFee,\n    });\n    if (supportsDepositApproval(this.config.btcWallet)) {\n      await this.config.btcWallet.approveDepositTerms(depositTerms);\n    }\n\n    const signedPsbts = await signPsbtsWithFallback(\n      this.config.btcWallet,\n      psbtsToSign,\n      signOptions,\n    );\n\n    const perVault: PerVaultPeginData[] = [];\n    for (let i = 0; i < signedPsbts.length; i++) {\n      assertPsbtUnsignedTxMatches({\n        requestedPsbtHex: psbtsToSign[i],\n        returnedPsbtHex: signedPsbts[i],\n      });\n\n      const peginInputSignature = extractPeginInputSignature(\n        signedPsbts[i],\n        depositorBtcPubkey,\n      );\n      // Critical Path #7: verify the depositor's script-path signature against a\n      // sighash recomputed from the PSBT we built (psbtsToSign[i]) before the\n      // signed tx is finalized and broadcast. The PegIn input is signed on input 0.\n      assertScriptPathSchnorrSignature({\n        requestedPsbtHex: psbtsToSign[i],\n        signatureHex: peginInputSignature,\n        signerXOnlyPubkeyHex: depositorBtcPubkey,\n        inputIndex: 0,\n      });\n\n      const depositorSignedPeginTxHex = finalizePeginInputPsbt(signedPsbts[i]);\n\n      perVault.push({\n        htlcVout: i,\n        htlcValue: prePeginResult.htlcValues[i],\n        peginTxHex: depositorSignedPeginTxHex,\n        peginTxid: peginTxResults[i].txid,\n        peginInputSignature,\n        vaultScriptPubKey: peginTxResults[i].vaultScriptPubKey,\n      });\n    }\n\n    return {\n      fundedPrePeginTxHex,\n      prePeginTxid,\n      perVault,\n      depositTerms,\n    };\n  }\n\n  /**\n   * Signs and broadcasts a funded peg-in transaction to the Bitcoin network.\n   *\n   * This method:\n   * 1. Parses the funded transaction hex\n   * 2. Fetches UTXO data from mempool for each input\n   * 3. Creates a PSBT with proper witnessUtxo/tapInternalKey\n   * 4. Signs via btcWallet.signPsbt()\n   * 5. Finalizes and extracts the transaction\n   * 6. Broadcasts via mempool API\n   *\n   * IMPORTANT — this method does NOT gate on Ethereum finality. Committing\n   * BTC to the HTLC while the peg-in registration is still reorg-exposed can\n   * strand the deposit: the vault record disappears from the chain while the\n   * BTC stays locked until the HTLC refund timelock. Callers must await\n   * `waitForPeginRegistrationDepth` for the registered vault(s) before calling\n   * this. The gate is not applied here because the params carry no vault ID —\n   * adding one would be a breaking signature change.\n   *\n   * @param params - Transaction hex and depositor public key\n   * @returns The broadcasted Bitcoin transaction ID\n   * @throws Error if signing or broadcasting fails\n   */\n  async signAndBroadcast(params: SignAndBroadcastParams): Promise<string> {\n    const { fundedPrePeginTxHex, depositorBtcPubkey } = params;\n\n    // Step 1: Parse the funded transaction\n    const cleanHex = fundedPrePeginTxHex.startsWith(\"0x\")\n      ? fundedPrePeginTxHex.slice(2)\n      : fundedPrePeginTxHex;\n    const tx = Transaction.fromHex(cleanHex);\n\n    if (tx.ins.length === 0) {\n      throw new Error(\"Transaction has no inputs\");\n    }\n\n    // Step 2: Create PSBT and add inputs with UTXO data from mempool\n    const psbt = new Psbt();\n    psbt.setVersion(tx.version);\n    psbt.setLocktime(tx.locktime);\n\n    const publicKeyNoCoord = Buffer.from(\n      normalizeXOnlyPubkey(depositorBtcPubkey),\n      \"hex\",\n    );\n    const apiUrl = this.config.mempoolApiUrl;\n\n    // Resolve prevout data for each input (local cache or mempool API)\n    const utxoDataPromises = tx.ins.map((input) => {\n      const txid = Buffer.from(input.hash).reverse().toString(\"hex\");\n      const vout = input.index;\n      return resolveUtxoInfo(txid, vout, params.localPrevouts, apiUrl).then(\n        (utxoData) => ({ input, utxoData, txid, vout }),\n      );\n    });\n\n    const inputsWithUtxoData = await Promise.all(utxoDataPromises);\n\n    // Cross-validate: total input value must cover total output value.\n    // A mismatch indicates the mempool API returned manipulated UTXO data,\n    // which could lead to fee-siphoning or invalid signatures.\n    const totalInputValue = inputsWithUtxoData.reduce(\n      (sum, i) => sum + BigInt(i.utxoData.value),\n      0n,\n    );\n    const totalOutputValue = tx.outs.reduce(\n      (sum, out) => sum + BigInt(out.value),\n      0n,\n    );\n    if (totalInputValue < totalOutputValue) {\n      throw new Error(\n        `UTXO value mismatch: total input value (${totalInputValue} sat) is less than ` +\n          `total output value (${totalOutputValue} sat). ` +\n          `This may indicate the mempool API returned manipulated UTXO data.`,\n      );\n    }\n\n    const impliedFee = totalInputValue - totalOutputValue;\n    if (impliedFee > MAX_REASONABLE_FEE_SATS) {\n      throw new Error(\n        `Implied transaction fee (${impliedFee} sat) exceeds maximum reasonable fee ` +\n          `(${MAX_REASONABLE_FEE_SATS} sat). This may indicate manipulated UTXO data.`,\n      );\n    }\n\n    // Add inputs with proper PSBT fields based on script type\n    for (const { input, utxoData, txid, vout } of inputsWithUtxoData) {\n      const psbtInputFields = getPsbtInputFields(\n        {\n          txid,\n          vout,\n          value: utxoData.value,\n          scriptPubKey: utxoData.scriptPubKey,\n        },\n        publicKeyNoCoord,\n      );\n\n      psbt.addInput({\n        hash: input.hash,\n        index: input.index,\n        sequence: input.sequence,\n        ...psbtInputFields,\n      });\n    }\n\n    // Step 3: Add outputs\n    for (const output of tx.outs) {\n      psbt.addOutput({\n        script: output.script,\n        value: output.value,\n      });\n    }\n\n    // Step 3.5: intent-wallet ceremony (derive → approve) immediately before\n    // signing. Placed after prevout resolution — a network failure there must\n    // not burn a two-screen device ceremony — and adjacent to signPsbt to keep\n    // the approve→sign gap minimal (the seam invariant). No-op for wallets that\n    // do not support deposit approval.\n    await ensurePrePeginTermsApproval({\n      wallet: this.config.btcWallet,\n      depositTerms: params.depositTerms,\n      fundedPrePeginTxHex,\n      depositorBtcPubkey,\n    });\n\n    // Step 4: Sign PSBT via wallet\n    const requestedPsbtHex = psbt.toHex();\n    const signedPsbtHex =\n      await this.config.btcWallet.signPsbt(requestedPsbtHex);\n\n    assertPsbtUnsignedTxMatches({\n      requestedPsbtHex,\n      returnedPsbtHex: signedPsbtHex,\n    });\n\n    // Far-side check of the returned signatures (CLAUDE.md §8: never trust\n    // the wallet's success/finalization). Taproot key-path inputs are\n    // Schnorr-verified and counted; P2WPKH funding is ECDSA-verified\n    // (throwing on failure) without counting; any other input type throws.\n    const verifiedInputs = assertReturnedKeyPathSignatures({\n      requestedPsbtHex,\n      returnedPsbtHex: signedPsbtHex,\n    });\n    // An approval wallet signs key-path under a wallet policy, so every input\n    // must have been verified; 0 would mean the check silently covered nothing.\n    if (\n      supportsDepositApproval(this.config.btcWallet) &&\n      verifiedInputs !== psbt.data.inputs.length\n    ) {\n      throw new Error(\n        `Key-path verification covered ${verifiedInputs} of ${psbt.data.inputs.length} Pre-PegIn ` +\n          `inputs; an approval wallet signs every input key-path, so the unverified ones must not be broadcast.`,\n      );\n    }\n\n    const signedPsbt = Psbt.fromHex(signedPsbtHex);\n\n    // Step 5: Finalize and extract transaction\n    try {\n      signedPsbt.finalizeAllInputs();\n    } catch (e) {\n      // Some wallets (e.g. UniSat, OKX) auto-finalize PSBTs before returning them.\n      // Attempting to finalize again throws, which is expected and safe to skip —\n      // but verify the wallet actually finalized all inputs.\n      const allFinalized = signedPsbt.data.inputs.every(\n        (inp) => inp.finalScriptWitness || inp.finalScriptSig,\n      );\n      if (!allFinalized) {\n        throw new Error(\n          `PSBT finalization failed and wallet did not auto-finalize: ${e}`,\n        );\n      }\n    }\n\n    const signedTxHex = signedPsbt.extractTransaction().toHex();\n\n    // Step 6: Broadcast to Bitcoin network\n    const btcTxid = await pushTx(signedTxHex, apiUrl);\n\n    return btcTxid;\n  }\n\n  /**\n   * Registers a peg-in on Ethereum by calling the BTCVaultRegistry contract.\n   *\n   * This method:\n   * 1. Re-verifies the PopSignature against the currently connected ETH\n   *    and BTC wallets — refuses to proceed if either has changed\n   * 2. Derives vault ID and checks if it already exists (pre-flight)\n   * 3. Encodes the contract call using viem\n   * 4. Estimates gas (catches contract errors early with proper revert\n   *    reasons)\n   * 5. Sends transaction with pre-estimated gas via\n   *    ethWallet.sendTransaction()\n   *\n   * The PopSignature must be obtained via\n   * {@link signProofOfPossession} before this call.\n   *\n   * @param params - Registration parameters including the PopSignature\n   *                 and the prepared Pre-PegIn / PegIn transactions\n   * @returns Result containing Ethereum transaction hash and vault ID\n   * @throws Error if the PopSignature does not match the connected wallets\n   * @throws Error if the vault already exists\n   * @throws Error if contract simulation fails (e.g., invalid signature,\n   *         unauthorized)\n   */\n  async registerPeginOnChain(\n    params: RegisterPeginParams,\n  ): Promise<RegisterPeginResult> {\n    const {\n      unsignedPrePeginTx,\n      depositorSignedPeginTx,\n      vaultProvider,\n      hashlock,\n      htlcVout,\n      depositorPayoutBtcAddress,\n      depositorWotsPkHash,\n      popSignature,\n    } = params;\n\n    // Step 1: Re-verify the PoP artifact against the currently connected\n    // wallets so a mid-flow account/wallet switch fails here instead of\n    // surfacing downstream as an opaque contract revert.\n    if (!this.config.ethWallet.account) {\n      throw new Error(\"Ethereum wallet account not found\");\n    }\n    const depositorEthAddress = this.config.ethWallet.account.address;\n    if (\n      !isAddressEqual(popSignature.depositorEthAddress, depositorEthAddress)\n    ) {\n      throw new Error(\n        `Proof of possession was signed for ${popSignature.depositorEthAddress} ` +\n          `but the Ethereum wallet is currently connected to ${depositorEthAddress}. ` +\n          `Reconnect the original account or call signProofOfPossession() again.`,\n      );\n    }\n    // The raw (parity-preserving) pubkey is required to validate P2WPKH\n    // payout addresses; the x-only form on `popSignature` would let an\n    // attacker substitute the opposite-parity P2WPKH address.\n    const verifiedBtcPubkeyRaw =\n      await this.assertPopMatchesBtcWallet(popSignature);\n    const btcPopSignature = popSignature.btcPopSignature;\n\n    // Step 2: Format parameters for contract call\n    const depositorBtcPubkeyHex = ensureHexPrefix(\n      popSignature.depositorBtcPubkey,\n    );\n    const unsignedPrePeginTxHex = ensureHexPrefix(unsignedPrePeginTx);\n    const depositorSignedPeginTxHex = ensureHexPrefix(depositorSignedPeginTx);\n\n    // Only read the wallet address if the caller didn't supply one — avoids\n    // an unnecessary adapter prompt on the common explicit-address path.\n    const resolvedPayoutAddress =\n      depositorPayoutBtcAddress ?? (await this.config.btcWallet.getAddress());\n    const payoutScriptPubKey = this.resolvePayoutScriptPubKey(\n      verifiedBtcPubkeyRaw,\n      resolvedPayoutAddress,\n    );\n\n    // Step 3: Calculate pegin tx hash and derive vault ID, then check if it already exists\n    const peginTxHash = calculateBtcTxHash(depositorSignedPeginTxHex);\n    const derivedVaultIdHex = await deriveVaultId(\n      stripHexPrefix(peginTxHash),\n      stripHexPrefix(depositorEthAddress),\n    );\n    const vaultId = ensureHexPrefix(derivedVaultIdHex) as Hex;\n    const exists = await this.checkVaultExists(vaultId);\n\n    if (exists) {\n      throw new Error(\n        `Vault already exists (ID: ${vaultId}, peginTxHash: ${peginTxHash}). ` +\n          `Vault IDs are derived from the pegin transaction hash and depositor address. ` +\n          `To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`,\n      );\n    }\n\n    // Step 4: Query required pegin fee and current VP commission from chain.\n    // Both reads happen at submit time to minimise drift between display and\n    // consequence; per the validation-layer rule, no caching.\n    const publicClient = this.config.publicClient;\n\n    let peginFee: bigint;\n    try {\n      peginFee = (await publicClient.readContract({\n        address: this.config.vaultContracts.btcVaultRegistry,\n        abi: BTCVaultRegistryABI,\n        functionName: \"getPegInFee\",\n        args: [vaultProvider],\n      })) as bigint;\n    } catch (error) {\n      throw new Error(\n        \"Failed to query pegin fee from the contract. \" +\n          \"Please check your network connection and that the contract address is correct.\",\n        { cause: error },\n      );\n    }\n\n    const maxAcceptableCommissionBps =\n      await this.resolveMaxAcceptableCommissionBps(\n        vaultProvider,\n        params.quotedCommissionBps,\n      );\n\n    // Step 5: Encode the contract call data\n    const callData = encodeFunctionData({\n      abi: BTCVaultRegistryABI,\n      functionName: \"submitPeginRequest\",\n      args: [\n        depositorEthAddress,\n        depositorBtcPubkeyHex,\n        btcPopSignature,\n        unsignedPrePeginTxHex,\n        depositorSignedPeginTxHex,\n        vaultProvider,\n        maxAcceptableCommissionBps,\n        hashlock,\n        htlcVout,\n        payoutScriptPubKey,\n        depositorWotsPkHash,\n      ],\n    });\n\n    // Step 6: Estimate gas first to catch contract errors before showing wallet popup\n    // This ensures users see actual contract revert reasons instead of gas errors\n    // The gas estimate is then passed to sendTransaction to avoid double estimation\n    let gasEstimate: bigint;\n    try {\n      gasEstimate = await publicClient.estimateGas({\n        to: this.config.vaultContracts.btcVaultRegistry,\n        data: callData,\n        value: peginFee,\n        account: this.config.ethWallet.account.address,\n      });\n    } catch (error) {\n      // Estimation failed - handle contract error with actual revert reason\n      handleContractError(error); // always throws (return type: never)\n    }\n\n    // Step 7: Submit peg-in request to contract (estimation passed)\n    let ethTxHash: Hex;\n    try {\n      // Send transaction with pre-estimated gas to skip internal estimation\n      // Note: viem's sendTransaction uses `gas`, not `gasLimit`\n      ethTxHash = await this.config.ethWallet.sendTransaction({\n        to: this.config.vaultContracts.btcVaultRegistry,\n        data: callData,\n        value: peginFee,\n        account: this.config.ethWallet.account,\n        chain: this.config.ethChain,\n        gas: gasEstimate,\n      });\n    } catch (error) {\n      // Use proper error handler for better error messages\n      handleContractError(error); // always throws (return type: never)\n    }\n\n    // Step 8: Wait for transaction receipt and verify it was not reverted.\n    // Smart-account-aware wrapper so Safe-style multisigs work alongside\n    // Externally Owned Accounts (EOAs — wallets controlled by a single\n    // private key, e.g. MetaMask). The EOA path is unchanged.\n    const receipt = await waitForTransactionReceiptSmartAware({\n      publicClient,\n      walletAddress: this.config.ethWallet.account.address,\n      hash: ethTxHash,\n      timeout: RECEIPT_TIMEOUT_MS,\n    });\n    if (receipt.status === \"reverted\") {\n      handleContractError(\n        new Error(\n          `Transaction reverted. Hash: ${receipt.transactionHash}. ` +\n            `Check the transaction on block explorer for details.`,\n        ),\n      );\n    }\n\n    return {\n      ethTxHash: receipt.transactionHash,\n      vaultId,\n      peginTxHash,\n    };\n  }\n\n  /**\n   * Register multiple pegins on Ethereum in a single transaction.\n   *\n   * Uses the contract's submitPeginRequestBatch() to submit all vault\n   * registrations atomically. All vaults must share the same vault provider.\n   * The PoP signature is signed once and included in each request.\n   *\n   * @param params - Batch registration parameters\n   * @returns Batch result with per-vault IDs and single ETH tx hash\n   */\n  async registerPeginBatchOnChain(\n    params: RegisterPeginBatchParams,\n  ): Promise<RegisterPeginBatchResult> {\n    const { vaultProvider, unsignedPrePeginTx, requests, popSignature } =\n      params;\n\n    if (requests.length === 0) {\n      throw new Error(\"Batch pegin requires at least one request\");\n    }\n\n    // Step 1: Re-verify the PoP (same reasoning as registerPeginOnChain).\n    if (!this.config.ethWallet.account) {\n      throw new Error(\"Ethereum wallet account not found\");\n    }\n    const depositorEthAddress = this.config.ethWallet.account.address;\n    if (\n      !isAddressEqual(popSignature.depositorEthAddress, depositorEthAddress)\n    ) {\n      throw new Error(\n        `Proof of possession was signed for ${popSignature.depositorEthAddress} ` +\n          `but the Ethereum wallet is currently connected to ${depositorEthAddress}. ` +\n          `Reconnect the original account or call signProofOfPossession() again.`,\n      );\n    }\n    // The raw (parity-preserving) pubkey is required to validate P2WPKH\n    // payout addresses; the x-only form on `popSignature` would let an\n    // attacker substitute the opposite-parity P2WPKH address.\n    const verifiedBtcPubkeyRaw =\n      await this.assertPopMatchesBtcWallet(popSignature);\n    const btcPopSignature = popSignature.btcPopSignature;\n\n    // Step 2: Resolve per-request payout scriptPubKey. The verified pubkey\n    // comes from the just-checked PoP; `depositorPayoutBtcAddress` is\n    // required per-request, so no wallet read is needed here.\n    const resolvedPayoutScripts: Hex[] = requests.map((req) =>\n      this.resolvePayoutScriptPubKey(\n        verifiedBtcPubkeyRaw,\n        req.depositorPayoutBtcAddress,\n      ),\n    );\n\n    // Step 3: Pre-compute vault IDs and check for duplicates\n    const vaultResults: BatchPeginResultItem[] = [];\n    for (const req of requests) {\n      const depositorSignedPeginTxHex = ensureHexPrefix(\n        req.depositorSignedPeginTx,\n      );\n      const peginTxHash = calculateBtcTxHash(depositorSignedPeginTxHex);\n      const derivedVaultIdHex = await deriveVaultId(\n        stripHexPrefix(peginTxHash),\n        stripHexPrefix(depositorEthAddress),\n      );\n      const vaultId = ensureHexPrefix(derivedVaultIdHex) as Hex;\n      const exists = await this.checkVaultExists(vaultId);\n      if (exists) {\n        throw new Error(\n          `Vault already exists (ID: ${vaultId}, peginTxHash: ${peginTxHash}). ` +\n            `To create a new vault, use different UTXOs or a different amount.`,\n        );\n      }\n      vaultResults.push({ vaultId, peginTxHash });\n    }\n\n    // Step 4: Query pegin fee, compute total, and read current VP commission.\n    // Commission read happens at submit time per the validation-layer rule.\n    const publicClient = this.config.publicClient;\n\n    let peginFee: bigint;\n    try {\n      peginFee = (await publicClient.readContract({\n        address: this.config.vaultContracts.btcVaultRegistry,\n        abi: BTCVaultRegistryABI,\n        functionName: \"getPegInFee\",\n        args: [vaultProvider],\n      })) as bigint;\n    } catch (error) {\n      throw new Error(\n        \"Failed to query pegin fee from the contract. \" +\n          \"Please check your network connection and that the contract address is correct.\",\n        { cause: error },\n      );\n    }\n    const totalFee = peginFee * BigInt(requests.length);\n\n    const maxAcceptableCommissionBps =\n      await this.resolveMaxAcceptableCommissionBps(\n        vaultProvider,\n        params.quotedCommissionBps,\n      );\n\n    // Step 5: Build BatchPeginRequest[] tuple array. Depositor BTC pubkey,\n    // PoP, and Pre-PegIn tx hex are shared across the batch (carried on\n    // the top-level params / PopSignature, not per request).\n    const depositorBtcPubkeyHex = ensureHexPrefix(\n      popSignature.depositorBtcPubkey,\n    ) as Hex;\n    const unsignedPrePeginTxHex = ensureHexPrefix(unsignedPrePeginTx) as Hex;\n    const batchRequests = requests.map((req, i) => ({\n      depositorBtcPubKey: depositorBtcPubkeyHex,\n      btcPopSignature,\n      unsignedPrePeginTx: unsignedPrePeginTxHex,\n      depositorSignedPeginTx: ensureHexPrefix(\n        req.depositorSignedPeginTx,\n      ) as Hex,\n      hashlock: req.hashlock,\n      htlcVout: req.htlcVout,\n      referralCode: NO_REFERRAL_CODE,\n      depositorPayoutBtcAddress: resolvedPayoutScripts[i],\n      depositorWotsPkHash: req.depositorWotsPkHash,\n    }));\n\n    // Step 6: Encode batch call data\n    const callData = encodeFunctionData({\n      abi: BTCVaultRegistryABI,\n      functionName: \"submitPeginRequestBatch\",\n      args: [\n        depositorEthAddress,\n        vaultProvider,\n        maxAcceptableCommissionBps,\n        batchRequests,\n      ],\n    });\n\n    // Step 7: Estimate gas\n    let gasEstimate: bigint;\n    try {\n      gasEstimate = await publicClient.estimateGas({\n        to: this.config.vaultContracts.btcVaultRegistry,\n        data: callData,\n        value: totalFee,\n        account: this.config.ethWallet.account.address,\n      });\n    } catch (error) {\n      handleContractError(error); // always throws (return type: never)\n    }\n\n    // Step 8: Submit batch transaction\n    let ethTxHash: Hex;\n    try {\n      ethTxHash = await this.config.ethWallet.sendTransaction({\n        to: this.config.vaultContracts.btcVaultRegistry,\n        data: callData,\n        value: totalFee,\n        account: this.config.ethWallet.account,\n        chain: this.config.ethChain,\n        gas: gasEstimate,\n      });\n    } catch (error) {\n      handleContractError(error); // always throws (return type: never)\n    }\n\n    // Step 9: Wait for receipt\n    // Use the smart-account-aware wrapper so Safe-style wallets (whose\n    // `eth_sendTransaction` returns a `safeTxHash`, not a real tx hash) work\n    // alongside Externally Owned Accounts (EOAs — wallets controlled by a\n    // single private key, e.g. MetaMask). The EOA path is unchanged.\n    const receipt = await waitForTransactionReceiptSmartAware({\n      publicClient,\n      walletAddress: this.config.ethWallet.account.address,\n      hash: ethTxHash,\n      timeout: RECEIPT_TIMEOUT_MS,\n    });\n    if (receipt.status === \"reverted\") {\n      handleContractError(\n        new Error(\n          `Batch transaction reverted. Hash: ${receipt.transactionHash}. ` +\n            `Check the transaction on block explorer for details.`,\n        ),\n      );\n    }\n\n    return {\n      ethTxHash: receipt.transactionHash,\n      vaults: vaultResults,\n    };\n  }\n\n  // Anchor to quoted+headroom when supplied (refuse if chain drifted past it);\n  // otherwise fall back to chain-current+headroom — see #1691.\n  private async resolveMaxAcceptableCommissionBps(\n    vaultProvider: Address,\n    quotedCommissionBps?: number,\n  ): Promise<number> {\n    // Approval-capable wallets froze the ceiling on-device at prepare time\n    // (DepositTerms.commissionFee from the quoted bps). The chain-current\n    // fallback could exceed that approved ceiling, letting registration\n    // admit a commission the device would refuse to pay out — require the\n    // same quote instead.\n    if (\n      quotedCommissionBps === undefined &&\n      supportsDepositApproval(this.config.btcWallet)\n    ) {\n      throw new Error(\n        \"quotedCommissionBps is required when the wallet approved deposit \" +\n          \"terms: the registration ceiling must anchor to the approved quote.\",\n      );\n    }\n    let currentBps: number;\n    try {\n      const reader = new ViemVaultRegistryReader(\n        this.config.publicClient,\n        this.config.vaultContracts.btcVaultRegistry,\n      );\n      currentBps = await reader.getVaultProviderCommission(vaultProvider);\n    } catch (error) {\n      throw new Error(\n        \"Failed to query vault provider commission from the contract. \" +\n          \"Please check your network connection and that the contract address is correct.\",\n        { cause: error },\n      );\n    }\n\n    if (quotedCommissionBps !== undefined) {\n      if (currentBps > quotedCommissionBps + COMMISSION_BPS_HEADROOM) {\n        throw new Error(\n          `Vault provider commission changed since quote: quoted ${quotedCommissionBps} bps, ` +\n            `chain currently reports ${currentBps} bps (allowed drift ${COMMISSION_BPS_HEADROOM} bps). ` +\n            `Please refresh to see the new commission and try again.`,\n        );\n      }\n      return capMaxAcceptableCommissionBps(quotedCommissionBps);\n    }\n\n    return capMaxAcceptableCommissionBps(currentBps);\n  }\n\n  /**\n   * Check if a vault already exists for a given vault ID.\n   *\n   * The contract returns a default struct (with `depositor === zeroAddress`)\n   * when no vault is registered, so existence is signalled in the response,\n   * not via a thrown error. RPC/network failures are propagated rather than\n   * silently treated as \"vault doesn't exist\", which would otherwise let\n   * downstream calls run with stale assumptions.\n   *\n   * @param vaultId - The Bitcoin transaction hash (vault ID)\n   * @returns True if vault exists, false otherwise\n   * @throws If the underlying RPC read fails\n   */\n  private async checkVaultExists(vaultId: Hex): Promise<boolean> {\n    const publicClient = this.config.publicClient;\n\n    const result = (await publicClient.readContract({\n      address: this.config.vaultContracts.btcVaultRegistry,\n      abi: BTCVaultRegistryABI,\n      functionName: \"getBtcVaultBasicInfo\",\n      args: [vaultId],\n    })) as { depositor: Address };\n\n    return result.depositor !== zeroAddress;\n  }\n\n  /**\n   * Resolve the BTC scriptPubKey to register as the depositor's payout sink.\n   *\n   * `address` is validated against the verified depositor pubkey, sourced\n   * from `assertPopMatchesBtcWallet`'s return value rather than\n   * `popSignature.depositorBtcPubkey` (which is x-only, parity stripped).\n   * For wallets that expose a compressed key this preserves y-parity end to\n   * end. For Taproot wallets that only expose an x-only key, the helper\n   * itself fails closed for P2WPKH — the parity is unknowable, so the\n   * payout sink must be a P2TR address derived from that same x.\n   *\n   * The helper does not call into the wallet so the batch path can resolve\n   * many requests without any extra adapter reads. Threat closed: a\n   * state-race or stale FE state that lets a non-wallet address reach the\n   * on-chain payout-script registration.\n   */\n  private resolvePayoutScriptPubKey(\n    verifiedDepositorBtcPubkeyRaw: string,\n    address: string,\n  ): Hex {\n    if (\n      !isAddressFromPublicKey(\n        address,\n        verifiedDepositorBtcPubkeyRaw,\n        this.config.btcNetwork,\n      )\n    ) {\n      // Diagnostic carve-out: x-only key + P2WPKH address always fails (y-parity\n      // is unknowable from x-only). Surface a specific, actionable message so\n      // Taproot-wallet integrators don't have to chase the generic mismatch.\n      const isXOnlyKey =\n        stripHexPrefix(verifiedDepositorBtcPubkeyRaw).length ===\n        X_ONLY_PUBKEY_HEX_LEN;\n      if (\n        isXOnlyKey &&\n        isP2wpkhAddressForNetwork(address, this.config.btcNetwork)\n      ) {\n        throw new Error(\n          `BTC payout address \"${address}\" is a P2WPKH (Native SegWit) address, ` +\n            `but the connected wallet only exposes an x-only public key. ` +\n            `P2WPKH validation requires a compressed key with known y-parity. ` +\n            `Use a P2TR (Taproot) payout address instead.`,\n        );\n      }\n      throw new Error(\n        `BTC payout address \"${address}\" is not derived from the connected ` +\n          `wallet's public key. The payout sink must be controlled by the same ` +\n          `key that signs the pegin; refusing to register a mismatched address.`,\n      );\n    }\n\n    const network = getNetwork(this.config.btcNetwork);\n    try {\n      return `0x${bitcoin.address.toOutputScript(address, network).toString(\"hex\")}` as Hex;\n    } catch {\n      throw new Error(\n        `Invalid BTC payout address: \"${address}\". ` +\n          `Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`,\n      );\n    }\n  }\n\n  /**\n   * Sign a BIP-322 BTC Proof-of-Possession binding the connected BTC\n   * wallet to the connected ETH account for this chain and vault\n   * registry. The returned {@link PopSignature} can be reused across\n   * every register call in the same session.\n   *\n   * The witness is verified against the depositor key before it is\n   * returned — Schnorr for one-item (P2TR), ECDSA over the BIP-322\n   * P2WPKH virtual transaction for two-item — see {@link verifyPopWitness}.\n   *\n   * @throws If the wallet returns a malformed witness or a signature that\n   *         does not verify.\n   */\n  async signProofOfPossession(): Promise<PopSignature> {\n    if (!this.config.ethWallet.account) {\n      throw new Error(\"Ethereum wallet account not found\");\n    }\n    const depositorEthAddress = this.config.ethWallet.account.address;\n\n    const depositorBtcPubkey = normalizeXOnlyPubkey(\n      await this.config.btcWallet.getPublicKeyHex(),\n    );\n\n    // Message format matches BTCProofOfPossession.sol buildMessage()\n    const verifyingContract = this.config.vaultContracts.btcVaultRegistry;\n    const popMessage = `${depositorEthAddress.toLowerCase()}:${this.config.ethChain.id}:pegin:${verifyingContract.toLowerCase()}`;\n    const raw = await this.config.btcWallet.signMessage(\n      popMessage,\n      \"bip322-simple\",\n    );\n\n    const btcPopSignature = normalizePopSignature(raw);\n    // Fail before the Ethereum registration: vaultd rejects a bad PoP permanently.\n    // The verdict is informational — both shapes are fully verified, and\n    // anything invalid already threw.\n    verifyPopWitness(\n      new TextEncoder().encode(popMessage),\n      depositorBtcPubkey,\n      btcPopSignature,\n    );\n\n    return { btcPopSignature, depositorEthAddress, depositorBtcPubkey };\n  }\n\n  /**\n   * Confirm the connected BTC wallet still matches the PoP it produced, and\n   * return the wallet's *raw* pubkey hex (parity-preserving form, as the\n   * wallet adapter returns it). The raw form is required by callers that\n   * validate Native SegWit / P2WPKH addresses, since P2WPKH is derived from\n   * a parity-bearing compressed key — an x-only form would let an attacker\n   * substitute the opposite-parity P2WPKH address.\n   */\n  private async assertPopMatchesBtcWallet(\n    popSignature: PopSignature,\n  ): Promise<string> {\n    const currentBtcPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n    const currentBtcPubkey = normalizeXOnlyPubkey(currentBtcPubkeyRaw);\n    // Normalize the PoP-embedded key the same way in case a consumer\n    // serialized it through a path that changed casing or re-added 0x.\n    const popBtcPubkey = normalizeXOnlyPubkey(popSignature.depositorBtcPubkey);\n    if (currentBtcPubkey !== popBtcPubkey) {\n      throw new Error(\n        `Proof of possession was signed with BTC pubkey ${popBtcPubkey} ` +\n          `but the BTC wallet is currently connected to ${currentBtcPubkey}. ` +\n          `Reconnect the original wallet or call signProofOfPossession() again.`,\n      );\n    }\n    return currentBtcPubkeyRaw;\n  }\n\n  /**\n   * Gets the configured Bitcoin network.\n   *\n   * @returns The Bitcoin network (mainnet, testnet, signet, regtest)\n   */\n  getNetwork(): Network {\n    return this.config.btcNetwork;\n  }\n\n  /**\n   * Gets the configured BTCVaultRegistry contract address.\n   *\n   * @returns The Ethereum address of the BTCVaultRegistry contract\n   */\n  getVaultContractAddress(): Address {\n    return this.config.vaultContracts.btcVaultRegistry;\n  }\n}\n\n/**\n * Representative byte lengths used by {@link estimateSubmitPeginRequestBatchGas}\n * when synthesizing calldata before the depositor has signed anything. Sized\n * to approximate the real broadcast values so EIP-2028 calldata gas (16 per\n * non-zero byte, 4 per zero byte) lands close to the real estimate.\n */\nconst DUMMY_POP_SIGNATURE_BYTES = 80;\nconst DUMMY_UNSIGNED_PRE_PEGIN_TX_BYTES = 250;\nconst DUMMY_SIGNED_PEGIN_TX_BYTES = 300;\nconst DUMMY_PAYOUT_SCRIPTPUBKEY_BYTES = 22;\nconst DUMMY_FILLER_BYTE = \"ab\";\n\n/**\n * Build a `depositorSignedPeginTx` placeholder whose derived vault ID is\n * unique to (depositor, batch index). Real BTC transactions parse the txid\n * from their byte content, so embedding the depositor address + index makes\n * every dummy request produce a vault ID outside the user's existing set —\n * the contract's vault-uniqueness check then doesn't revert during\n * `estimateGas`.\n */\nfunction buildDummyDepositorSignedPeginTx(\n  depositorEthAddress: Address,\n  index: number,\n): Hex {\n  const filler = DUMMY_FILLER_BYTE.repeat(DUMMY_SIGNED_PEGIN_TX_BYTES);\n  const addressBytes = stripHexPrefix(depositorEthAddress).toLowerCase();\n  const indexBytes = index.toString(16).padStart(8, \"0\");\n  const marker = `${addressBytes}${indexBytes}`;\n  const suffix = filler.slice(marker.length);\n  return `0x${marker}${suffix}` as Hex;\n}\n\nfunction buildDummyBatchPeginRequest(\n  depositorEthAddress: Address,\n  index: number,\n): {\n  depositorBtcPubKey: Hex;\n  btcPopSignature: Hex;\n  unsignedPrePeginTx: Hex;\n  depositorSignedPeginTx: Hex;\n  hashlock: Hex;\n  htlcVout: number;\n  referralCode: number;\n  depositorPayoutBtcAddress: Hex;\n  depositorWotsPkHash: Hex;\n} {\n  const repeat = (bytes: number): Hex =>\n    `0x${DUMMY_FILLER_BYTE.repeat(bytes)}` as Hex;\n\n  return {\n    depositorBtcPubKey: repeat(32),\n    btcPopSignature: repeat(DUMMY_POP_SIGNATURE_BYTES),\n    unsignedPrePeginTx: repeat(DUMMY_UNSIGNED_PRE_PEGIN_TX_BYTES),\n    depositorSignedPeginTx: buildDummyDepositorSignedPeginTx(\n      depositorEthAddress,\n      index,\n    ),\n    hashlock: repeat(32),\n    htlcVout: index,\n    referralCode: NO_REFERRAL_CODE,\n    depositorPayoutBtcAddress: repeat(DUMMY_PAYOUT_SCRIPTPUBKEY_BYTES),\n    depositorWotsPkHash: repeat(32),\n  };\n}\n\nexport interface EstimateSubmitPeginRequestBatchGasParams {\n  publicClient: PublicClient;\n  btcVaultRegistry: Address;\n  depositorEthAddress: Address;\n  vaultProvider: Address;\n  batchSize: number;\n}\n\n/**\n * Estimate gas for a `submitPeginRequestBatch` call before the depositor has\n * signed anything. Synthesizes calldata using representative dummy bytes for\n * fields the depositor would normally produce (signed PegIn tx, PoP sig,\n * WOTS hash, payout script). The estimate is approximate — calldata-byte\n * gas is correct, contract-side branches that depend on the real values may\n * diverge — but it lands within the usual gas-estimate margin.\n *\n * Passes {@link MAX_ACCEPTABLE_COMMISSION_BPS_CAP} for the\n * `maxAcceptableCommissionBps` argument so the simulation does not revert on\n * the contract's commission-drift check regardless of the VP's current\n * commission. The real submit path resolves an accurate, drift-checked value\n * via {@link PeginManager.resolveMaxAcceptableCommissionBps}.\n *\n * Throws if the contract reverts during simulation; callers should treat the\n * thrown error as \"unable to estimate\" and decide how to surface it.\n */\nexport async function estimateSubmitPeginRequestBatchGas(\n  params: EstimateSubmitPeginRequestBatchGasParams,\n): Promise<bigint> {\n  const {\n    publicClient,\n    btcVaultRegistry,\n    depositorEthAddress,\n    vaultProvider,\n    batchSize,\n  } = params;\n\n  if (batchSize <= 0) {\n    throw new Error(\n      `estimateSubmitPeginRequestBatchGas requires batchSize >= 1 (received ${batchSize})`,\n    );\n  }\n\n  const peginFee = (await publicClient.readContract({\n    address: btcVaultRegistry,\n    abi: BTCVaultRegistryABI,\n    functionName: \"getPegInFee\",\n    args: [vaultProvider],\n  })) as bigint;\n  const totalFee = peginFee * BigInt(batchSize);\n\n  const requests = Array.from({ length: batchSize }, (_, i) =>\n    buildDummyBatchPeginRequest(depositorEthAddress, i),\n  );\n\n  const callData = encodeFunctionData({\n    abi: BTCVaultRegistryABI,\n    functionName: \"submitPeginRequestBatch\",\n    args: [\n      depositorEthAddress,\n      vaultProvider,\n      MAX_ACCEPTABLE_COMMISSION_BPS_CAP,\n      requests,\n    ],\n  });\n\n  return publicClient.estimateGas({\n    to: btcVaultRegistry,\n    data: callData,\n    value: totalFee,\n    account: depositorEthAddress,\n  });\n}\n"],"names":["U32_MASK64","_32n","fromBig","n","le","split","lst","len","Ah","Al","i","h","l","rotlSH","s","rotlSL","rotlBH","rotlBL","TXID_HEX_LENGTH","buildDepositTerms","inputs","txid","MAX_VP_COMMISSION_BPS_EXCLUSIVE","bpsDenominator","BPS_DENOMINATOR","vaults","peginAmount","index","COMMISSION_BPS_HEADROOM","MAX_ACCEPTABLE_COMMISSION_BPS_CAP","capMaxAcceptableCommissionBps","bps","HEX_SIGNATURE_REGEX","UNPREFIXED_HEX_SIGNATURE_REGEX","BASE64_SIGNATURE_REGEX","normalizeXOnlyPubkey","raw","processPublicKeyToXOnly","normalizePopSignature","bytes","Buffer","ensurePrePeginTermsApproval","params","wallet","depositTerms","fundedPrePeginTxHex","depositorBtcPubkey","approveDepositTerms","cleanHex","Transaction","holdsApproval","fundingOutpoints","parseFundingOutpointsFromTx","deriveVaultRoot","hexToUint8Array","Rho160","Id160","_","Pi160","idxLR","res","j","k","idxL","idxR","shifts160","shiftsL160","idx","shiftsR160","Kl160","Kr160","ripemd_f","group","x","y","z","BUF_160","_RIPEMD160","HashMD","__publicField","h0","h1","h2","h3","h4","view","offset","al","ar","bl","br","cl","cr","dl","dr","el","er","rGroup","hbl","hbr","rl","rr","sl","sr","tl","rotl","tr","clean","ripemd160","createHasher","_0n","_1n","_2n","_7n","_256n","_0x71n","SHA3_PI","SHA3_ROTL","_SHA3_IOTA","round","R","t","IOTAS","SHA3_IOTA_H","SHA3_IOTA_L","rotlH","rotlL","keccakP","rounds","B","idx1","idx0","B0","B1","Th","Tl","curH","curL","shift","PI","Keccak","blockLen","suffix","outputLen","enableXOF","anumber","u32","swap32IfBE","data","aexists","abytes","state","pos","take","out","bufferOut","aoutput","to","genKeccak","info","keccak_256","WOTS_SEED_SIZE","CHAIN_ELEMENT_SIZE","WOTS_DIGIT_BITS","WOTS_CHECKSUM_DIGITS","CHECKSUM_MINOR_DIGIT_INDEX","CHECKSUM_MAJOR_DIGIT_INDEX","ASSERT_WOTS_BLOCK_DIGIT_COUNTS","toHex","b","hash160","sha256","maxDigitValue","d","defaultChecksumRadix","wMax","radix","createWotsConfig","chainStartForDigit","seed","digitIndex","suffixBytes","preimage","computeChainTerminal","start","steps","current","deriveBlockPublicKey","blockSeed","config","checksumMinorMax","checksumMajorMax","messageTerminals","digit","terminal","checksumMinorStart","checksumMinorTerminal","checksumMajorStart","checksumMajorTerminal","deriveWotsBlocksFromSeed","blocks","blockIdx","blockSeedInput","block","validateTerminal","label","computeWotsBlockPublicKeysHash","publicKeys","pk","totalTips","buffer","digest","expandPerVaultSecrets","root","vaultCount","perVaultWotsKeys","wotsPkHashes","htlcSecretHexes","hashlocks","wotsSeed","expandWotsSeed","wotsPublicKeys","secretBytes","expandHashlockSecret","secretHex","uint8ArrayToHex","computeHashlock","ensureHexPrefix","P2TR_WITNESS_ITEMS","P2WPKH_WITNESS_ITEMS","COMPRESSED_PUBKEY_BYTES","SEC1_EVEN_Y_PREFIX","SEC1_ODD_Y_PREFIX","SEC1_PREFIX_BYTES","SCHNORR_SIG_BYTES","SIGHASH_DEFAULT","SIGHASH_ALL","X_ONLY_PUBKEY_HEX","WITNESS_BODY_HEX","decodeWitnessItems","witnessHex","body","decodeWitnessStack","verifyPopWitness","messageBytes","depositorXOnlyHex","items","item","signature","hashType","xOnly","verifyBip322Simple","encodedSignature","pubkey","_a","ecc","witnessXOnlyHex","P2WPKH_ENCODED_SIG_MIN","P2WPKH_ENCODED_SIG_MAX","verifyBip322P2wpkhSimple","NO_REFERRAL_CODE","SIZING_PASS_PLACEHOLDER_BYTES32_HEX","PROVISIONAL_TERMS_PLACEHOLDER_TXID_HEX","isP2wpkhAddressForNetwork","address","network","expectedHrp","decoded","bitcoin","resolveUtxoInfo","vout","localPrevouts","apiUrl","local","getUtxoInfo","RECEIPT_TIMEOUT_MS","PeginManager","depositorBtcPubkeyRaw","supportsDepositApproval","walletChange","requireChangeAddress","isAddressFromPublicKey","sizing","validateDepositTerms","u","authAnchorHex","authAnchorHash","authAnchorBytes","expandAuthAnchor","err","derived","commit","assertAuthAnchorOpReturn","commitTransaction","placeholderHashlocks","numLocalChallengers","prePegin","buildPrePeginPsbt","stripHexPrefix","selection","selectUtxosForPegin","peginOutputCount","args","placeholderLower","vaultProviderBtcPubkey","vaultKeeperBtcPubkeys","universalChallengerBtcPubkeys","prePeginParams","prePeginResult","getNetwork","fundPeginTransaction","fundedFee","sum","prePeginTxid","calculateBtcTxHash","peginTxResults","psbtsToSign","signOptions","peginTxResult","buildPeginTxFromFundedPrePegin","peginInputPsbtResult","buildPeginInputPsbt","createTaprootScriptPathSignOptions","signedPsbts","signPsbtsWithFallback","perVault","assertPsbtUnsignedTxMatches","peginInputSignature","extractPeginInputSignature","assertScriptPathSchnorrSignature","depositorSignedPeginTxHex","finalizePeginInputPsbt","tx","psbt","Psbt","publicKeyNoCoord","utxoDataPromises","input","utxoData","inputsWithUtxoData","totalInputValue","totalOutputValue","impliedFee","MAX_REASONABLE_FEE_SATS","psbtInputFields","getPsbtInputFields","output","requestedPsbtHex","signedPsbtHex","verifiedInputs","assertReturnedKeyPathSignatures","signedPsbt","e","inp","signedTxHex","pushTx","unsignedPrePeginTx","depositorSignedPeginTx","vaultProvider","hashlock","htlcVout","depositorPayoutBtcAddress","depositorWotsPkHash","popSignature","depositorEthAddress","isAddressEqual","verifiedBtcPubkeyRaw","btcPopSignature","depositorBtcPubkeyHex","unsignedPrePeginTxHex","resolvedPayoutAddress","payoutScriptPubKey","peginTxHash","derivedVaultIdHex","deriveVaultId","vaultId","publicClient","peginFee","BTCVaultRegistryABI","error","maxAcceptableCommissionBps","callData","encodeFunctionData","gasEstimate","handleContractError","ethTxHash","receipt","waitForTransactionReceiptSmartAware","requests","resolvedPayoutScripts","req","vaultResults","totalFee","batchRequests","quotedCommissionBps","currentBps","ViemVaultRegistryReader","zeroAddress","verifiedDepositorBtcPubkeyRaw","X_ONLY_PUBKEY_HEX_LEN","verifyingContract","popMessage","currentBtcPubkeyRaw","currentBtcPubkey","popBtcPubkey","DUMMY_POP_SIGNATURE_BYTES","DUMMY_UNSIGNED_PRE_PEGIN_TX_BYTES","DUMMY_SIGNED_PEGIN_TX_BYTES","DUMMY_PAYOUT_SCRIPTPUBKEY_BYTES","DUMMY_FILLER_BYTE","buildDummyDepositorSignedPeginTx","filler","addressBytes","indexBytes","marker","buildDummyBatchPeginRequest","repeat","estimateSubmitPeginRequestBatchGas","btcVaultRegistry","batchSize"],"mappings":"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","x_google_ignoreList":[0,5,6]}