@babylonlabs-io/ts-sdk 0.69.1 → 0.70.1

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 (93) hide show
  1. package/dist/{PeginManager-BI3pacy0.js → PeginManager-BNtg6jgY.js} +5 -5
  2. package/dist/{PeginManager-BI3pacy0.js.map → PeginManager-BNtg6jgY.js.map} +1 -1
  3. package/dist/{PeginManager-DZE2nnjt.cjs → PeginManager-CvI99Uhd.cjs} +2 -2
  4. package/dist/{PeginManager-DZE2nnjt.cjs.map → PeginManager-CvI99Uhd.cjs.map} +1 -1
  5. package/dist/{batchPoll-Bc_UKaTz.js → batchPoll-BM4iQ9jT.js} +3 -3
  6. package/dist/{batchPoll-Bc_UKaTz.js.map → batchPoll-BM4iQ9jT.js.map} +1 -1
  7. package/dist/{batchPoll-C9cZ5usJ.cjs → batchPoll-cqpEfBjr.cjs} +2 -2
  8. package/dist/{batchPoll-C9cZ5usJ.cjs.map → batchPoll-cqpEfBjr.cjs.map} +1 -1
  9. package/dist/buildAndBroadcastReclaim-iNJfx0ZG.cjs +2 -0
  10. package/dist/buildAndBroadcastReclaim-iNJfx0ZG.cjs.map +1 -0
  11. package/dist/{buildAndBroadcastRefund-DY4ZZcFL.js → buildAndBroadcastReclaim-kBHwOL02.js} +692 -598
  12. package/dist/buildAndBroadcastReclaim-kBHwOL02.js.map +1 -0
  13. package/dist/constants-BCdDRd_Y.cjs +2 -0
  14. package/dist/constants-BCdDRd_Y.cjs.map +1 -0
  15. package/dist/constants-DRiWbItj.js +24 -0
  16. package/dist/constants-DRiWbItj.js.map +1 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.js +256 -244
  19. package/dist/{mempoolApi-71R_CNZa.js → mempoolApi-CfOFmov6.js} +2 -2
  20. package/dist/{mempoolApi-71R_CNZa.js.map → mempoolApi-CfOFmov6.js.map} +1 -1
  21. package/dist/{mempoolApi-BJN9fGEd.cjs → mempoolApi-Q90mz17e.cjs} +2 -2
  22. package/dist/{mempoolApi-BJN9fGEd.cjs.map → mempoolApi-Q90mz17e.cjs.map} +1 -1
  23. package/dist/noPayout-BKP3mRu3.cjs +2 -0
  24. package/dist/noPayout-BKP3mRu3.cjs.map +1 -0
  25. package/dist/noPayout-BdATUPjF.js +280 -0
  26. package/dist/noPayout-BdATUPjF.js.map +1 -0
  27. package/dist/signPsbtsWithFallback-Bo1PJX90.cjs +2 -0
  28. package/dist/signPsbtsWithFallback-Bo1PJX90.cjs.map +1 -0
  29. package/dist/{signPsbtsWithFallback-DCZO2h6i.js → signPsbtsWithFallback-X6ivsbh7.js} +56 -47
  30. package/dist/signPsbtsWithFallback-X6ivsbh7.js.map +1 -0
  31. package/dist/tbv/core/clients/index.cjs +1 -1
  32. package/dist/tbv/core/clients/index.js +2 -2
  33. package/dist/tbv/core/index.cjs +1 -1
  34. package/dist/tbv/core/index.js +255 -243
  35. package/dist/tbv/core/managers/PayoutManager.d.ts.map +1 -1
  36. package/dist/tbv/core/managers/index.cjs +1 -1
  37. package/dist/tbv/core/managers/index.js +2 -2
  38. package/dist/tbv/core/primitives/index.cjs +1 -1
  39. package/dist/tbv/core/primitives/index.d.ts +4 -0
  40. package/dist/tbv/core/primitives/index.d.ts.map +1 -1
  41. package/dist/tbv/core/primitives/index.js +52 -46
  42. package/dist/tbv/core/primitives/psbt/__tests__/depositorClaim.test.d.ts +16 -0
  43. package/dist/tbv/core/primitives/psbt/__tests__/depositorClaim.test.d.ts.map +1 -0
  44. package/dist/tbv/core/primitives/psbt/__tests__/reclaim.test.d.ts +10 -0
  45. package/dist/tbv/core/primitives/psbt/__tests__/reclaim.test.d.ts.map +1 -0
  46. package/dist/tbv/core/primitives/psbt/constants.d.ts +7 -0
  47. package/dist/tbv/core/primitives/psbt/constants.d.ts.map +1 -1
  48. package/dist/tbv/core/primitives/psbt/depositorClaim.d.ts +47 -0
  49. package/dist/tbv/core/primitives/psbt/depositorClaim.d.ts.map +1 -0
  50. package/dist/tbv/core/primitives/psbt/pegin.d.ts.map +1 -1
  51. package/dist/tbv/core/primitives/psbt/reclaim.d.ts +93 -0
  52. package/dist/tbv/core/primitives/psbt/reclaim.d.ts.map +1 -0
  53. package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts.map +1 -1
  54. package/dist/tbv/core/services/index.cjs +1 -1
  55. package/dist/tbv/core/services/index.d.ts +1 -0
  56. package/dist/tbv/core/services/index.d.ts.map +1 -1
  57. package/dist/tbv/core/services/index.js +50 -44
  58. package/dist/tbv/core/services/reclaim/__tests__/buildAndBroadcastReclaim.test.d.ts +9 -0
  59. package/dist/tbv/core/services/reclaim/__tests__/buildAndBroadcastReclaim.test.d.ts.map +1 -0
  60. package/dist/tbv/core/services/reclaim/buildAndBroadcastReclaim.d.ts +79 -0
  61. package/dist/tbv/core/services/reclaim/buildAndBroadcastReclaim.d.ts.map +1 -0
  62. package/dist/tbv/core/services/reclaim/errors.d.ts +22 -0
  63. package/dist/tbv/core/services/reclaim/errors.d.ts.map +1 -0
  64. package/dist/tbv/core/services/reclaim/index.d.ts +9 -0
  65. package/dist/tbv/core/services/reclaim/index.d.ts.map +1 -0
  66. package/dist/tbv/index.cjs +1 -1
  67. package/dist/tbv/index.js +255 -243
  68. package/dist/{toRefundInputs-B62WZ9co.cjs → toRefundInputs-BJojfg3k.cjs} +2 -2
  69. package/dist/{toRefundInputs-B62WZ9co.cjs.map → toRefundInputs-BJojfg3k.cjs.map} +1 -1
  70. package/dist/{toRefundInputs-amYZu79x.js → toRefundInputs-DPNYBFkP.js} +4 -4
  71. package/dist/{toRefundInputs-amYZu79x.js.map → toRefundInputs-DPNYBFkP.js.map} +1 -1
  72. package/dist/{verifyScriptPathSchnorrSignature-Dy9gF5RF.js → verifyScriptPathSchnorrSignature-CQYucnJA.js} +143 -125
  73. package/dist/verifyScriptPathSchnorrSignature-CQYucnJA.js.map +1 -0
  74. package/dist/verifyScriptPathSchnorrSignature-D-ppKNjT.cjs +2 -0
  75. package/dist/verifyScriptPathSchnorrSignature-D-ppKNjT.cjs.map +1 -0
  76. package/package.json +1 -1
  77. package/dist/buildAndBroadcastRefund-CPPGvzXb.cjs +0 -2
  78. package/dist/buildAndBroadcastRefund-CPPGvzXb.cjs.map +0 -1
  79. package/dist/buildAndBroadcastRefund-DY4ZZcFL.js.map +0 -1
  80. package/dist/constants-DU5CGcqO.cjs +0 -2
  81. package/dist/constants-DU5CGcqO.cjs.map +0 -1
  82. package/dist/constants-GjWXdaqV.js +0 -23
  83. package/dist/constants-GjWXdaqV.js.map +0 -1
  84. package/dist/noPayout-CXn-geIS.js +0 -178
  85. package/dist/noPayout-CXn-geIS.js.map +0 -1
  86. package/dist/noPayout-Ox27Td9x.cjs +0 -2
  87. package/dist/noPayout-Ox27Td9x.cjs.map +0 -1
  88. package/dist/signPsbtsWithFallback-C5cVgYhh.cjs +0 -2
  89. package/dist/signPsbtsWithFallback-C5cVgYhh.cjs.map +0 -1
  90. package/dist/signPsbtsWithFallback-DCZO2h6i.js.map +0 -1
  91. package/dist/verifyScriptPathSchnorrSignature-Dy9gF5RF.js.map +0 -1
  92. package/dist/verifyScriptPathSchnorrSignature-la8XOAFm.cjs +0 -2
  93. package/dist/verifyScriptPathSchnorrSignature-la8XOAFm.cjs.map +0 -1
