@babylonlabs-io/ts-sdk 0.28.0 → 0.28.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 (53) hide show
  1. package/dist/PeginManager-Da4uSHzl.cjs +2 -0
  2. package/dist/PeginManager-Da4uSHzl.cjs.map +1 -0
  3. package/dist/{deriveVaultRoot-DAMZDqg-.js → PeginManager-DzMSIQ0I.js} +1131 -1043
  4. package/dist/PeginManager-DzMSIQ0I.js.map +1 -0
  5. package/dist/buildAndBroadcastRefund-DkEpTFkv.cjs +2 -0
  6. package/dist/buildAndBroadcastRefund-DkEpTFkv.cjs.map +1 -0
  7. package/dist/{buildAndBroadcastRefund-Cc4-L7gX.js → buildAndBroadcastRefund-xWS8frc6.js} +318 -329
  8. package/dist/buildAndBroadcastRefund-xWS8frc6.js.map +1 -0
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.js +4 -4
  11. package/dist/{sha2-CPdTLk1u.js → sha2-6wN58S6R.js} +9 -9
  12. package/dist/{sha2-CPdTLk1u.js.map → sha2-6wN58S6R.js.map} +1 -1
  13. package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts.map +1 -1
  14. package/dist/tbv/core/clients/index.cjs +1 -1
  15. package/dist/tbv/core/clients/index.js +2 -2
  16. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts +80 -70
  17. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts.map +1 -1
  18. package/dist/tbv/core/index.cjs +1 -1
  19. package/dist/tbv/core/index.js +4 -4
  20. package/dist/tbv/core/managers/PeginManager.d.ts +64 -27
  21. package/dist/tbv/core/managers/PeginManager.d.ts.map +1 -1
  22. package/dist/tbv/core/managers/index.d.ts +1 -1
  23. package/dist/tbv/core/managers/index.d.ts.map +1 -1
  24. package/dist/tbv/core/services/deposit/validation.d.ts +0 -4
  25. package/dist/tbv/core/services/deposit/validation.d.ts.map +1 -1
  26. package/dist/tbv/core/services/index.cjs +1 -1
  27. package/dist/tbv/core/services/index.js +1 -1
  28. package/dist/tbv/index.cjs +1 -1
  29. package/dist/tbv/index.js +4 -4
  30. package/dist/testing/MockBitcoinWallet.d.ts +1 -0
  31. package/dist/testing/MockBitcoinWallet.d.ts.map +1 -1
  32. package/dist/testing/index.cjs +1 -1
  33. package/dist/testing/index.cjs.map +1 -1
  34. package/dist/testing/index.js +35 -34
  35. package/dist/testing/index.js.map +1 -1
  36. package/dist/{types-CQ86O7NX.js → types-CnG3JsRs.js} +111 -81
  37. package/dist/types-CnG3JsRs.js.map +1 -0
  38. package/dist/types-jmEyzzhY.cjs +2 -0
  39. package/dist/types-jmEyzzhY.cjs.map +1 -0
  40. package/dist/{vault-registry-reader-CshEgmS0.js → vault-registry-reader-BywZhqJL.js} +37 -37
  41. package/dist/{vault-registry-reader-CshEgmS0.js.map → vault-registry-reader-BywZhqJL.js.map} +1 -1
  42. package/dist/{vault-registry-reader-_2BjSjoN.cjs → vault-registry-reader-DdruADqa.cjs} +2 -2
  43. package/dist/{vault-registry-reader-_2BjSjoN.cjs.map → vault-registry-reader-DdruADqa.cjs.map} +1 -1
  44. package/package.json +1 -1
  45. package/dist/buildAndBroadcastRefund-Cc4-L7gX.js.map +0 -1
  46. package/dist/buildAndBroadcastRefund-OoaQaNqn.cjs +0 -2
  47. package/dist/buildAndBroadcastRefund-OoaQaNqn.cjs.map +0 -1
  48. package/dist/deriveVaultRoot-B4gnRbW_.cjs +0 -2
  49. package/dist/deriveVaultRoot-B4gnRbW_.cjs.map +0 -1
  50. package/dist/deriveVaultRoot-DAMZDqg-.js.map +0 -1
  51. package/dist/types-CQ86O7NX.js.map +0 -1
  52. package/dist/types-CcwaEPE1.cjs +0 -2
  53. package/dist/types-CcwaEPE1.cjs.map +0 -1
