@babylonlabs-io/ts-sdk 0.28.0 → 0.29.0

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