@babylonlabs-io/ts-sdk 6.0.2 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/{BTCVaultRegistry.abi-DnP4UkB5.js → BTCVaultRegistry.abi-C19m1l4i.js} +42 -1
  2. package/dist/{BTCVaultRegistry.abi-DnP4UkB5.js.map → BTCVaultRegistry.abi-C19m1l4i.js.map} +1 -1
  3. package/dist/{BTCVaultRegistry.abi-DzbfZ9_s.cjs → BTCVaultRegistry.abi-C4bQi-H9.cjs} +2 -2
  4. package/dist/{BTCVaultRegistry.abi-DzbfZ9_s.cjs.map → BTCVaultRegistry.abi-C4bQi-H9.cjs.map} +1 -1
  5. package/dist/PayoutManager-3-MzBVLj.js.map +1 -1
  6. package/dist/PayoutManager-PQqeqX41.cjs.map +1 -1
  7. package/dist/{PeginManager-D_ZUfbIy.cjs → PeginManager-BNJUATq2.cjs} +2 -2
  8. package/dist/PeginManager-BNJUATq2.cjs.map +1 -0
  9. package/dist/{PeginManager-m3IlM4wS.js → PeginManager-p88tE5r2.js} +4 -4
  10. package/dist/PeginManager-p88tE5r2.js.map +1 -0
  11. package/dist/ProtocolParams.abi-DzjpPHcl.cjs +2 -0
  12. package/dist/ProtocolParams.abi-DzjpPHcl.cjs.map +1 -0
  13. package/dist/{ProtocolParams.abi-CuDl7AuC.js → ProtocolParams.abi-vMl0TZ2q.js} +6 -1
  14. package/dist/ProtocolParams.abi-vMl0TZ2q.js.map +1 -0
  15. package/dist/VaultErrors.abi-BIY0p6Wn.js +5 -0
  16. package/dist/{VaultErrors.abi-Dc3UnB_h.js.map → VaultErrors.abi-BIY0p6Wn.js.map} +1 -1
  17. package/dist/VaultErrors.abi-BV0qeG6M.cjs +2 -0
  18. package/dist/{VaultErrors.abi-Hjn1CdLs.cjs.map → VaultErrors.abi-BV0qeG6M.cjs.map} +1 -1
  19. package/dist/{buildAndBroadcastReclaim-CMjlyooo.cjs → buildAndBroadcastReclaim-Blxt7B0K.cjs} +2 -2
  20. package/dist/{buildAndBroadcastReclaim-D8l-QJWo.js.map → buildAndBroadcastReclaim-Blxt7B0K.cjs.map} +1 -1
  21. package/dist/{buildAndBroadcastReclaim-D8l-QJWo.js → buildAndBroadcastReclaim-C2CkzCVn.js} +3 -3
  22. package/dist/buildAndBroadcastReclaim-C2CkzCVn.js.map +1 -0
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.js +9 -9
  25. package/dist/{pegin-registration-client-BlrXyZpF.js → pegin-registration-client-B8A4P-Vv.js} +232 -205
  26. package/dist/pegin-registration-client-B8A4P-Vv.js.map +1 -0
  27. package/dist/pegin-registration-client-JtZkosZQ.cjs +2 -0
  28. package/dist/pegin-registration-client-JtZkosZQ.cjs.map +1 -0
  29. package/dist/{signer-set-reader-Csz8RXQi.js → signer-set-reader-BJ3g6rid.js} +3 -3
  30. package/dist/{signer-set-reader-Csz8RXQi.js.map → signer-set-reader-BJ3g6rid.js.map} +1 -1
  31. package/dist/{signer-set-reader-CNEfzwuA.cjs → signer-set-reader-C8xSyTMb.cjs} +2 -2
  32. package/dist/{signer-set-reader-CNEfzwuA.cjs.map → signer-set-reader-C8xSyTMb.cjs.map} +1 -1
  33. package/dist/tbv/core/clients/eth/index.cjs +1 -1
  34. package/dist/tbv/core/clients/eth/index.js +3 -3
  35. package/dist/tbv/core/clients/eth/pegin-registration-client.d.ts.map +1 -1
  36. package/dist/tbv/core/clients/eth/protocol-params-reader.d.ts +1 -1
  37. package/dist/tbv/core/clients/eth/protocol-params-reader.d.ts.map +1 -1
  38. package/dist/tbv/core/clients/eth/types.d.ts +11 -1
  39. package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
  40. package/dist/tbv/core/clients/index.cjs +1 -1
  41. package/dist/tbv/core/clients/index.js +3 -3
  42. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts +34 -0
  43. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts.map +1 -1
  44. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts +4 -0
  45. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts.map +1 -1
  46. package/dist/tbv/core/contracts/abis/vaultErrors.abi.json.d.ts +1 -1
  47. package/dist/tbv/core/contracts/index.cjs +1 -1
  48. package/dist/tbv/core/contracts/index.js +3 -3
  49. package/dist/tbv/core/deposit-terms/depositTerms.d.ts +3 -3
  50. package/dist/tbv/core/deposit-terms/prePeginApproval.d.ts +2 -2
  51. package/dist/tbv/core/index.cjs +1 -1
  52. package/dist/tbv/core/index.js +9 -9
  53. package/dist/tbv/core/managers/index.cjs +1 -1
  54. package/dist/tbv/core/managers/index.js +1 -1
  55. package/dist/tbv/core/primitives/psbt/__tests__/depositorClaim.test.d.ts +1 -1
  56. package/dist/tbv/core/primitives/psbt/payout.d.ts +2 -1
  57. package/dist/tbv/core/primitives/psbt/payout.d.ts.map +1 -1
  58. package/dist/tbv/core/services/index.cjs +1 -1
  59. package/dist/tbv/core/services/index.js +1 -1
  60. package/dist/tbv/index.cjs +1 -1
  61. package/dist/tbv/index.js +9 -9
  62. package/dist/{toRefundInputs-D5tx3eeA.js → toRefundInputs-CZ9aqp2o.js} +2 -2
  63. package/dist/{toRefundInputs-D5tx3eeA.js.map → toRefundInputs-CZ9aqp2o.js.map} +1 -1
  64. package/dist/{toRefundInputs-Df6eRITl.cjs → toRefundInputs-CzZujjq-.cjs} +2 -2
  65. package/dist/{toRefundInputs-Df6eRITl.cjs.map → toRefundInputs-CzZujjq-.cjs.map} +1 -1
  66. package/dist/types-Bt1FM6d8.cjs +2 -0
  67. package/dist/types-Bt1FM6d8.cjs.map +1 -0
  68. package/dist/{types-K_aM5GZO.js → types-D7p5jFlm.js} +135 -62
  69. package/dist/types-D7p5jFlm.js.map +1 -0
  70. package/dist/verifyScriptPathSchnorrSignature-BVGPEZXW.js.map +1 -1
  71. package/dist/verifyScriptPathSchnorrSignature-p3sVoWQi.cjs.map +1 -1
  72. package/package.json +1 -1
  73. package/dist/PeginManager-D_ZUfbIy.cjs.map +0 -1
  74. package/dist/PeginManager-m3IlM4wS.js.map +0 -1
  75. package/dist/ProtocolParams.abi-CuDl7AuC.js.map +0 -1
  76. package/dist/ProtocolParams.abi-DWfIh6VH.cjs +0 -2
  77. package/dist/ProtocolParams.abi-DWfIh6VH.cjs.map +0 -1
  78. package/dist/VaultErrors.abi-Dc3UnB_h.js +0 -5
  79. package/dist/VaultErrors.abi-Hjn1CdLs.cjs +0 -2
  80. package/dist/buildAndBroadcastReclaim-CMjlyooo.cjs.map +0 -1
  81. package/dist/pegin-registration-client-BlrXyZpF.js.map +0 -1
  82. package/dist/pegin-registration-client-DOb-Iznp.cjs +0 -2
  83. package/dist/pegin-registration-client-DOb-Iznp.cjs.map +0 -1
  84. package/dist/types-BnZIbDHb.cjs +0 -2
  85. package/dist/types-BnZIbDHb.cjs.map +0 -1
  86. package/dist/types-K_aM5GZO.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babylonlabs-io/ts-sdk",