@@ -1,21 +1,22 @@
1
- var zt = Object.defineProperty;
2
- var Yt = (e, t, n) => t in e ? zt(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
- var p = (e, t, n) => Yt(e, typeof t != "symbol" ? t + "" : t, n);
4
- import * as Jt from "bitcoinjs-lib";
5
- import { Transaction as Qt, Psbt as dt } from "bitcoinjs-lib";
1
+ var Jt = Object.defineProperty;
2
+ var te = (e, t, n) => t in e ? Jt(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
+ var b = (e, t, n) => te(e, typeof t != "symbol" ? t + "" : t, n);
4
+ import * as ee from "bitcoinjs-lib";
5
+ import { Transaction as ne, Psbt as ft } from "bitcoinjs-lib";
6
6
  import { Buffer as et } from "buffer";
7
- import { isAddressEqual as ft, createPublicClient as j, http as q, encodeFunctionData as gt, zeroAddress as te } from "viem";
8
- import { c as ee } from "./signing-BZigafm0.js";
9
- import { deriveVaultId as pt } from "@babylonlabs-io/babylon-tbv-rust-wasm";
10
- import { b as ne, a as se, d as oe, e as re, f as ie } from "./challengeAssert-j2Vwqo0-.js";
11
- import { s as v, g as mt, e as _, i as ae, p as ce, u as le, h as he } from "./bitcoin-B-Y0DlqR.js";
12
- import { M as bt } from "./validation-CxqROCno.js";
13
- import { b as ue, f as G, i as de } from "./psbtInputFields-DeTFSJOq.js";
14
- import { p as fe, f as ge } from "./fundPeginTransaction-oV-dNJOU.js";
15
- import { p as pe, f as me } from "./vault-registry-reader-CshEgmS0.js";
16
- import { B as S } from "./types-CQ86O7NX.js";
17
- import { c as St, H as be, r as W, a as H, b as nt, u as we, d as wt, e as F, f as U, g as ye, s as L, h as Ot } from "./sha2-CPdTLk1u.js";
18
- const C = {
7
+ import { isAddressEqual as gt, createPublicClient as j, http as z, encodeFunctionData as pt, zeroAddress as se } from "viem";
8
+ import { deriveVaultId as mt } from "@babylonlabs-io/babylon-tbv-rust-wasm";
9
+ import { b as bt, a as oe, d as re, e as ie, f as ae } from "./challengeAssert-j2Vwqo0-.js";
10
+ import { u as $t, h as nt, e as I, s as _, g as wt, i as ce, p as le } from "./bitcoin-B-Y0DlqR.js";
11
+ import { h as ue } from "./buildAndBroadcastRefund-xWS8frc6.js";
12
+ import { c as he } from "./signing-BZigafm0.js";
13
+ import { M as yt } from "./validation-CxqROCno.js";
14
+ import { a as Rt, b as U, c as A, d as F, e as st, s as L, f as Ut, H as de, r as V, u as fe, g as xt, h as ge } from "./sha2-6wN58S6R.js";
15
+ import { b as pe, f as q, i as me } from "./psbtInputFields-DeTFSJOq.js";
16
+ import { p as be, f as we } from "./fundPeginTransaction-oV-dNJOU.js";
17
+ import { p as ye, f as xe } from "./vault-registry-reader-BywZhqJL.js";
18
+ import { B as C } from "./types-CnG3JsRs.js";
19
+ const S = {
19
20
  // VaultAlreadyExists()
20
21
  "0x04aabf33": "Vault already exists: This Bitcoin transaction has already been registered. Please select different UTXOs or use a different amount to create a unique transaction.",
21
22
  // ScriptPubKeyMismatch() - taproot output doesn't match expected script
@@ -49,7 +50,7 @@ const C = {
49
50
  // PeginTransactionAlreadyUsed()
50
51
  "0x7ed061c9": "This pegin transaction has already been used to activate another vault."
51
52
  };
52
- function it(e) {
53
+ function at(e) {
53
54
  if (!e || typeof e != "object") return;
54
55
  const t = e;
55
56
  if (typeof t.data == "string" && t.data.startsWith("0x"))
@@ -68,24 +69,24 @@ function it(e) {
68
69
  if (i)
69
70
  return i[1];
70
71
  }
71
- function An(e) {
72
- const t = it(e);
72
+ function Ln(e) {
73
+ const t = at(e);
73
74
  if (t) {
74
75
  const n = t.substring(0, 10);
75
- return C[t] ?? C[n];
76
+ return S[t] ?? S[n];
76
77
  }
77
78
  }
78
- function Hn(e) {
79
- const t = it(e);
79
+ function Vn(e) {
80
+ const t = at(e);
80
81
  if (t === void 0) return !1;
81
82
  const n = t.substring(0, 10);
82
- return t in C || n in C;
83
+ return t in S || n in S;
83
84
  }
84
- function A(e) {
85
+ function H(e) {
85
86
  console.error("[Contract Error] Raw error:", e);
86
- const t = it(e);
87
+ const t = at(e);
87
88
  if (console.error("[Contract Error] Extracted error data:", t), t) {
88
- const s = t.substring(0, 10), o = C[t] ?? C[s];
89
+ const s = t.substring(0, 10), o = S[t] ?? S[s];
89
90
  if (o)
90
91
  throw console.error("[Contract Error] Known error:", o), new Error(o);
91
92
  }
@@ -103,281 +104,899 @@ function A(e) {
103
104
  }
104
105
  throw e instanceof Error ? (console.error("[Contract Error] Unhandled error:", e.message), e) : new Error(`Contract call failed: ${String(e)}`);
105
106
  }
106
- const xe = 0, Pe = /^0x[0-9a-f]+$/i, Ee = /^[0-9a-f]+$/i, Te = /^[A-Za-z0-9+/]+={0,2}$/;
107
- function O(e) {
108
- if (typeof e != "string" || e.length === 0)
109
- throw new Error("BTC wallet returned empty public key");
110
- return ce(e).toLowerCase();
107
+ const W = /* @__PURE__ */ BigInt(2 ** 32 - 1), Pt = /* @__PURE__ */ BigInt(32);
108
+ function Pe(e, t = !1) {
109
+ return t ? { h: Number(e & W), l: Number(e >> Pt & W) } : { h: Number(e >> Pt & W) | 0, l: Number(e & W) | 0 };
111
110
  }
112
- function ke(e) {
113
- if (typeof e != "string" || e.length === 0)
114
- throw new Error("BTC wallet returned empty BIP-322 signature");
115
- if (e.startsWith("0x") || e.startsWith("0X")) {
116
- if (!Pe.test(e) || e.length < 4 || e.length % 2 !== 0)
117
- throw new Error("BTC wallet returned malformed hex BIP-322 signature");
118
- return e.toLowerCase();
111
+ function Ee(e, t = !1) {
112
+ const n = e.length;
113
+ let s = new Uint32Array(n), o = new Uint32Array(n);
114
+ for (let r = 0; r < n; r++) {
115
+ const { h: i, l: a } = Pe(e[r], t);
116
+ [s[r], o[r]] = [i, a];
119
117
  }
120
- if (Ee.test(e)) {
121
- if (e.length % 2 !== 0)
122
- throw new Error("BTC wallet returned malformed hex BIP-322 signature");
123
- return `0x${e.toLowerCase()}`;
118
+ return [s, o];
119
+ }
120
+ const ke = (e, t, n) => e << n | t >>> 32 - n, Te = (e, t, n) => t << n | e >>> 32 - n, _e = (e, t, n) => t << n - 32 | e >>> 64 - n, ve = (e, t, n) => e << n - 32 | t >>> 64 - n;
121
+ class Lt {
122
+ constructor(t, n) {
123
+ b(this, "oHash");
124
+ b(this, "iHash");
125
+ b(this, "blockLen");
126
+ b(this, "outputLen");
127
+ b(this, "finished", !1);
128
+ b(this, "destroyed", !1);
129
+ if (Rt(t), U(n, void 0, "key"), this.iHash = t.create(), typeof this.iHash.update != "function")
130
+ throw new Error("Expected instance of class which extends utils.Hash");
131
+ this.blockLen = this.iHash.blockLen, this.outputLen = this.iHash.outputLen;
132
+ const s = this.blockLen, o = new Uint8Array(s);
133
+ o.set(n.length > s ? t.create().update(n).digest() : n);
134
+ for (let r = 0; r < o.length; r++)
135
+ o[r] ^= 54;
136
+ this.iHash.update(o), this.oHash = t.create();
137
+ for (let r = 0; r < o.length; r++)
138
+ o[r] ^= 106;
139
+ this.oHash.update(o), A(o);
140
+ }
141
+ update(t) {
142
+ return F(this), this.iHash.update(t), this;
143
+ }
144
+ digestInto(t) {
145
+ F(this), U(t, this.outputLen, "output"), this.finished = !0, this.iHash.digestInto(t), this.oHash.update(t), this.oHash.digestInto(t), this.destroy();
146
+ }
147
+ digest() {
148
+ const t = new Uint8Array(this.oHash.outputLen);
149
+ return this.digestInto(t), t;
150
+ }
151
+ _cloneInto(t) {
152
+ t || (t = Object.create(Object.getPrototypeOf(this), {}));
153
+ const { oHash: n, iHash: s, finished: o, destroyed: r, blockLen: i, outputLen: a } = this;
154
+ return t = t, t.finished = o, t.destroyed = r, t.blockLen = i, t.outputLen = a, t.oHash = n._cloneInto(t.oHash), t.iHash = s._cloneInto(t.iHash), t;
155
+ }
156
+ clone() {
157
+ return this._cloneInto();
158
+ }
159
+ destroy() {
160
+ this.destroyed = !0, this.oHash.destroy(), this.iHash.destroy();
124
161
  }
125
- if (!Te.test(e) || e.length % 4 !== 0)
126
- throw new Error("BTC wallet returned malformed base64 BIP-322 signature");
127
- const t = et.from(e, "base64");
128
- if (t.length === 0 || t.toString("base64") !== e)
129
- throw new Error("BTC wallet returned malformed base64 BIP-322 signature");
130
- return `0x${t.toString("hex")}`;
131
162
  }
132
- function _e(e, t, n, s) {
133
- const o = n == null ? void 0 : n[`${e}:${t}`];
134
- return o ? Promise.resolve({
135
- txid: e,
136
- vout: t,
137
- value: o.value,
138
- scriptPubKey: o.scriptPubKey
139
- }) : me(e, t, s);
163
+ const Vt = (e, t, n) => new Lt(e, t).update(n).digest();
164
+ Vt.create = (e, t) => new Lt(e, t);
165
+ const G = /* @__PURE__ */ Uint8Array.of(0), Et = /* @__PURE__ */ Uint8Array.of();
166
+ function ct(e, t, n, s = 32) {
167
+ Rt(e), st(s, "length");
168
+ const o = e.outputLen;
169
+ if (s > 255 * o)
170
+ throw new Error("Length must be <= 255*HashLen");
171
+ const r = Math.ceil(s / o);
172
+ n === void 0 ? n = Et : U(n, void 0, "info");
173
+ const i = new Uint8Array(r * o), a = Vt.create(e, t), l = a._cloneInto(), u = new Uint8Array(a.outputLen);
174
+ for (let c = 0; c < r; c++)
175
+ G[0] = c + 1, l.update(c === 0 ? Et : u).update(n).update(G).digestInto(u), i.set(u, o * c), a._cloneInto(l);
176
+ return a.destroy(), l.destroy(), A(u, G), i.slice(0, s);
140
177
  }
141
- const yt = 12e4;
142
- class Cn {
143
- /**
144
- * Creates a new PeginManager instance.
145
- *
146
- * @param config - Manager configuration including wallets and contract addresses
147
- */
148
- constructor(t) {
149
- p(this, "config");
150
- this.config = t;
151
- }
152
- /**
153
- * Prepares a peg-in by building the Pre-PegIn HTLC transaction,
154
- * funding it, constructing the PegIn transaction, and signing the PegIn input.
155
- *
156
- * This method orchestrates the following steps:
157
- * 1. Get depositor BTC public key from wallet
158
- * 2. Build unfunded Pre-PegIn transaction (HTLC output) using primitives
159
- * 3. Select UTXOs to cover the HTLC value
160
- * 4. Fund the Pre-PegIn transaction
161
- * 5. Derive the PegIn transaction from the funded Pre-PegIn tx
162
- * 6. Build PSBT for signing the PegIn input (HTLC leaf 0)
163
- * 7. Sign via BTC wallet and extract depositor signature
164
- *
165
- * The returned `fundedPrePeginTxHex` is funded but unsigned (inputs unsigned).
166
- * Use `signAndBroadcast()` AFTER registering on Ethereum to broadcast it.
167
- *
168
- * @param params - Pegin parameters including amount, HTLC params, UTXOs
169
- * @returns Pegin result with funded Pre-PegIn tx, signed PegIn input, and signatures
170
- * @throws Error if wallet operations fail or insufficient funds
171
- */
172
- async preparePegin(t) {
173
- const n = await this.config.btcWallet.getPublicKeyHex(), s = O(n), o = v(t.vaultProviderBtcPubkey), r = t.vaultKeeperBtcPubkeys.map(v), i = t.universalChallengerBtcPubkeys.map(v);
174
- if (t.hashlocks.length !== t.amounts.length)
178
+ const Z = new TextEncoder().encode("babylonvault"), kt = 255, Tt = 65535, _t = 2, Ie = "hashlock", Be = "auth-anchor", He = "wots-seed";
179
+ function Wt(e) {
180
+ if (!Number.isInteger(e) || e < 0 || e > 4294967295)
181
+ throw new Error(`i2osp4: value must be a u32, got ${e}`);
182
+ const t = new Uint8Array(4);
183
+ return t[0] = e >>> 24 & 255, t[1] = e >>> 16 & 255, t[2] = e >>> 8 & 255, t[3] = e & 255, t;
184
+ }
185
+ function lt(e, t = new Uint8Array(0)) {
186
+ const n = new TextEncoder().encode(e);
187
+ if (n.length === 0 || n.length > kt)
188
+ throw new Error(
189
+ `info: label length must be in [1, ${kt}], got ${n.length}`
190
+ );
191
+ if (t.length > Tt)
192
+ throw new Error(
193
+ `info: ctx length must be in [0, ${Tt}], got ${t.length}`
194
+ );
195
+ const s = Z.length + 1 + n.length + _t + t.length, o = new Uint8Array(s);
196
+ let r = 0;
197
+ return o.set(Z, r), r += Z.length, o[r] = n.length, r += 1, o.set(n, r), r += n.length, o[r] = t.length >>> 8 & 255, o[r + 1] = t.length & 255, r += _t, o.set(t, r), o;
198
+ }
199
+ const vt = 32, Ae = 32, Se = 32, Ce = 64;
200
+ function ut(e) {
201
+ if (e.length !== vt)
202
+ throw new Error(
203
+ `vault-secrets: root must be exactly ${vt} bytes, got ${e.length}`
204
+ );
205
+ }
206
+ function Wn(e) {
207
+ return ut(e), ct(
208
+ L,
209
+ e,
210
+ lt(Be),
211
+ Ae
212
+ );
213
+ }
214
+ function Oe(e, t) {
215
+ return ut(e), ct(
216
+ L,
217
+ e,
218
+ lt(Ie, Wt(t)),
219
+ Se
220
+ );
221
+ }
222
+ function $e(e, t) {
223
+ return ut(e), ct(
224
+ L,
225
+ e,
226
+ lt(He, Wt(t)),
227
+ Ce
228
+ );
229
+ }
230
+ const R = 32, Y = 32, ot = 36, Nt = 32, X = 4, Re = X + R + X + Nt;
231
+ function rt(e, t, n) {
232
+ e[t] = n >>> 24 & 255, e[t + 1] = n >>> 16 & 255, e[t + 2] = n >>> 8 & 255, e[t + 3] = n & 255;
233
+ }
234
+ function Ue(e) {
235
+ if (e.txid.length !== Y)
236
+ throw new Error(
237
+ `outpoint.txid must be exactly ${Y} bytes, got ${e.txid.length}`
238
+ );
239
+ if (!Number.isInteger(e.vout) || e.vout < 0 || e.vout > 4294967295)
240
+ throw new Error(`outpoint.vout must be a u32, got ${e.vout}`);
241
+ const t = new Uint8Array(ot);
242
+ return t.set(e.txid, 0), rt(t, Y, e.vout), t;
243
+ }
244
+ function It(e, t) {
245
+ const n = Math.min(e.length, t.length);
246
+ for (let s = 0; s < n; s++)
247
+ if (e[s] !== t[s]) return e[s] - t[s];
248
+ return e.length - t.length;
249
+ }
250
+ function Le(e) {
251
+ if (e.length === 0)
252
+ throw new Error(
253
+ "buildFundingOutpointsCommitment: outpoints must be non-empty"
254
+ );
255
+ const t = e.map(Ue);
256
+ t.sort(It);
257
+ for (let s = 1; s < t.length; s++)
258
+ if (It(t[s - 1], t[s]) === 0)
175
259
  throw new Error(
176
- `hashlocks.length (${t.hashlocks.length}) must equal amounts.length (${t.amounts.length})`
177
- );
178
- if (t.hashlocks.length === 0)
179
- throw new Error("hashlocks must contain at least one entry");
180
- const a = r.length, l = {
181
- depositorPubkey: s,
182
- vaultProviderPubkey: o,
183
- vaultKeeperPubkeys: r,
184
- universalChallengerPubkeys: i,
185
- hashlocks: t.hashlocks,
186
- timelockRefund: t.timelockRefund,
187
- pegInAmounts: t.amounts,
188
- feeRate: t.protocolFeeRate,
189
- numLocalChallengers: a,
190
- councilQuorum: t.councilQuorum,
191
- councilSize: t.councilSize,
192
- network: this.config.btcNetwork
193
- }, h = await ne(l), c = ue(
194
- [...t.availableUTXOs],
195
- h.totalOutputValue,
196
- t.mempoolFeeRate,
197
- fe(
198
- h.htlcValues.length,
199
- l.authAnchorHash
200
- )
201
- ), b = mt(this.config.btcNetwork), m = ge({
202
- unfundedTxHex: h.psbtHex,
203
- selectedUTXOs: c.selectedUTXOs,
204
- changeAddress: t.changeAddress,
205
- changeAmount: c.changeAmount,
206
- network: b
207
- }), w = v(G(m)), g = [], E = [], P = [];
208
- for (let u = 0; u < t.hashlocks.length; u++) {
209
- const d = await se({
210
- prePeginParams: l,
211
- timelockPegin: t.timelockPegin,
212
- fundedPrePeginTxHex: m,
213
- htlcVout: u
214
- }), x = await oe({
215
- peginTxHex: d.txHex,
216
- fundedPrePeginTxHex: m,
217
- depositorPubkey: s,
218
- vaultProviderPubkey: o,
219
- vaultKeeperPubkeys: r,
220
- universalChallengerPubkeys: i,
221
- hashlock: t.hashlocks[u],
222
- timelockRefund: t.timelockRefund,
223
- network: this.config.btcNetwork
224
- });
225
- g.push(d), E.push(x.psbtHex), P.push(
226
- ee(n, 1)
260
+ "buildFundingOutpointsCommitment: duplicate outpoint detected"
227
261
  );
262
+ const n = new Uint8Array(t.length * ot);
263
+ for (let s = 0; s < t.length; s++)
264
+ n.set(t[s], s * ot);
265
+ return L(n);
266
+ }
267
+ function Ve(e) {
268
+ if (e.depositorBtcPubkey.length !== R)
269
+ throw new Error(
270
+ `vaultContext: depositorBtcPubkey must be exactly ${R} bytes, got ${e.depositorBtcPubkey.length}`
271
+ );
272
+ const t = Le(e.fundingOutpoints), n = new Uint8Array(Re);
273
+ let s = 0;
274
+ return rt(n, s, R), s += X, n.set(e.depositorBtcPubkey, s), s += R, rt(n, s, Nt), s += X, n.set(t, s), n;
275
+ }
276
+ const We = "babylon-vault", Mt = 32, Bt = Mt * 2, Ne = /^[0-9a-f]+$/;
277
+ async function Me(e, t) {
278
+ const n = Ve(t), s = $t(n), o = await e.deriveContextHash(We, s);
279
+ if (typeof o != "string")
280
+ throw new Error(
281
+ `deriveVaultRoot: wallet must return a string, got ${typeof o}`
282
+ );
283
+ if (o.length !== Bt)
284
+ throw new Error(
285
+ `deriveVaultRoot: wallet must return a ${Bt}-character hex string (${Mt} bytes), got length ${o.length}`
286
+ );
287
+ if (!Ne.test(o))
288
+ throw new Error(
289
+ "deriveVaultRoot: wallet must return lowercase hex per derive-context-hash.md §2.1; got value with non-lowercase or non-hex characters"
290
+ );
291
+ return nt(o);
292
+ }
293
+ const Fe = /* @__PURE__ */ Uint8Array.from([
294
+ 7,
295
+ 4,
296
+ 13,
297
+ 1,
298
+ 10,
299
+ 6,
300
+ 15,
301
+ 3,
302
+ 12,
303
+ 0,
304
+ 9,
305
+ 5,
306
+ 2,
307
+ 14,
308
+ 11,
309
+ 8
310
+ ]), Ft = Uint8Array.from(new Array(16).fill(0).map((e, t) => t)), Xe = Ft.map((e) => (9 * e + 5) % 16), Xt = /* @__PURE__ */ (() => {
311
+ const n = [[Ft], [Xe]];
312
+ for (let s = 0; s < 4; s++)
313
+ for (let o of n)
314
+ o.push(o[s].map((r) => Fe[r]));
315
+ return n;
316
+ })(), Kt = Xt[0], Dt = Xt[1], jt = /* @__PURE__ */ [
317
+ [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
318
+ [12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],
319
+ [13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],
320
+ [14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],
321
+ [15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5]
322
+ ].map((e) => Uint8Array.from(e)), Ke = /* @__PURE__ */ Kt.map((e, t) => e.map((n) => jt[t][n])), De = /* @__PURE__ */ Dt.map((e, t) => e.map((n) => jt[t][n])), je = /* @__PURE__ */ Uint32Array.from([
323
+ 0,
324
+ 1518500249,
325
+ 1859775393,
326
+ 2400959708,
327
+ 2840853838
328
+ ]), ze = /* @__PURE__ */ Uint32Array.from([
329
+ 1352829926,
330
+ 1548603684,
331
+ 1836072691,
332
+ 2053994217,
333
+ 0
334
+ ]);
335
+ function Ht(e, t, n, s) {
336
+ return e === 0 ? t ^ n ^ s : e === 1 ? t & n | ~t & s : e === 2 ? (t | ~n) ^ s : e === 3 ? t & s | n & ~s : t ^ (n | ~s);
337
+ }
338
+ const N = /* @__PURE__ */ new Uint32Array(16);
339
+ class qe extends de {
340
+ constructor() {
341
+ super(64, 20, 8, !0);
342
+ b(this, "h0", 1732584193);
343
+ b(this, "h1", -271733879);
344
+ b(this, "h2", -1732584194);
345
+ b(this, "h3", 271733878);
346
+ b(this, "h4", -1009589776);
347
+ }
348
+ get() {
349
+ const { h0: n, h1: s, h2: o, h3: r, h4: i } = this;
350
+ return [n, s, o, r, i];
351
+ }
352
+ set(n, s, o, r, i) {
353
+ this.h0 = n | 0, this.h1 = s | 0, this.h2 = o | 0, this.h3 = r | 0, this.h4 = i | 0;
354
+ }
355
+ process(n, s) {
356
+ for (let p = 0; p < 16; p++, s += 4)
357
+ N[p] = n.getUint32(s, !0);
358
+ let o = this.h0 | 0, r = o, i = this.h1 | 0, a = i, l = this.h2 | 0, u = l, c = this.h3 | 0, y = c, g = this.h4 | 0, h = g;
359
+ for (let p = 0; p < 5; p++) {
360
+ const T = 4 - p, P = je[p], v = ze[p], d = Kt[p], x = Dt[p], f = Ke[p], m = De[p];
361
+ for (let w = 0; w < 16; w++) {
362
+ const E = V(o + Ht(p, i, l, c) + N[d[w]] + P, f[w]) + g | 0;
363
+ o = g, g = c, c = V(l, 10) | 0, l = i, i = E;
364
+ }
365
+ for (let w = 0; w < 16; w++) {
366
+ const E = V(r + Ht(T, a, u, y) + N[x[w]] + v, m[w]) + h | 0;
367
+ r = h, h = y, y = V(u, 10) | 0, u = a, a = E;
368
+ }
228
369
  }
229
- const k = await this.signPsbtsWithFallback(
230
- E,
231
- P
232
- ), f = [];
233
- for (let u = 0; u < k.length; u++) {
234
- const d = re(
235
- k[u],
236
- s
237
- ), x = ie(k[u]);
238
- f.push({
239
- htlcVout: u,
240
- htlcValue: h.htlcValues[u],
241
- peginTxHex: x,
242
- peginTxid: g[u].txid,
243
- peginInputSignature: d,
244
- vaultScriptPubKey: g[u].vaultScriptPubKey
245
- });
246
- }
247
- return {
248
- fundedPrePeginTxHex: m,
249
- prePeginTxid: w,
250
- perVault: f,
251
- selectedUTXOs: c.selectedUTXOs,
252
- fee: c.fee,
253
- changeAmount: c.changeAmount
254
- };
370
+ this.set(this.h1 + l + y | 0, this.h2 + c + h | 0, this.h3 + g + r | 0, this.h4 + o + a | 0, this.h0 + i + u | 0);
255
371
  }
256
- /**
257
- * Signs multiple PSBTs using batch signing if available, falling back to sequential signing.
258
- *
259
- * Wallets that support native batch signing (e.g. UniSat) will sign all PSBTs
260
- * in a single interaction. Others (e.g. Ledger, AppKit) implement signPsbts
261
- * by looping signPsbt internally, so the UX depends on the wallet adapter.
262
- */
263
- async signPsbtsWithFallback(t, n) {
264
- if (typeof this.config.btcWallet.signPsbts == "function") {
265
- const o = await this.config.btcWallet.signPsbts(
266
- t,
267
- n
268
- );
269
- if (o.length !== t.length)
270
- throw new Error(
271
- `Expected ${t.length} signed PSBTs but received ${o.length}`
272
- );
273
- return o;
372
+ roundClean() {
373
+ A(N);
374
+ }
375
+ destroy() {
376
+ this.destroyed = !0, A(this.buffer), this.set(0, 0, 0, 0, 0);
377
+ }
378
+ }
379
+ const Ge = /* @__PURE__ */ Ut(() => new qe()), Ze = BigInt(0), O = BigInt(1), Ye = BigInt(2), Qe = BigInt(7), Je = BigInt(256), tn = BigInt(113), zt = [], qt = [], Gt = [];
380
+ for (let e = 0, t = O, n = 1, s = 0; e < 24; e++) {
381
+ [n, s] = [s, (2 * n + 3 * s) % 5], zt.push(2 * (5 * s + n)), qt.push((e + 1) * (e + 2) / 2 % 64);
382
+ let o = Ze;
383
+ for (let r = 0; r < 7; r++)
384
+ t = (t << O ^ (t >> Qe) * tn) % Je, t & Ye && (o ^= O << (O << BigInt(r)) - O);
385
+ Gt.push(o);
386
+ }
387
+ const Zt = Ee(Gt, !0), en = Zt[0], nn = Zt[1], At = (e, t, n) => n > 32 ? _e(e, t, n) : ke(e, t, n), St = (e, t, n) => n > 32 ? ve(e, t, n) : Te(e, t, n);
388
+ function sn(e, t = 24) {
389
+ const n = new Uint32Array(10);
390
+ for (let s = 24 - t; s < 24; s++) {
391
+ for (let i = 0; i < 10; i++)
392
+ n[i] = e[i] ^ e[i + 10] ^ e[i + 20] ^ e[i + 30] ^ e[i + 40];
393
+ for (let i = 0; i < 10; i += 2) {
394
+ const a = (i + 8) % 10, l = (i + 2) % 10, u = n[l], c = n[l + 1], y = At(u, c, 1) ^ n[a], g = St(u, c, 1) ^ n[a + 1];
395
+ for (let h = 0; h < 50; h += 10)
396
+ e[i + h] ^= y, e[i + h + 1] ^= g;
274
397
  }
275
- const s = [];
276
- for (let o = 0; o < t.length; o++) {
277
- const r = await this.config.btcWallet.signPsbt(
278
- t[o],
279
- n[o]
280
- );
281
- s.push(r);
398
+ let o = e[2], r = e[3];
399
+ for (let i = 0; i < 24; i++) {
400
+ const a = qt[i], l = At(o, r, a), u = St(o, r, a), c = zt[i];
401
+ o = e[c], r = e[c + 1], e[c] = l, e[c + 1] = u;
282
402
  }
283
- return s;
284
- }
285
- /**
286
- * Signs and broadcasts a funded peg-in transaction to the Bitcoin network.
287
- *
288
- * This method:
289
- * 1. Parses the funded transaction hex
290
- * 2. Fetches UTXO data from mempool for each input
291
- * 3. Creates a PSBT with proper witnessUtxo/tapInternalKey
292
- * 4. Signs via btcWallet.signPsbt()
293
- * 5. Finalizes and extracts the transaction
294
- * 6. Broadcasts via mempool API
295
- *
296
- * @param params - Transaction hex and depositor public key
297
- * @returns The broadcasted Bitcoin transaction ID
298
- * @throws Error if signing or broadcasting fails
299
- */
300
- async signAndBroadcast(t) {
301
- const { fundedPrePeginTxHex: n, depositorBtcPubkey: s } = t, o = n.startsWith("0x") ? n.slice(2) : n, r = Qt.fromHex(o);
302
- if (r.ins.length === 0)
303
- throw new Error("Transaction has no inputs");
304
- const i = new dt();
305
- i.setVersion(r.version), i.setLocktime(r.locktime);
306
- const a = et.from(
307
- O(s),
308
- "hex"
309
- ), l = this.config.mempoolApiUrl, h = r.ins.map((f) => {
310
- const u = et.from(f.hash).reverse().toString("hex"), d = f.index;
311
- return _e(u, d, t.localPrevouts, l).then(
312
- (x) => ({ input: f, utxoData: x, txid: u, vout: d })
313
- );
314
- }), c = await Promise.all(h), b = c.reduce(
315
- (f, u) => f + BigInt(u.utxoData.value),
316
- 0n
317
- ), m = r.outs.reduce(
318
- (f, u) => f + BigInt(u.value),
319
- 0n
320
- );
321
- if (b < m)
403
+ for (let i = 0; i < 50; i += 10) {
404
+ for (let a = 0; a < 10; a++)
405
+ n[a] = e[i + a];
406
+ for (let a = 0; a < 10; a++)
407
+ e[i + a] ^= ~n[(a + 2) % 10] & n[(a + 4) % 10];
408
+ }
409
+ e[0] ^= en[s], e[1] ^= nn[s];
410
+ }
411
+ A(n);
412
+ }
413
+ class ht {
414
+ // NOTE: we accept arguments in bytes instead of bits here.
415
+ constructor(t, n, s, o = !1, r = 24) {
416
+ b(this, "state");
417
+ b(this, "pos", 0);
418
+ b(this, "posOut", 0);
419
+ b(this, "finished", !1);
420
+ b(this, "state32");
421
+ b(this, "destroyed", !1);
422
+ b(this, "blockLen");
423
+ b(this, "suffix");
424
+ b(this, "outputLen");
425
+ b(this, "enableXOF", !1);
426
+ b(this, "rounds");
427
+ if (this.blockLen = t, this.suffix = n, this.outputLen = s, this.enableXOF = o, this.rounds = r, st(s, "outputLen"), !(0 < t && t < 200))
428
+ throw new Error("only keccak-f1600 function is supported");
429
+ this.state = new Uint8Array(200), this.state32 = fe(this.state);
430
+ }
431
+ clone() {
432
+ return this._cloneInto();
433
+ }
434
+ keccak() {
435
+ xt(this.state32), sn(this.state32, this.rounds), xt(this.state32), this.posOut = 0, this.pos = 0;
436
+ }
437
+ update(t) {
438
+ F(this), U(t);
439
+ const { blockLen: n, state: s } = this, o = t.length;
440
+ for (let r = 0; r < o; ) {
441
+ const i = Math.min(n - this.pos, o - r);
442
+ for (let a = 0; a < i; a++)
443
+ s[this.pos++] ^= t[r++];
444
+ this.pos === n && this.keccak();
445
+ }
446
+ return this;
447
+ }
448
+ finish() {
449
+ if (this.finished)
450
+ return;
451
+ this.finished = !0;
452
+ const { state: t, suffix: n, pos: s, blockLen: o } = this;
453
+ t[s] ^= n, (n & 128) !== 0 && s === o - 1 && this.keccak(), t[o - 1] ^= 128, this.keccak();
454
+ }
455
+ writeInto(t) {
456
+ F(this, !1), U(t), this.finish();
457
+ const n = this.state, { blockLen: s } = this;
458
+ for (let o = 0, r = t.length; o < r; ) {
459
+ this.posOut >= s && this.keccak();
460
+ const i = Math.min(s - this.posOut, r - o);
461
+ t.set(n.subarray(this.posOut, this.posOut + i), o), this.posOut += i, o += i;
462
+ }
463
+ return t;
464
+ }
465
+ xofInto(t) {
466
+ if (!this.enableXOF)
467
+ throw new Error("XOF is not possible for this instance");
468
+ return this.writeInto(t);
469
+ }
470
+ xof(t) {
471
+ return st(t), this.xofInto(new Uint8Array(t));
472
+ }
473
+ digestInto(t) {
474
+ if (ge(t, this), this.finished)
475
+ throw new Error("digest() was already called");
476
+ return this.writeInto(t), this.destroy(), t;
477
+ }
478
+ digest() {
479
+ return this.digestInto(new Uint8Array(this.outputLen));
480
+ }
481
+ destroy() {
482
+ this.destroyed = !0, A(this.state);
483
+ }
484
+ _cloneInto(t) {
485
+ const { blockLen: n, suffix: s, outputLen: o, rounds: r, enableXOF: i } = this;
486
+ return t || (t = new ht(n, s, o, i, r)), t.state32.set(this.state32), t.pos = this.pos, t.posOut = this.posOut, t.finished = this.finished, t.rounds = r, t.suffix = s, t.outputLen = o, t.enableXOF = i, t.destroyed = this.destroyed, t;
487
+ }
488
+ }
489
+ const on = (e, t, n, s = {}) => Ut(() => new ht(t, e, n), s), rn = /* @__PURE__ */ on(1, 136, 32), Ct = 64, k = 20, it = 4, Yt = 2, an = 0, cn = 1, M = [64, 64], ln = (e) => Array.from(e).map((t) => t.toString(16).padStart(2, "0")).join("");
490
+ function dt(e) {
491
+ return Ge(L(e));
492
+ }
493
+ function Qt(e) {
494
+ return (1 << e) - 1;
495
+ }
496
+ function un(e) {
497
+ let t = 1;
498
+ for (; t * t < e + 1; ) t++;
499
+ return Math.max(t, 2);
500
+ }
501
+ function hn(e) {
502
+ const t = it, n = e * Qt(t);
503
+ return { d: t, n: e, checksum_radix: un(n) };
504
+ }
505
+ function Q(e, t) {
506
+ const n = [];
507
+ let s = t;
508
+ for (; s > 0; )
509
+ n.push(s & 255), s >>>= 8;
510
+ const o = new Uint8Array(e.length + n.length);
511
+ o.set(e);
512
+ for (let r = 0; r < n.length; r++)
513
+ o[e.length + r] = n[r];
514
+ return dt(o);
515
+ }
516
+ function J(e, t) {
517
+ let n = e;
518
+ for (let s = 0; s < t; s++)
519
+ n = dt(n);
520
+ return n;
521
+ }
522
+ function dn(e, t) {
523
+ const n = Qt(t.d), s = t.checksum_radix - 1, o = Math.floor(t.n * n / t.checksum_radix), r = [];
524
+ for (let c = 0; c < t.n; c++) {
525
+ const y = Q(e, c + Yt), g = J(y, n);
526
+ r.push(Array.from(g));
527
+ }
528
+ const i = Q(
529
+ e,
530
+ an
531
+ ), a = J(
532
+ i,
533
+ s
534
+ ), l = Q(
535
+ e,
536
+ cn
537
+ ), u = J(
538
+ l,
539
+ o
540
+ );
541
+ return {
542
+ config: t,
543
+ message_terminals: r,
544
+ checksum_major_terminal: Array.from(u),
545
+ checksum_minor_terminal: Array.from(a)
546
+ };
547
+ }
548
+ async function fn(e) {
549
+ try {
550
+ if (e.length !== Ct)
322
551
  throw new Error(
323
- `UTXO value mismatch: total input value (${b} sat) is less than total output value (${m} sat). This may indicate the mempool API returned manipulated UTXO data.`
552
+ `WOTS seed must be exactly ${Ct} bytes, got ${e.length}`
324
553
  );
325
- const w = b - m;
326
- if (w > bt)
554
+ const t = [];
555
+ for (let n = 0; n < M.length; n++) {
556
+ const s = M[n], o = hn(s), r = new Uint8Array(e.length + 1);
557
+ r.set(e), r[e.length] = n;
558
+ const i = dt(r);
559
+ try {
560
+ const a = dn(i, o);
561
+ if (a.config.d !== it)
562
+ throw new Error(
563
+ `Block ${n}: expected d=${it}, got d=${a.config.d}`
564
+ );
565
+ if (a.config.n !== s)
566
+ throw new Error(
567
+ `Block ${n}: expected n=${s}, got n=${a.config.n}`
568
+ );
569
+ if (a.message_terminals.length !== s)
570
+ throw new Error(
571
+ `Block ${n}: expected ${s} message terminals, got ${a.message_terminals.length}`
572
+ );
573
+ for (let l = 0; l < a.message_terminals.length; l++)
574
+ if (a.message_terminals[l].length !== k)
575
+ throw new Error(
576
+ `Block ${n} terminal ${l}: expected ${k} bytes, got ${a.message_terminals[l].length}`
577
+ );
578
+ if (a.checksum_minor_terminal.length !== k)
579
+ throw new Error(
580
+ `Block ${n} checksum_minor: expected ${k} bytes`
581
+ );
582
+ if (a.checksum_major_terminal.length !== k)
583
+ throw new Error(
584
+ `Block ${n} checksum_major: expected ${k} bytes`
585
+ );
586
+ t.push(a);
587
+ } finally {
588
+ r.fill(0), i.fill(0);
589
+ }
590
+ }
591
+ if (t.length !== M.length)
327
592
  throw new Error(
328
- `Implied transaction fee (${w} sat) exceeds maximum reasonable fee (${bt} sat). This may indicate manipulated UTXO data.`
593
+ `Expected ${M.length} blocks, got ${t.length}`
329
594
  );
330
- for (const { input: f, utxoData: u, txid: d, vout: x } of c) {
331
- const y = de(
332
- {
333
- value: u.value,
334
- scriptPubKey: u.scriptPubKey
335
- },
336
- a
595
+ return t;
596
+ } finally {
597
+ e.fill(0);
598
+ }
599
+ }
600
+ function tt(e, t, n) {
601
+ if (e.length !== k)
602
+ throw new Error(
603
+ `Block ${t} ${n}: expected ${k} bytes, got ${e.length}`
604
+ );
605
+ for (let s = 0; s < e.length; s++) {
606
+ const o = e[s];
607
+ if (!Number.isInteger(o) || o < 0 || o > 255)
608
+ throw new Error(
609
+ `Block ${t} ${n}[${s}]: invalid byte value ${o}`
337
610
  );
338
- i.addInput({
339
- hash: f.hash,
340
- index: f.index,
341
- sequence: f.sequence,
342
- ...y
343
- });
344
- }
345
- for (const f of r.outs)
346
- i.addOutput({
347
- script: f.script,
348
- value: f.value
349
- });
350
- const g = await this.config.btcWallet.signPsbt(i.toHex()), E = dt.fromHex(g);
351
- try {
352
- E.finalizeAllInputs();
353
- } catch (f) {
354
- if (!E.data.inputs.every(
355
- (d) => d.finalScriptWitness || d.finalScriptSig
356
- ))
611
+ }
612
+ }
613
+ function gn(e) {
614
+ if (e.length === 0)
615
+ throw new Error("Public keys array must not be empty");
616
+ for (let r = 0; r < e.length; r++) {
617
+ const i = e[r];
618
+ tt(i.checksum_minor_terminal, r, "checksum_minor_terminal"), tt(i.checksum_major_terminal, r, "checksum_major_terminal");
619
+ for (let a = 0; a < i.message_terminals.length; a++)
620
+ tt(i.message_terminals[a], r, `message_terminal[${a}]`);
621
+ }
622
+ let t = 0;
623
+ for (const r of e)
624
+ t += Yt + r.message_terminals.length;
625
+ const n = new Uint8Array(t * k);
626
+ let s = 0;
627
+ for (const r of e) {
628
+ n.set(r.checksum_minor_terminal, s), s += k, n.set(r.checksum_major_terminal, s), s += k;
629
+ for (const i of r.message_terminals)
630
+ n.set(i, s), s += k;
631
+ }
632
+ const o = rn(n);
633
+ return `0x${ln(o)}`;
634
+ }
635
+ function Nn(e) {
636
+ const t = (e instanceof Error ? e.message : typeof e == "string" ? e : "").toLowerCase();
637
+ return t.includes("wots") && t.includes("hash") && t.includes("does not match");
638
+ }
639
+ const pn = 0, mn = /^0x[0-9a-f]+$/i, bn = /^[0-9a-f]+$/i, wn = /^[A-Za-z0-9+/]+={0,2}$/, yn = "00".repeat(32);
640
+ function $(e) {
641
+ if (typeof e != "string" || e.length === 0)
642
+ throw new Error("BTC wallet returned empty public key");
643
+ return le(e).toLowerCase();
644
+ }
645
+ function xn(e) {
646
+ if (typeof e != "string" || e.length === 0)
647
+ throw new Error("BTC wallet returned empty BIP-322 signature");
648
+ if (e.startsWith("0x") || e.startsWith("0X")) {
649
+ if (!mn.test(e) || e.length < 4 || e.length % 2 !== 0)
650
+ throw new Error("BTC wallet returned malformed hex BIP-322 signature");
651
+ return e.toLowerCase();
652
+ }
653
+ if (bn.test(e)) {
654
+ if (e.length % 2 !== 0)
655
+ throw new Error("BTC wallet returned malformed hex BIP-322 signature");
656
+ return `0x${e.toLowerCase()}`;
657
+ }
658
+ if (!wn.test(e) || e.length % 4 !== 0)
659
+ throw new Error("BTC wallet returned malformed base64 BIP-322 signature");
660
+ const t = et.from(e, "base64");
661
+ if (t.length === 0 || t.toString("base64") !== e)
662
+ throw new Error("BTC wallet returned malformed base64 BIP-322 signature");
663
+ return `0x${t.toString("hex")}`;
664
+ }
665
+ function Pn(e, t, n, s) {
666
+ const o = n == null ? void 0 : n[`${e}:${t}`];
667
+ return o ? Promise.resolve({
668
+ txid: e,
669
+ vout: t,
670
+ value: o.value,
671
+ scriptPubKey: o.scriptPubKey
672
+ }) : xe(e, t, s);
673
+ }
674
+ const Ot = 12e4;
675
+ class Mn {
676
+ /**
677
+ * Creates a new PeginManager instance.
678
+ *
679
+ * @param config - Manager configuration including wallets and contract addresses
680
+ */
681
+ constructor(t) {
682
+ b(this, "config");
683
+ this.config = t;
684
+ }
685
+ /**
686
+ * Prepare a peg-in: sizing pass → vault-root derivation (one wallet
687
+ * popup) → per-vault WOTS / hashlock derivation → commit pass with
688
+ * batch PSBT signing (one popup). Returns broadcast-ready txs, the
689
+ * pubkey snapshot, and the sensitive derived material.
690
+ *
691
+ * @throws If the wallet rejects, insufficient funds, or an internal
692
+ * invariant violation.
693
+ */
694
+ async preparePegin(t) {
695
+ if (t.amounts.length === 0)
696
+ throw new Error("amounts must contain at least one entry");
697
+ const n = await this.config.btcWallet.getPublicKeyHex(), s = $(n), o = await this.prepareSizing(s, t), r = o.selectedUTXOs.map(
698
+ (h) => ({
699
+ txid: nt(h.txid),
700
+ vout: h.vout
701
+ })
702
+ ), i = await Me(this.config.btcWallet, {
703
+ depositorBtcPubkey: nt(s),
704
+ fundingOutpoints: r
705
+ }), a = await this.expandPerVaultSecrets(i, t.amounts.length), { perVaultWotsKeys: l, wotsPkHashes: u, htlcSecretHexes: c, hashlocks: y } = a, g = await this.preparePeginCommit({
706
+ depositorBtcPubkeyRaw: n,
707
+ depositorBtcPubkey: s,
708
+ hashlocks: y,
709
+ sizing: o,
710
+ params: t
711
+ });
712
+ for (let h = 0; h < g.perVault.length; h++)
713
+ if (g.perVault[h].htlcVout !== h)
357
714
  throw new Error(
358
- `PSBT finalization failed and wallet did not auto-finalize: ${f}`
715
+ `Internal invariant violation: htlcVout/index mismatch at vault ${h} (expected ${h}, got ${g.perVault[h].htlcVout})`
359
716
  );
717
+ return {
718
+ transaction: {
719
+ ...g,
720
+ selectedUTXOs: o.selectedUTXOs,
721
+ fee: o.fee,
722
+ changeAmount: o.changeAmount
723
+ },
724
+ depositorBtcPubkey: s,
725
+ derivedSecrets: {
726
+ perVaultWotsKeys: l,
727
+ wotsPkHashes: u,
728
+ htlcSecretHexes: c
729
+ }
730
+ };
731
+ }
732
+ /**
733
+ * Derive per-vault WOTS keys + HTLC preimages from the wallet root.
734
+ * Takes ownership of `root`: zeros the buffer (and per-vault secret
735
+ * buffers) before returning, regardless of how the caller exits.
736
+ */
737
+ async expandPerVaultSecrets(t, n) {
738
+ const s = [], o = [], r = [], i = [];
739
+ try {
740
+ for (let a = 0; a < n; a++) {
741
+ const l = $e(t, a);
742
+ try {
743
+ const c = await fn(l);
744
+ s.push(c), o.push(gn(c));
745
+ } finally {
746
+ l.fill(0);
747
+ }
748
+ const u = Oe(t, a);
749
+ try {
750
+ const c = $t(u);
751
+ r.push(c), i.push(
752
+ ue(I(c)).slice(2)
753
+ );
754
+ } finally {
755
+ u.fill(0);
756
+ }
757
+ }
758
+ } finally {
759
+ t.fill(0);
360
760
  }
361
- const P = E.extractTransaction().toHex();
362
- return await pe(P, l);
761
+ return { perVaultWotsKeys: s, wotsPkHashes: o, htlcSecretHexes: r, hashlocks: i };
363
762
  }
364
763
  /**
365
- * Registers a peg-in on Ethereum by calling the BTCVaultRegistry contract.
366
- *
367
- * This method:
368
- * 1. Re-verifies the PopSignature against the currently connected ETH
369
- * and BTC wallets — refuses to proceed if either has changed
370
- * 2. Derives vault ID and checks if it already exists (pre-flight)
371
- * 3. Encodes the contract call using viem
372
- * 4. Estimates gas (catches contract errors early with proper revert
373
- * reasons)
374
- * 5. Sends transaction with pre-estimated gas via
375
- * ethWallet.sendTransaction()
764
+ * Build unfunded Pre-PegIn + select UTXOs. No PSBT signing.
376
765
  *
377
- * The PopSignature must be obtained via
378
- * {@link signProofOfPossession} before this call.
379
- *
380
- * @param params - Registration parameters including the PopSignature
766
+ * Returns the full selection result (UTXOs, fee, changeAmount) so the
767
+ * commit pass funds the broadcast tx with the exact same set used to
768
+ * build the vault-context funding-outpoints commitment. Re-running
769
+ * `selectUtxosForPegin` in the commit pass would be deterministic given
770
+ * the same inputs, but threading the result through guarantees the
771
+ * domain separator structurally matches the funded tx inputs.
772
+ */
773
+ async prepareSizing(t, n) {
774
+ const s = n.amounts.map(
775
+ () => yn
776
+ ), o = n.vaultKeeperBtcPubkeys.length, r = await bt({
777
+ depositorPubkey: t,
778
+ vaultProviderPubkey: _(n.vaultProviderBtcPubkey),
779
+ vaultKeeperPubkeys: n.vaultKeeperBtcPubkeys.map(_),
780
+ universalChallengerPubkeys: n.universalChallengerBtcPubkeys.map(_),
781
+ hashlocks: s,
782
+ timelockRefund: n.timelockRefund,
783
+ pegInAmounts: n.amounts,
784
+ feeRate: n.protocolFeeRate,
785
+ numLocalChallengers: o,
786
+ councilQuorum: n.councilQuorum,
787
+ councilSize: n.councilSize,
788
+ network: this.config.btcNetwork
789
+ }), i = pe(
790
+ [...n.availableUTXOs],
791
+ r.totalOutputValue,
792
+ n.mempoolFeeRate,
793
+ // No auth-anchor OP_RETURN in this PR (deferred to PR5).
794
+ be(r.htlcValues.length)
795
+ );
796
+ return {
797
+ selectedUTXOs: i.selectedUTXOs,
798
+ fee: i.fee,
799
+ changeAmount: i.changeAmount
800
+ };
801
+ }
802
+ /** Build PegIn txs and batch-sign their inputs with real hashlocks. */
803
+ async preparePeginCommit(t) {
804
+ const {
805
+ depositorBtcPubkeyRaw: n,
806
+ depositorBtcPubkey: s,
807
+ hashlocks: o,
808
+ sizing: r,
809
+ params: i
810
+ } = t, a = _(i.vaultProviderBtcPubkey), l = i.vaultKeeperBtcPubkeys.map(_), u = i.universalChallengerBtcPubkeys.map(_), c = l.length, y = {
811
+ depositorPubkey: s,
812
+ vaultProviderPubkey: a,
813
+ vaultKeeperPubkeys: l,
814
+ universalChallengerPubkeys: u,
815
+ hashlocks: o,
816
+ timelockRefund: i.timelockRefund,
817
+ pegInAmounts: i.amounts,
818
+ feeRate: i.protocolFeeRate,
819
+ numLocalChallengers: c,
820
+ councilQuorum: i.councilQuorum,
821
+ councilSize: i.councilSize,
822
+ network: this.config.btcNetwork
823
+ }, g = await bt(y), h = wt(this.config.btcNetwork), p = we({
824
+ unfundedTxHex: g.psbtHex,
825
+ selectedUTXOs: r.selectedUTXOs,
826
+ changeAddress: i.changeAddress,
827
+ changeAmount: r.changeAmount,
828
+ network: h
829
+ }), T = _(q(p)), P = [], v = [], d = [];
830
+ for (let m = 0; m < o.length; m++) {
831
+ const w = await oe({
832
+ prePeginParams: y,
833
+ timelockPegin: i.timelockPegin,
834
+ fundedPrePeginTxHex: p,
835
+ htlcVout: m
836
+ }), E = await re({
837
+ peginTxHex: w.txHex,
838
+ fundedPrePeginTxHex: p,
839
+ depositorPubkey: s,
840
+ vaultProviderPubkey: a,
841
+ vaultKeeperPubkeys: l,
842
+ universalChallengerPubkeys: u,
843
+ hashlock: o[m],
844
+ timelockRefund: i.timelockRefund,
845
+ network: this.config.btcNetwork
846
+ });
847
+ P.push(w), v.push(E.psbtHex), d.push(
848
+ he(n, 1)
849
+ );
850
+ }
851
+ const x = await this.signPsbtsWithFallback(
852
+ v,
853
+ d
854
+ ), f = [];
855
+ for (let m = 0; m < x.length; m++) {
856
+ const w = ie(
857
+ x[m],
858
+ s
859
+ ), E = ae(x[m]);
860
+ f.push({
861
+ htlcVout: m,
862
+ htlcValue: g.htlcValues[m],
863
+ peginTxHex: E,
864
+ peginTxid: P[m].txid,
865
+ peginInputSignature: w,
866
+ vaultScriptPubKey: P[m].vaultScriptPubKey
867
+ });
868
+ }
869
+ return {
870
+ fundedPrePeginTxHex: p,
871
+ prePeginTxid: T,
872
+ perVault: f
873
+ };
874
+ }
875
+ /**
876
+ * Signs multiple PSBTs using batch signing if available, falling back to sequential signing.
877
+ *
878
+ * Wallets that support native batch signing (e.g. UniSat) will sign all PSBTs
879
+ * in a single interaction. Others (e.g. Ledger, AppKit) implement signPsbts
880
+ * by looping signPsbt internally, so the UX depends on the wallet adapter.
881
+ */
882
+ async signPsbtsWithFallback(t, n) {
883
+ if (typeof this.config.btcWallet.signPsbts == "function") {
884
+ const o = await this.config.btcWallet.signPsbts(
885
+ t,
886
+ n
887
+ );
888
+ if (o.length !== t.length)
889
+ throw new Error(
890
+ `Expected ${t.length} signed PSBTs but received ${o.length}`
891
+ );
892
+ return o;
893
+ }
894
+ const s = [];
895
+ for (let o = 0; o < t.length; o++) {
896
+ const r = await this.config.btcWallet.signPsbt(
897
+ t[o],
898
+ n[o]
899
+ );
900
+ s.push(r);
901
+ }
902
+ return s;
903
+ }
904
+ /**
905
+ * Signs and broadcasts a funded peg-in transaction to the Bitcoin network.
906
+ *
907
+ * This method:
908
+ * 1. Parses the funded transaction hex
909
+ * 2. Fetches UTXO data from mempool for each input
910
+ * 3. Creates a PSBT with proper witnessUtxo/tapInternalKey
911
+ * 4. Signs via btcWallet.signPsbt()
912
+ * 5. Finalizes and extracts the transaction
913
+ * 6. Broadcasts via mempool API
914
+ *
915
+ * @param params - Transaction hex and depositor public key
916
+ * @returns The broadcasted Bitcoin transaction ID
917
+ * @throws Error if signing or broadcasting fails
918
+ */
919
+ async signAndBroadcast(t) {
920
+ const { fundedPrePeginTxHex: n, depositorBtcPubkey: s } = t, o = n.startsWith("0x") ? n.slice(2) : n, r = ne.fromHex(o);
921
+ if (r.ins.length === 0)
922
+ throw new Error("Transaction has no inputs");
923
+ const i = new ft();
924
+ i.setVersion(r.version), i.setLocktime(r.locktime);
925
+ const a = et.from(
926
+ $(s),
927
+ "hex"
928
+ ), l = this.config.mempoolApiUrl, u = r.ins.map((d) => {
929
+ const x = et.from(d.hash).reverse().toString("hex"), f = d.index;
930
+ return Pn(x, f, t.localPrevouts, l).then(
931
+ (m) => ({ input: d, utxoData: m, txid: x, vout: f })
932
+ );
933
+ }), c = await Promise.all(u), y = c.reduce(
934
+ (d, x) => d + BigInt(x.utxoData.value),
935
+ 0n
936
+ ), g = r.outs.reduce(
937
+ (d, x) => d + BigInt(x.value),
938
+ 0n
939
+ );
940
+ if (y < g)
941
+ throw new Error(
942
+ `UTXO value mismatch: total input value (${y} sat) is less than total output value (${g} sat). This may indicate the mempool API returned manipulated UTXO data.`
943
+ );
944
+ const h = y - g;
945
+ if (h > yt)
946
+ throw new Error(
947
+ `Implied transaction fee (${h} sat) exceeds maximum reasonable fee (${yt} sat). This may indicate manipulated UTXO data.`
948
+ );
949
+ for (const { input: d, utxoData: x, txid: f, vout: m } of c) {
950
+ const w = me(
951
+ {
952
+ value: x.value,
953
+ scriptPubKey: x.scriptPubKey
954
+ },
955
+ a
956
+ );
957
+ i.addInput({
958
+ hash: d.hash,
959
+ index: d.index,
960
+ sequence: d.sequence,
961
+ ...w
962
+ });
963
+ }
964
+ for (const d of r.outs)
965
+ i.addOutput({
966
+ script: d.script,
967
+ value: d.value
968
+ });
969
+ const p = await this.config.btcWallet.signPsbt(i.toHex()), T = ft.fromHex(p);
970
+ try {
971
+ T.finalizeAllInputs();
972
+ } catch (d) {
973
+ if (!T.data.inputs.every(
974
+ (f) => f.finalScriptWitness || f.finalScriptSig
975
+ ))
976
+ throw new Error(
977
+ `PSBT finalization failed and wallet did not auto-finalize: ${d}`
978
+ );
979
+ }
980
+ const P = T.extractTransaction().toHex();
981
+ return await ye(P, l);
982
+ }
983
+ /**
984
+ * Registers a peg-in on Ethereum by calling the BTCVaultRegistry contract.
985
+ *
986
+ * This method:
987
+ * 1. Re-verifies the PopSignature against the currently connected ETH
988
+ * and BTC wallets — refuses to proceed if either has changed
989
+ * 2. Derives vault ID and checks if it already exists (pre-flight)
990
+ * 3. Encodes the contract call using viem
991
+ * 4. Estimates gas (catches contract errors early with proper revert
992
+ * reasons)
993
+ * 5. Sends transaction with pre-estimated gas via
994
+ * ethWallet.sendTransaction()
995
+ *
996
+ * The PopSignature must be obtained via
997
+ * {@link signProofOfPossession} before this call.
998
+ *
999
+ * @param params - Registration parameters including the PopSignature
381
1000
  * and the prepared Pre-PegIn / PegIn transactions
382
1001
  * @returns Result containing Ethereum transaction hash and vault ID
383
1002
  * @throws Error if the PopSignature does not match the connected wallets
@@ -394,35 +1013,35 @@ class Cn {
394
1013
  htlcVout: i,
395
1014
  depositorPayoutBtcAddress: a,
396
1015
  depositorWotsPkHash: l,
397
- popSignature: h
1016
+ popSignature: u
398
1017
  } = t;
399
1018
  if (!this.config.ethWallet.account)
400
1019
  throw new Error("Ethereum wallet account not found");
401
1020
  const c = this.config.ethWallet.account.address;
402
- if (!ft(h.depositorEthAddress, c))
1021
+ if (!gt(u.depositorEthAddress, c))
403
1022
  throw new Error(
404
- `Proof of possession was signed for ${h.depositorEthAddress} but the Ethereum wallet is currently connected to ${c}. Reconnect the original account or call signProofOfPossession() again.`
1023
+ `Proof of possession was signed for ${u.depositorEthAddress} but the Ethereum wallet is currently connected to ${c}. Reconnect the original account or call signProofOfPossession() again.`
405
1024
  );
406
- await this.assertPopMatchesBtcWallet(h);
407
- const b = h.btcPopSignature, m = _(h.depositorBtcPubkey), w = _(n), g = _(s), E = await this.resolvePayoutScriptPubKey(
1025
+ await this.assertPopMatchesBtcWallet(u);
1026
+ const y = u.btcPopSignature, g = I(u.depositorBtcPubkey), h = I(n), p = I(s), T = await this.resolvePayoutScriptPubKey(
408
1027
  a
409
- ), P = G(g), k = await pt(
410
- v(P),
411
- v(c)
412
- ), f = _(k);
413
- if (await this.checkVaultExists(f))
1028
+ ), P = q(p), v = await mt(
1029
+ _(P),
1030
+ _(c)
1031
+ ), d = I(v);
1032
+ if (await this.checkVaultExists(d))
414
1033
  throw new Error(
415
- `Vault already exists (ID: ${f}, peginTxHash: ${P}). Vault IDs are derived from the pegin transaction hash and depositor address. To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`
1034
+ `Vault already exists (ID: ${d}, peginTxHash: ${P}). Vault IDs are derived from the pegin transaction hash and depositor address. To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`
416
1035
  );
417
- const d = j({
1036
+ const f = j({
418
1037
  chain: this.config.ethChain,
419
- transport: q()
1038
+ transport: z()
420
1039
  });
421
- let x;
1040
+ let m;
422
1041
  try {
423
- x = await d.readContract({
1042
+ m = await f.readContract({
424
1043
  address: this.config.vaultContracts.btcVaultRegistry,
425
- abi: S,
1044
+ abi: C,
426
1045
  functionName: "getPegInFee",
427
1046
  args: [o]
428
1047
  });
@@ -431,57 +1050,57 @@ class Cn {
431
1050
  "Failed to query pegin fee from the contract. Please check your network connection and that the contract address is correct."
432
1051
  );
433
1052
  }
434
- const y = gt({
435
- abi: S,
1053
+ const w = pt({
1054
+ abi: C,
436
1055
  functionName: "submitPeginRequest",
437
1056
  args: [
438
1057
  c,
439
- m,
440
- b,
441
- w,
442
1058
  g,
1059
+ y,
1060
+ h,
1061
+ p,
443
1062
  o,
444
1063
  r,
445
1064
  i,
446
- E,
1065
+ T,
447
1066
  l
448
1067
  ]
449
1068
  });
450
- let I;
1069
+ let E;
451
1070
  try {
452
- I = await d.estimateGas({
1071
+ E = await f.estimateGas({
453
1072
  to: this.config.vaultContracts.btcVaultRegistry,
454
- data: y,
455
- value: x,
1073
+ data: w,
1074
+ value: m,
456
1075
  account: this.config.ethWallet.account.address
457
1076
  });
458
- } catch (K) {
459
- A(K);
1077
+ } catch (D) {
1078
+ H(D);
460
1079
  }
461
1080
  let B;
462
1081
  try {
463
1082
  B = await this.config.ethWallet.sendTransaction({
464
1083
  to: this.config.vaultContracts.btcVaultRegistry,
465
- data: y,
466
- value: x,
1084
+ data: w,
1085
+ value: m,
467
1086
  account: this.config.ethWallet.account,
468
1087
  chain: this.config.ethChain,
469
- gas: I
1088
+ gas: E
470
1089
  });
471
- } catch (K) {
472
- A(K);
1090
+ } catch (D) {
1091
+ H(D);
473
1092
  }
474
- const D = await d.waitForTransactionReceipt({
1093
+ const K = await f.waitForTransactionReceipt({
475
1094
  hash: B,
476
- timeout: yt
1095
+ timeout: Ot
477
1096
  });
478
- return D.status === "reverted" && A(
1097
+ return K.status === "reverted" && H(
479
1098
  new Error(
480
1099
  `Transaction reverted. Hash: ${B}. Check the transaction on block explorer for details.`
481
1100
  )
482
1101
  ), {
483
- ethTxHash: D.transactionHash,
484
- vaultId: f,
1102
+ ethTxHash: K.transactionHash,
1103
+ vaultId: d,
485
1104
  peginTxHash: P
486
1105
  };
487
1106
  }
@@ -502,750 +1121,219 @@ class Cn {
502
1121
  if (!this.config.ethWallet.account)
503
1122
  throw new Error("Ethereum wallet account not found");
504
1123
  const i = this.config.ethWallet.account.address;
505
- if (!ft(r.depositorEthAddress, i))
1124
+ if (!gt(r.depositorEthAddress, i))
506
1125
  throw new Error(
507
1126
  `Proof of possession was signed for ${r.depositorEthAddress} but the Ethereum wallet is currently connected to ${i}. Reconnect the original account or call signProofOfPossession() again.`
508
1127
  );
509
1128
  await this.assertPopMatchesBtcWallet(r);
510
1129
  const a = r.btcPopSignature, l = [];
511
- for (const d of o)
1130
+ for (const f of o)
512
1131
  l.push(
513
- await this.resolvePayoutScriptPubKey(d.depositorPayoutBtcAddress)
1132
+ await this.resolvePayoutScriptPubKey(f.depositorPayoutBtcAddress)
514
1133
  );
515
- const h = [];
516
- for (const d of o) {
517
- const x = _(
518
- d.depositorSignedPeginTx
519
- ), y = G(x), I = await pt(
520
- v(y),
521
- v(i)
522
- ), B = _(I);
1134
+ const u = [];
1135
+ for (const f of o) {
1136
+ const m = I(
1137
+ f.depositorSignedPeginTx
1138
+ ), w = q(m), E = await mt(
1139
+ _(w),
1140
+ _(i)
1141
+ ), B = I(E);
523
1142
  if (await this.checkVaultExists(B))
524
- throw new Error(
525
- `Vault already exists (ID: ${B}, peginTxHash: ${y}). To create a new vault, use different UTXOs or a different amount.`
526
- );
527
- h.push({ vaultId: B, peginTxHash: y });
528
- }
529
- const c = j({
530
- chain: this.config.ethChain,
531
- transport: q()
532
- });
533
- let b;
534
- try {
535
- b = await c.readContract({
536
- address: this.config.vaultContracts.btcVaultRegistry,
537
- abi: S,
538
- functionName: "getPegInFee",
539
- args: [n]
540
- });
541
- } catch {
542
- throw new Error(
543
- "Failed to query pegin fee from the contract. Please check your network connection and that the contract address is correct."
544
- );
545
- }
546
- const m = b * BigInt(o.length), w = _(
547
- r.depositorBtcPubkey
548
- ), g = _(s), E = o.map((d, x) => ({
549
- depositorBtcPubKey: w,
550
- btcPopSignature: a,
551
- unsignedPrePeginTx: g,
552
- depositorSignedPeginTx: _(
553
- d.depositorSignedPeginTx
554
- ),
555
- hashlock: d.hashlock,
556
- htlcVout: d.htlcVout,
557
- referralCode: xe,
558
- depositorPayoutBtcAddress: l[x],
559
- depositorWotsPkHash: d.depositorWotsPkHash
560
- })), P = gt({
561
- abi: S,
562
- functionName: "submitPeginRequestBatch",
563
- args: [i, n, E]
564
- });
565
- let k;
566
- try {
567
- k = await c.estimateGas({
568
- to: this.config.vaultContracts.btcVaultRegistry,
569
- data: P,
570
- value: m,
571
- account: this.config.ethWallet.account.address
572
- });
573
- } catch (d) {
574
- A(d);
575
- }
576
- let f;
577
- try {
578
- f = await this.config.ethWallet.sendTransaction({
579
- to: this.config.vaultContracts.btcVaultRegistry,
580
- data: P,
581
- value: m,
582
- account: this.config.ethWallet.account,
583
- chain: this.config.ethChain,
584
- gas: k
585
- });
586
- } catch (d) {
587
- A(d);
588
- }
589
- const u = await c.waitForTransactionReceipt({
590
- hash: f,
591
- timeout: yt
592
- });
593
- return u.status === "reverted" && A(
594
- new Error(
595
- `Batch transaction reverted. Hash: ${f}. Check the transaction on block explorer for details.`
596
- )
597
- ), {
598
- ethTxHash: u.transactionHash,
599
- vaults: h
600
- };
601
- }
602
- /**
603
- * Check if a vault already exists for a given vault ID.
604
- *
605
- * @param vaultId - The Bitcoin transaction hash (vault ID)
606
- * @returns True if vault exists, false otherwise
607
- */
608
- async checkVaultExists(t) {
609
- try {
610
- return (await j({
611
- chain: this.config.ethChain,
612
- transport: q()
613
- }).readContract({
614
- address: this.config.vaultContracts.btcVaultRegistry,
615
- abi: S,
616
- functionName: "getBtcVaultBasicInfo",
617
- args: [t]
618
- }))[0] !== te;
619
- } catch {
620
- return !1;
621
- }
622
- }
623
- /**
624
- * Resolve the BTC payout address to a scriptPubKey hex for the contract.
625
- *
626
- * If a payout address is provided, converts it directly.
627
- * If omitted, uses the wallet's address and validates it against the
628
- * wallet's public key to guard against a compromised wallet provider.
629
- */
630
- async resolvePayoutScriptPubKey(t) {
631
- let n;
632
- if (t)
633
- n = t;
634
- else {
635
- n = await this.config.btcWallet.getAddress();
636
- const o = await this.config.btcWallet.getPublicKeyHex();
637
- if (!ae(
638
- n,
639
- o,
640
- this.config.btcNetwork
641
- ))
642
- throw new Error(
643
- "The BTC address from your wallet does not match the wallet's public key. Please ensure your wallet is using a supported address type (Taproot or Native SegWit)."
644
- );
645
- }
646
- const s = mt(this.config.btcNetwork);
647
- try {
648
- return `0x${Jt.address.toOutputScript(n, s).toString("hex")}`;
649
- } catch {
650
- throw new Error(
651
- `Invalid BTC payout address: "${n}". Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`
652
- );
653
- }
654
- }
655
- /**
656
- * Sign a BIP-322 BTC Proof-of-Possession binding the connected BTC
657
- * wallet to the connected ETH account for this chain and vault
658
- * registry. The returned {@link PopSignature} can be reused across
659
- * every register call in the same session.
660
- */
661
- async signProofOfPossession() {
662
- if (!this.config.ethWallet.account)
663
- throw new Error("Ethereum wallet account not found");
664
- const t = this.config.ethWallet.account.address, n = O(
665
- await this.config.btcWallet.getPublicKeyHex()
666
- ), s = this.config.vaultContracts.btcVaultRegistry, o = `${t.toLowerCase()}:${this.config.ethChain.id}:pegin:${s.toLowerCase()}`, r = await this.config.btcWallet.signMessage(
667
- o,
668
- "bip322-simple"
669
- );
670
- return {
671
- btcPopSignature: ke(r),
672
- depositorEthAddress: t,
673
- depositorBtcPubkey: n
674
- };
675
- }
676
- async assertPopMatchesBtcWallet(t) {
677
- const n = O(
678
- await this.config.btcWallet.getPublicKeyHex()
679
- ), s = O(t.depositorBtcPubkey);
680
- if (n !== s)
681
- throw new Error(
682
- `Proof of possession was signed with BTC pubkey ${s} but the BTC wallet is currently connected to ${n}. Reconnect the original wallet or call signProofOfPossession() again.`
683
- );
684
- }
685
- /**
686
- * Gets the configured Bitcoin network.
687
- *
688
- * @returns The Bitcoin network (mainnet, testnet, signet, regtest)
689
- */
690
- getNetwork() {
691
- return this.config.btcNetwork;
692
- }
693
- /**
694
- * Gets the configured BTCVaultRegistry contract address.
695
- *
696
- * @returns The Ethereum address of the BTCVaultRegistry contract
697
- */
698
- getVaultContractAddress() {
699
- return this.config.vaultContracts.btcVaultRegistry;
700
- }
701
- }
702
- const M = /* @__PURE__ */ BigInt(2 ** 32 - 1), xt = /* @__PURE__ */ BigInt(32);
703
- function Ie(e, t = !1) {
704
- return t ? { h: Number(e & M), l: Number(e >> xt & M) } : { h: Number(e >> xt & M) | 0, l: Number(e & M) | 0 };
705
- }
706
- function ve(e, t = !1) {
707
- const n = e.length;
708
- let s = new Uint32Array(n), o = new Uint32Array(n);
709
- for (let r = 0; r < n; r++) {
710
- const { h: i, l: a } = Ie(e[r], t);
711
- [s[r], o[r]] = [i, a];
712
- }
713
- return [s, o];
714
- }
715
- const Be = (e, t, n) => e << n | t >>> 32 - n, Ae = (e, t, n) => t << n | e >>> 32 - n, He = (e, t, n) => t << n - 32 | e >>> 64 - n, Ce = (e, t, n) => e << n - 32 | t >>> 64 - n, Se = /* @__PURE__ */ Uint8Array.from([
716
- 7,
717
- 4,
718
- 13,
719
- 1,
720
- 10,
721
- 6,
722
- 15,
723
- 3,
724
- 12,
725
- 0,
726
- 9,
727
- 5,
728
- 2,
729
- 14,
730
- 11,
731
- 8
732
- ]), $t = Uint8Array.from(new Array(16).fill(0).map((e, t) => t)), Oe = $t.map((e) => (9 * e + 5) % 16), Rt = /* @__PURE__ */ (() => {
733
- const n = [[$t], [Oe]];
734
- for (let s = 0; s < 4; s++)
735
- for (let o of n)
736
- o.push(o[s].map((r) => Se[r]));
737
- return n;
738
- })(), Ut = Rt[0], Lt = Rt[1], Wt = /* @__PURE__ */ [
739
- [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
740
- [12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],
741
- [13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],
742
- [14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],
743
- [15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5]
744
- ].map((e) => Uint8Array.from(e)), $e = /* @__PURE__ */ Ut.map((e, t) => e.map((n) => Wt[t][n])), Re = /* @__PURE__ */ Lt.map((e, t) => e.map((n) => Wt[t][n])), Ue = /* @__PURE__ */ Uint32Array.from([
745
- 0,
746
- 1518500249,
747
- 1859775393,
748
- 2400959708,
749
- 2840853838
750
- ]), Le = /* @__PURE__ */ Uint32Array.from([
751
- 1352829926,
752
- 1548603684,
753
- 1836072691,
754
- 2053994217,
755
- 0
756
- ]);
757
- function Pt(e, t, n, s) {
758
- return e === 0 ? t ^ n ^ s : e === 1 ? t & n | ~t & s : e === 2 ? (t | ~n) ^ s : e === 3 ? t & s | n & ~s : t ^ (n | ~s);
759
- }
760
- const N = /* @__PURE__ */ new Uint32Array(16);
761
- class We extends be {
762
- constructor() {
763
- super(64, 20, 8, !0);
764
- p(this, "h0", 1732584193);
765
- p(this, "h1", -271733879);
766
- p(this, "h2", -1732584194);
767
- p(this, "h3", 271733878);
768
- p(this, "h4", -1009589776);
769
- }
770
- get() {
771
- const { h0: n, h1: s, h2: o, h3: r, h4: i } = this;
772
- return [n, s, o, r, i];
773
- }
774
- set(n, s, o, r, i) {
775
- this.h0 = n | 0, this.h1 = s | 0, this.h2 = o | 0, this.h3 = r | 0, this.h4 = i | 0;
776
- }
777
- process(n, s) {
778
- for (let g = 0; g < 16; g++, s += 4)
779
- N[g] = n.getUint32(s, !0);
780
- let o = this.h0 | 0, r = o, i = this.h1 | 0, a = i, l = this.h2 | 0, h = l, c = this.h3 | 0, b = c, m = this.h4 | 0, w = m;
781
- for (let g = 0; g < 5; g++) {
782
- const E = 4 - g, P = Ue[g], k = Le[g], f = Ut[g], u = Lt[g], d = $e[g], x = Re[g];
783
- for (let y = 0; y < 16; y++) {
784
- const I = W(o + Pt(g, i, l, c) + N[f[y]] + P, d[y]) + m | 0;
785
- o = m, m = c, c = W(l, 10) | 0, l = i, i = I;
786
- }
787
- for (let y = 0; y < 16; y++) {
788
- const I = W(r + Pt(E, a, h, b) + N[u[y]] + k, x[y]) + w | 0;
789
- r = w, w = b, b = W(h, 10) | 0, h = a, a = I;
790
- }
791
- }
792
- this.set(this.h1 + l + b | 0, this.h2 + c + w | 0, this.h3 + m + r | 0, this.h4 + o + a | 0, this.h0 + i + h | 0);
793
- }
794
- roundClean() {
795
- H(N);
796
- }
797
- destroy() {
798
- this.destroyed = !0, H(this.buffer), this.set(0, 0, 0, 0, 0);
799
- }
800
- }
801
- const Me = /* @__PURE__ */ St(() => new We()), Ne = BigInt(0), $ = BigInt(1), Ve = BigInt(2), Fe = BigInt(7), Xe = BigInt(256), De = BigInt(113), Mt = [], Nt = [], Vt = [];
802
- for (let e = 0, t = $, n = 1, s = 0; e < 24; e++) {
803
- [n, s] = [s, (2 * n + 3 * s) % 5], Mt.push(2 * (5 * s + n)), Nt.push((e + 1) * (e + 2) / 2 % 64);
804
- let o = Ne;
805
- for (let r = 0; r < 7; r++)
806
- t = (t << $ ^ (t >> Fe) * De) % Xe, t & Ve && (o ^= $ << ($ << BigInt(r)) - $);
807
- Vt.push(o);
808
- }
809
- const Ft = ve(Vt, !0), Ke = Ft[0], je = Ft[1], Et = (e, t, n) => n > 32 ? He(e, t, n) : Be(e, t, n), Tt = (e, t, n) => n > 32 ? Ce(e, t, n) : Ae(e, t, n);
810
- function qe(e, t = 24) {
811
- const n = new Uint32Array(10);
812
- for (let s = 24 - t; s < 24; s++) {
813
- for (let i = 0; i < 10; i++)
814
- n[i] = e[i] ^ e[i + 10] ^ e[i + 20] ^ e[i + 30] ^ e[i + 40];
815
- for (let i = 0; i < 10; i += 2) {
816
- const a = (i + 8) % 10, l = (i + 2) % 10, h = n[l], c = n[l + 1], b = Et(h, c, 1) ^ n[a], m = Tt(h, c, 1) ^ n[a + 1];
817
- for (let w = 0; w < 50; w += 10)
818
- e[i + w] ^= b, e[i + w + 1] ^= m;
819
- }
820
- let o = e[2], r = e[3];
821
- for (let i = 0; i < 24; i++) {
822
- const a = Nt[i], l = Et(o, r, a), h = Tt(o, r, a), c = Mt[i];
823
- o = e[c], r = e[c + 1], e[c] = l, e[c + 1] = h;
824
- }
825
- for (let i = 0; i < 50; i += 10) {
826
- for (let a = 0; a < 10; a++)
827
- n[a] = e[i + a];
828
- for (let a = 0; a < 10; a++)
829
- e[i + a] ^= ~n[(a + 2) % 10] & n[(a + 4) % 10];
830
- }
831
- e[0] ^= Ke[s], e[1] ^= je[s];
832
- }
833
- H(n);
834
- }
835
- class at {
836
- // NOTE: we accept arguments in bytes instead of bits here.
837
- constructor(t, n, s, o = !1, r = 24) {
838
- p(this, "state");
839
- p(this, "pos", 0);
840
- p(this, "posOut", 0);
841
- p(this, "finished", !1);
842
- p(this, "state32");
843
- p(this, "destroyed", !1);
844
- p(this, "blockLen");
845
- p(this, "suffix");
846
- p(this, "outputLen");
847
- p(this, "enableXOF", !1);
848
- p(this, "rounds");
849
- if (this.blockLen = t, this.suffix = n, this.outputLen = s, this.enableXOF = o, this.rounds = r, nt(s, "outputLen"), !(0 < t && t < 200))
850
- throw new Error("only keccak-f1600 function is supported");
851
- this.state = new Uint8Array(200), this.state32 = we(this.state);
852
- }
853
- clone() {
854
- return this._cloneInto();
855
- }
856
- keccak() {
857
- wt(this.state32), qe(this.state32, this.rounds), wt(this.state32), this.posOut = 0, this.pos = 0;
858
- }
859
- update(t) {
860
- F(this), U(t);
861
- const { blockLen: n, state: s } = this, o = t.length;
862
- for (let r = 0; r < o; ) {
863
- const i = Math.min(n - this.pos, o - r);
864
- for (let a = 0; a < i; a++)
865
- s[this.pos++] ^= t[r++];
866
- this.pos === n && this.keccak();
867
- }
868
- return this;
869
- }
870
- finish() {
871
- if (this.finished)
872
- return;
873
- this.finished = !0;
874
- const { state: t, suffix: n, pos: s, blockLen: o } = this;
875
- t[s] ^= n, (n & 128) !== 0 && s === o - 1 && this.keccak(), t[o - 1] ^= 128, this.keccak();
876
- }
877
- writeInto(t) {
878
- F(this, !1), U(t), this.finish();
879
- const n = this.state, { blockLen: s } = this;
880
- for (let o = 0, r = t.length; o < r; ) {
881
- this.posOut >= s && this.keccak();
882
- const i = Math.min(s - this.posOut, r - o);
883
- t.set(n.subarray(this.posOut, this.posOut + i), o), this.posOut += i, o += i;
884
- }
885
- return t;
886
- }
887
- xofInto(t) {
888
- if (!this.enableXOF)
889
- throw new Error("XOF is not possible for this instance");
890
- return this.writeInto(t);
891
- }
892
- xof(t) {
893
- return nt(t), this.xofInto(new Uint8Array(t));
894
- }
895
- digestInto(t) {
896
- if (ye(t, this), this.finished)
897
- throw new Error("digest() was already called");
898
- return this.writeInto(t), this.destroy(), t;
899
- }
900
- digest() {
901
- return this.digestInto(new Uint8Array(this.outputLen));
902
- }
903
- destroy() {
904
- this.destroyed = !0, H(this.state);
905
- }
906
- _cloneInto(t) {
907
- const { blockLen: n, suffix: s, outputLen: o, rounds: r, enableXOF: i } = this;
908
- return t || (t = new at(n, s, o, i, r)), t.state32.set(this.state32), t.pos = this.pos, t.posOut = this.posOut, t.finished = this.finished, t.rounds = r, t.suffix = s, t.outputLen = o, t.enableXOF = i, t.destroyed = this.destroyed, t;
909
- }
910
- }
911
- const Ge = (e, t, n, s = {}) => St(() => new at(t, e, n), s), Ze = /* @__PURE__ */ Ge(1, 136, 32), kt = 64, T = 20, st = 4, Xt = 2, ze = 0, Ye = 1, V = [64, 64], Je = (e) => Array.from(e).map((t) => t.toString(16).padStart(2, "0")).join("");
912
- function ct(e) {
913
- return Me(L(e));
914
- }
915
- function Dt(e) {
916
- return (1 << e) - 1;
917
- }
918
- function Qe(e) {
919
- let t = 1;
920
- for (; t * t < e + 1; ) t++;
921
- return Math.max(t, 2);
922
- }
923
- function tn(e) {
924
- const t = st, n = e * Dt(t);
925
- return { d: t, n: e, checksum_radix: Qe(n) };
926
- }
927
- function Z(e, t) {
928
- const n = [];
929
- let s = t;
930
- for (; s > 0; )
931
- n.push(s & 255), s >>>= 8;
932
- const o = new Uint8Array(e.length + n.length);
933
- o.set(e);
934
- for (let r = 0; r < n.length; r++)
935
- o[e.length + r] = n[r];
936
- return ct(o);
937
- }
938
- function z(e, t) {
939
- let n = e;
940
- for (let s = 0; s < t; s++)
941
- n = ct(n);
942
- return n;
943
- }
944
- function en(e, t) {
945
- const n = Dt(t.d), s = t.checksum_radix - 1, o = Math.floor(t.n * n / t.checksum_radix), r = [];
946
- for (let c = 0; c < t.n; c++) {
947
- const b = Z(e, c + Xt), m = z(b, n);
948
- r.push(Array.from(m));
949
- }
950
- const i = Z(
951
- e,
952
- ze
953
- ), a = z(
954
- i,
955
- s
956
- ), l = Z(
957
- e,
958
- Ye
959
- ), h = z(
960
- l,
961
- o
962
- );
963
- return {
964
- config: t,
965
- message_terminals: r,
966
- checksum_major_terminal: Array.from(h),
967
- checksum_minor_terminal: Array.from(a)
968
- };
969
- }
970
- async function Sn(e) {
971
- try {
972
- if (e.length !== kt)
973
- throw new Error(
974
- `WOTS seed must be exactly ${kt} bytes, got ${e.length}`
975
- );
976
- const t = [];
977
- for (let n = 0; n < V.length; n++) {
978
- const s = V[n], o = tn(s), r = new Uint8Array(e.length + 1);
979
- r.set(e), r[e.length] = n;
980
- const i = ct(r);
981
- try {
982
- const a = en(i, o);
983
- if (a.config.d !== st)
984
- throw new Error(
985
- `Block ${n}: expected d=${st}, got d=${a.config.d}`
986
- );
987
- if (a.config.n !== s)
988
- throw new Error(
989
- `Block ${n}: expected n=${s}, got n=${a.config.n}`
990
- );
991
- if (a.message_terminals.length !== s)
992
- throw new Error(
993
- `Block ${n}: expected ${s} message terminals, got ${a.message_terminals.length}`
994
- );
995
- for (let l = 0; l < a.message_terminals.length; l++)
996
- if (a.message_terminals[l].length !== T)
997
- throw new Error(
998
- `Block ${n} terminal ${l}: expected ${T} bytes, got ${a.message_terminals[l].length}`
999
- );
1000
- if (a.checksum_minor_terminal.length !== T)
1001
- throw new Error(
1002
- `Block ${n} checksum_minor: expected ${T} bytes`
1003
- );
1004
- if (a.checksum_major_terminal.length !== T)
1005
- throw new Error(
1006
- `Block ${n} checksum_major: expected ${T} bytes`
1007
- );
1008
- t.push(a);
1009
- } finally {
1010
- r.fill(0), i.fill(0);
1011
- }
1143
+ throw new Error(
1144
+ `Vault already exists (ID: ${B}, peginTxHash: ${w}). To create a new vault, use different UTXOs or a different amount.`
1145
+ );
1146
+ u.push({ vaultId: B, peginTxHash: w });
1012
1147
  }
1013
- if (t.length !== V.length)
1148
+ const c = j({
1149
+ chain: this.config.ethChain,
1150
+ transport: z()
1151
+ });
1152
+ let y;
1153
+ try {
1154
+ y = await c.readContract({
1155
+ address: this.config.vaultContracts.btcVaultRegistry,
1156
+ abi: C,
1157
+ functionName: "getPegInFee",
1158
+ args: [n]
1159
+ });
1160
+ } catch {
1014
1161
  throw new Error(
1015
- `Expected ${V.length} blocks, got ${t.length}`
1162
+ "Failed to query pegin fee from the contract. Please check your network connection and that the contract address is correct."
1016
1163
  );
1017
- return t;
1018
- } finally {
1019
- e.fill(0);
1164
+ }
1165
+ const g = y * BigInt(o.length), h = I(
1166
+ r.depositorBtcPubkey
1167
+ ), p = I(s), T = o.map((f, m) => ({
1168
+ depositorBtcPubKey: h,
1169
+ btcPopSignature: a,
1170
+ unsignedPrePeginTx: p,
1171
+ depositorSignedPeginTx: I(
1172
+ f.depositorSignedPeginTx
1173
+ ),
1174
+ hashlock: f.hashlock,
1175
+ htlcVout: f.htlcVout,
1176
+ referralCode: pn,
1177
+ depositorPayoutBtcAddress: l[m],
1178
+ depositorWotsPkHash: f.depositorWotsPkHash
1179
+ })), P = pt({
1180
+ abi: C,
1181
+ functionName: "submitPeginRequestBatch",
1182
+ args: [i, n, T]
1183
+ });
1184
+ let v;
1185
+ try {
1186
+ v = await c.estimateGas({
1187
+ to: this.config.vaultContracts.btcVaultRegistry,
1188
+ data: P,
1189
+ value: g,
1190
+ account: this.config.ethWallet.account.address
1191
+ });
1192
+ } catch (f) {
1193
+ H(f);
1194
+ }
1195
+ let d;
1196
+ try {
1197
+ d = await this.config.ethWallet.sendTransaction({
1198
+ to: this.config.vaultContracts.btcVaultRegistry,
1199
+ data: P,
1200
+ value: g,
1201
+ account: this.config.ethWallet.account,
1202
+ chain: this.config.ethChain,
1203
+ gas: v
1204
+ });
1205
+ } catch (f) {
1206
+ H(f);
1207
+ }
1208
+ const x = await c.waitForTransactionReceipt({
1209
+ hash: d,
1210
+ timeout: Ot
1211
+ });
1212
+ return x.status === "reverted" && H(
1213
+ new Error(
1214
+ `Batch transaction reverted. Hash: ${d}. Check the transaction on block explorer for details.`
1215
+ )
1216
+ ), {
1217
+ ethTxHash: x.transactionHash,
1218
+ vaults: u
1219
+ };
1020
1220
  }
1021
- }
1022
- function Y(e, t, n) {
1023
- if (e.length !== T)
1024
- throw new Error(
1025
- `Block ${t} ${n}: expected ${T} bytes, got ${e.length}`
1026
- );
1027
- for (let s = 0; s < e.length; s++) {
1028
- const o = e[s];
1029
- if (!Number.isInteger(o) || o < 0 || o > 255)
1221
+ /**
1222
+ * Check if a vault already exists for a given vault ID.
1223
+ *
1224
+ * @param vaultId - The Bitcoin transaction hash (vault ID)
1225
+ * @returns True if vault exists, false otherwise
1226
+ */
1227
+ async checkVaultExists(t) {
1228
+ try {
1229
+ return (await j({
1230
+ chain: this.config.ethChain,
1231
+ transport: z()
1232
+ }).readContract({
1233
+ address: this.config.vaultContracts.btcVaultRegistry,
1234
+ abi: C,
1235
+ functionName: "getBtcVaultBasicInfo",
1236
+ args: [t]
1237
+ })).depositor !== se;
1238
+ } catch {
1239
+ return !1;
1240
+ }
1241
+ }
1242
+ /**
1243
+ * Resolve the BTC payout address to a scriptPubKey hex for the contract.
1244
+ *
1245
+ * If a payout address is provided, converts it directly.
1246
+ * If omitted, uses the wallet's address and validates it against the
1247
+ * wallet's public key to guard against a compromised wallet provider.
1248
+ */
1249
+ async resolvePayoutScriptPubKey(t) {
1250
+ let n;
1251
+ if (t)
1252
+ n = t;
1253
+ else {
1254
+ n = await this.config.btcWallet.getAddress();
1255
+ const o = await this.config.btcWallet.getPublicKeyHex();
1256
+ if (!ce(
1257
+ n,
1258
+ o,
1259
+ this.config.btcNetwork
1260
+ ))
1261
+ throw new Error(
1262
+ "The BTC address from your wallet does not match the wallet's public key. Please ensure your wallet is using a supported address type (Taproot or Native SegWit)."
1263
+ );
1264
+ }
1265
+ const s = wt(this.config.btcNetwork);
1266
+ try {
1267
+ return `0x${ee.address.toOutputScript(n, s).toString("hex")}`;
1268
+ } catch {
1030
1269
  throw new Error(
1031
- `Block ${t} ${n}[${s}]: invalid byte value ${o}`
1270
+ `Invalid BTC payout address: "${n}". Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`
1032
1271
  );
1272
+ }
1033
1273
  }
1034
- }
1035
- function On(e) {
1036
- if (e.length === 0)
1037
- throw new Error("Public keys array must not be empty");
1038
- for (let r = 0; r < e.length; r++) {
1039
- const i = e[r];
1040
- Y(i.checksum_minor_terminal, r, "checksum_minor_terminal"), Y(i.checksum_major_terminal, r, "checksum_major_terminal");
1041
- for (let a = 0; a < i.message_terminals.length; a++)
1042
- Y(i.message_terminals[a], r, `message_terminal[${a}]`);
1043
- }
1044
- let t = 0;
1045
- for (const r of e)
1046
- t += Xt + r.message_terminals.length;
1047
- const n = new Uint8Array(t * T);
1048
- let s = 0;
1049
- for (const r of e) {
1050
- n.set(r.checksum_minor_terminal, s), s += T, n.set(r.checksum_major_terminal, s), s += T;
1051
- for (const i of r.message_terminals)
1052
- n.set(i, s), s += T;
1053
- }
1054
- const o = Ze(n);
1055
- return `0x${Je(o)}`;
1056
- }
1057
- function $n(e) {
1058
- const t = (e instanceof Error ? e.message : typeof e == "string" ? e : "").toLowerCase();
1059
- return t.includes("wots") && t.includes("hash") && t.includes("does not match");
1060
- }
1061
- class Kt {
1062
- constructor(t, n) {
1063
- p(this, "oHash");
1064
- p(this, "iHash");
1065
- p(this, "blockLen");
1066
- p(this, "outputLen");
1067
- p(this, "finished", !1);
1068
- p(this, "destroyed", !1);
1069
- if (Ot(t), U(n, void 0, "key"), this.iHash = t.create(), typeof this.iHash.update != "function")
1070
- throw new Error("Expected instance of class which extends utils.Hash");
1071
- this.blockLen = this.iHash.blockLen, this.outputLen = this.iHash.outputLen;
1072
- const s = this.blockLen, o = new Uint8Array(s);
1073
- o.set(n.length > s ? t.create().update(n).digest() : n);
1074
- for (let r = 0; r < o.length; r++)
1075
- o[r] ^= 54;
1076
- this.iHash.update(o), this.oHash = t.create();
1077
- for (let r = 0; r < o.length; r++)
1078
- o[r] ^= 106;
1079
- this.oHash.update(o), H(o);
1080
- }
1081
- update(t) {
1082
- return F(this), this.iHash.update(t), this;
1083
- }
1084
- digestInto(t) {
1085
- F(this), U(t, this.outputLen, "output"), this.finished = !0, this.iHash.digestInto(t), this.oHash.update(t), this.oHash.digestInto(t), this.destroy();
1086
- }
1087
- digest() {
1088
- const t = new Uint8Array(this.oHash.outputLen);
1089
- return this.digestInto(t), t;
1274
+ /**
1275
+ * Sign a BIP-322 BTC Proof-of-Possession binding the connected BTC
1276
+ * wallet to the connected ETH account for this chain and vault
1277
+ * registry. The returned {@link PopSignature} can be reused across
1278
+ * every register call in the same session.
1279
+ */
1280
+ async signProofOfPossession() {
1281
+ if (!this.config.ethWallet.account)
1282
+ throw new Error("Ethereum wallet account not found");
1283
+ const t = this.config.ethWallet.account.address, n = $(
1284
+ await this.config.btcWallet.getPublicKeyHex()
1285
+ ), s = this.config.vaultContracts.btcVaultRegistry, o = `${t.toLowerCase()}:${this.config.ethChain.id}:pegin:${s.toLowerCase()}`, r = await this.config.btcWallet.signMessage(
1286
+ o,
1287
+ "bip322-simple"
1288
+ );
1289
+ return {
1290
+ btcPopSignature: xn(r),
1291
+ depositorEthAddress: t,
1292
+ depositorBtcPubkey: n
1293
+ };
1090
1294
  }
1091
- _cloneInto(t) {
1092
- t || (t = Object.create(Object.getPrototypeOf(this), {}));
1093
- const { oHash: n, iHash: s, finished: o, destroyed: r, blockLen: i, outputLen: a } = this;
1094
- return t = t, t.finished = o, t.destroyed = r, t.blockLen = i, t.outputLen = a, t.oHash = n._cloneInto(t.oHash), t.iHash = s._cloneInto(t.iHash), t;
1295
+ async assertPopMatchesBtcWallet(t) {
1296
+ const n = $(
1297
+ await this.config.btcWallet.getPublicKeyHex()
1298
+ ), s = $(t.depositorBtcPubkey);
1299
+ if (n !== s)
1300
+ throw new Error(
1301
+ `Proof of possession was signed with BTC pubkey ${s} but the BTC wallet is currently connected to ${n}. Reconnect the original wallet or call signProofOfPossession() again.`
1302
+ );
1095
1303
  }
1096
- clone() {
1097
- return this._cloneInto();
1304
+ /**
1305
+ * Gets the configured Bitcoin network.
1306
+ *
1307
+ * @returns The Bitcoin network (mainnet, testnet, signet, regtest)
1308
+ */
1309
+ getNetwork() {
1310
+ return this.config.btcNetwork;
1098
1311
  }
1099
- destroy() {
1100
- this.destroyed = !0, this.oHash.destroy(), this.iHash.destroy();
1312
+ /**
1313
+ * Gets the configured BTCVaultRegistry contract address.
1314
+ *
1315
+ * @returns The Ethereum address of the BTCVaultRegistry contract
1316
+ */
1317
+ getVaultContractAddress() {
1318
+ return this.config.vaultContracts.btcVaultRegistry;
1101
1319
  }
1102
1320
  }
1103
- const jt = (e, t, n) => new Kt(e, t).update(n).digest();
1104
- jt.create = (e, t) => new Kt(e, t);
1105
- const J = /* @__PURE__ */ Uint8Array.of(0), _t = /* @__PURE__ */ Uint8Array.of();
1106
- function lt(e, t, n, s = 32) {
1107
- Ot(e), nt(s, "length");
1108
- const o = e.outputLen;
1109
- if (s > 255 * o)
1110
- throw new Error("Length must be <= 255*HashLen");
1111
- const r = Math.ceil(s / o);
1112
- n === void 0 ? n = _t : U(n, void 0, "info");
1113
- const i = new Uint8Array(r * o), a = jt.create(e, t), l = a._cloneInto(), h = new Uint8Array(a.outputLen);
1114
- for (let c = 0; c < r; c++)
1115
- J[0] = c + 1, l.update(c === 0 ? _t : h).update(n).update(J).digestInto(h), i.set(h, o * c), a._cloneInto(l);
1116
- return a.destroy(), l.destroy(), H(h, J), i.slice(0, s);
1117
- }
1118
- const Q = new TextEncoder().encode("babylonvault"), It = 255, vt = 65535, Bt = 2, nn = "hashlock", sn = "auth-anchor", on = "wots-seed";
1119
- function qt(e) {
1120
- if (!Number.isInteger(e) || e < 0 || e > 4294967295)
1121
- throw new Error(`i2osp4: value must be a u32, got ${e}`);
1122
- const t = new Uint8Array(4);
1123
- return t[0] = e >>> 24 & 255, t[1] = e >>> 16 & 255, t[2] = e >>> 8 & 255, t[3] = e & 255, t;
1124
- }
1125
- function ht(e, t = new Uint8Array(0)) {
1126
- const n = new TextEncoder().encode(e);
1127
- if (n.length === 0 || n.length > It)
1128
- throw new Error(
1129
- `info: label length must be in [1, ${It}], got ${n.length}`
1130
- );
1131
- if (t.length > vt)
1132
- throw new Error(
1133
- `info: ctx length must be in [0, ${vt}], got ${t.length}`
1134
- );
1135
- const s = Q.length + 1 + n.length + Bt + t.length, o = new Uint8Array(s);
1136
- let r = 0;
1137
- return o.set(Q, r), r += Q.length, o[r] = n.length, r += 1, o.set(n, r), r += n.length, o[r] = t.length >>> 8 & 255, o[r + 1] = t.length & 255, r += Bt, o.set(t, r), o;
1138
- }
1139
- const At = 32, rn = 32, an = 32, cn = 64;
1140
- function ut(e) {
1141
- if (e.length !== At)
1142
- throw new Error(
1143
- `vault-secrets: root must be exactly ${At} bytes, got ${e.length}`
1144
- );
1145
- }
1146
- function Rn(e) {
1147
- return ut(e), lt(
1148
- L,
1149
- e,
1150
- ht(sn),
1151
- rn
1152
- );
1153
- }
1154
- function Un(e, t) {
1155
- return ut(e), lt(
1156
- L,
1157
- e,
1158
- ht(nn, qt(t)),
1159
- an
1160
- );
1161
- }
1162
- function Ln(e, t) {
1163
- return ut(e), lt(
1164
- L,
1165
- e,
1166
- ht(on, qt(t)),
1167
- cn
1168
- );
1169
- }
1170
- const R = 32, tt = 32, ot = 36, Gt = 32, X = 4, ln = X + R + X + Gt;
1171
- function rt(e, t, n) {
1172
- e[t] = n >>> 24 & 255, e[t + 1] = n >>> 16 & 255, e[t + 2] = n >>> 8 & 255, e[t + 3] = n & 255;
1173
- }
1174
- function hn(e) {
1175
- if (e.txid.length !== tt)
1176
- throw new Error(
1177
- `outpoint.txid must be exactly ${tt} bytes, got ${e.txid.length}`
1178
- );
1179
- if (!Number.isInteger(e.vout) || e.vout < 0 || e.vout > 4294967295)
1180
- throw new Error(`outpoint.vout must be a u32, got ${e.vout}`);
1181
- const t = new Uint8Array(ot);
1182
- return t.set(e.txid, 0), rt(t, tt, e.vout), t;
1183
- }
1184
- function Ht(e, t) {
1185
- const n = Math.min(e.length, t.length);
1186
- for (let s = 0; s < n; s++)
1187
- if (e[s] !== t[s]) return e[s] - t[s];
1188
- return e.length - t.length;
1189
- }
1190
- function un(e) {
1191
- if (e.length === 0)
1192
- throw new Error(
1193
- "buildFundingOutpointsCommitment: outpoints must be non-empty"
1194
- );
1195
- const t = e.map(hn);
1196
- t.sort(Ht);
1197
- for (let s = 1; s < t.length; s++)
1198
- if (Ht(t[s - 1], t[s]) === 0)
1199
- throw new Error(
1200
- "buildFundingOutpointsCommitment: duplicate outpoint detected"
1201
- );
1202
- const n = new Uint8Array(t.length * ot);
1203
- for (let s = 0; s < t.length; s++)
1204
- n.set(t[s], s * ot);
1205
- return L(n);
1206
- }
1207
- function dn(e) {
1208
- if (e.depositorBtcPubkey.length !== R)
1209
- throw new Error(
1210
- `vaultContext: depositorBtcPubkey must be exactly ${R} bytes, got ${e.depositorBtcPubkey.length}`
1211
- );
1212
- const t = un(e.fundingOutpoints), n = new Uint8Array(ln);
1213
- let s = 0;
1214
- return rt(n, s, R), s += X, n.set(e.depositorBtcPubkey, s), s += R, rt(n, s, Gt), s += X, n.set(t, s), n;
1215
- }
1216
- const fn = "babylon-vault", Zt = 32, Ct = Zt * 2, gn = /^[0-9a-f]+$/;
1217
- async function Wn(e, t) {
1218
- const n = dn(t), s = le(n), o = await e.deriveContextHash(fn, s);
1219
- if (typeof o != "string")
1220
- throw new Error(
1221
- `deriveVaultRoot: wallet must return a string, got ${typeof o}`
1222
- );
1223
- if (o.length !== Ct)
1224
- throw new Error(
1225
- `deriveVaultRoot: wallet must return a ${Ct}-character hex string (${Zt} bytes), got length ${o.length}`
1226
- );
1227
- if (!gn.test(o))
1228
- throw new Error(
1229
- "deriveVaultRoot: wallet must return lowercase hex per derive-context-hash.md §2.1; got value with non-lowercase or non-hex characters"
1230
- );
1231
- return he(o);
1232
- }
1233
1321
  export {
1234
- C,
1235
- Cn as P,
1236
- fn as V,
1237
- $n as a,
1238
- Rn as b,
1239
- On as c,
1240
- Sn as d,
1241
- it as e,
1242
- Un as f,
1243
- An as g,
1244
- A as h,
1245
- Hn as i,
1246
- Ln as j,
1247
- un as k,
1248
- dn as l,
1249
- Wn as m
1322
+ S as C,
1323
+ Mn as P,
1324
+ We as V,
1325
+ Nn as a,
1326
+ Wn as b,
1327
+ gn as c,
1328
+ fn as d,
1329
+ at as e,
1330
+ Oe as f,
1331
+ Ln as g,
1332
+ H as h,
1333
+ Vn as i,
1334
+ $e as j,
1335
+ Le as k,
1336
+ Ve as l,
1337
+ Me as m
1250
1338
  };
1251
- //# sourceMappingURL=deriveVaultRoot-DAMZDqg-.js.map
1339
+ //# sourceMappingURL=PeginManager-DzMSIQ0I.js.map