@@ -0,0 +1,280 @@
1
+ import { initWasm as N, WasmPrePeginTx as U, assertPositiveBigintArray as _, getPrePeginHtlcConnectorInfo as q, tapInternalPubkey as V, getAssertNoPayoutScriptInfo as M } from "@babylonlabs-io/babylon-tbv-rust-wasm";
2
+ import { Buffer as m } from "buffer";
3
+ import { Transaction as k, Psbt as R, payments as D } from "bitcoinjs-lib";
4
+ import { u as T, T as H, h as g, s as v, d as O, p as F, k as W } from "./bitcoin-Ch_jxnDa.js";
5
+ import { n as G, d as z, P as y } from "./verifyScriptPathSchnorrSignature-CQYucnJA.js";
6
+ import { D as B } from "./fundPeginTransaction-B2wyjqp0.js";
7
+ async function ae(o) {
8
+ await N();
9
+ const { prePeginParams: e, fundedPrePeginTxHex: s, htlcVout: t, refundFee: i, hashlock: c } = o, f = G(
10
+ e.authAnchorHash
11
+ ), n = new U(
12
+ e.vaultCoreVersion,
13
+ e.depositorPubkey,
14
+ e.vaultProviderPubkey,
15
+ e.vaultKeeperPubkeys,
16
+ e.universalChallengerPubkeys,
17
+ [...e.hashlocks],
18
+ new BigUint64Array(
19
+ _(e.pegInAmounts, "pegInAmounts")
20
+ ),
21
+ e.timelockRefund,
22
+ e.feeRate,
23
+ e.minPeginFeeRate,
24
+ e.numLocalChallengers,
25
+ e.councilQuorum,
26
+ e.councilSize,
27
+ e.network,
28
+ f
29
+ );
30
+ let r = null;
31
+ try {
32
+ const l = n.getHtlcScriptPubKey(t).toLowerCase(), w = n.getHtlcValue(t);
33
+ r = n.fromFundedTransaction(s);
34
+ const u = r.buildRefundTx(i, t), P = await q({
35
+ txGraphVersion: e.vaultCoreVersion,
36
+ depositorPubkey: e.depositorPubkey,
37
+ vaultProviderPubkey: e.vaultProviderPubkey,
38
+ vaultKeeperPubkeys: e.vaultKeeperPubkeys,
39
+ universalChallengerPubkeys: e.universalChallengerPubkeys,
40
+ hashlock: c,
41
+ timelockRefund: e.timelockRefund,
42
+ network: e.network
43
+ }), b = s.startsWith("0x") ? s.slice(2) : s, p = k.fromHex(b), d = p.outs[t];
44
+ if (!d)
45
+ throw new Error(
46
+ `HTLC output at vout ${t} not found in funded Pre-PegIn tx (tx has ${p.outs.length} outputs)`
47
+ );
48
+ const $ = T(
49
+ new Uint8Array(d.script)
50
+ ).toLowerCase();
51
+ if ($ !== l)
52
+ throw new Error(
53
+ `HTLC scriptPubKey mismatch at vout ${t}: reconstructed template expects ${l}, funded tx carries ${$}. Refund refused — the (hashlocks, pegInAmounts) vector does not match the on-chain commitment.`
54
+ );
55
+ const x = BigInt(d.value);
56
+ if (x !== w)
57
+ throw new Error(
58
+ `HTLC value mismatch at vout ${t}: reconstructed template expects ${w} sat, funded tx carries ${x} sat. Refund refused — the pegInAmounts vector does not match the on-chain commitment.`
59
+ );
60
+ const a = k.fromHex(u);
61
+ if (a.ins.length !== 1)
62
+ throw new Error(
63
+ `Refund transaction must have exactly 1 input, got ${a.ins.length}`
64
+ );
65
+ const h = a.ins[0], C = p.getId(), S = T(
66
+ new Uint8Array(h.hash).slice().reverse()
67
+ );
68
+ if (S !== C)
69
+ throw new Error(
70
+ `Refund input does not reference the Pre-PegIn transaction. Expected ${C}, got ${S}`
71
+ );
72
+ if (h.index !== t)
73
+ throw new Error(
74
+ `Refund input index ${h.index} does not match expected htlcVout ${t}`
75
+ );
76
+ const I = new R();
77
+ if (I.setVersion(a.version), I.setLocktime(a.locktime), I.addInput({
78
+ hash: h.hash,
79
+ index: h.index,
80
+ sequence: h.sequence,
81
+ witnessUtxo: {
82
+ script: d.script,
83
+ value: d.value
84
+ },
85
+ tapLeafScript: [
86
+ {
87
+ leafVersion: H,
88
+ script: m.from(g(P.refundScript)),
89
+ controlBlock: m.from(
90
+ g(P.refundControlBlock)
91
+ )
92
+ }
93
+ ],
94
+ tapInternalKey: m.from(V)
95
+ }), a.outs.length !== 1)
96
+ throw new Error(
97
+ `Refund transaction must have exactly 1 output, got ${a.outs.length}`
98
+ );
99
+ const E = a.outs[0], A = v(
100
+ O(e.depositorPubkey)
101
+ ).toLowerCase(), L = T(
102
+ new Uint8Array(E.script)
103
+ ).toLowerCase();
104
+ if (L !== A)
105
+ throw new Error(
106
+ `Refund output scriptPubKey ${L} does not match the depositor's BIP-86 address ${A}. Refund refused — the reclaimed funds would not return to the depositor.`
107
+ );
108
+ const K = x - i;
109
+ if (BigInt(E.value) !== K)
110
+ throw new Error(
111
+ `Refund output value ${BigInt(E.value)} sat does not equal the HTLC value ${x} sat minus the requested fee ${i} sat (expected ${K} sat). Refund refused — the reclaimed amount would be burned as excess fee.`
112
+ );
113
+ return I.addOutput({
114
+ script: E.script,
115
+ value: E.value
116
+ }), { psbtHex: I.toHex() };
117
+ } finally {
118
+ r == null || r.free(), n.free();
119
+ }
120
+ }
121
+ const X = 2, Q = 4294967293, Y = 214, j = 299, J = 4;
122
+ function Z(o) {
123
+ if (!Number.isInteger(o) || o < 1)
124
+ throw new Error(
125
+ `Reclaim input count must be a positive integer, got ${o}.`
126
+ );
127
+ return Math.ceil(
128
+ (Y + j * o) / J
129
+ );
130
+ }
131
+ function ie(o, e) {
132
+ if (!Number.isFinite(o) || o <= 0)
133
+ throw new Error(
134
+ `Reclaim fee rate must be a positive number, got ${o}.`
135
+ );
136
+ return BigInt(Math.ceil(o * Z(e)));
137
+ }
138
+ function ue(o) {
139
+ const { depositorPubkey: e, inputs: s, feeSats: t } = o;
140
+ if (s.length === 0)
141
+ throw new Error("Reclaim requires at least one input; got none.");
142
+ if (t <= 0n)
143
+ throw new Error(
144
+ `Reclaim fee must be positive, got ${t} sat. Refusing to build a transaction that would not relay.`
145
+ );
146
+ const i = z(e), c = T(
147
+ new Uint8Array(i.scriptPubKey)
148
+ ).toLowerCase(), f = new R();
149
+ f.setVersion(X), f.setLocktime(0);
150
+ let n = 0n;
151
+ const r = /* @__PURE__ */ new Set();
152
+ if (s.forEach((u, P) => {
153
+ const b = k.fromHex(
154
+ v(u.depositorSignedPeginTxHex)
155
+ ), p = b.getId(), d = b.outs[y];
156
+ if (!d)
157
+ throw new Error(
158
+ `PegIn ${p} has no output at vout ${y} (tx has ${b.outs.length}); there is no depositor-claim reserve to reclaim.`
159
+ );
160
+ const $ = T(
161
+ new Uint8Array(d.script)
162
+ ).toLowerCase();
163
+ if ($ !== c)
164
+ throw new Error(
165
+ `Input ${P}: PegIn ${p} vout ${y} pays ${$}, but the connected wallet's depositor-claim script is ${c}. Reclaim refused — this reserve belongs to a different wallet.`
166
+ );
167
+ const x = v(
168
+ u.observed.scriptPubKey
169
+ ).toLowerCase();
170
+ if (x !== c)
171
+ throw new Error(
172
+ `Input ${P}: the observed UTXO ${p}:${y} pays ${x}, expected ${c}. Reclaim refused — chain state disagrees with the contract's PegIn.`
173
+ );
174
+ const a = BigInt(d.value);
175
+ if (a !== u.observed.value)
176
+ throw new Error(
177
+ `Input ${P}: PegIn ${p} vout ${y} carries ${a} sat, but the observed UTXO carries ${u.observed.value} sat. Reclaim refused.`
178
+ );
179
+ if (a !== u.expectedValue)
180
+ throw new Error(
181
+ `Input ${P}: PegIn ${p} vout ${y} carries ${a} sat, but this vault's parameters compute a depositor-claim value of ${u.expectedValue} sat. Reclaim refused.`
182
+ );
183
+ const h = `${p}:${y}`;
184
+ if (r.has(h))
185
+ throw new Error(
186
+ `Input ${P} repeats outpoint ${h}, which is already being swept by an earlier input. Reclaim refused.`
187
+ );
188
+ r.add(h), n += a, f.addInput({
189
+ hash: p,
190
+ index: y,
191
+ sequence: Q,
192
+ witnessUtxo: { script: d.script, value: d.value },
193
+ tapLeafScript: [
194
+ {
195
+ leafVersion: H,
196
+ script: i.leafScript,
197
+ controlBlock: i.controlBlock
198
+ }
199
+ ],
200
+ tapInternalKey: i.internalKey
201
+ });
202
+ }), t >= n)
203
+ throw new Error(
204
+ `Reclaim fee ${t} sat is not less than the swept total ${n} sat. Refusing to build a transaction with no output.`
205
+ );
206
+ const l = n - t;
207
+ if (l <= B)
208
+ throw new Error(
209
+ `Reclaim output ${l} sat is at or below the dust threshold ${B} sat. The reserve is not at risk — it stays where it is until fee rates fall.`
210
+ );
211
+ const w = v(
212
+ O(e)
213
+ );
214
+ return f.addOutput({
215
+ script: m.from(g(w)),
216
+ value: Number(l)
217
+ }), { psbtHex: f.toHex(), outputValue: l, totalInputValue: n };
218
+ }
219
+ async function ce(o) {
220
+ const e = v(o.noPayoutTxHex), s = k.fromHex(e), { noPayoutScript: t, noPayoutControlBlock: i } = await M(
221
+ o.connectorParams,
222
+ o.challengerPubkey
223
+ ), c = g(t), f = g(i), n = new R();
224
+ n.setVersion(s.version), n.setLocktime(s.locktime);
225
+ for (let r = 0; r < s.ins.length; r++) {
226
+ const l = s.ins[r], w = o.prevouts[r];
227
+ if (!w)
228
+ throw new Error(`Missing prevout data for input ${r}`);
229
+ const u = {
230
+ hash: l.hash,
231
+ index: l.index,
232
+ sequence: l.sequence,
233
+ witnessUtxo: {
234
+ script: m.from(g(v(w.script_pubkey))),
235
+ value: w.value
236
+ }
237
+ };
238
+ r === 0 && (u.tapLeafScript = [
239
+ {
240
+ leafVersion: H,
241
+ script: m.from(c),
242
+ controlBlock: m.from(f)
243
+ }
244
+ ], u.tapInternalKey = m.from(V)), n.addInput(u);
245
+ }
246
+ for (const r of s.outs)
247
+ n.addOutput({
248
+ script: r.script,
249
+ value: r.value
250
+ });
251
+ return n.toHex();
252
+ }
253
+ function le(o, e, s) {
254
+ const t = k.fromHex(v(o));
255
+ if (t.outs.length !== 1)
256
+ throw new Error(
257
+ `NoPayout transaction must have exactly 1 output, got ${t.outs.length}`
258
+ );
259
+ const i = g(F(e)), { output: c } = D.p2tr({
260
+ internalPubkey: m.from(i),
261
+ network: W(s)
262
+ });
263
+ if (!c)
264
+ throw new Error(
265
+ "Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation"
266
+ );
267
+ if (!t.outs[0].script.equals(c))
268
+ throw new Error(
269
+ "NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address"
270
+ );
271
+ }
272
+ export {
273
+ ue as a,
274
+ ae as b,
275
+ ce as c,
276
+ le as d,
277
+ ie as e,
278
+ Z as r
279
+ };
280
+ //# sourceMappingURL=noPayout-BdATUPjF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noPayout-BdATUPjF.js","sources":["../src/tbv/core/primitives/psbt/refund.ts","../src/tbv/core/primitives/psbt/reclaim.ts","../src/tbv/core/primitives/psbt/noPayout.ts"],"sourcesContent":["/**\n * Refund PSBT Builder Primitive\n *\n * Builds an unsigned refund PSBT for a depositor to reclaim BTC from\n * a timed-out Pre-PegIn HTLC output via the refund script (leaf 1).\n *\n * The refund script enforces a CSV timelock (timelockRefund blocks) and\n * requires only the depositor's Schnorr signature — no vault provider or\n * keeper involvement.\n *\n * @module primitives/psbt/refund\n */\n\nimport {\n assertPositiveBigintArray,\n getPrePeginHtlcConnectorInfo,\n initWasm,\n tapInternalPubkey,\n WasmPrePeginTx,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport { normalizeAuthAnchorHash, type PrePeginParams } from \"./pegin\";\n\n/**\n * Parameters for building a refund PSBT\n */\nexport interface BuildRefundPsbtParams {\n /** Same PrePeginParams used when the original Pre-PegIn tx was created */\n prePeginParams: PrePeginParams;\n /** Funded Pre-PegIn transaction hex (the tx whose HTLC output is being refunded) */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output in the Pre-PegIn transaction */\n htlcVout: number;\n /** Transaction fee in satoshis for the refund transaction */\n refundFee: bigint;\n /** SHA256 hash commitment for the HTLC (64 hex chars, no 0x prefix) */\n hashlock: string;\n}\n\n/**\n * Result of building a refund PSBT\n */\nexport interface BuildRefundPsbtResult {\n /** PSBT hex ready for depositor signing */\n psbtHex: string;\n}\n\n/**\n * Build a PSBT for signing the refund transaction.\n *\n * The refund transaction spends the Pre-PegIn HTLC output via leaf 1\n * (the refund script: `<timelockRefund> CSV DROP <depositorPubkey> CHECKSIG`).\n * The PSBT includes the tapLeafScript entry so the depositor's wallet can\n * sign using Taproot script-path spending.\n *\n * The input's sequence is set to `timelockRefund` by the WASM, enforcing\n * the Bitcoin CSV timelock. The refund broadcast will be rejected by the\n * network if the timelock has not yet expired.\n *\n * @param params - Refund PSBT parameters\n * @returns PSBT hex for depositor signing\n * @throws If the HTLC output at htlcVout is not found\n * @throws If the refund transaction does not have exactly 1 input\n */\nexport async function buildRefundPsbt(\n params: BuildRefundPsbtParams,\n): Promise<BuildRefundPsbtResult> {\n await initWasm();\n\n const { prePeginParams, fundedPrePeginTxHex, htlcVout, refundFee, hashlock } =\n params;\n\n // The 14th positional arg `auth_anchor_hash` is `Option<String>` in\n // the Rust WASM constructor (the 9th arg `min_pegin_fee_rate` requires\n // the two-rate constructor from btc-vault #1930). Production peg-ins\n // (PeginManager) always commit an OP_RETURN <PUSH32 SHA256(authAnchor)>\n // output at `vout = hashlocks.length`; the unfunded template must\n // include it so `fromFundedTransaction` aligns with the funded tx.\n // Normalize identically to the peg-in primitives (`0x` strip,\n // lowercase, length/charset validation) so a direct primitive caller\n // reusing successful peg-in params doesn't hand unnormalized bytes to\n // WASM. Pass `undefined` for legacy non-auth-anchored Pre-PegIns.\n const normalizedAuthAnchorHash = normalizeAuthAnchorHash(\n prePeginParams.authAnchorHash,\n );\n // Reconstruct the template under the same graph version the Pre-PegIn\n // was originally built with (the vault's stamped vaultCoreVersion).\n const unfundedTx = new WasmPrePeginTx(\n prePeginParams.vaultCoreVersion,\n prePeginParams.depositorPubkey,\n prePeginParams.vaultProviderPubkey,\n prePeginParams.vaultKeeperPubkeys,\n prePeginParams.universalChallengerPubkeys,\n [...prePeginParams.hashlocks],\n new BigUint64Array(\n assertPositiveBigintArray(prePeginParams.pegInAmounts, \"pegInAmounts\"),\n ),\n prePeginParams.timelockRefund,\n prePeginParams.feeRate,\n prePeginParams.minPeginFeeRate,\n prePeginParams.numLocalChallengers,\n prePeginParams.councilQuorum,\n prePeginParams.councilSize,\n prePeginParams.network,\n normalizedAuthAnchorHash,\n );\n\n let fundedTx: WasmPrePeginTx | null = null;\n try {\n // Cross-check the reconstructed unfunded template against the funded\n // transaction: the WASM template's HTLC scriptPubKey at `htlcVout`\n // must equal the bytes the funded tx carries at the same output.\n // If they disagree, the template was reconstructed from the wrong\n // (hashlocks, amounts) vector — signing it would produce a refund\n // that does not spend the on-chain HTLC the depositor expects.\n // This is the explicit invariant the audit recommends: never sign a\n // refund whose template doesn't match the on-chain output bytes.\n const expectedHtlcScriptPubKey = unfundedTx\n .getHtlcScriptPubKey(htlcVout)\n .toLowerCase();\n // The reconstructed template's HTLC output value at `htlcVout`,\n // sized by WASM from the supplied `pegInAmounts` via the protocol\n // formula `htlcValue = peginAmount + depositorClaimValue + minPeginFee`.\n // Captured before `fromFundedTransaction` to bind it to the value the\n // funded tx actually carries (see the cross-check below).\n const expectedHtlcValue = unfundedTx.getHtlcValue(htlcVout);\n\n fundedTx = unfundedTx.fromFundedTransaction(fundedPrePeginTxHex);\n\n const refundTxHex = fundedTx.buildRefundTx(refundFee, htlcVout);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: prePeginParams.vaultCoreVersion,\n depositorPubkey: prePeginParams.depositorPubkey,\n vaultProviderPubkey: prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys: prePeginParams.universalChallengerPubkeys,\n hashlock,\n timelockRefund: prePeginParams.timelockRefund,\n network: prePeginParams.network,\n });\n\n const cleanPrePeginHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const prePeginTx = Transaction.fromHex(cleanPrePeginHex);\n\n const htlcOutput = prePeginTx.outs[htlcVout];\n if (!htlcOutput) {\n throw new Error(\n `HTLC output at vout ${htlcVout} not found in funded Pre-PegIn tx ` +\n `(tx has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const actualHtlcScriptPubKey = uint8ArrayToHex(\n new Uint8Array(htlcOutput.script),\n ).toLowerCase();\n if (actualHtlcScriptPubKey !== expectedHtlcScriptPubKey) {\n throw new Error(\n `HTLC scriptPubKey mismatch at vout ${htlcVout}: reconstructed ` +\n `template expects ${expectedHtlcScriptPubKey}, funded tx carries ` +\n `${actualHtlcScriptPubKey}. Refund refused — the (hashlocks, ` +\n `pegInAmounts) vector does not match the on-chain commitment.`,\n );\n }\n\n // Value cross-check (mirrors the script check above): the template's\n // HTLC value — derived by WASM from `pegInAmounts` via the protocol\n // formula — must equal the value the funded tx pays at this output.\n // A caller that hands the full HTLC output value (or any wrong amount)\n // as `pegInAmounts` would inflate the template value and trip this\n // guard, rather than silently signing a refund built from a template\n // that disagrees with the on-chain commitment.\n const actualHtlcValue = BigInt(htlcOutput.value);\n if (actualHtlcValue !== expectedHtlcValue) {\n throw new Error(\n `HTLC value mismatch at vout ${htlcVout}: reconstructed template ` +\n `expects ${expectedHtlcValue} sat, funded tx carries ` +\n `${actualHtlcValue} sat. Refund refused — the pegInAmounts vector ` +\n `does not match the on-chain commitment.`,\n );\n }\n\n const refundTx = Transaction.fromHex(refundTxHex);\n\n if (refundTx.ins.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 input, got ${refundTx.ins.length}`,\n );\n }\n\n const refundInput = refundTx.ins[0];\n\n // Verify the refund input spends the correct Pre-PegIn HTLC output\n const prePeginTxid = prePeginTx.getId();\n const refundInputTxid = uint8ArrayToHex(\n new Uint8Array(refundInput.hash).slice().reverse(),\n );\n if (refundInputTxid !== prePeginTxid) {\n throw new Error(\n `Refund input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${refundInputTxid}`,\n );\n }\n if (refundInput.index !== htlcVout) {\n throw new Error(\n `Refund input index ${refundInput.index} does not match expected htlcVout ${htlcVout}`,\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(refundTx.version);\n psbt.setLocktime(refundTx.locktime);\n\n psbt.addInput({\n hash: refundInput.hash,\n index: refundInput.index,\n sequence: refundInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n controlBlock: Buffer.from(\n hexToUint8Array(htlcConnector.refundControlBlock),\n ),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n });\n\n // Output side: pin the single refund output to the depositor's own\n // BIP-86 P2TR address, mirroring the input-side pinning above. WASM\n // builds the refund output from the refund leaf's depositor key, so a\n // correct template always pays exactly one output back to the depositor.\n // Asserting it here means a malformed template (or a tampered WASM)\n // cannot redirect the reclaimed funds to a script the depositor does\n // not control.\n if (refundTx.outs.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 output, got ${refundTx.outs.length}`,\n );\n }\n const refundOutput = refundTx.outs[0];\n const expectedDepositorScriptPubKey = stripHexPrefix(\n deriveBip86ScriptPubKeyHex(prePeginParams.depositorPubkey),\n ).toLowerCase();\n const actualRefundOutputScriptPubKey = uint8ArrayToHex(\n new Uint8Array(refundOutput.script),\n ).toLowerCase();\n if (actualRefundOutputScriptPubKey !== expectedDepositorScriptPubKey) {\n throw new Error(\n `Refund output scriptPubKey ${actualRefundOutputScriptPubKey} does not ` +\n `match the depositor's BIP-86 address ${expectedDepositorScriptPubKey}. ` +\n `Refund refused — the reclaimed funds would not return to the depositor.`,\n );\n }\n\n // Value: the single refund output must return the full HTLC value minus\n // exactly the requested fee. The refund is 1-in/1-out (asserted above), so\n // a value below `htlcValue - refundFee` means WASM applied a larger fee\n // than requested — the difference would be burned as miner fee. Pin it so\n // the depositor reclaims the expected amount, not a silently reduced one.\n const expectedRefundOutputValue = actualHtlcValue - refundFee;\n if (BigInt(refundOutput.value) !== expectedRefundOutputValue) {\n throw new Error(\n `Refund output value ${BigInt(refundOutput.value)} sat does not equal ` +\n `the HTLC value ${actualHtlcValue} sat minus the requested fee ` +\n `${refundFee} sat (expected ${expectedRefundOutputValue} sat). ` +\n `Refund refused — the reclaimed amount would be burned as excess fee.`,\n );\n }\n\n psbt.addOutput({\n script: refundOutput.script,\n value: refundOutput.value,\n });\n\n return { psbtHex: psbt.toHex() };\n } finally {\n fundedTx?.free();\n unfundedTx.free();\n }\n}\n","/**\n * Reclaim PSBT Builder Primitive\n *\n * Builds an unsigned PSBT that sweeps the depositor-claim reserve — PegIn\n * vout 1 — back to the depositor's own BIP-86 address.\n *\n * The reserve funds the depositor's `claim_tx`, their recourse if the vault\n * provider fails during peg-out. When the vault provider claims instead and\n * the depositor withdraws normally, nothing ever spends it. This primitive is\n * the only thing in the repository that can.\n *\n * Spend path: the single `<depositor> OP_CHECKSIG` tapleaf (see\n * ./depositorClaim). No timelock, no counterparty signature — the depositor's\n * Schnorr signature alone. That is also why the *caller* must gate: this\n * builder will happily sweep a reserve whose vault is still live, which would\n * permanently void the depositor's pre-signed recourse graph. Eligibility is\n * enforced upstream, in the service.\n *\n * @module primitives/psbt/reclaim\n */\n\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport { DUST_THRESHOLD } from \"../../utils/fee/constants\";\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport {\n PEGIN_DEPOSITOR_CLAIM_VOUT,\n deriveDepositorClaimDescriptor,\n} from \"./depositorClaim\";\n\n/**\n * nVersion for the reclaim transaction. Plain v2, not TRUC: the reserve is only\n * offered once its PegIn is deeply confirmed, so the v2/v3 PegIn's nVersion-3\n * topology limits no longer constrain its children.\n */\nconst RECLAIM_TX_VERSION = 2;\n\n/**\n * nSequence for every reclaim input: RBF-enabled, no relative timelock. The\n * claim leaf carries no CSV, so this is a fee-bumping signal only.\n */\nconst RECLAIM_INPUT_SEQUENCE = 0xfffffffd;\n\n/**\n * Weight units of the reclaim transaction's skeleton — everything except the\n * inputs. Non-witness `version(4) + inCount(1) + outCount(1) + locktime(4) +\n * output(8 + 1 + 34)` = 53 B × 4, plus the 2 WU SegWit marker and flag.\n */\nconst RECLAIM_SKELETON_WEIGHT_UNITS = 214;\n\n/**\n * Weight units each script-path input adds. Non-witness `outpoint(36) +\n * scriptSigLen(1) + sequence(4)` = 41 B × 4 = 164, plus a witness of\n * `stackCount(1) + sig(1 + 64) + leafScript(1 + 34) + controlBlock(1 + 33)` =\n * 135 WU.\n *\n * Exact rather than conservative: every element is fixed-length here — a\n * 64-byte BIP-340 signature under SIGHASH_DEFAULT, the 34-byte leaf, and a\n * 33-byte control block with no merkle path.\n */\nconst RECLAIM_INPUT_WEIGHT_UNITS = 299;\n\n/** Weight units per virtual byte. */\nconst WEIGHT_UNITS_PER_VBYTE = 4;\n\n/**\n * Virtual size of an N-in/1-out reclaim transaction.\n *\n * `REFUND_VSIZE = 160` does not generalise to N inputs, and\n * `computePeginBaseFeeSats` is wrong for this shape entirely — its\n * `P2TR_INPUT_SIZE = 58` is a *key-path* input and under-fees a script-path\n * spend by roughly a quarter.\n *\n * N=1 → 129 vB; each additional input adds 75 vB.\n */\nexport function reclaimVsize(numInputs: number): number {\n if (!Number.isInteger(numInputs) || numInputs < 1) {\n throw new Error(\n `Reclaim input count must be a positive integer, got ${numInputs}.`,\n );\n }\n return Math.ceil(\n (RECLAIM_SKELETON_WEIGHT_UNITS +\n RECLAIM_INPUT_WEIGHT_UNITS * numInputs) /\n WEIGHT_UNITS_PER_VBYTE,\n );\n}\n\n/** Absolute fee in satoshis for an N-in/1-out reclaim at a given rate. */\nexport function estimateReclaimFeeSats(\n feeRateSatsVb: number,\n numInputs: number,\n): bigint {\n if (!Number.isFinite(feeRateSatsVb) || feeRateSatsVb <= 0) {\n throw new Error(\n `Reclaim fee rate must be a positive number, got ${feeRateSatsVb}.`,\n );\n }\n return BigInt(Math.ceil(feeRateSatsVb * reclaimVsize(numInputs)));\n}\n\n/** One depositor-claim reserve to sweep, with the material to bind it. */\nexport interface ReclaimReserve {\n /**\n * The contract's own copy of the depositor-signed PegIn transaction\n * (`VaultProtocolInfo.depositorSignedPeginTx`). Authoritative: its SegWit\n * txid equals the broadcast PegIn's, and its `outs[1]` carries the reserve's\n * script and value at no extra RPC cost.\n */\n depositorSignedPeginTxHex: string;\n /** Independent chain observation of `peginTxid:1` (esplora UTXO lookup). */\n observed: {\n /** scriptPubKey hex, with or without `0x` prefix. */\n scriptPubKey: string;\n /** Output value in satoshis. */\n value: bigint;\n };\n /**\n * The reserve value recomputed from this vault's protocol parameters via\n * `computeMinClaimValue`. Bound so a doctored PegIn that agrees with itself\n * and with a compromised indexer still fails.\n */\n expectedValue: bigint;\n}\n\nexport interface BuildReclaimPsbtParams {\n /**\n * The **connected wallet's live** x-only pubkey, 64-char hex. Never the\n * indexer's `depositorBtcPubkey`: re-deriving from the live key is what\n * proves the wallet about to sign is the wallet that can spend, and rejects\n * the wrong-wallet case with an error instead of an unspendable broadcast.\n */\n depositorPubkey: string;\n /**\n * Reserves to sweep. An array so batching several vaults into one\n * transaction is a later change rather than a rewrite; today the app passes\n * exactly one.\n */\n inputs: ReclaimReserve[];\n /** Absolute fee in satoshis. The caller sizes it; see `reclaimVsize`. */\n feeSats: bigint;\n}\n\nexport interface BuildReclaimPsbtResult {\n /** PSBT hex ready for depositor signing. */\n psbtHex: string;\n /** Value of the single output — what the depositor actually receives. */\n outputValue: bigint;\n /** Sum of the swept reserves, before fee. */\n totalInputValue: bigint;\n}\n\n/**\n * Build the N-in/1-out reclaim PSBT.\n *\n * Every input is bound three ways before it reaches the PSBT: the contract's\n * PegIn bytes, the chain observation, and a JS re-derivation from the live\n * wallet key must agree on both script and value. Any disagreement throws.\n *\n * @throws If `inputs` is empty, the fee is non-positive, any input fails its\n * script or value bind, or the resulting output would be at or below dust.\n */\nexport function buildReclaimPsbt(\n params: BuildReclaimPsbtParams,\n): BuildReclaimPsbtResult {\n const { depositorPubkey, inputs, feeSats } = params;\n\n if (inputs.length === 0) {\n throw new Error(\"Reclaim requires at least one input; got none.\");\n }\n if (feeSats <= 0n) {\n throw new Error(\n `Reclaim fee must be positive, got ${feeSats} sat. Refusing to build a ` +\n `transaction that would not relay.`,\n );\n }\n\n // One derivation, reused for every input's bind and for the destination.\n const descriptor = deriveDepositorClaimDescriptor(depositorPubkey);\n const expectedScriptPubKey = uint8ArrayToHex(\n new Uint8Array(descriptor.scriptPubKey),\n ).toLowerCase();\n\n const psbt = new Psbt();\n psbt.setVersion(RECLAIM_TX_VERSION);\n psbt.setLocktime(0);\n\n let totalInputValue = 0n;\n const seenOutpoints = new Set<string>();\n\n inputs.forEach((input, i) => {\n const peginTx = Transaction.fromHex(\n stripHexPrefix(input.depositorSignedPeginTxHex),\n );\n const peginTxid = peginTx.getId();\n\n const claimOut = peginTx.outs[PEGIN_DEPOSITOR_CLAIM_VOUT];\n if (!claimOut) {\n throw new Error(\n `PegIn ${peginTxid} has no output at vout ` +\n `${PEGIN_DEPOSITOR_CLAIM_VOUT} (tx has ${peginTx.outs.length}); ` +\n `there is no depositor-claim reserve to reclaim.`,\n );\n }\n\n // Bind 1: the contract's PegIn bytes against the JS re-derivation from the\n // live wallet key. This is the assertion that proves the connected wallet\n // can actually spend the output we are about to sign for.\n const contractScriptPubKey = uint8ArrayToHex(\n new Uint8Array(claimOut.script),\n ).toLowerCase();\n if (contractScriptPubKey !== expectedScriptPubKey) {\n throw new Error(\n `Input ${i}: PegIn ${peginTxid} vout ${PEGIN_DEPOSITOR_CLAIM_VOUT} pays ` +\n `${contractScriptPubKey}, but the connected wallet's depositor-claim ` +\n `script is ${expectedScriptPubKey}. Reclaim refused — this reserve ` +\n `belongs to a different wallet.`,\n );\n }\n\n // Bind 2: the independent chain observation must agree with both.\n const observedScriptPubKey = stripHexPrefix(\n input.observed.scriptPubKey,\n ).toLowerCase();\n if (observedScriptPubKey !== expectedScriptPubKey) {\n throw new Error(\n `Input ${i}: the observed UTXO ${peginTxid}:${PEGIN_DEPOSITOR_CLAIM_VOUT} ` +\n `pays ${observedScriptPubKey}, expected ${expectedScriptPubKey}. ` +\n `Reclaim refused — chain state disagrees with the contract's PegIn.`,\n );\n }\n\n // Value bind, same three ways.\n const contractValue = BigInt(claimOut.value);\n if (contractValue !== input.observed.value) {\n throw new Error(\n `Input ${i}: PegIn ${peginTxid} vout ${PEGIN_DEPOSITOR_CLAIM_VOUT} ` +\n `carries ${contractValue} sat, but the observed UTXO carries ` +\n `${input.observed.value} sat. Reclaim refused.`,\n );\n }\n if (contractValue !== input.expectedValue) {\n throw new Error(\n `Input ${i}: PegIn ${peginTxid} vout ${PEGIN_DEPOSITOR_CLAIM_VOUT} ` +\n `carries ${contractValue} sat, but this vault's parameters compute a ` +\n `depositor-claim value of ${input.expectedValue} sat. Reclaim refused.`,\n );\n }\n\n // A batch that names the same vault twice would otherwise double-count the\n // swept total and then fail deep inside bitcoinjs. Reject it here, where\n // the message can say which input is the duplicate.\n const outpoint = `${peginTxid}:${PEGIN_DEPOSITOR_CLAIM_VOUT}`;\n if (seenOutpoints.has(outpoint)) {\n throw new Error(\n `Input ${i} repeats outpoint ${outpoint}, which is already being ` +\n `swept by an earlier input. Reclaim refused.`,\n );\n }\n seenOutpoints.add(outpoint);\n\n totalInputValue += contractValue;\n\n psbt.addInput({\n hash: peginTxid,\n index: PEGIN_DEPOSITOR_CLAIM_VOUT,\n sequence: RECLAIM_INPUT_SEQUENCE,\n witnessUtxo: { script: claimOut.script, value: claimOut.value },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: descriptor.leafScript,\n controlBlock: descriptor.controlBlock,\n },\n ],\n tapInternalKey: descriptor.internalKey,\n });\n });\n\n if (feeSats >= totalInputValue) {\n throw new Error(\n `Reclaim fee ${feeSats} sat is not less than the swept total ` +\n `${totalInputValue} sat. Refusing to build a transaction with no output.`,\n );\n }\n\n const outputValue = totalInputValue - feeSats;\n if (outputValue <= DUST_THRESHOLD) {\n throw new Error(\n `Reclaim output ${outputValue} sat is at or below the dust threshold ` +\n `${DUST_THRESHOLD} sat. The reserve is not at risk — it stays where it ` +\n `is until fee rates fall.`,\n );\n }\n\n const destination = stripHexPrefix(\n deriveBip86ScriptPubKeyHex(depositorPubkey),\n );\n psbt.addOutput({\n script: Buffer.from(hexToUint8Array(destination)),\n value: Number(outputValue),\n });\n\n return { psbtHex: psbt.toHex(), outputValue, totalInputValue };\n}\n","/**\n * NoPayout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's NoPayout transaction\n * (depositor-as-claimer path, per challenger). The depositor signs input 0\n * using the NoPayout taproot script from WasmAssertPayoutNoPayoutConnector.\n *\n * @module primitives/psbt/noPayout\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — Assert output 0 NoPayout connector\n */\n\nimport {\n type AssertPayoutNoPayoutConnectorParams,\n type Network,\n getAssertNoPayoutScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n getNetwork,\n hexToUint8Array,\n processPublicKeyToXOnly,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a NoPayout PSBT\n */\nexport interface NoPayoutParams {\n /** NoPayout transaction hex (unsigned) from VP */\n noPayoutTxHex: string;\n /** Challenger's x-only public key (hex encoded) */\n challengerPubkey: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the Assert Payout/NoPayout connector */\n connectorParams: AssertPayoutNoPayoutConnectorParams;\n}\n\n/**\n * Build unsigned NoPayout PSBT.\n *\n * The NoPayout transaction is specific to each challenger.\n * Input 0 is the one the depositor signs using the NoPayout taproot script path.\n *\n * @param params - NoPayout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildNoPayoutPsbt(\n params: NoPayoutParams,\n): Promise<string> {\n const noPayoutTxHex = stripHexPrefix(params.noPayoutTxHex);\n const noPayoutTx = Transaction.fromHex(noPayoutTxHex);\n\n // Get NoPayout script and control block for this challenger\n const { noPayoutScript, noPayoutControlBlock } =\n await getAssertNoPayoutScriptInfo(\n params.connectorParams,\n params.challengerPubkey,\n );\n\n const scriptBytes = hexToUint8Array(noPayoutScript);\n const controlBlockBytes = hexToUint8Array(noPayoutControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(noPayoutTx.version);\n psbt.setLocktime(noPayoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < noPayoutTx.ins.length; i++) {\n const input = noPayoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of noPayoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Validate that a NoPayout transaction pays to the challenger via the\n * protocol-defined output structure: a single BIP-86 P2TR output derived from\n * the challenger's x-only pubkey.\n *\n * Mirrors the per-role payout output validation now inlined in\n * `buildPayoutPsbt` for the NoPayout path, where the sink is fixed by the\n * protocol rather than read from on-chain registration\n * (see `crates/vault/src/transactions/nopayout.rs::NoPayoutTx::new`).\n *\n * @param noPayoutTxHex - Raw NoPayout transaction hex\n * @param challengerPubkey - Challenger's x-only public key (hex)\n * @param network - Bitcoin network used to derive the P2TR scriptPubKey\n * @throws If the transaction does not have exactly one output\n * @throws If the single output's scriptPubKey does not equal the BIP-86 P2TR\n * scriptPubKey for the challenger\n */\nexport function assertNoPayoutOutputMatchesChallenger(\n noPayoutTxHex: string,\n challengerPubkey: string,\n network: Network,\n): void {\n const tx = Transaction.fromHex(stripHexPrefix(noPayoutTxHex));\n\n if (tx.outs.length !== 1) {\n throw new Error(\n `NoPayout transaction must have exactly 1 output, got ${tx.outs.length}`,\n );\n }\n\n const xOnly = hexToUint8Array(processPublicKeyToXOnly(challengerPubkey));\n const { output: expectedScript } = payments.p2tr({\n internalPubkey: Buffer.from(xOnly),\n network: getNetwork(network),\n });\n if (!expectedScript) {\n throw new Error(\n \"Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation\",\n );\n }\n\n if (!tx.outs[0].script.equals(expectedScript)) {\n throw new Error(\n \"NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address\",\n );\n }\n}\n"],"names":["buildRefundPsbt","params","initWasm","prePeginParams","fundedPrePeginTxHex","htlcVout","refundFee","hashlock","normalizedAuthAnchorHash","normalizeAuthAnchorHash","unfundedTx","WasmPrePeginTx","assertPositiveBigintArray","fundedTx","expectedHtlcScriptPubKey","expectedHtlcValue","refundTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","cleanPrePeginHex","prePeginTx","Transaction","htlcOutput","actualHtlcScriptPubKey","uint8ArrayToHex","actualHtlcValue","refundTx","refundInput","prePeginTxid","refundInputTxid","psbt","Psbt","TAPSCRIPT_LEAF_VERSION","Buffer","hexToUint8Array","tapInternalPubkey","refundOutput","expectedDepositorScriptPubKey","stripHexPrefix","deriveBip86ScriptPubKeyHex","actualRefundOutputScriptPubKey","expectedRefundOutputValue","RECLAIM_TX_VERSION","RECLAIM_INPUT_SEQUENCE","RECLAIM_SKELETON_WEIGHT_UNITS","RECLAIM_INPUT_WEIGHT_UNITS","WEIGHT_UNITS_PER_VBYTE","reclaimVsize","numInputs","estimateReclaimFeeSats","feeRateSatsVb","buildReclaimPsbt","depositorPubkey","inputs","feeSats","descriptor","deriveDepositorClaimDescriptor","expectedScriptPubKey","totalInputValue","seenOutpoints","input","i","peginTx","peginTxid","claimOut","PEGIN_DEPOSITOR_CLAIM_VOUT","contractScriptPubKey","observedScriptPubKey","contractValue","outpoint","outputValue","DUST_THRESHOLD","destination","buildNoPayoutPsbt","noPayoutTxHex","noPayoutTx","noPayoutScript","noPayoutControlBlock","getAssertNoPayoutScriptInfo","scriptBytes","controlBlockBytes","prevout","inputData","output","assertNoPayoutOutputMatchesChallenger","challengerPubkey","network","tx","xOnly","processPublicKeyToXOnly","expectedScript","payments","getNetwork"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";var H=Object.defineProperty;var B=(t,e,r)=>e in t?H(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var b=(t,e,r)=>B(t,typeof e!="symbol"?e+"":e,r);const E=require("bitcoinjs-lib"),p=require("./bitcoin-m84N5a8o.cjs"),A=require("./sha2-DsrLC4NM.cjs");require("@babylonlabs-io/babylon-tbv-rust-wasm");const u=require("./verifyScriptPathSchnorrSignature-D-ppKNjT.cjs"),y=require("./constants-BCdDRd_Y.cjs"),d=require("./signing-Bnsro0hE.cjs");function O(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const r in t)if(r!=="default"){const o=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,o.get?o:{enumerable:!0,get:()=>t[r]})}}return e.default=t,Object.freeze(e)}const v=O(E),k=106,S=32,P=34;function R(t,e,r){const o=p.stripHexPrefix(t),s=v.Transaction.fromHex(o);if(s.outs.length<=e)throw new Error(`Pre-PegIn auth-anchor OP_RETURN missing: tx has ${s.outs.length} outputs, expected at least ${e+1} (vault outputs + OP_RETURN)`);const c=s.outs[e],i=c.script;if(i.length!==P||i[0]!==k||i[1]!==S)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${e} has unexpected script encoding (got ${i.length}-byte script with prefix 0x${i.slice(0,Math.min(2,i.length)).toString("hex")}; expected ${P}-byte OP_RETURN + PUSH32 layout)`);const l=i.slice(2).toString("hex").toLowerCase();if(l!==r.toLowerCase())throw new Error(`Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${e}: tx pushes ${l}, expected ${r}`);if(c.value!==0)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${e} has non-zero value ${c.value}; OP_RETURN outputs must be 0-value`)}function C(t){let e;try{e=v.Transaction.fromHex(p.stripHexPrefix(t))}catch{return}const r=[];for(let o=0;o<e.outs.length;o++){const s=e.outs[o],c=s.script;c.length===P&&c[0]===k&&c[1]===S&&s.value===0&&r.push({vout:o,hash:c.slice(2).toString("hex").toLowerCase()})}return r.length===1?r[0]:void 0}const f=66;function T(t){if(!t.startsWith("0x")&&!t.startsWith("0X"))throw new Error("Expected 0x-prefixed hex string");const e=t.slice(2);if(e.length%2!==0)throw new Error(`Hex string has odd length: ${e.length}`);if(!/^[0-9a-fA-F]*$/.test(e))throw new Error("Hex string contains non-hex characters");const r=new Uint8Array(e.length/2);for(let o=0;o<r.length;o++)r[o]=parseInt(e.slice(o*2,o*2+2),16);return r}function _(t){return`0x${Array.from(t).map(e=>e.toString(16).padStart(2,"0")).join("")}`}function h(t,e){if(t.length!==f)throw new Error(`${e} must be exactly 32 bytes (${f} hex chars with 0x prefix), got ${t.length}`)}function m(t){h(t,"Secret");const e=T(t),r=A.sha256(e);return _(r)}function N(t,e){return h(t,"Secret"),h(e,"Hashlock"),T(e),m(t).toLowerCase()===e.toLowerCase()}function w(t){return typeof t.approveDepositTerms=="function"}async function $(t){const e=t;if(typeof e.getChangeAddress!="function")throw new Error("Approval wallet does not implement getChangeAddress; it must expose its change branch, because the signing device accepts Pre-PegIn change only there.");return e.getChangeAddress()}function D(t){if(!w(t))return{};const e=t.holdsApprovedDepositTerms,r=t.validateDepositTerms,o=t.getChangeAddress;return{approveDepositTerms:s=>t.approveDepositTerms(s),...typeof o=="function"?{getChangeAddress:()=>o.call(t)}:{},...typeof e=="function"?{holdsApprovedDepositTerms:s=>e.call(t,s)}:{},...typeof r=="function"?{validateDepositTerms:s=>r.call(t,s)}:{}}}const x=0;class U{constructor(e){b(this,"config");this.config=e}async signPayoutTransaction(e){const r=await this.config.btcWallet.getPublicKeyHex(),{depositorPubkey:o}=p.validateWalletPubkey(r,e.depositorBtcPubkey),s=await u.buildPayoutPsbt({vaultCoreVersion:e.vaultCoreVersion,payoutTxHex:e.payoutTxHex,peginTxHex:e.peginTxHex,assertTxHex:e.assertTxHex,depositorBtcPubkey:o,vaultProviderBtcPubkey:e.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:e.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:e.universalChallengerBtcPubkeys,timelockPegin:e.timelockPegin,timelockAssert:e.timelockAssert,network:this.config.network,claimerBtcPubkey:e.claimerBtcPubkey,registeredPayoutScriptPubKey:e.registeredPayoutScriptPubKey,commissionBps:e.commissionBps,protocolFeeRate:e.protocolFeeRate,councilMembers:e.councilMembers,councilQuorum:e.councilQuorum,vkClaimerPayoutScriptPubKeys:e.vkClaimerPayoutScriptPubKeys,vpCommissionScriptPubKey:e.vpCommissionScriptPubKey}),c=await this.config.btcWallet.signPsbt(s.psbtHex,d.createTaprootScriptPathSignOptions(r,y.DEPOSITOR_SIGNED_INPUT_COUNT));u.assertPsbtUnsignedTxMatches({requestedPsbtHex:s.psbtHex,returnedPsbtHex:c});const i=u.extractPayoutSignature(c,o);return u.assertScriptPathSchnorrSignature({requestedPsbtHex:s.psbtHex,signatureHex:i,signerXOnlyPubkeyHex:o,inputIndex:x}),{signature:i,depositorBtcPubkey:o}}getNetwork(){return this.config.network}supportsBatchSigning(){return typeof this.config.btcWallet.signPsbts=="function"}async signPayoutTransactionsBatch(e){if(!this.supportsBatchSigning())throw new Error("Wallet does not support batch signing (signPsbts method not available)");const r=await this.config.btcWallet.getPublicKeyHex(),o=[],s=[],c=[];for(const n of e){const{depositorPubkey:a}=p.validateWalletPubkey(r,n.depositorBtcPubkey);c.push(a);const g=await u.buildPayoutPsbt({vaultCoreVersion:n.vaultCoreVersion,payoutTxHex:n.payoutTxHex,peginTxHex:n.peginTxHex,assertTxHex:n.assertTxHex,depositorBtcPubkey:a,vaultProviderBtcPubkey:n.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:n.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:n.universalChallengerBtcPubkeys,timelockPegin:n.timelockPegin,timelockAssert:n.timelockAssert,network:this.config.network,claimerBtcPubkey:n.claimerBtcPubkey,registeredPayoutScriptPubKey:n.registeredPayoutScriptPubKey,commissionBps:n.commissionBps,protocolFeeRate:n.protocolFeeRate,councilMembers:n.councilMembers,councilQuorum:n.councilQuorum,vkClaimerPayoutScriptPubKeys:n.vkClaimerPayoutScriptPubKeys,vpCommissionScriptPubKey:n.vpCommissionScriptPubKey});o.push(g.psbtHex),s.push(d.createTaprootScriptPathSignOptions(r,y.DEPOSITOR_SIGNED_INPUT_COUNT))}const i=await this.config.btcWallet.signPsbts(o,s);if(i.length!==e.length)throw new Error(`Expected ${e.length} signed PSBTs but received ${i.length}`);const l=[];for(let n=0;n<e.length;n++){const a=c[n];u.assertPsbtUnsignedTxMatches({requestedPsbtHex:o[n],returnedPsbtHex:i[n]});const g=u.extractPayoutSignature(i[n],a);u.assertScriptPathSchnorrSignature({requestedPsbtHex:o[n],signatureHex:g,signerXOnlyPubkeyHex:a,inputIndex:x}),l.push({payoutSignature:g,depositorBtcPubkey:a})}return l}}async function I(t,e,r){if(e.length===1)return[await t.signPsbt(e[0],r==null?void 0:r[0])];if(typeof t.signPsbts=="function"){const s=await t.signPsbts(e,r);if(s.length!==e.length)throw new Error(`Expected ${e.length} signed PSBTs but received ${s.length}`);return s}const o=[];for(let s=0;s<e.length;s++)o.push(await t.signPsbt(e[s],r==null?void 0:r[s]));return o}exports.PayoutManager=U;exports.assertAuthAnchorOpReturn=R;exports.computeHashlock=m;exports.findAuthAnchorOpReturn=C;exports.forwardDepositApproval=D;exports.requireChangeAddress=$;exports.signPsbtsWithFallback=I;exports.supportsDepositApproval=w;exports.validateSecretAgainstHashlock=N;
2
+ //# sourceMappingURL=signPsbtsWithFallback-Bo1PJX90.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signPsbtsWithFallback-Bo1PJX90.cjs","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/deposit-terms/depositTerms.ts","../src/tbv/core/managers/PayoutManager.ts","../src/tbv/core/managers/pegin/signPsbtsWithFallback.ts"],"sourcesContent":["/**\n * Structural verifier for the auth-anchor OP_RETURN in a funded\n * Pre-PegIn transaction.\n *\n * @module managers/pegin/assertAuthAnchorOpReturn\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { stripHexPrefix } from \"../../primitives/utils/bitcoin\";\n\n/** OP_RETURN opcode. */\nconst OP_RETURN = 0x6a;\n/** Push-32-bytes opcode (raw push, not OP_PUSHDATA1). */\nconst OP_PUSH32 = 0x20;\n/** Encoded length of a standard OP_RETURN script with a 32-byte payload. */\nconst OP_RETURN_PUSH32_SCRIPT_LEN = 1 + 1 + 32;\n\n/**\n * Verify the broadcast Pre-PegIn carries the expected OP_RETURN\n * commitment to the auth anchor.\n *\n * The OP_RETURN sits at `vout = vaultCount` (right after the per-vault\n * HTLC outputs and before the depositor-claim/change outputs) and\n * pushes the 32-byte `SHA256(authAnchor)`. The script encoding is\n * exactly `OP_RETURN || PUSH32 || <32 bytes>` (34 bytes). A\n * non-conformant WASM build that omitted the OP_RETURN, swapped its\n * position, or changed its push payload would let the depositor\n * obtain a valid bearer token for a Pre-PegIn whose on-chain\n * commitment doesn't actually bind the anchor — degrading the auth\n * from on-chain-bound to a shared secret. Fail closed.\n *\n * @throws If the OP_RETURN is missing, mis-located, mis-encoded, or\n * pushes a payload other than `expectedAuthAnchorHashHex`.\n */\nexport function assertAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n vaultCount: number,\n expectedAuthAnchorHashHex: string,\n): void {\n const cleanHex = stripHexPrefix(fundedPrePeginTxHex);\n const tx = bitcoin.Transaction.fromHex(cleanHex);\n\n if (tx.outs.length <= vaultCount) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN missing: tx has ${tx.outs.length} ` +\n `outputs, expected at least ${vaultCount + 1} (vault outputs + OP_RETURN)`,\n );\n }\n\n const opReturnOutput = tx.outs[vaultCount];\n const script = opReturnOutput.script;\n if (\n script.length !== OP_RETURN_PUSH32_SCRIPT_LEN ||\n script[0] !== OP_RETURN ||\n script[1] !== OP_PUSH32\n ) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has unexpected ` +\n `script encoding (got ${script.length}-byte script with prefix ` +\n `0x${script.slice(0, Math.min(2, script.length)).toString(\"hex\")}; ` +\n `expected ${OP_RETURN_PUSH32_SCRIPT_LEN}-byte OP_RETURN + PUSH32 layout)`,\n );\n }\n\n const pushedHex = script.slice(2).toString(\"hex\").toLowerCase();\n if (pushedHex !== expectedAuthAnchorHashHex.toLowerCase()) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${vaultCount}: ` +\n `tx pushes ${pushedHex}, expected ${expectedAuthAnchorHashHex}`,\n );\n }\n\n if (opReturnOutput.value !== 0) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has non-zero ` +\n `value ${opReturnOutput.value}; OP_RETURN outputs must be 0-value`,\n );\n }\n}\n\n/**\n * Scan a funded Pre-PegIn transaction for its auth-anchor commitment\n * (an `OP_RETURN || PUSH32 || <32 bytes>` output with value 0).\n *\n * Returns `{ vout, hash }` when exactly one such output is found.\n * Returns `undefined` when:\n * - the hex is unparseable,\n * - no matching output exists (legacy non-auth-anchored Pre-PegIn),\n * - more than one matching output exists (ambiguous / malformed).\n *\n * Used by the refund orchestrator to (a) locate the on-chain anchor\n * regardless of how many HTLCs preceded it and (b) detect multi-vault\n * funded transactions structurally: the single-vault refund path\n * reconstructs only one hashlock and expects the anchor at vout 1, so\n * any other vout signals a layout this call cannot safely refund.\n */\nexport function findAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n): { vout: number; hash: string } | undefined {\n let tx: bitcoin.Transaction;\n try {\n tx = bitcoin.Transaction.fromHex(stripHexPrefix(fundedPrePeginTxHex));\n } catch {\n return undefined;\n }\n\n const hits: { vout: number; hash: string }[] = [];\n for (let i = 0; i < tx.outs.length; i++) {\n const output = tx.outs[i];\n const script = output.script;\n if (\n script.length === OP_RETURN_PUSH32_SCRIPT_LEN &&\n script[0] === OP_RETURN &&\n script[1] === OP_PUSH32 &&\n output.value === 0\n ) {\n hits.push({\n vout: i,\n hash: script.slice(2).toString(\"hex\").toLowerCase(),\n });\n }\n }\n\n return hits.length === 1 ? hits[0] : undefined;\n}\n","/**\n * HTLC Secret / Hashlock Utilities\n *\n * Pure functions for computing and validating SHA-256 hashlocks used in the\n * vault deposit protocol's HTLC (Hash Time Lock Contract).\n *\n * The SDK does NOT generate secrets — that is the caller's responsibility.\n * Today callers use `crypto.getRandomValues(32)`; when the `deriveContextHash`\n * wallet API ships, callers will use `wallet.deriveContextHash(\"babylon-btc-vault\", ctx)`.\n * These utilities work identically regardless of how the secret was produced.\n *\n * On-chain contract validation (BTCVaultRegistry.activateVaultWithSecret):\n * if (sha256(abi.encodePacked(s)) != hashlock) revert InvalidSecret();\n *\n * @module htlc\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport type { Hex } from \"viem\";\n\n/** Expected hex length for a 0x-prefixed bytes32 value. */\nconst HEX_BYTES32_LENGTH = 66; // \"0x\" + 64 hex chars\n\n/**\n * Decode a 0x-prefixed hex string to bytes, with strict validation.\n * @throws if the input is not a valid 0x-prefixed hex string\n */\nfunction hexToBytes(hex: Hex): Uint8Array {\n if (!hex.startsWith(\"0x\") && !hex.startsWith(\"0X\")) {\n throw new Error(\"Expected 0x-prefixed hex string\");\n }\n const clean = hex.slice(2);\n if (clean.length % 2 !== 0) {\n throw new Error(`Hex string has odd length: ${clean.length}`);\n }\n if (!/^[0-9a-fA-F]*$/.test(clean)) {\n throw new Error(\"Hex string contains non-hex characters\");\n }\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Encode a Uint8Array as a 0x-prefixed lowercase hex string.\n */\nfunction bytesToHex(bytes: Uint8Array): Hex {\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate that a value is a 0x-prefixed bytes32 (exactly 32 bytes).\n * @throws if the value is not exactly 32 bytes\n */\nfunction assertBytes32(value: Hex, label: string): void {\n if (value.length !== HEX_BYTES32_LENGTH) {\n throw new Error(\n `${label} must be exactly 32 bytes (${HEX_BYTES32_LENGTH} hex chars with 0x prefix), got ${value.length}`,\n );\n }\n}\n\n/**\n * Compute the SHA-256 hashlock from a secret preimage.\n *\n * Matches the on-chain validation: `sha256(abi.encodePacked(s))` where `s` is a `bytes32`.\n * `abi.encodePacked(bytes32)` is just the raw 32 bytes — no ABI padding.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @returns 0x-prefixed bytes32 SHA-256 hash\n * @throws if secret is not exactly 32 bytes\n */\nexport function computeHashlock(secret: Hex): Hex {\n assertBytes32(secret, \"Secret\");\n const secretBytes = hexToBytes(secret);\n const hash = sha256(secretBytes);\n return bytesToHex(hash);\n}\n\n/**\n * Validate that a secret's SHA-256 hash matches the expected hashlock.\n *\n * Use this for client-side pre-validation before sending the activation\n * transaction to avoid wasting gas on a contract revert.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @param hashlock - 0x-prefixed bytes32 expected hashlock from the vault\n * @returns true if SHA-256(secret) matches the hashlock\n * @throws if secret or hashlock is not exactly 32 bytes\n */\nexport function validateSecretAgainstHashlock(\n secret: Hex,\n hashlock: Hex,\n): boolean {\n assertBytes32(secret, \"Secret\");\n assertBytes32(hashlock, \"Hashlock\");\n // Validate hashlock is valid hex (secret is validated inside computeHashlock)\n hexToBytes(hashlock);\n\n const computed = computeHashlock(secret);\n return computed.toLowerCase() === hashlock.toLowerCase();\n}\n","import type { BitcoinWallet } from \"../../../shared/wallets/interfaces\";\n\n// Field docs use /** */ so they survive into the emitted .d.ts — the published\n// package is the only contract the external provider author (#2109) sees.\n\nexport interface DepositTermsVaultGroup {\n /** 0-based; equals the group's position (groups are ascending by vout). */\n readonly htlcVout: number;\n /** x-only hex (64 chars), as validated on-chain upstream. */\n readonly vaultProviderBtcPubkey: string;\n /** sats */\n readonly peginAmount: bigint;\n /**\n * sats; the MAXIMUM commission the depositor accepts —\n * floor(peginAmount * maxAcceptableCommissionBps / 10_000), the same\n * ceiling the registration calldata carries. An approving wallet MUST\n * enforce the VP payout commission output `<= commissionFee` (e.g. the\n * Ledger vault app does, firmware >= c8db53e), and every commission the\n * contract admits stays under this ceiling (floor is monotonic in bps),\n * so no contract-admitted deposit can be refused at payout. The actual\n * stamped commission may be lower. Display the quoted value in UI, not this.\n */\n readonly commissionFee: bigint;\n /** sats; the same value for every vault. */\n readonly depositorClaimValue: bigint;\n /**\n * sats; the cap an approving wallet enforces on the PegIn tx fee. Equals\n * the graph's exact (minimum) PegIn fee, which is deterministic — so the\n * cap is satisfied exact-by-construction.\n */\n readonly peginMaxFee: bigint;\n}\n\n/**\n * Field names follow btc-vault vocabulary (the protocol source of truth);\n * a device-wire encoder maps them to its intent fields (e.g. the Ledger TLV:\n * protocolFeeRate -> base_fee_rate, timelockPegin -> pegin_csv_timelock,\n * timelockAssert -> payout_timelock, peginAmount -> vault_amount).\n */\nexport interface DepositTerms {\n /**\n * btc-vault tx-graph version (`vaultCoreVersion`) these terms describe —\n * the vault's stamped on-chain version for resumes, the chain's\n * `activeVaultCoreVersion` for fresh deposits. It selects the PegIn shape\n * an approving wallet must expect: v1 = 2 outputs, no anchor; v2/v3 = TRUC\n * nVersion 3, 3 outputs with a 240-sat P2A anchor at vout 2, and an\n * Assert OP_RETURN marker that raises the claim value\n * (btc-vault `transactions/pegin.rs`, `assert_marker.rs`). A provider that\n * supports only one shape MUST reject the others here rather than\n * mis-validating the PSBTs later.\n */\n vaultCoreVersion: number;\n /**\n * sat/vB; the tx-graph fee rate (protocolFeeRate), NOT the mempool funding\n * rate. Approving wallets bound each payout's fee against this rate —\n * pass the exact graph rate, not an inflated ceiling.\n */\n protocolFeeRate: bigint;\n /** Vault-UTXO CSV timelock (blocks). */\n timelockPegin: number;\n /**\n * btc-vault `timelock_assert` (t2) — the CSV on Assert output 0. Its own\n * param, though production derives it and `timelockPegin` from one value.\n */\n timelockAssert: number;\n /** HTLC refund CSV timelock (blocks). */\n timelockRefund: number;\n /**\n * 64-char hex in display order. A device-wire encoder may need the\n * little-endian form — some hardware byte-compares it against\n * PSBT_IN_PREVIOUS_TXID rather than recomputing the txid.\n */\n prepeginTxid: string;\n /** sats; the funded Pre-PegIn fee (an approving wallet caps the signed fee at this). */\n prepeginMaxFee: bigint;\n /**\n * x-only hex. Sorted ascending by the upstream on-chain validation\n * (validateOnChainParticipantKeys); the builder passes them through\n * unasserted — approving devices may reject unsorted lists at load.\n */\n vaultKeeperBtcPubkeys: readonly string[];\n /**\n * x-only hex, sorted ascending upstream independently of vaultKeeperBtcPubkeys (same\n * pass-through contract). Universal challengers only — the full graph\n * challenger set is vaultKeeperBtcPubkeys ∪ universalChallengerBtcPubkeys (vault keepers are the local\n * challengers).\n */\n universalChallengerBtcPubkeys: readonly string[];\n /** Per-vault groups, ordered by ascending htlcVout. */\n vaults: readonly DepositTermsVaultGroup[];\n}\n\n/**\n * Implemented only by depositor-approval wallets (e.g. a Ledger vault\n * provider). Provider obligations:\n *\n * - Envelope: validate terms against the device's envelope BEFORE the\n * ceremony, rejecting with the shape `{ name: \"DepositTermsRejectedError\",\n * reason: \"device-envelope\", message }` (matched structurally, not by class).\n * - Idempotence: a byte-equal re-approval MUST be a no-op while the\n * device-side approval is live; anything that invalidates it (a later\n * `deriveContextHash`, a signing failure) MUST clear the memo.\n *\n * Seam invariant: any derive invalidates a prior approval, so the SDK\n * re-approves after every derive and before the next terms-bound signature.\n * The re-approval sites are `PeginManager.preparePegin`,\n * `runDepositorPresignFlow`, and `signAndBroadcast` (the Pre-PegIn broadcast,\n * which re-derives before approving unless `holdsApprovedDepositTerms`\n * reports the byte-equal intent still live — see `ensurePrePeginTermsApproval`).\n */\nexport interface DepositTermsApprover {\n approveDepositTerms(terms: DepositTerms): Promise<void>;\n /**\n * OPTIONAL fast-path probe: can the Pre-PegIn signature for exactly these\n * terms proceed under the connection's held approval without a new\n * ceremony? MUST report false once that Pre-PegIn was signed (one-shot),\n * MUST answer from host state without device I/O, MUST return false on any\n * doubt, and MUST never throw. A stale true fails closed at the next\n * signature — this is a UX optimization, never an authorization.\n */\n holdsApprovedDepositTerms?(terms: DepositTerms): Promise<boolean>;\n /**\n * OPTIONAL validate-only pre-check (#2110): reject terms the device\n * envelope would refuse, with the same `{ name:\n * \"DepositTermsRejectedError\", reason: \"device-envelope\", message }` shape\n * as `approveDepositTerms`, WITHOUT any device I/O and WITHOUT touching a\n * held approval — the SDK calls it before the first derive screen, so a\n * side effect here would cost or invalidate a physical ceremony. Success\n * is NOT an approval: `approveDepositTerms` still runs its own envelope\n * gate before the ceremony. Callers may pass provisional terms whose\n * `prepeginTxid` is a placeholder (the real txid exists only post-derive),\n * so implementations MUST NOT validate or bind `prepeginTxid` here.\n */\n validateDepositTerms?(terms: DepositTerms): Promise<void>;\n}\n\n/**\n * Where Pre-PegIn change must pay. Approval (policy) wallets sign key-path\n * under a wallet policy whose change branch the device alone can derive and\n * mark internal — the receive address is NOT acceptable change\n * (`process_in_outs.c:114-117` @ e400d8d8).\n *\n * Separate from {@link DepositTermsApprover} because only the Pre-PegIn build\n * needs it: the presign/payout ceremonies approve terms without ever creating\n * change, so they must not require a wallet to implement this.\n *\n * MUST be stable across a deposit flow: the app reads it to build the tx and\n * `preparePegin` re-reads it to verify, so mid-flow rotation fails that gate.\n */\nexport interface PrePeginChangeSource {\n getChangeAddress(): Promise<string>;\n}\n\n/** Probes {@link DepositTermsApprover.approveDepositTerms}. */\nexport function supportsDepositApproval(\n wallet: BitcoinWallet,\n): wallet is BitcoinWallet & DepositTermsApprover {\n return (\n typeof (wallet as Partial<DepositTermsApprover>).approveDepositTerms ===\n \"function\"\n );\n}\n\n/**\n * The wallet's change address, for the one caller that needs it.\n *\n * Narrowing on `approveDepositTerms` alone cannot promise this method, so\n * calling it off the narrowed value would die on `is not a function` in the\n * middle of `preparePegin`, after the pubkey read. Ask here instead and fail\n * with something a provider author can act on.\n *\n * @throws If the wallet cannot report a change address.\n */\nexport async function requireChangeAddress(\n wallet: BitcoinWallet,\n): Promise<string> {\n const changeSource = wallet as Partial<PrePeginChangeSource>;\n if (typeof changeSource.getChangeAddress !== \"function\") {\n throw new Error(\n \"Approval wallet does not implement getChangeAddress; it must expose its change branch, \" +\n \"because the signing device accepts Pre-PegIn change only there.\",\n );\n }\n return changeSource.getChangeAddress();\n}\n\n/**\n * Spreadable forward of the approval capability for wallet-wrapper objects.\n * Object spread drops prototype methods, so every `{...wallet}` wrapper site\n * must re-attach the capability explicitly: `...forwardDepositApproval(wallet)`.\n */\nexport function forwardDepositApproval(\n wallet: BitcoinWallet,\n): Partial<DepositTermsApprover & PrePeginChangeSource> {\n if (!supportsDepositApproval(wallet)) {\n return {};\n }\n const holdsApprovedDepositTerms = wallet.holdsApprovedDepositTerms;\n const validateDepositTerms = wallet.validateDepositTerms;\n const getChangeAddress = (wallet as Partial<PrePeginChangeSource>)\n .getChangeAddress;\n return {\n approveDepositTerms: (terms) => wallet.approveDepositTerms(terms),\n // All optional in the seam: forward only what the provider implements, so\n // wrapper consumers can keep probing by typeof.\n ...(typeof getChangeAddress === \"function\"\n ? { getChangeAddress: () => getChangeAddress.call(wallet) }\n : {}),\n ...(typeof holdsApprovedDepositTerms === \"function\"\n ? {\n holdsApprovedDepositTerms: (terms: DepositTerms) =>\n holdsApprovedDepositTerms.call(wallet, terms),\n }\n : {}),\n ...(typeof validateDepositTerms === \"function\"\n ? {\n validateDepositTerms: (terms: DepositTerms) =>\n validateDepositTerms.call(wallet, terms),\n }\n : {}),\n };\n}\n\nexport interface BuildDepositTermsInputs {\n /** btc-vault tx-graph version the graph is built under. */\n vaultCoreVersion: number;\n protocolFeeRate: bigint;\n timelockPegin: number;\n /** btc-vault `timelock_assert` (t2) — its own param; NOT derived from timelockPegin here. */\n timelockAssert: number;\n timelockRefund: number;\n prepeginTxid: string;\n prepeginMaxFee: bigint;\n vaultProviderBtcPubkey: string;\n vaultKeeperBtcPubkeys: readonly string[];\n universalChallengerBtcPubkeys: readonly string[];\n /** Ceiling bps, not the quote — see {@link DepositTermsVaultGroup.commissionFee}. */\n maxAcceptableCommissionBps: number;\n peginAmounts: readonly bigint[];\n depositorClaimValue: bigint;\n peginMaxFee: bigint;\n}\n","/**\n * Payout Manager\n *\n * High-level manager that orchestrates the payout signing flow by coordinating\n * SDK primitives ({@link buildPayoutPsbt}, {@link extractPayoutSignature})\n * with a user-provided Bitcoin wallet.\n *\n * The Payout transaction references the Assert transaction (input 1).\n *\n * @see {@link PeginManager} - For Steps 1–4 of the peg-in flow\n * @see {@link buildPayoutPsbt} - Lower-level primitive for custom implementations\n * @see {@link extractPayoutSignature} - Extract signatures from signed PSBTs\n *\n * @module managers/PayoutManager\n */\n\nimport type { BitcoinWallet, SignPsbtOptions } from \"../../../shared/wallets\";\nimport {\n assertPsbtUnsignedTxMatches,\n assertScriptPathSchnorrSignature,\n buildPayoutPsbt,\n extractPayoutSignature,\n validateWalletPubkey,\n type Network,\n} from \"../primitives\";\nimport { DEPOSITOR_SIGNED_INPUT_COUNT } from \"../primitives/psbt/constants\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\n\n/** Payout PSBTs are signed by the depositor on input 0 (Taproot script-path). */\nconst PAYOUT_SIGNED_INPUT_INDEX = 0;\n\n/**\n * Configuration for the PayoutManager.\n */\nexport interface PayoutManagerConfig {\n /**\n * Bitcoin network to use for transactions.\n */\n network: Network;\n\n /**\n * Bitcoin wallet for signing payout transactions.\n */\n btcWallet: BitcoinWallet;\n}\n\n/**\n * Base parameters shared by both payout transaction types.\n */\ninterface SignPayoutBaseParams {\n /**\n * Vault core (tx-graph) version the vault was registered under — the\n * vault's stamped on-chain `vaultCoreVersion`. Forwarded to\n * {@link buildPayoutPsbt} to derive the matching graph's payout scripts.\n */\n vaultCoreVersion: number;\n\n /**\n * Peg-in transaction hex.\n * The original transaction that created the vault output being spent.\n */\n peginTxHex: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex).\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex).\n */\n vaultKeeperBtcPubkeys: string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex).\n */\n universalChallengerBtcPubkeys: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n /** btc-vault `timelock_assert`; payout input 1's sequence. */\n timelockAssert: number;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex). This MUST be the\n * key registered on-chain for the vault — typically read from\n * `BTCVaultRegistry.getBtcVaultBasicInfo(...).depositorBtcPubKey`.\n *\n * Required: omitting it would degrade `validateWalletPubkey` to a\n * self-comparison, allowing the wrong wallet to produce a signature\n * over a script tree that doesn't match the on-chain UTXO.\n */\n depositorBtcPubkey: string;\n\n /**\n * The on-chain registered depositor payout scriptPubKey (hex, with or without 0x prefix).\n * Used to validate that the VP-provided payout transaction actually pays to the\n * correct depositor payout address before signing.\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * The claimer's x-only BTC public key for this payout (64-char hex, no prefix).\n * Forwarded to {@link buildPayoutPsbt} for per-role output validation.\n */\n claimerBtcPubkey: string;\n\n /**\n * VP commission in basis points (`1..=9999`). Forwarded to {@link buildPayoutPsbt}.\n */\n commissionBps: number;\n\n /**\n * Version-locked tx-graph fee rate (sat/vB) the graph was built with.\n * Forwarded to {@link buildPayoutPsbt} for the fee band.\n */\n protocolFeeRate: bigint;\n\n /**\n * Security council member x-only pubkeys (hex); forwarded to\n * {@link buildPayoutPsbt} to rebuild the Assert:0 payout leaf and to size the\n * fee floor (see PayoutParams).\n */\n councilMembers: string[];\n\n /** M-of-N council quorum; shapes the Assert:0 council leaf (see PayoutParams). */\n councilQuorum: number;\n\n /**\n * RFC-006 resolved payout destinations, keyed by lowercased x-only operation\n * pubkey. Forwarded verbatim to {@link buildPayoutPsbt}; every VK claimer\n * must be present.\n */\n vkClaimerPayoutScriptPubKeys: Readonly<Record<string, string>>;\n /** RFC-006 VP commission destination. Forwarded to {@link buildPayoutPsbt}. */\n vpCommissionScriptPubKey: string;\n}\n\n/**\n * Parameters for signing a Payout transaction.\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface SignPayoutParams extends SignPayoutBaseParams {\n /**\n * Payout transaction hex (unsigned).\n * This is the transaction from the vault provider that needs depositor signature.\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex.\n * Payout input 1 references Assert output 0.\n */\n assertTxHex: string;\n}\n\n/**\n * Result of signing a payout transaction.\n */\nexport interface PayoutSignatureResult {\n /**\n * 64-byte Schnorr signature (128 hex characters).\n */\n signature: string;\n\n /**\n * Depositor's BTC public key used for signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * High-level manager for payout transaction signing.\n *\n * @remarks\n * After registering your peg-in on Ethereum (Step 3), the vault provider prepares\n * claim/payout transaction pairs. You must sign each payout transaction using this\n * manager and submit the signatures to the vault provider's RPC API.\n *\n * **What happens internally:**\n * 1. Validates your wallet's public key matches the vault's depositor\n * 2. Builds an unsigned PSBT with taproot script path spend info\n * 3. Signs input 0 (the vault UTXO) with your wallet\n * 4. Extracts the 64-byte Schnorr signature\n *\n * **Note:** The payout transaction has 2 inputs. PayoutManager only signs input 0\n * (from the peg-in tx). Input 1 (from the assert tx) is signed by the vault provider.\n *\n * @see {@link PeginManager} - For the complete peg-in flow context\n * @see {@link buildPayoutPsbt} - Lower-level primitive used internally\n * @see {@link extractPayoutSignature} - Signature extraction primitive\n */\nexport class PayoutManager {\n private readonly config: PayoutManagerConfig;\n\n /**\n * Creates a new PayoutManager instance.\n *\n * @param config - Manager configuration including wallet\n */\n constructor(config: PayoutManagerConfig) {\n this.config = config;\n }\n\n /**\n * Signs a Payout transaction and extracts the Schnorr signature.\n *\n * Flow:\n * 1. Vault provider submits Claim transaction\n * 2. Claimer submits Assert transaction to prove validity\n * 3. Payout can be executed (references Assert tx)\n *\n * This method orchestrates the following steps:\n * 1. Get wallet's public key and convert to x-only format\n * 2. Validate wallet pubkey matches on-chain depositor pubkey (if provided)\n * 3. Build unsigned PSBT using primitives\n * 4. Sign PSBT via btcWallet.signPsbt()\n * 5. Extract 64-byte Schnorr signature using primitives\n *\n * The returned signature can be submitted to the vault provider API.\n *\n * @param params - Payout signing parameters\n * @returns Signature result with 64-byte Schnorr signature and depositor pubkey\n * @throws Error if wallet pubkey doesn't match depositor pubkey\n * @throws Error if wallet operations fail or signature extraction fails\n */\n async signPayoutTransaction(\n params: SignPayoutParams,\n ): Promise<PayoutSignatureResult> {\n // Validate wallet pubkey matches depositor and get both formats\n const walletPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n const { depositorPubkey } = validateWalletPubkey(\n walletPubkeyRaw,\n params.depositorBtcPubkey,\n );\n\n // Build unsigned PSBT for Payout (uses Assert tx). Per-role output\n // validation happens inside buildPayoutPsbt against the resolved input\n // values.\n const payoutPsbt = await buildPayoutPsbt({\n vaultCoreVersion: params.vaultCoreVersion,\n payoutTxHex: params.payoutTxHex,\n peginTxHex: params.peginTxHex,\n assertTxHex: params.assertTxHex,\n depositorBtcPubkey: depositorPubkey,\n vaultProviderBtcPubkey: params.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: params.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: params.universalChallengerBtcPubkeys,\n timelockPegin: params.timelockPegin,\n timelockAssert: params.timelockAssert,\n network: this.config.network,\n claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n protocolFeeRate: params.protocolFeeRate,\n councilMembers: params.councilMembers,\n councilQuorum: params.councilQuorum,\n vkClaimerPayoutScriptPubKeys: params.vkClaimerPayoutScriptPubKeys,\n vpCommissionScriptPubKey: params.vpCommissionScriptPubKey,\n });\n\n // Sign PSBT via wallet (Taproot script-path spend, input 0 only)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n createTaprootScriptPathSignOptions(\n walletPubkeyRaw,\n DEPOSITOR_SIGNED_INPUT_COUNT,\n ),\n );\n\n assertPsbtUnsignedTxMatches({\n requestedPsbtHex: payoutPsbt.psbtHex,\n returnedPsbtHex: signedPsbtHex,\n });\n\n // Extract Schnorr signature\n const signature = extractPayoutSignature(signedPsbtHex, depositorPubkey);\n // Critical Path #7: verify the signature against a sighash recomputed from\n // the PSBT we built, not the wallet-returned one.\n assertScriptPathSchnorrSignature({\n requestedPsbtHex: payoutPsbt.psbtHex,\n signatureHex: signature,\n signerXOnlyPubkeyHex: depositorPubkey,\n inputIndex: PAYOUT_SIGNED_INPUT_INDEX,\n });\n\n return {\n signature,\n depositorBtcPubkey: depositorPubkey,\n };\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.network;\n }\n\n /**\n * Checks if the wallet supports batch signing (signPsbts).\n *\n * @returns true if batch signing is supported\n */\n supportsBatchSigning(): boolean {\n return typeof this.config.btcWallet.signPsbts === \"function\";\n }\n\n /**\n * Batch signs multiple payout transactions (1 per claimer).\n * This allows signing all transactions with a single wallet interaction.\n *\n * @param transactions - Array of payout params to sign\n * @returns Array of signature results matching input order\n * @throws Error if wallet doesn't support batch signing\n * @throws Error if any signing operation fails\n */\n async signPayoutTransactionsBatch(transactions: SignPayoutParams[]): Promise<\n Array<{\n payoutSignature: string;\n depositorBtcPubkey: string;\n }>\n > {\n if (!this.supportsBatchSigning()) {\n throw new Error(\n \"Wallet does not support batch signing (signPsbts method not available)\",\n );\n }\n\n // Get wallet pubkey once\n const walletPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n\n // Build all PSBTs (1 per claimer)\n const psbtsToSign: string[] = [];\n const signOptions: SignPsbtOptions[] = [];\n const depositorPubkeys: string[] = [];\n\n for (const tx of transactions) {\n // Validate wallet pubkey matches depositor\n const { depositorPubkey } = validateWalletPubkey(\n walletPubkeyRaw,\n tx.depositorBtcPubkey,\n );\n depositorPubkeys.push(depositorPubkey);\n\n // Build Payout PSBT (output validation runs inside buildPayoutPsbt\n // against resolved input values).\n const payoutPsbt = await buildPayoutPsbt({\n vaultCoreVersion: tx.vaultCoreVersion,\n payoutTxHex: tx.payoutTxHex,\n peginTxHex: tx.peginTxHex,\n assertTxHex: tx.assertTxHex,\n depositorBtcPubkey: depositorPubkey,\n vaultProviderBtcPubkey: tx.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: tx.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: tx.universalChallengerBtcPubkeys,\n timelockPegin: tx.timelockPegin,\n timelockAssert: tx.timelockAssert,\n network: this.config.network,\n claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n protocolFeeRate: tx.protocolFeeRate,\n councilMembers: tx.councilMembers,\n councilQuorum: tx.councilQuorum,\n vkClaimerPayoutScriptPubKeys: tx.vkClaimerPayoutScriptPubKeys,\n vpCommissionScriptPubKey: tx.vpCommissionScriptPubKey,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push(\n createTaprootScriptPathSignOptions(\n walletPubkeyRaw,\n DEPOSITOR_SIGNED_INPUT_COUNT,\n ),\n );\n }\n\n // Batch sign all PSBTs with single wallet interaction\n const signedPsbts = await this.config.btcWallet.signPsbts!(\n psbtsToSign,\n signOptions,\n );\n\n // Validate that wallet returned the expected number of signed PSBTs\n if (signedPsbts.length !== transactions.length) {\n throw new Error(\n `Expected ${transactions.length} signed PSBTs but received ${signedPsbts.length}`,\n );\n }\n\n // Extract signatures from signed PSBTs\n const results: Array<{\n payoutSignature: string;\n depositorBtcPubkey: string;\n }> = [];\n\n for (let i = 0; i < transactions.length; i++) {\n const depositorPubkey = depositorPubkeys[i];\n assertPsbtUnsignedTxMatches({\n requestedPsbtHex: psbtsToSign[i],\n returnedPsbtHex: signedPsbts[i],\n });\n const payoutSignature = extractPayoutSignature(\n signedPsbts[i],\n depositorPubkey,\n );\n assertScriptPathSchnorrSignature({\n requestedPsbtHex: psbtsToSign[i],\n signatureHex: payoutSignature,\n signerXOnlyPubkeyHex: depositorPubkey,\n inputIndex: PAYOUT_SIGNED_INPUT_INDEX,\n });\n\n results.push({\n payoutSignature,\n depositorBtcPubkey: depositorPubkey,\n });\n }\n\n return results;\n }\n}\n","/**\n * Wallet-signing helper that routes a lone PSBT to `signPsbt`, prefers native\n * `signPsbts` for real batches, and falls back to sequential `signPsbt` for\n * wallets that don't implement batch signing.\n *\n * @module managers/pegin/signPsbtsWithFallback\n */\n\nimport type {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../../shared/wallets\";\n\n/**\n * Sign one or more PSBTs against a wallet.\n *\n * A single PSBT is always signed via `signPsbt`, never the batch endpoint: it's\n * one wallet interaction either way, and `signPsbt` is the universally-required\n * wallet method (batch `signPsbts` is optional), so single-sign is the portable\n * choice — some integrations (notably MPC / institutional wallets) prefer it.\n * For a real batch (>1), wallets exposing native `signPsbts` (e.g. UniSat) sign\n * in one interaction; others loop `signPsbt`.\n *\n * @throws If native `signPsbts` returns a different number of signed PSBTs\n * than were submitted.\n */\nexport async function signPsbtsWithFallback(\n wallet: BitcoinWallet,\n psbtsHexes: string[],\n options?: SignPsbtOptions[],\n): Promise<string[]> {\n if (psbtsHexes.length === 1) {\n return [await wallet.signPsbt(psbtsHexes[0], options?.[0])];\n }\n\n if (typeof wallet.signPsbts === \"function\") {\n const signedPsbts = await wallet.signPsbts(psbtsHexes, options);\n if (signedPsbts.length !== psbtsHexes.length) {\n throw new Error(\n `Expected ${psbtsHexes.length} signed PSBTs but received ${signedPsbts.length}`,\n );\n }\n return signedPsbts;\n }\n\n const signedPsbts: string[] = [];\n for (let i = 0; i < psbtsHexes.length; i++) {\n signedPsbts.push(await wallet.signPsbt(psbtsHexes[i], options?.[i]));\n }\n return signedPsbts;\n}\n"],"names":["OP_RETURN","OP_PUSH32","OP_RETURN_PUSH32_SCRIPT_LEN","assertAuthAnchorOpReturn","fundedPrePeginTxHex","vaultCount","expectedAuthAnchorHashHex","cleanHex","stripHexPrefix","tx","bitcoin","opReturnOutput","script","pushedHex","findAuthAnchorOpReturn","hits","i","output","HEX_BYTES32_LENGTH","hexToBytes","hex","clean","bytes","bytesToHex","b","assertBytes32","value","label","computeHashlock","secret","secretBytes","hash","sha256","validateSecretAgainstHashlock","hashlock","supportsDepositApproval","wallet","requireChangeAddress","changeSource","forwardDepositApproval","holdsApprovedDepositTerms","validateDepositTerms","getChangeAddress","terms","PAYOUT_SIGNED_INPUT_INDEX","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","DEPOSITOR_SIGNED_INPUT_COUNT","assertPsbtUnsignedTxMatches","signature","extractPayoutSignature","assertScriptPathSchnorrSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature","signPsbtsWithFallback","psbtsHexes","options"],"mappings":"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"}