3
- "version": "6.0.2",
3
+ "version": "6.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1 +0,0 @@
1
- {"version":3,"file":"PeginManager-D_ZUfbIy.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/managers/pegin/normalizeWalletInputs.ts","../src/tbv/core/deposit-terms/prePeginApproval.ts","../../../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 * 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, so this path never approves-only: whether\n * the device still holds the approval is the wallet's to answer, through\n * `holdsApprovedDepositTerms`.\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 * 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 `BIG_BLOCK_DIGIT_COUNTS` (`crates/crypto/src/wots/mod.rs`).\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 isAddressEqual,\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 {\n ViemPeginRegistrationClient,\n type PopSignature,\n} from \"../clients/eth/pegin-registration-client\";\nimport { getUtxoInfo, pushTx, type UtxoInfo } from \"../clients/mempool\";\nimport type { WotsBlockPublicKey } from \"../clients/vault-provider/types\";\nimport {\n buildDepositTerms,\n capMaxAcceptableCommissionBps,\n ensurePrePeginTermsApproval,\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 extractPeginInputSignature,\n finalizePeginInputPsbt,\n type Network,\n type PrePeginParams,\n} from \"../primitives\";\nimport {\n hexToUint8Array,\n isAddressFromPublicKey,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../primitives/utils/bitcoin\";\nimport {\n calculateBtcTxHash,\n fundPeginTransaction,\n getNetwork,\n getPsbtInputFields,\n MAX_REASONABLE_FEE_SATS,\n peginOutputCount,\n selectUtxosForPegin,\n type UTXO,\n} from \"../utils\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\nimport { X_ONLY_PUBKEY_HEX_LEN } from \"../utils/validation\";\nimport {\n deriveVaultRoot,\n expandAuthAnchor,\n type FundingOutpoint,\n} from \"../vault-secrets\";\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 * One entry per vault; hashlocks are derived from the vault root, not passed in.\n * For single deposits, pass a single-element array.\n */\n amounts: readonly bigint[];\n\n /**\n * Vault provider's current RFC-006 operation key (x-only, 64-char hex), read\n * at the same pinned block as the rest of the deposit's protocol state:\n * `validateOnChainParticipantKeys(...).vaultProviderBtcPubkeyXOnly`. Not the\n * registration key, which differs from it once the provider has rotated, and\n * not the indexer's copy, which is only a hint.\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 keepers' current RFC-006 operation keys (x-only, 64-char hex), read\n * at the deposit's pinned block:\n * `validateOnChainParticipantKeys(...).vaultKeeperBtcPubkeysSorted`. Not the\n * roster's registration keys.\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n vaultKeeperBtcPubkeys: readonly string[];\n\n /**\n * Universal challengers' current RFC-006 operation keys (x-only, 64-char\n * hex), read at the deposit's pinned block:\n * `validateOnChainParticipantKeys(...).universalChallengerBtcPubkeysSorted`.\n * Not the roster's registration keys.\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 * 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 * Peg-in configuration fingerprint from the SDK's `computePeginFingerprint`,\n * computed over the same block-pinned protocol state the Pre-PegIn was built\n * against. The registry recomputes it at inclusion and reverts with\n * `PeginFingerprintChanged` if it moved.\n */\n expectedFingerprint: Hex;\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 * See {@link RegisterPeginParams.expectedFingerprint}. One value covers the\n * batch — the fingerprint has no per-request input and a batch fixes one\n * vault provider.\n */\n expectedFingerprint: Hex;\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 */\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, the BTC wallet account changes during\n * vault-root derivation, 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. The only\n // other read, right after derivation, is compared with it, never used.\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 // address the wallet's device accepts when it dictates one, else the\n // pubkey snapshot.\n if (supportsDepositApproval(this.config.btcWallet)) {\n // Approval (policy) wallets dictate their change address. Any other\n // change address fails mid-ceremony on the device, so this gate closes\n // that window before any approval screen.\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 // The root carries no trace of the account that derived it, yet every\n // on-chain commitment below comes from it. A wallet that switched account\n // during the derive would bind them to a key that cannot re-derive them\n // later, so refuse the root unless the wallet still reports the snapshot.\n try {\n const currentBtcPubkey = normalizeXOnlyPubkey(\n await this.config.btcWallet.getPublicKeyHex(),\n );\n if (currentBtcPubkey !== depositorBtcPubkey) {\n throw new Error(\n \"BTC wallet account changed during vault secret derivation. \" +\n \"The wallet no longer reports the account this deposit started with, \" +\n \"so the derived secrets cannot be used. Restart the deposit with the original account.\",\n );\n }\n } catch (err) {\n root.fill(0);\n throw err;\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 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(\n params.popSignature.depositorEthAddress,\n depositorEthAddress,\n )\n ) {\n throw new Error(\n `Proof of possession was signed for ${params.popSignature.depositorEthAddress} ` +\n `but the Ethereum wallet is currently connected to ${depositorEthAddress}. ` +\n `Reconnect the original account or call signProofOfPossession() again.`,\n );\n }\n const verifiedBtcPubkeyRaw = await this.assertPopMatchesBtcWallet(\n params.popSignature,\n );\n const resolvedPayoutAddress =\n params.depositorPayoutBtcAddress ??\n (await this.config.btcWallet.getAddress());\n const payoutScriptPubKey = this.resolvePayoutScriptPubKey(\n verifiedBtcPubkeyRaw,\n resolvedPayoutAddress,\n );\n return this.createRegistrationClient().registerPeginOnChain({\n unsignedPrePeginTx: params.unsignedPrePeginTx,\n depositorSignedPeginTx: params.depositorSignedPeginTx,\n vaultProvider: params.vaultProvider,\n hashlock: params.hashlock,\n htlcVout: params.htlcVout,\n depositorPayoutScriptPubKey: payoutScriptPubKey,\n depositorBtcPubkeyRaw: verifiedBtcPubkeyRaw,\n depositorWotsPkHash: params.depositorWotsPkHash,\n popSignature: params.popSignature,\n quotedCommissionBps: params.quotedCommissionBps,\n expectedFingerprint: params.expectedFingerprint,\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 if (params.requests.length === 0) {\n throw new Error(\"Batch pegin requires at least one request\");\n }\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(\n params.popSignature.depositorEthAddress,\n depositorEthAddress,\n )\n ) {\n throw new Error(\n `Proof of possession was signed for ${params.popSignature.depositorEthAddress} ` +\n `but the Ethereum wallet is currently connected to ${depositorEthAddress}. ` +\n `Reconnect the original account or call signProofOfPossession() again.`,\n );\n }\n const verifiedBtcPubkeyRaw = await this.assertPopMatchesBtcWallet(\n params.popSignature,\n );\n const resolvedPayoutScripts = params.requests.map((request) =>\n this.resolvePayoutScriptPubKey(\n verifiedBtcPubkeyRaw,\n request.depositorPayoutBtcAddress,\n ),\n );\n return this.createRegistrationClient().registerPeginBatchOnChain({\n vaultProvider: params.vaultProvider,\n unsignedPrePeginTx: params.unsignedPrePeginTx,\n popSignature: params.popSignature,\n depositorBtcPubkeyRaw: verifiedBtcPubkeyRaw,\n quotedCommissionBps: params.quotedCommissionBps,\n expectedFingerprint: params.expectedFingerprint,\n requests: params.requests.map((request, index) => ({\n depositorSignedPeginTx: request.depositorSignedPeginTx,\n hashlock: request.hashlock,\n htlcVout: request.htlcVout,\n depositorPayoutScriptPubKey: resolvedPayoutScripts[index],\n depositorWotsPkHash: request.depositorWotsPkHash,\n })),\n });\n }\n\n private createRegistrationClient(): ViemPeginRegistrationClient {\n return new ViemPeginRegistrationClient({\n ethWallet: this.config.ethWallet,\n ethChain: this.config.ethChain,\n publicClient: this.config.publicClient,\n btcVaultRegistry: this.config.vaultContracts.btcVaultRegistry,\n requireQuotedCommissionBps: supportsDepositApproval(\n this.config.btcWallet,\n ),\n });\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 ): string {\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 let outputScript: string;\n try {\n outputScript = bitcoin.address\n .toOutputScript(address, network)\n .toString(\"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 return outputScript;\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"],"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","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","_0n","_1n","_2n","_7n","_256n","_0x71n","SHA3_PI","SHA3_ROTL","_SHA3_IOTA","round","R","x","y","t","j","IOTAS","SHA3_IOTA_H","SHA3_IOTA_L","rotlH","rotlL","keccakP","rounds","B","idx1","idx0","B0","B1","Th","Tl","curH","curL","shift","PI","clean","Keccak","blockLen","suffix","outputLen","enableXOF","__publicField","anumber","u32","swap32IfBE","data","aexists","abytes","state","pos","take","out","bufferOut","aoutput","to","genKeccak","info","createHasher","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","ripemd160","sha256","maxDigitValue","d","defaultChecksumRadix","wMax","radix","createWotsConfig","chainStartForDigit","seed","digitIndex","suffixBytes","idx","preimage","computeChainTerminal","start","steps","current","deriveBlockPublicKey","blockSeed","config","k","checksumMinorMax","checksumMajorMax","messageTerminals","digit","terminal","checksumMinorStart","checksumMinorTerminal","checksumMajorStart","checksumMajorTerminal","deriveWotsBlocksFromSeed","blocks","blockIdx","blockSeedInput","block","validateTerminal","label","computeWotsBlockPublicKeysHash","publicKeys","pk","totalTips","buffer","offset","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","SIZING_PASS_PLACEHOLDER_BYTES32_HEX","PROVISIONAL_TERMS_PLACEHOLDER_TXID_HEX","isP2wpkhAddressForNetwork","address","network","expectedHrp","decoded","bitcoin","resolveUtxoInfo","vout","localPrevouts","apiUrl","local","getUtxoInfo","PeginManager","depositorBtcPubkeyRaw","supportsDepositApproval","walletChange","requireChangeAddress","isAddressFromPublicKey","sizing","validateDepositTerms","u","err","authAnchorHex","authAnchorHash","authAnchorBytes","expandAuthAnchor","derived","commit","assertAuthAnchorOpReturn","commitTransaction","placeholderHashlocks","numLocalChallengers","prePegin","buildPrePeginPsbt","stripHexPrefix","selection","selectUtxosForPegin","peginOutputCount","args","capMaxAcceptableCommissionBps","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","depositorEthAddress","isAddressEqual","verifiedBtcPubkeyRaw","resolvedPayoutAddress","payoutScriptPubKey","resolvedPayoutScripts","request","ViemPeginRegistrationClient","verifiedDepositorBtcPubkeyRaw","X_ONLY_PUBKEY_HEX_LEN","outputScript","verifyingContract","popMessage","btcPopSignature","popSignature","currentBtcPubkeyRaw","currentBtcPubkey","popBtcPubkey"],"mappings":"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","x_google_ignoreList":[0,4]}