@toon-protocol/client-mcp 0.20.3 → 0.20.4

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.
@@ -0,0 +1,3856 @@
1
+ import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
+ import {
3
+ Field,
4
+ aInRange,
5
+ abignumber,
6
+ abool,
7
+ abytes,
8
+ abytes2,
9
+ aexists,
10
+ ahash,
11
+ anumber,
12
+ aoutput,
13
+ asafenumber,
14
+ asciiToBytes,
15
+ bitLen,
16
+ bitMask,
17
+ bytesToHex,
18
+ bytesToHex2,
19
+ bytesToNumberBE,
20
+ clean,
21
+ concatBytes2 as concatBytes,
22
+ createCurveFields,
23
+ createHasher,
24
+ createHmacDrbg,
25
+ createKeygen,
26
+ getMinHashLength,
27
+ hexToBytes,
28
+ hexToBytes2,
29
+ isBytes,
30
+ mapHashToField,
31
+ mulEndoUnsafe,
32
+ negateCt,
33
+ normalizeZ,
34
+ numberToHexUnpadded,
35
+ pow2,
36
+ randomBytes,
37
+ randomBytes2,
38
+ rotlBH,
39
+ rotlBL,
40
+ rotlSH,
41
+ rotlSL,
42
+ sha256,
43
+ split,
44
+ swap32IfBE,
45
+ u32,
46
+ validateObject,
47
+ wNAF
48
+ } from "./chunk-6GXZ4KRO.js";
49
+
50
+ // ../../node_modules/.pnpm/@toon-protocol+core@3.1.2_typescript@5.9.3/node_modules/@toon-protocol/core/dist/chunk-5WT7ISKC.js
51
+ import { encode } from "@toon-format/toon";
52
+ import { decode } from "@toon-format/toon";
53
+ import { decode as decode2 } from "@toon-format/toon";
54
+ var ToonError = class extends Error {
55
+ code;
56
+ constructor(message, code, cause) {
57
+ super(message, { cause });
58
+ this.name = "ToonError";
59
+ this.code = code;
60
+ }
61
+ };
62
+ var InvalidEventError = class extends ToonError {
63
+ constructor(message, cause) {
64
+ super(message, "INVALID_EVENT", cause);
65
+ this.name = "InvalidEventError";
66
+ }
67
+ };
68
+ var PeerDiscoveryError = class extends ToonError {
69
+ constructor(message, cause) {
70
+ super(message, "PEER_DISCOVERY_FAILED", cause);
71
+ this.name = "PeerDiscoveryError";
72
+ }
73
+ };
74
+ var ToonEncodeError = class extends ToonError {
75
+ constructor(message, cause) {
76
+ super(message, "TOON_ENCODE_ERROR", cause);
77
+ this.name = "ToonEncodeError";
78
+ }
79
+ };
80
+ function encodeEventToToon(event) {
81
+ try {
82
+ const toonString = encode(event);
83
+ return new TextEncoder().encode(toonString);
84
+ } catch (error) {
85
+ throw new ToonEncodeError(
86
+ `Failed to encode event to TOON: ${error instanceof Error ? error.message : String(error)}`,
87
+ error instanceof Error ? error : void 0
88
+ );
89
+ }
90
+ }
91
+ function isValidHex(value, length) {
92
+ if (typeof value !== "string") return false;
93
+ if (value.length !== length) return false;
94
+ return /^[0-9a-f]+$/i.test(value);
95
+ }
96
+ var ToonDecodeError = class extends ToonError {
97
+ constructor(message, cause) {
98
+ super(message, "TOON_DECODE_ERROR", cause);
99
+ this.name = "ToonDecodeError";
100
+ }
101
+ };
102
+ function validateNostrEvent(obj) {
103
+ if (typeof obj !== "object" || obj === null) {
104
+ throw new ToonDecodeError("Decoded value is not an object");
105
+ }
106
+ const event = obj;
107
+ if (!isValidHex(event["id"], 64)) {
108
+ throw new ToonDecodeError(
109
+ "Invalid event id: must be a 64-character hex string"
110
+ );
111
+ }
112
+ if (!isValidHex(event["pubkey"], 64)) {
113
+ throw new ToonDecodeError(
114
+ "Invalid event pubkey: must be a 64-character hex string"
115
+ );
116
+ }
117
+ if (typeof event["kind"] !== "number" || !Number.isInteger(event["kind"])) {
118
+ throw new ToonDecodeError("Invalid event kind: must be an integer");
119
+ }
120
+ if (typeof event["content"] !== "string") {
121
+ throw new ToonDecodeError("Invalid event content: must be a string");
122
+ }
123
+ const tags = event["tags"];
124
+ if (!Array.isArray(tags)) {
125
+ throw new ToonDecodeError("Invalid event tags: must be an array");
126
+ }
127
+ for (let i = 0; i < tags.length; i++) {
128
+ const tag = tags[i];
129
+ if (!Array.isArray(tag)) {
130
+ throw new ToonDecodeError(`Invalid event tags[${i}]: must be an array`);
131
+ }
132
+ for (let j = 0; j < tag.length; j++) {
133
+ if (typeof tag[j] !== "string") {
134
+ throw new ToonDecodeError(
135
+ `Invalid event tags[${i}][${j}]: must be a string`
136
+ );
137
+ }
138
+ }
139
+ }
140
+ if (typeof event["created_at"] !== "number" || !Number.isInteger(event["created_at"])) {
141
+ throw new ToonDecodeError("Invalid event created_at: must be an integer");
142
+ }
143
+ if (!isValidHex(event["sig"], 128)) {
144
+ throw new ToonDecodeError(
145
+ "Invalid event sig: must be a 128-character hex string"
146
+ );
147
+ }
148
+ }
149
+ function decodeEventFromToon(data) {
150
+ try {
151
+ const toonString = new TextDecoder().decode(data);
152
+ const decoded = decode(toonString);
153
+ validateNostrEvent(decoded);
154
+ return decoded;
155
+ } catch (error) {
156
+ if (error instanceof ToonDecodeError) {
157
+ throw error;
158
+ }
159
+ throw new ToonDecodeError(
160
+ `Failed to decode TOON data: ${error instanceof Error ? error.message : String(error)}`,
161
+ error instanceof Error ? error : void 0
162
+ );
163
+ }
164
+ }
165
+
166
+ // ../../node_modules/.pnpm/@toon-protocol+core@3.1.2_typescript@5.9.3/node_modules/@toon-protocol/core/dist/index.js
167
+ import { finalizeEvent } from "nostr-tools/pure";
168
+ import { finalizeEvent as finalizeEvent2 } from "nostr-tools/pure";
169
+ import { finalizeEvent as finalizeEvent3 } from "nostr-tools/pure";
170
+ import { finalizeEvent as finalizeEvent4 } from "nostr-tools/pure";
171
+ import { finalizeEvent as finalizeEvent5 } from "nostr-tools/pure";
172
+ import { finalizeEvent as finalizeEvent6 } from "nostr-tools/pure";
173
+ import { finalizeEvent as finalizeEvent7 } from "nostr-tools/pure";
174
+ import { finalizeEvent as finalizeEvent8 } from "nostr-tools/pure";
175
+ import { finalizeEvent as finalizeEvent9 } from "nostr-tools/pure";
176
+ import { finalizeEvent as finalizeEvent10 } from "nostr-tools/pure";
177
+ import { SimplePool } from "nostr-tools/pool";
178
+ import { SimplePool as SimplePool2 } from "nostr-tools/pool";
179
+ import { getPublicKey } from "nostr-tools/pure";
180
+ import WebSocket from "ws";
181
+ import { getPublicKey as getPublicKey2, verifyEvent } from "nostr-tools/pure";
182
+
183
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/sha3.js
184
+ var _0n = BigInt(0);
185
+ var _1n = BigInt(1);
186
+ var _2n = BigInt(2);
187
+ var _7n = BigInt(7);
188
+ var _256n = BigInt(256);
189
+ var _0x71n = BigInt(113);
190
+ var SHA3_PI = [];
191
+ var SHA3_ROTL = [];
192
+ var _SHA3_IOTA = [];
193
+ for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
194
+ [x, y] = [y, (2 * x + 3 * y) % 5];
195
+ SHA3_PI.push(2 * (5 * y + x));
196
+ SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
197
+ let t = _0n;
198
+ for (let j = 0; j < 7; j++) {
199
+ R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
200
+ if (R & _2n)
201
+ t ^= _1n << (_1n << BigInt(j)) - _1n;
202
+ }
203
+ _SHA3_IOTA.push(t);
204
+ }
205
+ var IOTAS = split(_SHA3_IOTA, true);
206
+ var SHA3_IOTA_H = IOTAS[0];
207
+ var SHA3_IOTA_L = IOTAS[1];
208
+ var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
209
+ var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
210
+ function keccakP(s, rounds = 24) {
211
+ anumber(rounds, "rounds");
212
+ if (rounds < 1 || rounds > 24)
213
+ throw new Error('"rounds" expected integer 1..24');
214
+ const B = new Uint32Array(5 * 2);
215
+ for (let round = 24 - rounds; round < 24; round++) {
216
+ for (let x = 0; x < 10; x++)
217
+ B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
218
+ for (let x = 0; x < 10; x += 2) {
219
+ const idx1 = (x + 8) % 10;
220
+ const idx0 = (x + 2) % 10;
221
+ const B0 = B[idx0];
222
+ const B1 = B[idx0 + 1];
223
+ const Th = rotlH(B0, B1, 1) ^ B[idx1];
224
+ const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
225
+ for (let y = 0; y < 50; y += 10) {
226
+ s[x + y] ^= Th;
227
+ s[x + y + 1] ^= Tl;
228
+ }
229
+ }
230
+ let curH = s[2];
231
+ let curL = s[3];
232
+ for (let t = 0; t < 24; t++) {
233
+ const shift = SHA3_ROTL[t];
234
+ const Th = rotlH(curH, curL, shift);
235
+ const Tl = rotlL(curH, curL, shift);
236
+ const PI = SHA3_PI[t];
237
+ curH = s[PI];
238
+ curL = s[PI + 1];
239
+ s[PI] = Th;
240
+ s[PI + 1] = Tl;
241
+ }
242
+ for (let y = 0; y < 50; y += 10) {
243
+ const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3];
244
+ s[y] ^= ~s[y + 2] & s[y + 4];
245
+ s[y + 1] ^= ~s[y + 3] & s[y + 5];
246
+ s[y + 2] ^= ~s[y + 4] & s[y + 6];
247
+ s[y + 3] ^= ~s[y + 5] & s[y + 7];
248
+ s[y + 4] ^= ~s[y + 6] & s[y + 8];
249
+ s[y + 5] ^= ~s[y + 7] & s[y + 9];
250
+ s[y + 6] ^= ~s[y + 8] & b0;
251
+ s[y + 7] ^= ~s[y + 9] & b1;
252
+ s[y + 8] ^= ~b0 & b2;
253
+ s[y + 9] ^= ~b1 & b3;
254
+ }
255
+ s[0] ^= SHA3_IOTA_H[round];
256
+ s[1] ^= SHA3_IOTA_L[round];
257
+ }
258
+ clean(B);
259
+ }
260
+ var Keccak = class _Keccak {
261
+ state;
262
+ pos = 0;
263
+ posOut = 0;
264
+ finished = false;
265
+ state32;
266
+ destroyed = false;
267
+ blockLen;
268
+ suffix;
269
+ outputLen;
270
+ canXOF;
271
+ enableXOF = false;
272
+ rounds;
273
+ // NOTE: we accept arguments in bytes instead of bits here.
274
+ constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
275
+ this.blockLen = blockLen;
276
+ this.suffix = suffix;
277
+ this.outputLen = outputLen;
278
+ this.enableXOF = enableXOF;
279
+ this.canXOF = enableXOF;
280
+ this.rounds = rounds;
281
+ anumber(outputLen, "outputLen");
282
+ if (!(0 < blockLen && blockLen < 200))
283
+ throw new Error("only keccak-f1600 function is supported");
284
+ this.state = new Uint8Array(200);
285
+ this.state32 = u32(this.state);
286
+ }
287
+ clone() {
288
+ return this._cloneInto();
289
+ }
290
+ keccak() {
291
+ swap32IfBE(this.state32);
292
+ keccakP(this.state32, this.rounds);
293
+ swap32IfBE(this.state32);
294
+ this.posOut = 0;
295
+ this.pos = 0;
296
+ }
297
+ update(data) {
298
+ aexists(this);
299
+ abytes(data);
300
+ const { blockLen, state } = this;
301
+ const len = data.length;
302
+ for (let pos = 0; pos < len; ) {
303
+ const take = Math.min(blockLen - this.pos, len - pos);
304
+ for (let i = 0; i < take; i++)
305
+ state[this.pos++] ^= data[pos++];
306
+ if (this.pos === blockLen)
307
+ this.keccak();
308
+ }
309
+ return this;
310
+ }
311
+ finish() {
312
+ if (this.finished)
313
+ return;
314
+ this.finished = true;
315
+ const { state, suffix, pos, blockLen } = this;
316
+ state[pos] ^= suffix;
317
+ if ((suffix & 128) !== 0 && pos === blockLen - 1)
318
+ this.keccak();
319
+ state[blockLen - 1] ^= 128;
320
+ this.keccak();
321
+ }
322
+ writeInto(out) {
323
+ aexists(this, false);
324
+ abytes(out);
325
+ this.finish();
326
+ const bufferOut = this.state;
327
+ const { blockLen } = this;
328
+ for (let pos = 0, len = out.length; pos < len; ) {
329
+ if (this.posOut >= blockLen)
330
+ this.keccak();
331
+ const take = Math.min(blockLen - this.posOut, len - pos);
332
+ out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
333
+ this.posOut += take;
334
+ pos += take;
335
+ }
336
+ return out;
337
+ }
338
+ xofInto(out) {
339
+ if (!this.enableXOF)
340
+ throw new Error("XOF is not possible for this instance");
341
+ return this.writeInto(out);
342
+ }
343
+ xof(bytes) {
344
+ anumber(bytes);
345
+ return this.xofInto(new Uint8Array(bytes));
346
+ }
347
+ digestInto(out) {
348
+ aoutput(out, this);
349
+ if (this.finished)
350
+ throw new Error("digest() was already called");
351
+ this.writeInto(out.subarray(0, this.outputLen));
352
+ this.destroy();
353
+ }
354
+ digest() {
355
+ const out = new Uint8Array(this.outputLen);
356
+ this.digestInto(out);
357
+ return out;
358
+ }
359
+ destroy() {
360
+ this.destroyed = true;
361
+ clean(this.state);
362
+ }
363
+ _cloneInto(to) {
364
+ const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
365
+ to ||= new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
366
+ to.blockLen = blockLen;
367
+ to.state32.set(this.state32);
368
+ to.pos = this.pos;
369
+ to.posOut = this.posOut;
370
+ to.finished = this.finished;
371
+ to.rounds = rounds;
372
+ to.suffix = suffix;
373
+ to.outputLen = outputLen;
374
+ to.enableXOF = enableXOF;
375
+ to.canXOF = this.canXOF;
376
+ to.destroyed = this.destroyed;
377
+ return to;
378
+ }
379
+ };
380
+ var genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);
381
+ var keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
382
+
383
+ // ../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/hmac.js
384
+ var _HMAC = class {
385
+ oHash;
386
+ iHash;
387
+ blockLen;
388
+ outputLen;
389
+ canXOF = false;
390
+ finished = false;
391
+ destroyed = false;
392
+ constructor(hash, key) {
393
+ ahash(hash);
394
+ abytes(key, void 0, "key");
395
+ this.iHash = hash.create();
396
+ if (typeof this.iHash.update !== "function")
397
+ throw new Error("Expected instance of class which extends utils.Hash");
398
+ this.blockLen = this.iHash.blockLen;
399
+ this.outputLen = this.iHash.outputLen;
400
+ const blockLen = this.blockLen;
401
+ const pad = new Uint8Array(blockLen);
402
+ pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
403
+ for (let i = 0; i < pad.length; i++)
404
+ pad[i] ^= 54;
405
+ this.iHash.update(pad);
406
+ this.oHash = hash.create();
407
+ for (let i = 0; i < pad.length; i++)
408
+ pad[i] ^= 54 ^ 92;
409
+ this.oHash.update(pad);
410
+ clean(pad);
411
+ }
412
+ update(buf) {
413
+ aexists(this);
414
+ this.iHash.update(buf);
415
+ return this;
416
+ }
417
+ digestInto(out) {
418
+ aexists(this);
419
+ aoutput(out, this);
420
+ this.finished = true;
421
+ const buf = out.subarray(0, this.outputLen);
422
+ this.iHash.digestInto(buf);
423
+ this.oHash.update(buf);
424
+ this.oHash.digestInto(buf);
425
+ this.destroy();
426
+ }
427
+ digest() {
428
+ const out = new Uint8Array(this.oHash.outputLen);
429
+ this.digestInto(out);
430
+ return out;
431
+ }
432
+ _cloneInto(to) {
433
+ to ||= Object.create(Object.getPrototypeOf(this), {});
434
+ const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
435
+ to = to;
436
+ to.finished = finished;
437
+ to.destroyed = destroyed;
438
+ to.blockLen = blockLen;
439
+ to.outputLen = outputLen;
440
+ to.oHash = oHash._cloneInto(to.oHash);
441
+ to.iHash = iHash._cloneInto(to.iHash);
442
+ return to;
443
+ }
444
+ clone() {
445
+ return this._cloneInto();
446
+ }
447
+ destroy() {
448
+ this.destroyed = true;
449
+ this.oHash.destroy();
450
+ this.iHash.destroy();
451
+ }
452
+ };
453
+ var hmac = /* @__PURE__ */ (() => {
454
+ const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest());
455
+ hmac_.create = (hash, key) => new _HMAC(hash, key);
456
+ return hmac_;
457
+ })();
458
+
459
+ // ../../node_modules/.pnpm/@noble+curves@2.2.0/node_modules/@noble/curves/abstract/weierstrass.js
460
+ var divNearest = (num2, den) => (num2 + (num2 >= 0 ? den : -den) / _2n2) / den;
461
+ function _splitEndoScalar(k, basis, n) {
462
+ aInRange("scalar", k, _0n2, n);
463
+ const [[a1, b1], [a2, b2]] = basis;
464
+ const c1 = divNearest(b2 * k, n);
465
+ const c2 = divNearest(-b1 * k, n);
466
+ let k1 = k - c1 * a1 - c2 * a2;
467
+ let k2 = -c1 * b1 - c2 * b2;
468
+ const k1neg = k1 < _0n2;
469
+ const k2neg = k2 < _0n2;
470
+ if (k1neg)
471
+ k1 = -k1;
472
+ if (k2neg)
473
+ k2 = -k2;
474
+ const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n2;
475
+ if (k1 < _0n2 || k1 >= MAX_NUM || k2 < _0n2 || k2 >= MAX_NUM) {
476
+ throw new Error("splitScalar (endomorphism): failed for k");
477
+ }
478
+ return { k1neg, k1, k2neg, k2 };
479
+ }
480
+ function validateSigFormat(format) {
481
+ if (!["compact", "recovered", "der"].includes(format))
482
+ throw new Error('Signature format must be "compact", "recovered", or "der"');
483
+ return format;
484
+ }
485
+ function validateSigOpts(opts, def) {
486
+ validateObject(opts);
487
+ const optsn = {};
488
+ for (let optName of Object.keys(def)) {
489
+ optsn[optName] = opts[optName] === void 0 ? def[optName] : opts[optName];
490
+ }
491
+ abool(optsn.lowS, "lowS");
492
+ abool(optsn.prehash, "prehash");
493
+ if (optsn.format !== void 0)
494
+ validateSigFormat(optsn.format);
495
+ return optsn;
496
+ }
497
+ var DERErr = class extends Error {
498
+ constructor(m = "") {
499
+ super(m);
500
+ }
501
+ };
502
+ var DER = {
503
+ // asn.1 DER encoding utils
504
+ Err: DERErr,
505
+ // Basic building block is TLV (Tag-Length-Value)
506
+ _tlv: {
507
+ encode: (tag, data) => {
508
+ const { Err: E } = DER;
509
+ asafenumber(tag, "tag");
510
+ if (tag < 0 || tag > 255)
511
+ throw new E("tlv.encode: wrong tag");
512
+ if (typeof data !== "string")
513
+ throw new TypeError('"data" expected string, got type=' + typeof data);
514
+ if (data.length & 1)
515
+ throw new E("tlv.encode: unpadded data");
516
+ const dataLen = data.length / 2;
517
+ const len = numberToHexUnpadded(dataLen);
518
+ if (len.length / 2 & 128)
519
+ throw new E("tlv.encode: long form length too big");
520
+ const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
521
+ const t = numberToHexUnpadded(tag);
522
+ return t + lenLen + len + data;
523
+ },
524
+ // v - value, l - left bytes (unparsed)
525
+ decode(tag, data) {
526
+ const { Err: E } = DER;
527
+ data = abytes2(data, void 0, "DER data");
528
+ let pos = 0;
529
+ if (tag < 0 || tag > 255)
530
+ throw new E("tlv.encode: wrong tag");
531
+ if (data.length < 2 || data[pos++] !== tag)
532
+ throw new E("tlv.decode: wrong tlv");
533
+ const first = data[pos++];
534
+ const isLong = !!(first & 128);
535
+ let length = 0;
536
+ if (!isLong)
537
+ length = first;
538
+ else {
539
+ const lenLen = first & 127;
540
+ if (!lenLen)
541
+ throw new E("tlv.decode(long): indefinite length not supported");
542
+ if (lenLen > 4)
543
+ throw new E("tlv.decode(long): byte length is too big");
544
+ const lengthBytes = data.subarray(pos, pos + lenLen);
545
+ if (lengthBytes.length !== lenLen)
546
+ throw new E("tlv.decode: length bytes not complete");
547
+ if (lengthBytes[0] === 0)
548
+ throw new E("tlv.decode(long): zero leftmost byte");
549
+ for (const b of lengthBytes)
550
+ length = length << 8 | b;
551
+ pos += lenLen;
552
+ if (length < 128)
553
+ throw new E("tlv.decode(long): not minimal encoding");
554
+ }
555
+ const v = data.subarray(pos, pos + length);
556
+ if (v.length !== length)
557
+ throw new E("tlv.decode: wrong value length");
558
+ return { v, l: data.subarray(pos + length) };
559
+ }
560
+ },
561
+ // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
562
+ // since we always use positive integers here. It must always be empty:
563
+ // - add zero byte if exists
564
+ // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
565
+ _int: {
566
+ encode(num2) {
567
+ const { Err: E } = DER;
568
+ abignumber(num2);
569
+ if (num2 < _0n2)
570
+ throw new E("integer: negative integers are not allowed");
571
+ let hex = numberToHexUnpadded(num2);
572
+ if (Number.parseInt(hex[0], 16) & 8)
573
+ hex = "00" + hex;
574
+ if (hex.length & 1)
575
+ throw new E("unexpected DER parsing assertion: unpadded hex");
576
+ return hex;
577
+ },
578
+ decode(data) {
579
+ const { Err: E } = DER;
580
+ if (data.length < 1)
581
+ throw new E("invalid signature integer: empty");
582
+ if (data[0] & 128)
583
+ throw new E("invalid signature integer: negative");
584
+ if (data.length > 1 && data[0] === 0 && !(data[1] & 128))
585
+ throw new E("invalid signature integer: unnecessary leading zero");
586
+ return bytesToNumberBE(data);
587
+ }
588
+ },
589
+ toSig(bytes) {
590
+ const { Err: E, _int: int, _tlv: tlv } = DER;
591
+ const data = abytes2(bytes, void 0, "signature");
592
+ const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
593
+ if (seqLeftBytes.length)
594
+ throw new E("invalid signature: left bytes after parsing");
595
+ const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
596
+ const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
597
+ if (sLeftBytes.length)
598
+ throw new E("invalid signature: left bytes after parsing");
599
+ return { r: int.decode(rBytes), s: int.decode(sBytes) };
600
+ },
601
+ hexFromSig(sig) {
602
+ const { _tlv: tlv, _int: int } = DER;
603
+ const rs = tlv.encode(2, int.encode(sig.r));
604
+ const ss = tlv.encode(2, int.encode(sig.s));
605
+ const seq = rs + ss;
606
+ return tlv.encode(48, seq);
607
+ }
608
+ };
609
+ Object.freeze(DER._tlv);
610
+ Object.freeze(DER._int);
611
+ Object.freeze(DER);
612
+ var _0n2 = /* @__PURE__ */ BigInt(0);
613
+ var _1n2 = /* @__PURE__ */ BigInt(1);
614
+ var _2n2 = /* @__PURE__ */ BigInt(2);
615
+ var _3n = /* @__PURE__ */ BigInt(3);
616
+ var _4n = /* @__PURE__ */ BigInt(4);
617
+ function weierstrass(params, extraOpts = {}) {
618
+ const validated = createCurveFields("weierstrass", params, extraOpts);
619
+ const Fp = validated.Fp;
620
+ const Fn = validated.Fn;
621
+ let CURVE = validated.CURVE;
622
+ const { h: cofactor, n: CURVE_ORDER } = CURVE;
623
+ validateObject(extraOpts, {}, {
624
+ allowInfinityPoint: "boolean",
625
+ clearCofactor: "function",
626
+ isTorsionFree: "function",
627
+ fromBytes: "function",
628
+ toBytes: "function",
629
+ endo: "object"
630
+ });
631
+ const { endo, allowInfinityPoint } = extraOpts;
632
+ if (endo) {
633
+ if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
634
+ throw new Error('invalid endo: expected "beta": bigint and "basises": array');
635
+ }
636
+ }
637
+ const lengths = getWLengths(Fp, Fn);
638
+ function assertCompressionIsSupported() {
639
+ if (!Fp.isOdd)
640
+ throw new Error("compression is not supported: Field does not have .isOdd()");
641
+ }
642
+ function pointToBytes2(_c, point, isCompressed) {
643
+ if (allowInfinityPoint && point.is0())
644
+ return Uint8Array.of(0);
645
+ const { x, y } = point.toAffine();
646
+ const bx = Fp.toBytes(x);
647
+ abool(isCompressed, "isCompressed");
648
+ if (isCompressed) {
649
+ assertCompressionIsSupported();
650
+ const hasEvenY = !Fp.isOdd(y);
651
+ return concatBytes(pprefix(hasEvenY), bx);
652
+ } else {
653
+ return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y));
654
+ }
655
+ }
656
+ function pointFromBytes(bytes) {
657
+ abytes2(bytes, void 0, "Point");
658
+ const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths;
659
+ const length = bytes.length;
660
+ const head = bytes[0];
661
+ const tail = bytes.subarray(1);
662
+ if (allowInfinityPoint && length === 1 && head === 0)
663
+ return { x: Fp.ZERO, y: Fp.ZERO };
664
+ if (length === comp && (head === 2 || head === 3)) {
665
+ const x = Fp.fromBytes(tail);
666
+ if (!Fp.isValid(x))
667
+ throw new Error("bad point: is not on curve, wrong x");
668
+ const y2 = weierstrassEquation(x);
669
+ let y;
670
+ try {
671
+ y = Fp.sqrt(y2);
672
+ } catch (sqrtError) {
673
+ const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
674
+ throw new Error("bad point: is not on curve, sqrt error" + err);
675
+ }
676
+ assertCompressionIsSupported();
677
+ const evenY = Fp.isOdd(y);
678
+ const evenH = (head & 1) === 1;
679
+ if (evenH !== evenY)
680
+ y = Fp.neg(y);
681
+ return { x, y };
682
+ } else if (length === uncomp && head === 4) {
683
+ const L = Fp.BYTES;
684
+ const x = Fp.fromBytes(tail.subarray(0, L));
685
+ const y = Fp.fromBytes(tail.subarray(L, L * 2));
686
+ if (!isValidXY(x, y))
687
+ throw new Error("bad point: is not on curve");
688
+ return { x, y };
689
+ } else {
690
+ throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`);
691
+ }
692
+ }
693
+ const encodePoint = extraOpts.toBytes === void 0 ? pointToBytes2 : extraOpts.toBytes;
694
+ const decodePoint = extraOpts.fromBytes === void 0 ? pointFromBytes : extraOpts.fromBytes;
695
+ function weierstrassEquation(x) {
696
+ const x2 = Fp.sqr(x);
697
+ const x3 = Fp.mul(x2, x);
698
+ return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b);
699
+ }
700
+ function isValidXY(x, y) {
701
+ const left = Fp.sqr(y);
702
+ const right = weierstrassEquation(x);
703
+ return Fp.eql(left, right);
704
+ }
705
+ if (!isValidXY(CURVE.Gx, CURVE.Gy))
706
+ throw new Error("bad curve params: generator point");
707
+ const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n), _4n);
708
+ const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
709
+ if (Fp.is0(Fp.add(_4a3, _27b2)))
710
+ throw new Error("bad curve params: a or b");
711
+ function acoord(title, n, banZero = false) {
712
+ if (!Fp.isValid(n) || banZero && Fp.is0(n))
713
+ throw new Error(`bad point coordinate ${title}`);
714
+ return n;
715
+ }
716
+ function aprjpoint(other) {
717
+ if (!(other instanceof Point))
718
+ throw new Error("Weierstrass Point expected");
719
+ }
720
+ function splitEndoScalarN(k) {
721
+ if (!endo || !endo.basises)
722
+ throw new Error("no endo");
723
+ return _splitEndoScalar(k, endo.basises, Fn.ORDER);
724
+ }
725
+ function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
726
+ k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
727
+ k1p = negateCt(k1neg, k1p);
728
+ k2p = negateCt(k2neg, k2p);
729
+ return k1p.add(k2p);
730
+ }
731
+ class Point {
732
+ // base / generator point
733
+ static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
734
+ // zero / infinity / identity point
735
+ static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
736
+ // 0, 1, 0
737
+ // math field
738
+ static Fp = Fp;
739
+ // scalar field
740
+ static Fn = Fn;
741
+ X;
742
+ Y;
743
+ Z;
744
+ /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
745
+ constructor(X, Y, Z) {
746
+ this.X = acoord("x", X);
747
+ this.Y = acoord("y", Y, true);
748
+ this.Z = acoord("z", Z);
749
+ Object.freeze(this);
750
+ }
751
+ static CURVE() {
752
+ return CURVE;
753
+ }
754
+ /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
755
+ static fromAffine(p) {
756
+ const { x, y } = p || {};
757
+ if (!p || !Fp.isValid(x) || !Fp.isValid(y))
758
+ throw new Error("invalid affine point");
759
+ if (p instanceof Point)
760
+ throw new Error("projective point not allowed");
761
+ if (Fp.is0(x) && Fp.is0(y))
762
+ return Point.ZERO;
763
+ return new Point(x, y, Fp.ONE);
764
+ }
765
+ static fromBytes(bytes) {
766
+ const P = Point.fromAffine(decodePoint(abytes2(bytes, void 0, "point")));
767
+ P.assertValidity();
768
+ return P;
769
+ }
770
+ static fromHex(hex) {
771
+ return Point.fromBytes(hexToBytes2(hex));
772
+ }
773
+ get x() {
774
+ return this.toAffine().x;
775
+ }
776
+ get y() {
777
+ return this.toAffine().y;
778
+ }
779
+ /**
780
+ *
781
+ * @param windowSize
782
+ * @param isLazy - true will defer table computation until the first multiplication
783
+ * @returns
784
+ */
785
+ precompute(windowSize = 8, isLazy = true) {
786
+ wnaf.createCache(this, windowSize);
787
+ if (!isLazy)
788
+ this.multiply(_3n);
789
+ return this;
790
+ }
791
+ // TODO: return `this`
792
+ /** A point on curve is valid if it conforms to equation. */
793
+ assertValidity() {
794
+ const p = this;
795
+ if (p.is0()) {
796
+ if (extraOpts.allowInfinityPoint && Fp.is0(p.X) && Fp.eql(p.Y, Fp.ONE) && Fp.is0(p.Z))
797
+ return;
798
+ throw new Error("bad point: ZERO");
799
+ }
800
+ const { x, y } = p.toAffine();
801
+ if (!Fp.isValid(x) || !Fp.isValid(y))
802
+ throw new Error("bad point: x or y not field elements");
803
+ if (!isValidXY(x, y))
804
+ throw new Error("bad point: equation left != right");
805
+ if (!p.isTorsionFree())
806
+ throw new Error("bad point: not in prime-order subgroup");
807
+ }
808
+ hasEvenY() {
809
+ const { y } = this.toAffine();
810
+ if (!Fp.isOdd)
811
+ throw new Error("Field doesn't support isOdd");
812
+ return !Fp.isOdd(y);
813
+ }
814
+ /** Compare one point to another. */
815
+ equals(other) {
816
+ aprjpoint(other);
817
+ const { X: X1, Y: Y1, Z: Z1 } = this;
818
+ const { X: X2, Y: Y2, Z: Z2 } = other;
819
+ const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
820
+ const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
821
+ return U1 && U2;
822
+ }
823
+ /** Flips point to one corresponding to (x, -y) in Affine coordinates. */
824
+ negate() {
825
+ return new Point(this.X, Fp.neg(this.Y), this.Z);
826
+ }
827
+ // Renes-Costello-Batina exception-free doubling formula.
828
+ // There is 30% faster Jacobian formula, but it is not complete.
829
+ // https://eprint.iacr.org/2015/1060, algorithm 3
830
+ // Cost: 8M + 3S + 3*a + 2*b3 + 15add.
831
+ double() {
832
+ const { a, b } = CURVE;
833
+ const b3 = Fp.mul(b, _3n);
834
+ const { X: X1, Y: Y1, Z: Z1 } = this;
835
+ let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO;
836
+ let t0 = Fp.mul(X1, X1);
837
+ let t1 = Fp.mul(Y1, Y1);
838
+ let t2 = Fp.mul(Z1, Z1);
839
+ let t3 = Fp.mul(X1, Y1);
840
+ t3 = Fp.add(t3, t3);
841
+ Z3 = Fp.mul(X1, Z1);
842
+ Z3 = Fp.add(Z3, Z3);
843
+ X3 = Fp.mul(a, Z3);
844
+ Y3 = Fp.mul(b3, t2);
845
+ Y3 = Fp.add(X3, Y3);
846
+ X3 = Fp.sub(t1, Y3);
847
+ Y3 = Fp.add(t1, Y3);
848
+ Y3 = Fp.mul(X3, Y3);
849
+ X3 = Fp.mul(t3, X3);
850
+ Z3 = Fp.mul(b3, Z3);
851
+ t2 = Fp.mul(a, t2);
852
+ t3 = Fp.sub(t0, t2);
853
+ t3 = Fp.mul(a, t3);
854
+ t3 = Fp.add(t3, Z3);
855
+ Z3 = Fp.add(t0, t0);
856
+ t0 = Fp.add(Z3, t0);
857
+ t0 = Fp.add(t0, t2);
858
+ t0 = Fp.mul(t0, t3);
859
+ Y3 = Fp.add(Y3, t0);
860
+ t2 = Fp.mul(Y1, Z1);
861
+ t2 = Fp.add(t2, t2);
862
+ t0 = Fp.mul(t2, t3);
863
+ X3 = Fp.sub(X3, t0);
864
+ Z3 = Fp.mul(t2, t1);
865
+ Z3 = Fp.add(Z3, Z3);
866
+ Z3 = Fp.add(Z3, Z3);
867
+ return new Point(X3, Y3, Z3);
868
+ }
869
+ // Renes-Costello-Batina exception-free addition formula.
870
+ // There is 30% faster Jacobian formula, but it is not complete.
871
+ // https://eprint.iacr.org/2015/1060, algorithm 1
872
+ // Cost: 12M + 0S + 3*a + 3*b3 + 23add.
873
+ add(other) {
874
+ aprjpoint(other);
875
+ const { X: X1, Y: Y1, Z: Z1 } = this;
876
+ const { X: X2, Y: Y2, Z: Z2 } = other;
877
+ let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO;
878
+ const a = CURVE.a;
879
+ const b3 = Fp.mul(CURVE.b, _3n);
880
+ let t0 = Fp.mul(X1, X2);
881
+ let t1 = Fp.mul(Y1, Y2);
882
+ let t2 = Fp.mul(Z1, Z2);
883
+ let t3 = Fp.add(X1, Y1);
884
+ let t4 = Fp.add(X2, Y2);
885
+ t3 = Fp.mul(t3, t4);
886
+ t4 = Fp.add(t0, t1);
887
+ t3 = Fp.sub(t3, t4);
888
+ t4 = Fp.add(X1, Z1);
889
+ let t5 = Fp.add(X2, Z2);
890
+ t4 = Fp.mul(t4, t5);
891
+ t5 = Fp.add(t0, t2);
892
+ t4 = Fp.sub(t4, t5);
893
+ t5 = Fp.add(Y1, Z1);
894
+ X3 = Fp.add(Y2, Z2);
895
+ t5 = Fp.mul(t5, X3);
896
+ X3 = Fp.add(t1, t2);
897
+ t5 = Fp.sub(t5, X3);
898
+ Z3 = Fp.mul(a, t4);
899
+ X3 = Fp.mul(b3, t2);
900
+ Z3 = Fp.add(X3, Z3);
901
+ X3 = Fp.sub(t1, Z3);
902
+ Z3 = Fp.add(t1, Z3);
903
+ Y3 = Fp.mul(X3, Z3);
904
+ t1 = Fp.add(t0, t0);
905
+ t1 = Fp.add(t1, t0);
906
+ t2 = Fp.mul(a, t2);
907
+ t4 = Fp.mul(b3, t4);
908
+ t1 = Fp.add(t1, t2);
909
+ t2 = Fp.sub(t0, t2);
910
+ t2 = Fp.mul(a, t2);
911
+ t4 = Fp.add(t4, t2);
912
+ t0 = Fp.mul(t1, t4);
913
+ Y3 = Fp.add(Y3, t0);
914
+ t0 = Fp.mul(t5, t4);
915
+ X3 = Fp.mul(t3, X3);
916
+ X3 = Fp.sub(X3, t0);
917
+ t0 = Fp.mul(t3, t1);
918
+ Z3 = Fp.mul(t5, Z3);
919
+ Z3 = Fp.add(Z3, t0);
920
+ return new Point(X3, Y3, Z3);
921
+ }
922
+ subtract(other) {
923
+ aprjpoint(other);
924
+ return this.add(other.negate());
925
+ }
926
+ is0() {
927
+ return this.equals(Point.ZERO);
928
+ }
929
+ /**
930
+ * Constant time multiplication.
931
+ * Uses wNAF method. Windowed method may be 10% faster,
932
+ * but takes 2x longer to generate and consumes 2x memory.
933
+ * Uses precomputes when available.
934
+ * Uses endomorphism for Koblitz curves.
935
+ * @param scalar - by which the point would be multiplied
936
+ * @returns New point
937
+ */
938
+ multiply(scalar) {
939
+ const { endo: endo2 } = extraOpts;
940
+ if (!Fn.isValidNot0(scalar))
941
+ throw new RangeError("invalid scalar: out of range");
942
+ let point, fake;
943
+ const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
944
+ if (endo2) {
945
+ const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
946
+ const { p: k1p, f: k1f } = mul(k1);
947
+ const { p: k2p, f: k2f } = mul(k2);
948
+ fake = k1f.add(k2f);
949
+ point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg);
950
+ } else {
951
+ const { p, f } = mul(scalar);
952
+ point = p;
953
+ fake = f;
954
+ }
955
+ return normalizeZ(Point, [point, fake])[0];
956
+ }
957
+ /**
958
+ * Non-constant-time multiplication. Uses double-and-add algorithm.
959
+ * It's faster, but should only be used when you don't care about
960
+ * an exposed secret key e.g. sig verification, which works over *public* keys.
961
+ */
962
+ multiplyUnsafe(scalar) {
963
+ const { endo: endo2 } = extraOpts;
964
+ const p = this;
965
+ const sc = scalar;
966
+ if (!Fn.isValid(sc))
967
+ throw new RangeError("invalid scalar: out of range");
968
+ if (sc === _0n2 || p.is0())
969
+ return Point.ZERO;
970
+ if (sc === _1n2)
971
+ return p;
972
+ if (wnaf.hasCache(this))
973
+ return this.multiply(sc);
974
+ if (endo2) {
975
+ const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
976
+ const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
977
+ return finishEndo(endo2.beta, p1, p2, k1neg, k2neg);
978
+ } else {
979
+ return wnaf.unsafe(p, sc);
980
+ }
981
+ }
982
+ /**
983
+ * Converts Projective point to affine (x, y) coordinates.
984
+ * (X, Y, Z) ∋ (x=X/Z, y=Y/Z).
985
+ * @param invertedZ - Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
986
+ */
987
+ toAffine(invertedZ) {
988
+ const p = this;
989
+ let iz = invertedZ;
990
+ const { X, Y, Z } = p;
991
+ if (Fp.eql(Z, Fp.ONE))
992
+ return { x: X, y: Y };
993
+ const is0 = p.is0();
994
+ if (iz == null)
995
+ iz = is0 ? Fp.ONE : Fp.inv(Z);
996
+ const x = Fp.mul(X, iz);
997
+ const y = Fp.mul(Y, iz);
998
+ const zz = Fp.mul(Z, iz);
999
+ if (is0)
1000
+ return { x: Fp.ZERO, y: Fp.ZERO };
1001
+ if (!Fp.eql(zz, Fp.ONE))
1002
+ throw new Error("invZ was invalid");
1003
+ return { x, y };
1004
+ }
1005
+ /**
1006
+ * Checks whether Point is free of torsion elements (is in prime subgroup).
1007
+ * Always torsion-free for cofactor=1 curves.
1008
+ */
1009
+ isTorsionFree() {
1010
+ const { isTorsionFree } = extraOpts;
1011
+ if (cofactor === _1n2)
1012
+ return true;
1013
+ if (isTorsionFree)
1014
+ return isTorsionFree(Point, this);
1015
+ return wnaf.unsafe(this, CURVE_ORDER).is0();
1016
+ }
1017
+ clearCofactor() {
1018
+ const { clearCofactor } = extraOpts;
1019
+ if (cofactor === _1n2)
1020
+ return this;
1021
+ if (clearCofactor)
1022
+ return clearCofactor(Point, this);
1023
+ return this.multiplyUnsafe(cofactor);
1024
+ }
1025
+ isSmallOrder() {
1026
+ if (cofactor === _1n2)
1027
+ return this.is0();
1028
+ return this.clearCofactor().is0();
1029
+ }
1030
+ toBytes(isCompressed = true) {
1031
+ abool(isCompressed, "isCompressed");
1032
+ this.assertValidity();
1033
+ return encodePoint(Point, this, isCompressed);
1034
+ }
1035
+ toHex(isCompressed = true) {
1036
+ return bytesToHex2(this.toBytes(isCompressed));
1037
+ }
1038
+ toString() {
1039
+ return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
1040
+ }
1041
+ }
1042
+ const bits = Fn.BITS;
1043
+ const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
1044
+ if (bits >= 8)
1045
+ Point.BASE.precompute(8);
1046
+ Object.freeze(Point.prototype);
1047
+ Object.freeze(Point);
1048
+ return Point;
1049
+ }
1050
+ function pprefix(hasEvenY) {
1051
+ return Uint8Array.of(hasEvenY ? 2 : 3);
1052
+ }
1053
+ function getWLengths(Fp, Fn) {
1054
+ return {
1055
+ secretKey: Fn.BYTES,
1056
+ publicKey: 1 + Fp.BYTES,
1057
+ publicKeyUncompressed: 1 + 2 * Fp.BYTES,
1058
+ publicKeyHasPrefix: true,
1059
+ // Raw compact `(r || s)` signature width; DER and recovered signatures use
1060
+ // different lengths outside this helper.
1061
+ signature: 2 * Fn.BYTES
1062
+ };
1063
+ }
1064
+ function ecdh(Point, ecdhOpts = {}) {
1065
+ const { Fn } = Point;
1066
+ const randomBytes_ = ecdhOpts.randomBytes === void 0 ? randomBytes2 : ecdhOpts.randomBytes;
1067
+ const lengths = Object.assign(getWLengths(Point.Fp, Fn), {
1068
+ seed: Math.max(getMinHashLength(Fn.ORDER), 16)
1069
+ });
1070
+ function isValidSecretKey(secretKey) {
1071
+ try {
1072
+ const num2 = Fn.fromBytes(secretKey);
1073
+ return Fn.isValidNot0(num2);
1074
+ } catch (error) {
1075
+ return false;
1076
+ }
1077
+ }
1078
+ function isValidPublicKey(publicKey, isCompressed) {
1079
+ const { publicKey: comp, publicKeyUncompressed } = lengths;
1080
+ try {
1081
+ const l = publicKey.length;
1082
+ if (isCompressed === true && l !== comp)
1083
+ return false;
1084
+ if (isCompressed === false && l !== publicKeyUncompressed)
1085
+ return false;
1086
+ return !!Point.fromBytes(publicKey);
1087
+ } catch (error) {
1088
+ return false;
1089
+ }
1090
+ }
1091
+ function randomSecretKey(seed) {
1092
+ seed = seed === void 0 ? randomBytes_(lengths.seed) : seed;
1093
+ return mapHashToField(abytes2(seed, lengths.seed, "seed"), Fn.ORDER);
1094
+ }
1095
+ function getPublicKey6(secretKey, isCompressed = true) {
1096
+ return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
1097
+ }
1098
+ function isProbPub(item) {
1099
+ const { secretKey, publicKey, publicKeyUncompressed } = lengths;
1100
+ const allowedLengths = Fn._lengths;
1101
+ if (!isBytes(item))
1102
+ return void 0;
1103
+ const l = abytes2(item, void 0, "key").length;
1104
+ const isPub = l === publicKey || l === publicKeyUncompressed;
1105
+ const isSec = l === secretKey || !!allowedLengths?.includes(l);
1106
+ if (isPub && isSec)
1107
+ return void 0;
1108
+ return isPub;
1109
+ }
1110
+ function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
1111
+ if (isProbPub(secretKeyA) === true)
1112
+ throw new Error("first arg must be private key");
1113
+ if (isProbPub(publicKeyB) === false)
1114
+ throw new Error("second arg must be public key");
1115
+ const s = Fn.fromBytes(secretKeyA);
1116
+ const b = Point.fromBytes(publicKeyB);
1117
+ return b.multiply(s).toBytes(isCompressed);
1118
+ }
1119
+ const utils = {
1120
+ isValidSecretKey,
1121
+ isValidPublicKey,
1122
+ randomSecretKey
1123
+ };
1124
+ const keygen = createKeygen(randomSecretKey, getPublicKey6);
1125
+ Object.freeze(utils);
1126
+ Object.freeze(lengths);
1127
+ return Object.freeze({ getPublicKey: getPublicKey6, getSharedSecret, keygen, Point, utils, lengths });
1128
+ }
1129
+ function ecdsa(Point, hash, ecdsaOpts = {}) {
1130
+ const hash_ = hash;
1131
+ ahash(hash_);
1132
+ validateObject(ecdsaOpts, {}, {
1133
+ hmac: "function",
1134
+ lowS: "boolean",
1135
+ randomBytes: "function",
1136
+ bits2int: "function",
1137
+ bits2int_modN: "function"
1138
+ });
1139
+ ecdsaOpts = Object.assign({}, ecdsaOpts);
1140
+ const randomBytes3 = ecdsaOpts.randomBytes === void 0 ? randomBytes2 : ecdsaOpts.randomBytes;
1141
+ const hmac2 = ecdsaOpts.hmac === void 0 ? (key, msg) => hmac(hash_, key, msg) : ecdsaOpts.hmac;
1142
+ const { Fp, Fn } = Point;
1143
+ const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
1144
+ const { keygen, getPublicKey: getPublicKey6, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
1145
+ const defaultSigOpts = {
1146
+ prehash: true,
1147
+ lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : true,
1148
+ format: "compact",
1149
+ extraEntropy: false
1150
+ };
1151
+ const hasLargeRecoveryLifts = CURVE_ORDER * _2n2 + _1n2 < Fp.ORDER;
1152
+ function isBiggerThanHalfOrder(number) {
1153
+ const HALF = CURVE_ORDER >> _1n2;
1154
+ return number > HALF;
1155
+ }
1156
+ function validateRS(title, num2) {
1157
+ if (!Fn.isValidNot0(num2))
1158
+ throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
1159
+ return num2;
1160
+ }
1161
+ function assertRecoverableCurve() {
1162
+ if (hasLargeRecoveryLifts)
1163
+ throw new Error('"recovered" sig type is not supported for cofactor >2 curves');
1164
+ }
1165
+ function validateSigLength(bytes, format) {
1166
+ validateSigFormat(format);
1167
+ const size = lengths.signature;
1168
+ const sizer = format === "compact" ? size : format === "recovered" ? size + 1 : void 0;
1169
+ return abytes2(bytes, sizer);
1170
+ }
1171
+ class Signature {
1172
+ r;
1173
+ s;
1174
+ recovery;
1175
+ constructor(r, s, recovery) {
1176
+ this.r = validateRS("r", r);
1177
+ this.s = validateRS("s", s);
1178
+ if (recovery != null) {
1179
+ assertRecoverableCurve();
1180
+ if (![0, 1, 2, 3].includes(recovery))
1181
+ throw new Error("invalid recovery id");
1182
+ this.recovery = recovery;
1183
+ }
1184
+ Object.freeze(this);
1185
+ }
1186
+ static fromBytes(bytes, format = defaultSigOpts.format) {
1187
+ validateSigLength(bytes, format);
1188
+ let recid;
1189
+ if (format === "der") {
1190
+ const { r: r2, s: s2 } = DER.toSig(abytes2(bytes));
1191
+ return new Signature(r2, s2);
1192
+ }
1193
+ if (format === "recovered") {
1194
+ recid = bytes[0];
1195
+ format = "compact";
1196
+ bytes = bytes.subarray(1);
1197
+ }
1198
+ const L = lengths.signature / 2;
1199
+ const r = bytes.subarray(0, L);
1200
+ const s = bytes.subarray(L, L * 2);
1201
+ return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
1202
+ }
1203
+ static fromHex(hex, format) {
1204
+ return this.fromBytes(hexToBytes2(hex), format);
1205
+ }
1206
+ assertRecovery() {
1207
+ const { recovery } = this;
1208
+ if (recovery == null)
1209
+ throw new Error("invalid recovery id: must be present");
1210
+ return recovery;
1211
+ }
1212
+ addRecoveryBit(recovery) {
1213
+ return new Signature(this.r, this.s, recovery);
1214
+ }
1215
+ // Unlike the top-level helper below, this method expects a digest that has
1216
+ // already been hashed to the curve's message representative.
1217
+ recoverPublicKey(messageHash) {
1218
+ const { r, s } = this;
1219
+ const recovery = this.assertRecovery();
1220
+ const radj = recovery === 2 || recovery === 3 ? r + CURVE_ORDER : r;
1221
+ if (!Fp.isValid(radj))
1222
+ throw new Error("invalid recovery id: sig.r+curve.n != R.x");
1223
+ const x = Fp.toBytes(radj);
1224
+ const R = Point.fromBytes(concatBytes(pprefix((recovery & 1) === 0), x));
1225
+ const ir = Fn.inv(radj);
1226
+ const h = bits2int_modN(abytes2(messageHash, void 0, "msgHash"));
1227
+ const u1 = Fn.create(-h * ir);
1228
+ const u2 = Fn.create(s * ir);
1229
+ const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
1230
+ if (Q.is0())
1231
+ throw new Error("invalid recovery: point at infinify");
1232
+ Q.assertValidity();
1233
+ return Q;
1234
+ }
1235
+ // Signatures should be low-s, to prevent malleability.
1236
+ hasHighS() {
1237
+ return isBiggerThanHalfOrder(this.s);
1238
+ }
1239
+ toBytes(format = defaultSigOpts.format) {
1240
+ validateSigFormat(format);
1241
+ if (format === "der")
1242
+ return hexToBytes2(DER.hexFromSig(this));
1243
+ const { r, s } = this;
1244
+ const rb = Fn.toBytes(r);
1245
+ const sb = Fn.toBytes(s);
1246
+ if (format === "recovered") {
1247
+ assertRecoverableCurve();
1248
+ return concatBytes(Uint8Array.of(this.assertRecovery()), rb, sb);
1249
+ }
1250
+ return concatBytes(rb, sb);
1251
+ }
1252
+ toHex(format) {
1253
+ return bytesToHex2(this.toBytes(format));
1254
+ }
1255
+ }
1256
+ Object.freeze(Signature.prototype);
1257
+ Object.freeze(Signature);
1258
+ const bits2int = ecdsaOpts.bits2int === void 0 ? function bits2int_def(bytes) {
1259
+ if (bytes.length > 8192)
1260
+ throw new Error("input is too large");
1261
+ const num2 = bytesToNumberBE(bytes);
1262
+ const delta = bytes.length * 8 - fnBits;
1263
+ return delta > 0 ? num2 >> BigInt(delta) : num2;
1264
+ } : ecdsaOpts.bits2int;
1265
+ const bits2int_modN = ecdsaOpts.bits2int_modN === void 0 ? function bits2int_modN_def(bytes) {
1266
+ return Fn.create(bits2int(bytes));
1267
+ } : ecdsaOpts.bits2int_modN;
1268
+ const ORDER_MASK = bitMask(fnBits);
1269
+ function int2octets(num2) {
1270
+ aInRange("num < 2^" + fnBits, num2, _0n2, ORDER_MASK);
1271
+ return Fn.toBytes(num2);
1272
+ }
1273
+ function validateMsgAndHash(message, prehash) {
1274
+ abytes2(message, void 0, "message");
1275
+ return prehash ? abytes2(hash_(message), void 0, "prehashed message") : message;
1276
+ }
1277
+ function prepSig(message, secretKey, opts) {
1278
+ const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
1279
+ message = validateMsgAndHash(message, prehash);
1280
+ const h1int = bits2int_modN(message);
1281
+ const d = Fn.fromBytes(secretKey);
1282
+ if (!Fn.isValidNot0(d))
1283
+ throw new Error("invalid private key");
1284
+ const seedArgs = [int2octets(d), int2octets(h1int)];
1285
+ if (extraEntropy != null && extraEntropy !== false) {
1286
+ const e = extraEntropy === true ? randomBytes3(lengths.secretKey) : extraEntropy;
1287
+ seedArgs.push(abytes2(e, void 0, "extraEntropy"));
1288
+ }
1289
+ const seed = concatBytes(...seedArgs);
1290
+ const m = h1int;
1291
+ function k2sig(kBytes) {
1292
+ const k = bits2int(kBytes);
1293
+ if (!Fn.isValidNot0(k))
1294
+ return;
1295
+ const ik = Fn.inv(k);
1296
+ const q = Point.BASE.multiply(k).toAffine();
1297
+ const r = Fn.create(q.x);
1298
+ if (r === _0n2)
1299
+ return;
1300
+ const s = Fn.create(ik * Fn.create(m + r * d));
1301
+ if (s === _0n2)
1302
+ return;
1303
+ let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n2);
1304
+ let normS = s;
1305
+ if (lowS && isBiggerThanHalfOrder(s)) {
1306
+ normS = Fn.neg(s);
1307
+ recovery ^= 1;
1308
+ }
1309
+ return new Signature(r, normS, hasLargeRecoveryLifts ? void 0 : recovery);
1310
+ }
1311
+ return { seed, k2sig };
1312
+ }
1313
+ function sign(message, secretKey, opts = {}) {
1314
+ const { seed, k2sig } = prepSig(message, secretKey, opts);
1315
+ const drbg = createHmacDrbg(hash_.outputLen, Fn.BYTES, hmac2);
1316
+ const sig = drbg(seed, k2sig);
1317
+ return sig.toBytes(opts.format);
1318
+ }
1319
+ function verify(signature, message, publicKey, opts = {}) {
1320
+ const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
1321
+ publicKey = abytes2(publicKey, void 0, "publicKey");
1322
+ message = validateMsgAndHash(message, prehash);
1323
+ if (!isBytes(signature)) {
1324
+ const end = signature instanceof Signature ? ", use sig.toBytes()" : "";
1325
+ throw new Error("verify expects Uint8Array signature" + end);
1326
+ }
1327
+ validateSigLength(signature, format);
1328
+ try {
1329
+ const sig = Signature.fromBytes(signature, format);
1330
+ const P = Point.fromBytes(publicKey);
1331
+ if (lowS && sig.hasHighS())
1332
+ return false;
1333
+ const { r, s } = sig;
1334
+ const h = bits2int_modN(message);
1335
+ const is = Fn.inv(s);
1336
+ const u1 = Fn.create(h * is);
1337
+ const u2 = Fn.create(r * is);
1338
+ const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
1339
+ if (R.is0())
1340
+ return false;
1341
+ const v = Fn.create(R.x);
1342
+ return v === r;
1343
+ } catch (e) {
1344
+ return false;
1345
+ }
1346
+ }
1347
+ function recoverPublicKey(signature, message, opts = {}) {
1348
+ const { prehash } = validateSigOpts(opts, defaultSigOpts);
1349
+ message = validateMsgAndHash(message, prehash);
1350
+ return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes();
1351
+ }
1352
+ return Object.freeze({
1353
+ keygen,
1354
+ getPublicKey: getPublicKey6,
1355
+ getSharedSecret,
1356
+ utils,
1357
+ lengths,
1358
+ Point,
1359
+ sign,
1360
+ verify,
1361
+ recoverPublicKey,
1362
+ Signature,
1363
+ hash: hash_
1364
+ });
1365
+ }
1366
+
1367
+ // ../../node_modules/.pnpm/@noble+curves@2.2.0/node_modules/@noble/curves/secp256k1.js
1368
+ var secp256k1_CURVE = {
1369
+ p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
1370
+ n: BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
1371
+ h: BigInt(1),
1372
+ a: BigInt(0),
1373
+ b: BigInt(7),
1374
+ Gx: BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
1375
+ Gy: BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")
1376
+ };
1377
+ var secp256k1_ENDO = {
1378
+ beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),
1379
+ basises: [
1380
+ [BigInt("0x3086d221a7d46bcde86c90e49284eb15"), -BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],
1381
+ [BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"), BigInt("0x3086d221a7d46bcde86c90e49284eb15")]
1382
+ ]
1383
+ };
1384
+ var _0n3 = /* @__PURE__ */ BigInt(0);
1385
+ var _2n3 = /* @__PURE__ */ BigInt(2);
1386
+ function sqrtMod(y) {
1387
+ const P = secp256k1_CURVE.p;
1388
+ const _3n2 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
1389
+ const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
1390
+ const b2 = y * y * y % P;
1391
+ const b3 = b2 * b2 * y % P;
1392
+ const b6 = pow2(b3, _3n2, P) * b3 % P;
1393
+ const b9 = pow2(b6, _3n2, P) * b3 % P;
1394
+ const b11 = pow2(b9, _2n3, P) * b2 % P;
1395
+ const b22 = pow2(b11, _11n, P) * b11 % P;
1396
+ const b44 = pow2(b22, _22n, P) * b22 % P;
1397
+ const b88 = pow2(b44, _44n, P) * b44 % P;
1398
+ const b176 = pow2(b88, _88n, P) * b88 % P;
1399
+ const b220 = pow2(b176, _44n, P) * b44 % P;
1400
+ const b223 = pow2(b220, _3n2, P) * b3 % P;
1401
+ const t1 = pow2(b223, _23n, P) * b22 % P;
1402
+ const t2 = pow2(t1, _6n, P) * b2 % P;
1403
+ const root = pow2(t2, _2n3, P);
1404
+ if (!Fpk1.eql(Fpk1.sqr(root), y))
1405
+ throw new Error("Cannot find square root");
1406
+ return root;
1407
+ }
1408
+ var Fpk1 = Field(secp256k1_CURVE.p, { sqrt: sqrtMod });
1409
+ var Pointk1 = /* @__PURE__ */ weierstrass(secp256k1_CURVE, {
1410
+ Fp: Fpk1,
1411
+ endo: secp256k1_ENDO
1412
+ });
1413
+ var secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha256);
1414
+ var TAGGED_HASH_PREFIXES = {};
1415
+ function taggedHash(tag, ...messages) {
1416
+ let tagP = TAGGED_HASH_PREFIXES[tag];
1417
+ if (tagP === void 0) {
1418
+ const tagH = sha256(asciiToBytes(tag));
1419
+ tagP = concatBytes(tagH, tagH);
1420
+ TAGGED_HASH_PREFIXES[tag] = tagP;
1421
+ }
1422
+ return sha256(concatBytes(tagP, ...messages));
1423
+ }
1424
+ var pointToBytes = (point) => point.toBytes(true).slice(1);
1425
+ var hasEven = (y) => y % _2n3 === _0n3;
1426
+ function schnorrGetExtPubKey(priv) {
1427
+ const { Fn, BASE } = Pointk1;
1428
+ const d_ = Fn.fromBytes(priv);
1429
+ const p = BASE.multiply(d_);
1430
+ const scalar = hasEven(p.y) ? d_ : Fn.neg(d_);
1431
+ return { scalar, bytes: pointToBytes(p) };
1432
+ }
1433
+ function lift_x(x) {
1434
+ const Fp = Fpk1;
1435
+ if (!Fp.isValidNot0(x))
1436
+ throw new Error("invalid x: Fail if x \u2265 p");
1437
+ const xx = Fp.create(x * x);
1438
+ const c = Fp.create(xx * x + BigInt(7));
1439
+ let y = Fp.sqrt(c);
1440
+ if (!hasEven(y))
1441
+ y = Fp.neg(y);
1442
+ const p = Pointk1.fromAffine({ x, y });
1443
+ p.assertValidity();
1444
+ return p;
1445
+ }
1446
+ var num = bytesToNumberBE;
1447
+ function challenge(...args) {
1448
+ return Pointk1.Fn.create(num(taggedHash("BIP0340/challenge", ...args)));
1449
+ }
1450
+ function schnorrGetPublicKey(secretKey) {
1451
+ return schnorrGetExtPubKey(secretKey).bytes;
1452
+ }
1453
+ function schnorrSign(message, secretKey, auxRand = randomBytes(32)) {
1454
+ const { Fn, BASE } = Pointk1;
1455
+ const m = abytes2(message, void 0, "message");
1456
+ const { bytes: px, scalar: d } = schnorrGetExtPubKey(secretKey);
1457
+ const a = abytes2(auxRand, 32, "auxRand");
1458
+ const t = Fn.toBytes(d ^ num(taggedHash("BIP0340/aux", a)));
1459
+ const rand = taggedHash("BIP0340/nonce", t, px, m);
1460
+ const k_ = Fn.create(num(rand));
1461
+ if (k_ === 0n)
1462
+ throw new Error("sign failed: k is zero");
1463
+ const p = BASE.multiply(k_);
1464
+ const k = hasEven(p.y) ? k_ : Fn.neg(k_);
1465
+ const rx = pointToBytes(p);
1466
+ const e = challenge(rx, px, m);
1467
+ const sig = new Uint8Array(64);
1468
+ sig.set(rx, 0);
1469
+ sig.set(Fn.toBytes(Fn.create(k + e * d)), 32);
1470
+ if (!schnorrVerify(sig, m, px))
1471
+ throw new Error("sign: Invalid signature produced");
1472
+ return sig;
1473
+ }
1474
+ function schnorrVerify(signature, message, publicKey) {
1475
+ const { Fp, Fn, BASE } = Pointk1;
1476
+ const sig = abytes2(signature, 64, "signature");
1477
+ const m = abytes2(message, void 0, "message");
1478
+ const pub = abytes2(publicKey, 32, "publicKey");
1479
+ try {
1480
+ const P = lift_x(num(pub));
1481
+ const r = num(sig.subarray(0, 32));
1482
+ if (!Fp.isValidNot0(r))
1483
+ return false;
1484
+ const s = num(sig.subarray(32, 64));
1485
+ if (!Fn.isValidNot0(s))
1486
+ return false;
1487
+ const e = challenge(Fn.toBytes(r), pointToBytes(P), m);
1488
+ const R = BASE.multiplyUnsafe(s).add(P.multiplyUnsafe(Fn.neg(e)));
1489
+ const { x, y } = R.toAffine();
1490
+ if (R.is0() || !hasEven(y) || x !== r)
1491
+ return false;
1492
+ return true;
1493
+ } catch (error) {
1494
+ return false;
1495
+ }
1496
+ }
1497
+ var schnorr = /* @__PURE__ */ (() => {
1498
+ const size = 32;
1499
+ const seedLength = 48;
1500
+ const randomSecretKey = (seed) => {
1501
+ seed = seed === void 0 ? randomBytes(seedLength) : seed;
1502
+ return mapHashToField(seed, secp256k1_CURVE.n);
1503
+ };
1504
+ return Object.freeze({
1505
+ keygen: createKeygen(randomSecretKey, schnorrGetPublicKey),
1506
+ getPublicKey: schnorrGetPublicKey,
1507
+ sign: schnorrSign,
1508
+ verify: schnorrVerify,
1509
+ Point: Pointk1,
1510
+ utils: Object.freeze({
1511
+ randomSecretKey,
1512
+ taggedHash,
1513
+ lift_x,
1514
+ pointToBytes
1515
+ }),
1516
+ lengths: Object.freeze({
1517
+ secretKey: size,
1518
+ publicKey: size,
1519
+ publicKeyHasPrefix: false,
1520
+ signature: size * 2,
1521
+ seed: seedLength
1522
+ })
1523
+ });
1524
+ })();
1525
+
1526
+ // ../../node_modules/.pnpm/@toon-protocol+settlement-digest@1.0.0/node_modules/@toon-protocol/settlement-digest/dist/index.js
1527
+ function hexToBytes3(hex) {
1528
+ const clean2 = hex.startsWith("0x") ? hex.slice(2) : hex;
1529
+ if (clean2.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(clean2)) {
1530
+ throw new Error(`Invalid hex string: ${hex}`);
1531
+ }
1532
+ return hexToBytes(clean2);
1533
+ }
1534
+ function bigintToBytes32BE(x) {
1535
+ if (x < 0n) {
1536
+ throw new Error("bigint must be non-negative for balance-proof encoding");
1537
+ }
1538
+ const out = new Uint8Array(32);
1539
+ let v = x;
1540
+ for (let i = 31; i >= 0; i--) {
1541
+ out[i] = Number(v & 0xffn);
1542
+ v >>= 8n;
1543
+ }
1544
+ if (v !== 0n) {
1545
+ throw new Error("bigint exceeds 256 bits");
1546
+ }
1547
+ return out;
1548
+ }
1549
+ function concatBytes2(...parts) {
1550
+ let len = 0;
1551
+ for (const p of parts) len += p.length;
1552
+ const out = new Uint8Array(len);
1553
+ let o = 0;
1554
+ for (const p of parts) {
1555
+ out.set(p, o);
1556
+ o += p.length;
1557
+ }
1558
+ return out;
1559
+ }
1560
+ var EIP712_PREFIX = new Uint8Array([25, 1]);
1561
+ var EIP712DOMAIN_TYPEHASH = keccak_256(
1562
+ new TextEncoder().encode(
1563
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
1564
+ )
1565
+ );
1566
+ var DOMAIN_NAME_HASH = keccak_256(
1567
+ new TextEncoder().encode("RollingSwapChannel")
1568
+ );
1569
+ var DOMAIN_VERSION_HASH = keccak_256(
1570
+ new TextEncoder().encode("2")
1571
+ );
1572
+ var CLAIM_TYPEHASH = keccak_256(
1573
+ new TextEncoder().encode(
1574
+ "ClaimBalanceProof(bytes32 channelId,uint256 cumulativeAmount,uint256 nonce,address recipient)"
1575
+ )
1576
+ );
1577
+ var COOP_CLOSE_TYPEHASH = keccak_256(
1578
+ new TextEncoder().encode(
1579
+ "CooperativeClose(bytes32 channelId,uint256 cumulativeAmount,uint256 nonce)"
1580
+ )
1581
+ );
1582
+ function leftPad32(bytes) {
1583
+ if (bytes.length > 32) {
1584
+ throw new Error(`cannot left-pad ${bytes.length} bytes into 32`);
1585
+ }
1586
+ const out = new Uint8Array(32);
1587
+ out.set(bytes, 32 - bytes.length);
1588
+ return out;
1589
+ }
1590
+ function eip712DomainSeparatorEvm(chainId, verifyingContractBytes) {
1591
+ if (verifyingContractBytes.length !== 20) {
1592
+ throw new Error(
1593
+ `verifyingContract must be 20 bytes (got ${verifyingContractBytes.length})`
1594
+ );
1595
+ }
1596
+ return keccak_256(
1597
+ concatBytes2(
1598
+ EIP712DOMAIN_TYPEHASH,
1599
+ DOMAIN_NAME_HASH,
1600
+ DOMAIN_VERSION_HASH,
1601
+ bigintToBytes32BE(chainId),
1602
+ leftPad32(verifyingContractBytes)
1603
+ )
1604
+ );
1605
+ }
1606
+ function eip712Digest(domainSeparator, structHash) {
1607
+ return keccak_256(concatBytes2(EIP712_PREFIX, domainSeparator, structHash));
1608
+ }
1609
+ function balanceProofHashEvm(channelIdBytes, cumulativeAmount, nonce, recipientBytes, chainId, verifyingContractBytes) {
1610
+ if (channelIdBytes.length !== 32) {
1611
+ throw new Error(
1612
+ `channelId must be 32 bytes (got ${channelIdBytes.length})`
1613
+ );
1614
+ }
1615
+ if (recipientBytes.length !== 20) {
1616
+ throw new Error(
1617
+ `recipient must be 20 bytes (got ${recipientBytes.length})`
1618
+ );
1619
+ }
1620
+ const structHash = keccak_256(
1621
+ concatBytes2(
1622
+ CLAIM_TYPEHASH,
1623
+ channelIdBytes,
1624
+ bigintToBytes32BE(cumulativeAmount),
1625
+ bigintToBytes32BE(nonce),
1626
+ leftPad32(recipientBytes)
1627
+ )
1628
+ );
1629
+ return eip712Digest(
1630
+ eip712DomainSeparatorEvm(chainId, verifyingContractBytes),
1631
+ structHash
1632
+ );
1633
+ }
1634
+ function balanceProofHashSolana(channelId, cumulativeAmount, nonce, recipient) {
1635
+ return sha256(
1636
+ concatBytes2(
1637
+ new TextEncoder().encode(channelId),
1638
+ bigintToBytes32BE(cumulativeAmount),
1639
+ bigintToBytes32BE(nonce),
1640
+ new TextEncoder().encode(recipient)
1641
+ )
1642
+ );
1643
+ }
1644
+ function minaHashToField(s) {
1645
+ const digestHex = bytesToHex(sha256(new TextEncoder().encode(s)));
1646
+ return BigInt("0x" + digestHex.slice(0, 60));
1647
+ }
1648
+ function balanceProofFieldsMina(channelId, cumulativeAmount, nonce, recipient) {
1649
+ return [
1650
+ minaHashToField(channelId),
1651
+ cumulativeAmount,
1652
+ nonce,
1653
+ minaHashToField(recipient)
1654
+ ];
1655
+ }
1656
+ function recoverEvmSigner(digest, sig65) {
1657
+ if (sig65.length !== 65) {
1658
+ throw new Error(
1659
+ `EVM signature must be 65 bytes (r||s||v), got ${sig65.length}`
1660
+ );
1661
+ }
1662
+ const v = sig65[64];
1663
+ if (v !== 27 && v !== 28) {
1664
+ throw new Error(`EVM signature v must be 27 or 28, got ${v}`);
1665
+ }
1666
+ const recovery = v - 27;
1667
+ const compactRS = sig65.slice(0, 64);
1668
+ const sig = secp256k1.Signature.fromBytes(
1669
+ compactRS,
1670
+ "compact"
1671
+ ).addRecoveryBit(recovery);
1672
+ const point = sig.recoverPublicKey(digest);
1673
+ const uncompressedPubkey = point.toBytes(false);
1674
+ const addrHash = keccak_256(uncompressedPubkey.slice(1));
1675
+ return "0x" + bytesToHex(addrHash.slice(-20)).toLowerCase();
1676
+ }
1677
+
1678
+ // ../../node_modules/.pnpm/@toon-protocol+core@3.1.2_typescript@5.9.3/node_modules/@toon-protocol/core/dist/index.js
1679
+ import { SimplePool as SimplePool3 } from "nostr-tools/pool";
1680
+ import { getPublicKey as getPublicKey3 } from "nostr-tools/pure";
1681
+ import WebSocket2 from "ws";
1682
+ import { getPublicKey as getPublicKey4 } from "nostr-tools/pure";
1683
+ import { getPublicKey as getPublicKey5 } from "nostr-tools/pure";
1684
+ var ILP_PEER_INFO_KIND = 10032;
1685
+ var BLOB_STORAGE_REQUEST_KIND = 5094;
1686
+ var ILP_SEGMENT_PATTERN = /^[a-z0-9-]+$/;
1687
+ var MAX_ILP_ADDRESS_LENGTH = 1023;
1688
+ function isValidIlpAddressStructure(address) {
1689
+ if (!address) return false;
1690
+ if (address.length > MAX_ILP_ADDRESS_LENGTH) return false;
1691
+ const segments = address.split(".");
1692
+ for (const segment of segments) {
1693
+ if (segment.length === 0) return false;
1694
+ if (!ILP_SEGMENT_PATTERN.test(segment)) return false;
1695
+ }
1696
+ return true;
1697
+ }
1698
+ function validateChainId(chainId) {
1699
+ if (!chainId) return false;
1700
+ const segments = chainId.split(":");
1701
+ if (segments.length < 2 || segments.length > 3) return false;
1702
+ return segments.every((s) => s.length > 0);
1703
+ }
1704
+ var RATE_REGEX = /^(0|[1-9]\d*)(\.\d+)?$/;
1705
+ var AMOUNT_REGEX = /^\d+$/;
1706
+ var MAX_NUMERIC_STRING_LENGTH = 80;
1707
+ function isObject(value) {
1708
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1709
+ }
1710
+ function isNonEmptyString(value) {
1711
+ return typeof value === "string" && value.length > 0;
1712
+ }
1713
+ function isNonNegativeInteger(value) {
1714
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
1715
+ }
1716
+ function validateAsset(asset, side) {
1717
+ if (!isObject(asset)) {
1718
+ return {
1719
+ valid: false,
1720
+ reason: `${side} must be an object`,
1721
+ field: side
1722
+ };
1723
+ }
1724
+ if (!isNonEmptyString(asset.assetCode)) {
1725
+ return {
1726
+ valid: false,
1727
+ reason: `${side}.assetCode must be a non-empty string`,
1728
+ field: `${side}.assetCode`
1729
+ };
1730
+ }
1731
+ if (!isNonNegativeInteger(asset.assetScale)) {
1732
+ return {
1733
+ valid: false,
1734
+ reason: `${side}.assetScale must be a non-negative integer`,
1735
+ field: `${side}.assetScale`
1736
+ };
1737
+ }
1738
+ if (typeof asset.chain !== "string" || !validateChainId(asset.chain)) {
1739
+ return {
1740
+ valid: false,
1741
+ reason: `${side}.chain must be a valid chain identifier (e.g., "evm:base:8453")`,
1742
+ field: `${side}.chain`
1743
+ };
1744
+ }
1745
+ return { valid: true };
1746
+ }
1747
+ function isValidSwapPair(pair) {
1748
+ if (!isObject(pair)) {
1749
+ return { valid: false, reason: "pair must be an object", field: "" };
1750
+ }
1751
+ const fromResult = validateAsset(pair.from, "from");
1752
+ if (!fromResult.valid) return fromResult;
1753
+ const toResult = validateAsset(pair.to, "to");
1754
+ if (!toResult.valid) return toResult;
1755
+ if (typeof pair.rate !== "string" || pair.rate.length > MAX_NUMERIC_STRING_LENGTH || !RATE_REGEX.test(pair.rate)) {
1756
+ return {
1757
+ valid: false,
1758
+ reason: `rate must be a non-negative decimal string (no leading zeros, no exponent, max ${MAX_NUMERIC_STRING_LENGTH} chars)`,
1759
+ field: "rate"
1760
+ };
1761
+ }
1762
+ if (pair.minAmount !== void 0) {
1763
+ if (typeof pair.minAmount !== "string" || pair.minAmount.length > MAX_NUMERIC_STRING_LENGTH || !AMOUNT_REGEX.test(pair.minAmount)) {
1764
+ return {
1765
+ valid: false,
1766
+ reason: `minAmount must be a non-negative integer string (max ${MAX_NUMERIC_STRING_LENGTH} digits)`,
1767
+ field: "minAmount"
1768
+ };
1769
+ }
1770
+ }
1771
+ if (pair.maxAmount !== void 0) {
1772
+ if (typeof pair.maxAmount !== "string" || pair.maxAmount.length > MAX_NUMERIC_STRING_LENGTH || !AMOUNT_REGEX.test(pair.maxAmount)) {
1773
+ return {
1774
+ valid: false,
1775
+ reason: `maxAmount must be a non-negative integer string (max ${MAX_NUMERIC_STRING_LENGTH} digits)`,
1776
+ field: "maxAmount"
1777
+ };
1778
+ }
1779
+ }
1780
+ if (pair.minAmount !== void 0 && pair.maxAmount !== void 0) {
1781
+ if (BigInt(pair.minAmount) > BigInt(pair.maxAmount)) {
1782
+ return {
1783
+ valid: false,
1784
+ reason: "minAmount must not exceed maxAmount",
1785
+ field: "minAmount/maxAmount"
1786
+ };
1787
+ }
1788
+ }
1789
+ return { valid: true };
1790
+ }
1791
+ function formatMessage(index, result) {
1792
+ return `swapPairs[${index}]: ${result.reason} (field: ${result.field})`;
1793
+ }
1794
+ function assertSwapPairForBuild(pair, index) {
1795
+ const result = isValidSwapPair(pair);
1796
+ if (!result.valid) {
1797
+ throw new ToonError(formatMessage(index, result), "INVALID_SWAP_PAIR");
1798
+ }
1799
+ }
1800
+ function assertSwapPairForParse(pair, index) {
1801
+ const result = isValidSwapPair(pair);
1802
+ if (!result.valid) {
1803
+ throw new InvalidEventError(formatMessage(index, result));
1804
+ }
1805
+ }
1806
+ function isObject2(value) {
1807
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1808
+ }
1809
+ function parseIlpPeerInfo(event) {
1810
+ if (event.kind !== ILP_PEER_INFO_KIND) {
1811
+ throw new InvalidEventError(
1812
+ `Expected event kind ${ILP_PEER_INFO_KIND}, got ${event.kind}`
1813
+ );
1814
+ }
1815
+ let parsed;
1816
+ try {
1817
+ parsed = JSON.parse(event.content);
1818
+ } catch (err) {
1819
+ throw new InvalidEventError(
1820
+ "Failed to parse event content as JSON",
1821
+ err instanceof Error ? err : void 0
1822
+ );
1823
+ }
1824
+ if (!isObject2(parsed)) {
1825
+ throw new InvalidEventError("Event content must be a JSON object");
1826
+ }
1827
+ const {
1828
+ ilpAddress,
1829
+ btpEndpoint,
1830
+ httpEndpoint,
1831
+ supportsUpgrade,
1832
+ blsHttpEndpoint,
1833
+ settlementEngine,
1834
+ assetCode,
1835
+ assetScale,
1836
+ ilpAddresses: rawIlpAddresses
1837
+ } = parsed;
1838
+ if (typeof ilpAddress !== "string" || ilpAddress.length === 0) {
1839
+ throw new InvalidEventError(
1840
+ "Missing or invalid required field: ilpAddress"
1841
+ );
1842
+ }
1843
+ if (btpEndpoint !== void 0 && typeof btpEndpoint !== "string") {
1844
+ throw new InvalidEventError("Invalid field: btpEndpoint must be a string");
1845
+ }
1846
+ if (httpEndpoint !== void 0 && typeof httpEndpoint !== "string") {
1847
+ throw new InvalidEventError("Invalid field: httpEndpoint must be a string");
1848
+ }
1849
+ if (supportsUpgrade !== void 0 && typeof supportsUpgrade !== "boolean") {
1850
+ throw new InvalidEventError("Invalid field: supportsUpgrade must be a boolean");
1851
+ }
1852
+ if (typeof assetCode !== "string" || assetCode.length === 0) {
1853
+ throw new InvalidEventError("Missing or invalid required field: assetCode");
1854
+ }
1855
+ if (typeof assetScale !== "number" || !Number.isInteger(assetScale)) {
1856
+ throw new InvalidEventError(
1857
+ "Missing or invalid required field: assetScale"
1858
+ );
1859
+ }
1860
+ if (settlementEngine !== void 0 && typeof settlementEngine !== "string") {
1861
+ throw new InvalidEventError(
1862
+ "Invalid optional field: settlementEngine must be a string"
1863
+ );
1864
+ }
1865
+ const {
1866
+ supportedChains,
1867
+ settlementAddresses,
1868
+ preferredTokens,
1869
+ tokenNetworks
1870
+ } = parsed;
1871
+ if (supportedChains !== void 0) {
1872
+ if (!Array.isArray(supportedChains)) {
1873
+ throw new InvalidEventError("supportedChains must be an array");
1874
+ }
1875
+ if (supportedChains.length === 0) {
1876
+ throw new InvalidEventError(
1877
+ "supportedChains must be a non-empty array when provided"
1878
+ );
1879
+ }
1880
+ for (const chainId of supportedChains) {
1881
+ if (typeof chainId !== "string" || !validateChainId(chainId)) {
1882
+ throw new InvalidEventError(
1883
+ `Invalid chain identifier: ${String(chainId)}`
1884
+ );
1885
+ }
1886
+ }
1887
+ }
1888
+ if (settlementAddresses !== void 0) {
1889
+ if (!isObject2(settlementAddresses)) {
1890
+ throw new InvalidEventError("settlementAddresses must be an object");
1891
+ }
1892
+ for (const [key, value] of Object.entries(settlementAddresses)) {
1893
+ if (!validateChainId(key)) {
1894
+ throw new InvalidEventError(
1895
+ `Invalid chain identifier in settlementAddresses: ${key}`
1896
+ );
1897
+ }
1898
+ if (typeof value !== "string" || value.length === 0) {
1899
+ throw new InvalidEventError(
1900
+ "settlementAddresses values must be non-empty strings"
1901
+ );
1902
+ }
1903
+ }
1904
+ if (Array.isArray(supportedChains)) {
1905
+ const chainSet = new Set(supportedChains);
1906
+ for (const key of Object.keys(settlementAddresses)) {
1907
+ if (!chainSet.has(key)) {
1908
+ throw new InvalidEventError(
1909
+ `settlementAddresses key '${key}' is not in supportedChains`
1910
+ );
1911
+ }
1912
+ }
1913
+ }
1914
+ }
1915
+ if (preferredTokens !== void 0) {
1916
+ if (!isObject2(preferredTokens)) {
1917
+ throw new InvalidEventError("preferredTokens must be an object");
1918
+ }
1919
+ }
1920
+ if (tokenNetworks !== void 0) {
1921
+ if (!isObject2(tokenNetworks)) {
1922
+ throw new InvalidEventError("tokenNetworks must be an object");
1923
+ }
1924
+ }
1925
+ const { feePerByte: rawFeePerByte } = parsed;
1926
+ let feePerByte;
1927
+ if (rawFeePerByte === void 0) {
1928
+ feePerByte = "0";
1929
+ } else if (typeof rawFeePerByte !== "string" || !/^\d+$/.test(rawFeePerByte)) {
1930
+ throw new InvalidEventError(
1931
+ `Invalid feePerByte: "${String(rawFeePerByte)}" must be a non-negative integer string`
1932
+ );
1933
+ } else {
1934
+ feePerByte = rawFeePerByte;
1935
+ }
1936
+ const { prefixPricing: rawPrefixPricing } = parsed;
1937
+ let prefixPricing;
1938
+ if (rawPrefixPricing !== void 0) {
1939
+ if (!isObject2(rawPrefixPricing)) {
1940
+ throw new InvalidEventError("prefixPricing must be an object");
1941
+ }
1942
+ const { basePrice } = rawPrefixPricing;
1943
+ if (typeof basePrice !== "string" || !/^\d+$/.test(basePrice)) {
1944
+ throw new InvalidEventError(
1945
+ `Invalid prefixPricing.basePrice: "${String(basePrice)}" must be a non-negative integer string`
1946
+ );
1947
+ }
1948
+ prefixPricing = { basePrice };
1949
+ }
1950
+ const { swapPairs: rawSwapPairs } = parsed;
1951
+ let swapPairs;
1952
+ if (rawSwapPairs !== void 0) {
1953
+ if (!Array.isArray(rawSwapPairs)) {
1954
+ throw new InvalidEventError("swapPairs must be an array");
1955
+ }
1956
+ rawSwapPairs.forEach((pair, index) => {
1957
+ assertSwapPairForParse(pair, index);
1958
+ });
1959
+ swapPairs = rawSwapPairs;
1960
+ }
1961
+ let ilpAddresses;
1962
+ if (rawIlpAddresses !== void 0) {
1963
+ if (!Array.isArray(rawIlpAddresses)) {
1964
+ throw new InvalidEventError("ilpAddresses must be an array");
1965
+ }
1966
+ for (const addr of rawIlpAddresses) {
1967
+ if (typeof addr !== "string" || addr.length === 0) {
1968
+ throw new InvalidEventError(
1969
+ "ilpAddresses elements must be non-empty strings"
1970
+ );
1971
+ }
1972
+ if (!isValidIlpAddressStructure(addr)) {
1973
+ throw new InvalidEventError(
1974
+ `Invalid ILP address in ilpAddresses: "${addr}"`
1975
+ );
1976
+ }
1977
+ }
1978
+ ilpAddresses = rawIlpAddresses;
1979
+ } else {
1980
+ ilpAddresses = [ilpAddress];
1981
+ }
1982
+ return {
1983
+ ilpAddress,
1984
+ btpEndpoint: typeof btpEndpoint === "string" ? btpEndpoint : "",
1985
+ ...httpEndpoint !== void 0 && typeof httpEndpoint === "string" && { httpEndpoint },
1986
+ ...supportsUpgrade !== void 0 && typeof supportsUpgrade === "boolean" && { supportsUpgrade },
1987
+ ...blsHttpEndpoint !== void 0 && typeof blsHttpEndpoint === "string" && { blsHttpEndpoint },
1988
+ assetCode,
1989
+ assetScale,
1990
+ ...settlementEngine !== void 0 && { settlementEngine },
1991
+ supportedChains: supportedChains !== void 0 ? supportedChains : [],
1992
+ settlementAddresses: settlementAddresses !== void 0 ? settlementAddresses : {},
1993
+ ...preferredTokens !== void 0 && {
1994
+ preferredTokens
1995
+ },
1996
+ ...tokenNetworks !== void 0 && {
1997
+ tokenNetworks
1998
+ },
1999
+ ilpAddresses,
2000
+ feePerByte,
2001
+ ...prefixPricing !== void 0 && { prefixPricing },
2002
+ ...swapPairs !== void 0 && { swapPairs }
2003
+ };
2004
+ }
2005
+ var EXPIRATION_TAG = "expiration";
2006
+ function getEventExpiration(event) {
2007
+ const tag = event.tags.find((t) => t[0] === EXPIRATION_TAG);
2008
+ if (!tag || tag[1] === void 0) return void 0;
2009
+ const ts = Number(tag[1]);
2010
+ if (!Number.isFinite(ts) || ts < 0) return void 0;
2011
+ return ts;
2012
+ }
2013
+ function isEventExpired(event, nowSeconds = Math.floor(Date.now() / 1e3)) {
2014
+ const exp = getEventExpiration(event);
2015
+ return exp !== void 0 && exp <= nowSeconds;
2016
+ }
2017
+ function buildIlpPeerInfoEvent(info, secretKey, options = {}) {
2018
+ if (info.feePerByte !== void 0) {
2019
+ if (typeof info.feePerByte !== "string" || !/^\d+$/.test(info.feePerByte)) {
2020
+ throw new ToonError(
2021
+ `Invalid feePerByte: "${String(info.feePerByte)}" must be a non-negative integer string`,
2022
+ "INVALID_FEE"
2023
+ );
2024
+ }
2025
+ }
2026
+ let effectiveInfo = info;
2027
+ if (info.ilpAddresses !== void 0) {
2028
+ const addresses = info.ilpAddresses;
2029
+ if (addresses.length === 0) {
2030
+ throw new ToonError(
2031
+ "ilpAddresses must be a non-empty array: a node must have at least one address",
2032
+ "ADDRESS_EMPTY_ADDRESSES"
2033
+ );
2034
+ }
2035
+ for (const addr of addresses) {
2036
+ if (!isValidIlpAddressStructure(addr)) {
2037
+ throw new ToonError(
2038
+ `Invalid ILP address in ilpAddresses: "${addr}"`,
2039
+ "ADDRESS_INVALID_PREFIX"
2040
+ );
2041
+ }
2042
+ }
2043
+ const primaryAddress = addresses[0];
2044
+ effectiveInfo = {
2045
+ ...info,
2046
+ ilpAddress: primaryAddress
2047
+ };
2048
+ }
2049
+ if (info.swapPairs !== void 0) {
2050
+ if (!Array.isArray(info.swapPairs)) {
2051
+ throw new ToonError(
2052
+ "swapPairs must be an array when provided",
2053
+ "INVALID_SWAP_PAIR"
2054
+ );
2055
+ }
2056
+ info.swapPairs.forEach((pair, index) => {
2057
+ assertSwapPairForBuild(pair, index);
2058
+ });
2059
+ }
2060
+ const createdAt = Math.floor(Date.now() / 1e3);
2061
+ const tags = [];
2062
+ if (options.ttlSeconds !== void 0 && options.ttlSeconds > 0) {
2063
+ tags.push([
2064
+ EXPIRATION_TAG,
2065
+ String(createdAt + Math.floor(options.ttlSeconds))
2066
+ ]);
2067
+ }
2068
+ return finalizeEvent(
2069
+ {
2070
+ kind: ILP_PEER_INFO_KIND,
2071
+ content: JSON.stringify(effectiveInfo),
2072
+ tags,
2073
+ created_at: createdAt
2074
+ },
2075
+ secretKey
2076
+ );
2077
+ }
2078
+ function buildBlobStorageRequest(params, secretKey) {
2079
+ if (!params.blobData || params.blobData.length === 0) {
2080
+ throw new ToonError(
2081
+ "Blob storage request blobData is required and must not be empty",
2082
+ "DVM_MISSING_INPUT"
2083
+ );
2084
+ }
2085
+ if (typeof params.bid !== "string" || params.bid === "") {
2086
+ throw new ToonError(
2087
+ "Blob storage request bid must be a non-empty string (USDC micro-units)",
2088
+ "DVM_INVALID_BID"
2089
+ );
2090
+ }
2091
+ const contentType = params.contentType ?? "application/octet-stream";
2092
+ const base64Blob = params.blobData.toString("base64");
2093
+ const tags = [];
2094
+ tags.push(["i", base64Blob, "blob"]);
2095
+ tags.push(["bid", params.bid, "usdc"]);
2096
+ tags.push(["output", contentType]);
2097
+ if (params.params !== void 0) {
2098
+ for (const p of params.params) {
2099
+ tags.push(["param", p.key, p.value]);
2100
+ }
2101
+ }
2102
+ return finalizeEvent9(
2103
+ {
2104
+ kind: BLOB_STORAGE_REQUEST_KIND,
2105
+ content: "",
2106
+ tags,
2107
+ created_at: Math.floor(Date.now() / 1e3)
2108
+ },
2109
+ secretKey
2110
+ );
2111
+ }
2112
+ var genesis_peers_default = [
2113
+ {
2114
+ pubkey: "2813187eb66741f9509de2055161f328a0f04e01e1fc20188610b8dbd0591ea5",
2115
+ relayUrl: "wss://relay-ws.devnet.toonprotocol.dev",
2116
+ ilpAddress: "g.proxy",
2117
+ btpEndpoint: "wss://proxy.devnet.toonprotocol.dev:443"
2118
+ }
2119
+ ];
2120
+ var PUBKEY_REGEX3 = /^[0-9a-f]{64}$/;
2121
+ var ILP_ADDRESS_REGEX = /^g\.[a-zA-Z0-9.-]+$/;
2122
+ function isValidPubkey2(pubkey) {
2123
+ return PUBKEY_REGEX3.test(pubkey);
2124
+ }
2125
+ function isValidRelayUrl(url) {
2126
+ return url.startsWith("wss://") || url.startsWith("ws://");
2127
+ }
2128
+ function isValidIlpAddress(address) {
2129
+ return ILP_ADDRESS_REGEX.test(address);
2130
+ }
2131
+ function isValidBtpEndpoint(url) {
2132
+ return url.startsWith("wss://") || url.startsWith("ws://");
2133
+ }
2134
+ function isValidGenesisPeer(entry) {
2135
+ if (typeof entry !== "object" || entry === null) return false;
2136
+ const obj = entry;
2137
+ return typeof obj["pubkey"] === "string" && typeof obj["relayUrl"] === "string" && typeof obj["ilpAddress"] === "string" && typeof obj["btpEndpoint"] === "string" && isValidPubkey2(obj["pubkey"]) && isValidRelayUrl(obj["relayUrl"]) && isValidIlpAddress(obj["ilpAddress"]) && isValidBtpEndpoint(obj["btpEndpoint"]);
2138
+ }
2139
+ function deduplicateByPubkey(peers) {
2140
+ const map = /* @__PURE__ */ new Map();
2141
+ for (const peer of peers) {
2142
+ map.set(peer.pubkey, peer);
2143
+ }
2144
+ return [...map.values()];
2145
+ }
2146
+ function loadGenesisPeers() {
2147
+ const envOverride = process.env["TOON_GENESIS_PEERS"];
2148
+ if (envOverride !== void 0) {
2149
+ let parsed;
2150
+ try {
2151
+ parsed = JSON.parse(envOverride);
2152
+ } catch {
2153
+ console.warn("Failed to parse TOON_GENESIS_PEERS JSON:", envOverride);
2154
+ return [];
2155
+ }
2156
+ if (!Array.isArray(parsed)) {
2157
+ console.warn("TOON_GENESIS_PEERS JSON is not an array");
2158
+ return [];
2159
+ }
2160
+ const valid2 = [];
2161
+ for (const entry of parsed) {
2162
+ if (isValidGenesisPeer(entry)) {
2163
+ valid2.push(entry);
2164
+ } else {
2165
+ console.warn("Skipping invalid TOON_GENESIS_PEERS entry:", entry);
2166
+ }
2167
+ }
2168
+ return deduplicateByPubkey(valid2);
2169
+ }
2170
+ const raw = genesis_peers_default;
2171
+ const valid = [];
2172
+ for (const entry of raw) {
2173
+ if (isValidGenesisPeer(entry)) {
2174
+ valid.push(entry);
2175
+ } else {
2176
+ console.warn("Skipping invalid genesis peer entry:", entry);
2177
+ }
2178
+ }
2179
+ return deduplicateByPubkey(valid);
2180
+ }
2181
+ function loadAdditionalPeers(json) {
2182
+ let parsed;
2183
+ try {
2184
+ parsed = JSON.parse(json);
2185
+ } catch {
2186
+ console.warn("Failed to parse additional peers JSON:", json);
2187
+ return [];
2188
+ }
2189
+ if (!Array.isArray(parsed)) {
2190
+ console.warn("Additional peers JSON is not an array");
2191
+ return [];
2192
+ }
2193
+ const valid = [];
2194
+ for (const entry of parsed) {
2195
+ if (isValidGenesisPeer(entry)) {
2196
+ valid.push(entry);
2197
+ } else {
2198
+ console.warn("Skipping invalid additional peer entry:", entry);
2199
+ }
2200
+ }
2201
+ return valid;
2202
+ }
2203
+ function loadAllPeers(additionalPeersJson) {
2204
+ const genesis = loadGenesisPeers();
2205
+ if (!additionalPeersJson) {
2206
+ return genesis;
2207
+ }
2208
+ const additional = loadAdditionalPeers(additionalPeersJson);
2209
+ return deduplicateByPubkey([...genesis, ...additional]);
2210
+ }
2211
+ var GenesisPeerLoader = {
2212
+ loadGenesisPeers,
2213
+ loadAdditionalPeers,
2214
+ loadAllPeers
2215
+ };
2216
+ var DEFAULT_GATEWAY_URL = "https://arweave.net/graphql";
2217
+ var GRAPHQL_QUERY = `
2218
+ query {
2219
+ transactions(
2220
+ tags: [
2221
+ { name: "App-Name", values: ["toon"] },
2222
+ { name: "type", values: ["ilp-peer-info"] }
2223
+ ],
2224
+ first: 100
2225
+ ) {
2226
+ edges {
2227
+ node {
2228
+ id
2229
+ tags {
2230
+ name
2231
+ value
2232
+ }
2233
+ }
2234
+ }
2235
+ }
2236
+ }
2237
+ `;
2238
+ function isValidIlpPeerInfo(entry) {
2239
+ if (typeof entry !== "object" || entry === null) return false;
2240
+ const obj = entry;
2241
+ return typeof obj["ilpAddress"] === "string" && isValidIlpAddress(obj["ilpAddress"]) && typeof obj["btpEndpoint"] === "string" && isValidBtpEndpoint(obj["btpEndpoint"]) && typeof obj["assetCode"] === "string" && obj["assetCode"].length > 0 && typeof obj["assetScale"] === "number" && Number.isInteger(obj["assetScale"]) && obj["assetScale"] >= 0 && (obj["settlementEngine"] === void 0 || typeof obj["settlementEngine"] === "string");
2242
+ }
2243
+ function getPubkeyFromTags(tags) {
2244
+ const tag = tags.find((t) => t.name === "pubkey");
2245
+ return tag?.value;
2246
+ }
2247
+ async function fetchPeers(gatewayUrl = DEFAULT_GATEWAY_URL) {
2248
+ const result = /* @__PURE__ */ new Map();
2249
+ try {
2250
+ const response = await fetch(gatewayUrl, {
2251
+ method: "POST",
2252
+ headers: { "Content-Type": "application/json" },
2253
+ body: JSON.stringify({ query: GRAPHQL_QUERY })
2254
+ });
2255
+ const json = await response.json();
2256
+ const edges = json?.data?.transactions?.edges;
2257
+ if (!Array.isArray(edges)) {
2258
+ return result;
2259
+ }
2260
+ const baseUrl = gatewayUrl.replace(/\/graphql$/, "");
2261
+ for (const edge of edges) {
2262
+ const txId = edge?.node?.id;
2263
+ const tags = edge?.node?.tags;
2264
+ if (!txId || !Array.isArray(tags)) continue;
2265
+ const pubkey = getPubkeyFromTags(tags);
2266
+ if (!pubkey || !isValidPubkey2(pubkey)) continue;
2267
+ if (result.has(pubkey)) continue;
2268
+ try {
2269
+ const dataResponse = await fetch(`${baseUrl}/${txId}`);
2270
+ const data = await dataResponse.json();
2271
+ if (isValidIlpPeerInfo(data)) {
2272
+ result.set(pubkey, data);
2273
+ } else {
2274
+ console.warn(
2275
+ `Skipping transaction ${txId}: invalid IlpPeerInfo data`
2276
+ );
2277
+ }
2278
+ } catch (err) {
2279
+ console.warn(`Failed to fetch transaction data for ${txId}:`, err);
2280
+ }
2281
+ }
2282
+ } catch (err) {
2283
+ console.warn("ArDrive peer registry unavailable:", err);
2284
+ }
2285
+ return result;
2286
+ }
2287
+ async function publishPeerInfo(peerInfo, pubkey, turboClient) {
2288
+ if (!isValidPubkey2(pubkey)) {
2289
+ throw new PeerDiscoveryError(`Invalid pubkey: ${pubkey}`);
2290
+ }
2291
+ try {
2292
+ const json = JSON.stringify(peerInfo);
2293
+ const result = await turboClient.uploadFile({
2294
+ fileStreamFactory: () => Buffer.from(json, "utf-8"),
2295
+ fileSizeFactory: () => Buffer.byteLength(json, "utf-8"),
2296
+ dataItemOpts: {
2297
+ tags: [
2298
+ { name: "App-Name", value: "toon" },
2299
+ { name: "type", value: "ilp-peer-info" },
2300
+ { name: "pubkey", value: pubkey },
2301
+ { name: "version", value: "1" },
2302
+ { name: "Content-Type", value: "application/json" }
2303
+ ]
2304
+ }
2305
+ });
2306
+ return result.id;
2307
+ } catch (err) {
2308
+ throw new PeerDiscoveryError(
2309
+ "Failed to publish peer info to ArDrive",
2310
+ err instanceof Error ? err : void 0
2311
+ );
2312
+ }
2313
+ }
2314
+ var ArDrivePeerRegistry = {
2315
+ fetchPeers,
2316
+ publishPeerInfo
2317
+ };
2318
+ function negotiateSettlementChain(requesterChains, responderChains, requesterPreferredTokens, responderPreferredTokens) {
2319
+ const responderSet = new Set(responderChains);
2320
+ const intersection = requesterChains.filter(
2321
+ (chain) => responderSet.has(chain)
2322
+ );
2323
+ if (intersection.length === 0) {
2324
+ return null;
2325
+ }
2326
+ if (requesterPreferredTokens) {
2327
+ const requesterMatch = intersection.find(
2328
+ (chain) => requesterPreferredTokens[chain] !== void 0
2329
+ );
2330
+ if (requesterMatch) {
2331
+ return requesterMatch;
2332
+ }
2333
+ }
2334
+ if (responderPreferredTokens) {
2335
+ const responderMatch = intersection.find(
2336
+ (chain) => responderPreferredTokens[chain] !== void 0
2337
+ );
2338
+ if (responderMatch) {
2339
+ return responderMatch;
2340
+ }
2341
+ }
2342
+ return intersection[0] ?? null;
2343
+ }
2344
+ function resolveTokenForChain(chain, requesterPreferredTokens, responderPreferredTokens) {
2345
+ if (requesterPreferredTokens?.[chain] !== void 0) {
2346
+ return requesterPreferredTokens[chain];
2347
+ }
2348
+ if (responderPreferredTokens?.[chain] !== void 0) {
2349
+ return responderPreferredTokens[chain];
2350
+ }
2351
+ return void 0;
2352
+ }
2353
+ var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
2354
+ function base58Encode(bytes) {
2355
+ let zeros = 0;
2356
+ for (let i = 0; i < bytes.length && bytes[i] === 0; i++) zeros++;
2357
+ let value = 0n;
2358
+ for (const byte of bytes) {
2359
+ value = value * 256n + BigInt(byte);
2360
+ }
2361
+ let result = "";
2362
+ while (value > 0n) {
2363
+ result = BASE58_ALPHABET[Number(value % 58n)] + result;
2364
+ value = value / 58n;
2365
+ }
2366
+ for (let i = 0; i < zeros; i++) {
2367
+ result = "1" + result;
2368
+ }
2369
+ return result || "1";
2370
+ }
2371
+ function base58Decode(str) {
2372
+ let zeros = 0;
2373
+ for (let i = 0; i < str.length && str[i] === "1"; i++) zeros++;
2374
+ let value = 0n;
2375
+ for (const ch of str) {
2376
+ const idx = BASE58_ALPHABET.indexOf(ch);
2377
+ if (idx === -1) throw new Error(`Invalid base58 character: ${ch}`);
2378
+ value = value * 58n + BigInt(idx);
2379
+ }
2380
+ const hex = value === 0n ? "" : value.toString(16);
2381
+ const hexPadded = hex.length % 2 ? "0" + hex : hex;
2382
+ const rawBytes = [];
2383
+ for (let i = 0; i < hexPadded.length; i += 2) {
2384
+ rawBytes.push(parseInt(hexPadded.slice(i, i + 2), 16));
2385
+ }
2386
+ const result = new Uint8Array(zeros + rawBytes.length);
2387
+ result.set(rawBytes, zeros);
2388
+ return result;
2389
+ }
2390
+ var MINA_PRIVATE_KEY_VERSION = 90;
2391
+ function hexToMinaBase58PrivateKey(privateKey) {
2392
+ if (!/^(0x)?[0-9a-fA-F]{64}$/.test(privateKey)) {
2393
+ return privateKey;
2394
+ }
2395
+ const beScalar = hexToBytes3(privateKey);
2396
+ const leScalar = Uint8Array.from(beScalar).reverse();
2397
+ const payload = concatBytes2(
2398
+ Uint8Array.from([MINA_PRIVATE_KEY_VERSION, 1]),
2399
+ leScalar
2400
+ );
2401
+ const checksum = sha256(sha256(payload)).slice(0, 4);
2402
+ return base58Encode(concatBytes2(payload, checksum));
2403
+ }
2404
+ var BootstrapError = class extends ToonError {
2405
+ constructor(message, cause) {
2406
+ super(message, "BOOTSTRAP_FAILED", cause);
2407
+ this.name = "BootstrapError";
2408
+ }
2409
+ };
2410
+ var BootstrapService = class {
2411
+ config;
2412
+ secretKey;
2413
+ pubkey;
2414
+ ownIlpInfo;
2415
+ pool;
2416
+ connectorAdmin;
2417
+ channelClient;
2418
+ claimSigner;
2419
+ // ILP-first flow additions
2420
+ ilpClient;
2421
+ settlementInfo;
2422
+ ownIlpAddress;
2423
+ toonEncoder;
2424
+ toonDecoder;
2425
+ basePricePerByte;
2426
+ // Event emitter
2427
+ listeners = [];
2428
+ phase = "discovering";
2429
+ /**
2430
+ * Creates a new BootstrapService instance.
2431
+ *
2432
+ * @param config - Bootstrap configuration with known peers and optional ILP-first settings
2433
+ * @param secretKey - Our Nostr secret key for signing events
2434
+ * @param ownIlpInfo - Our ILP peer info to publish
2435
+ * @param pool - Optional SimplePool instance (creates new one if not provided)
2436
+ */
2437
+ constructor(config, secretKey, ownIlpInfo, pool) {
2438
+ this.config = {
2439
+ knownPeers: config.knownPeers,
2440
+ queryTimeout: config.queryTimeout ?? 5e3,
2441
+ ardriveEnabled: config.ardriveEnabled ?? true,
2442
+ defaultRelayUrl: config.defaultRelayUrl ?? ""
2443
+ };
2444
+ this.secretKey = secretKey;
2445
+ this.pubkey = getPublicKey3(secretKey);
2446
+ this.ownIlpInfo = ownIlpInfo;
2447
+ this.pool = pool ?? new SimplePool3();
2448
+ this.settlementInfo = config.settlementInfo;
2449
+ this.ownIlpAddress = config.ownIlpAddress;
2450
+ this.toonEncoder = config.toonEncoder;
2451
+ this.toonDecoder = config.toonDecoder;
2452
+ this.basePricePerByte = config.basePricePerByte ?? 10n;
2453
+ }
2454
+ /**
2455
+ * Set the ILP client for sending packets via the connector.
2456
+ * Kept separate from constructor for backward compatibility with existing code
2457
+ * that creates the client after construction.
2458
+ */
2459
+ setIlpClient(client) {
2460
+ this.ilpClient = client;
2461
+ }
2462
+ /**
2463
+ * @deprecated Use setIlpClient instead
2464
+ */
2465
+ setAgentRuntimeClient(client) {
2466
+ this.setIlpClient(client);
2467
+ }
2468
+ /**
2469
+ * Set the connector admin client for adding peers/routes.
2470
+ */
2471
+ setConnectorAdmin(admin) {
2472
+ this.connectorAdmin = admin;
2473
+ }
2474
+ /**
2475
+ * Set the channel client for opening payment channels.
2476
+ */
2477
+ setChannelClient(client) {
2478
+ this.channelClient = client;
2479
+ }
2480
+ /**
2481
+ * Set the claim signer for creating signed balance proofs.
2482
+ * Used by clients to sign payment channel claims for ILP packets.
2483
+ */
2484
+ setClaimSigner(signer) {
2485
+ this.claimSigner = signer;
2486
+ }
2487
+ /**
2488
+ * Get the current bootstrap phase.
2489
+ */
2490
+ getPhase() {
2491
+ return this.phase;
2492
+ }
2493
+ /**
2494
+ * Register an event listener.
2495
+ */
2496
+ on(listener) {
2497
+ this.listeners.push(listener);
2498
+ }
2499
+ /**
2500
+ * Unregister an event listener.
2501
+ */
2502
+ off(listener) {
2503
+ this.listeners = this.listeners.filter((l) => l !== listener);
2504
+ }
2505
+ /**
2506
+ * Emit a bootstrap event to all listeners.
2507
+ */
2508
+ emit(event) {
2509
+ for (const listener of this.listeners) {
2510
+ try {
2511
+ listener(event);
2512
+ } catch {
2513
+ }
2514
+ }
2515
+ }
2516
+ /**
2517
+ * Transition to a new phase, emitting phase change event.
2518
+ */
2519
+ setPhase(newPhase) {
2520
+ const previousPhase = this.phase;
2521
+ this.phase = newPhase;
2522
+ this.emit({ type: "bootstrap:phase", phase: newPhase, previousPhase });
2523
+ }
2524
+ /**
2525
+ * Load peers from genesis config, ArDrive, and optional env var JSON.
2526
+ * Merges all sources, deduplicating by pubkey (ArDrive overrides genesis for matching pubkeys).
2527
+ */
2528
+ async loadPeers(additionalPeersJson) {
2529
+ const genesisPeers = GenesisPeerLoader.loadAllPeers(additionalPeersJson);
2530
+ const ardrivePeers = [];
2531
+ if (this.config.ardriveEnabled) {
2532
+ try {
2533
+ const ardriveMap = await ArDrivePeerRegistry.fetchPeers();
2534
+ for (const [pubkey, info] of ardriveMap) {
2535
+ if (!this.config.defaultRelayUrl) continue;
2536
+ ardrivePeers.push({
2537
+ pubkey,
2538
+ relayUrl: this.config.defaultRelayUrl,
2539
+ ilpAddress: info.ilpAddress,
2540
+ btpEndpoint: info.btpEndpoint
2541
+ });
2542
+ }
2543
+ } catch (error) {
2544
+ console.warn(
2545
+ "[Bootstrap] ArDrive peer fetch failed, using genesis peers only:",
2546
+ error instanceof Error ? error.message : "Unknown error"
2547
+ );
2548
+ }
2549
+ }
2550
+ const merged = /* @__PURE__ */ new Map();
2551
+ for (const peer of genesisPeers) {
2552
+ merged.set(peer.pubkey, peer);
2553
+ }
2554
+ for (const peer of ardrivePeers) {
2555
+ merged.set(peer.pubkey, peer);
2556
+ }
2557
+ return [...merged.values()];
2558
+ }
2559
+ /**
2560
+ * Bootstrap with all known peers.
2561
+ *
2562
+ * Loads peers from genesis config, ArDrive, and optional env var JSON,
2563
+ * then attempts to bootstrap with each peer in order.
2564
+ * Returns results for successfully bootstrapped peers.
2565
+ * Continues to next peer on failure.
2566
+ *
2567
+ * @param additionalPeersJson - Optional JSON string of additional peers to merge
2568
+ * @returns Array of successful bootstrap results
2569
+ */
2570
+ async bootstrap(additionalPeersJson) {
2571
+ const results = [];
2572
+ try {
2573
+ this.setPhase("discovering");
2574
+ const allPeers = await this.loadPeers(additionalPeersJson);
2575
+ const knownPeersMap = /* @__PURE__ */ new Map();
2576
+ for (const peer of this.config.knownPeers) {
2577
+ knownPeersMap.set(peer.pubkey, peer);
2578
+ }
2579
+ for (const peer of allPeers) {
2580
+ if (!knownPeersMap.has(peer.pubkey)) {
2581
+ knownPeersMap.set(peer.pubkey, {
2582
+ pubkey: peer.pubkey,
2583
+ relayUrl: peer.relayUrl,
2584
+ btpEndpoint: peer.btpEndpoint
2585
+ });
2586
+ }
2587
+ }
2588
+ this.setPhase("registering");
2589
+ for (const knownPeer of knownPeersMap.values()) {
2590
+ try {
2591
+ const result = await this.bootstrapWithPeer(knownPeer);
2592
+ results.push(result);
2593
+ console.log(
2594
+ `[Bootstrap] Successfully bootstrapped with ${knownPeer.pubkey.slice(0, 16)}...`
2595
+ );
2596
+ } catch (error) {
2597
+ console.warn(
2598
+ `[Bootstrap] Failed to bootstrap with ${knownPeer.pubkey.slice(0, 16)}...:`,
2599
+ error instanceof Error ? error.message : "Unknown error"
2600
+ );
2601
+ }
2602
+ }
2603
+ if (this.ilpClient && results.length > 0) {
2604
+ this.setPhase("announcing");
2605
+ for (const result of results) {
2606
+ try {
2607
+ await this.announceViaIlp(result);
2608
+ } catch (error) {
2609
+ const reason = error instanceof Error ? error.message : "Unknown error";
2610
+ this.emit({
2611
+ type: "bootstrap:announce-failed",
2612
+ peerId: result.registeredPeerId,
2613
+ reason
2614
+ });
2615
+ console.warn(
2616
+ `[Bootstrap] Announce failed for ${result.registeredPeerId}:`,
2617
+ reason
2618
+ );
2619
+ }
2620
+ }
2621
+ }
2622
+ const channelCount = results.filter((r) => r.channelId).length;
2623
+ this.setPhase("ready");
2624
+ this.emit({
2625
+ type: "bootstrap:ready",
2626
+ peerCount: results.length,
2627
+ channelCount
2628
+ });
2629
+ } catch (error) {
2630
+ this.setPhase("failed");
2631
+ console.error(
2632
+ "[Bootstrap] Bootstrap failed:",
2633
+ error instanceof Error ? error.message : "Unknown error"
2634
+ );
2635
+ }
2636
+ return results;
2637
+ }
2638
+ /**
2639
+ * Bootstrap with a single known peer.
2640
+ *
2641
+ * @param knownPeer - The known peer to bootstrap with
2642
+ * @returns Bootstrap result with peer info and registered peer ID
2643
+ * @throws BootstrapError if pubkey is invalid or peer info query fails
2644
+ */
2645
+ async bootstrapWithPeer(knownPeer) {
2646
+ const PUBKEY_REGEX4 = /^[0-9a-f]{64}$/;
2647
+ if (!PUBKEY_REGEX4.test(knownPeer.pubkey)) {
2648
+ throw new BootstrapError(
2649
+ `Invalid pubkey format for known peer: ${knownPeer.pubkey}`
2650
+ );
2651
+ }
2652
+ console.log(`[Bootstrap] Querying ${knownPeer.relayUrl} for peer info...`);
2653
+ const peerInfo = await this.queryPeerInfo(knownPeer);
2654
+ const registeredPeerId = `nostr-${knownPeer.pubkey.slice(0, 16)}`;
2655
+ if (this.connectorAdmin) {
2656
+ try {
2657
+ console.log(`[Bootstrap] Adding peer to connector routing table...`);
2658
+ await this.addPeerToConnector(knownPeer, peerInfo);
2659
+ this.emit({
2660
+ type: "bootstrap:peer-registered",
2661
+ peerId: registeredPeerId,
2662
+ peerPubkey: knownPeer.pubkey,
2663
+ ilpAddress: peerInfo.ilpAddress
2664
+ });
2665
+ } catch (error) {
2666
+ console.warn(
2667
+ `[Bootstrap] Failed to register peer ${registeredPeerId} with connector:`,
2668
+ error instanceof Error ? error.message : "Unknown error"
2669
+ );
2670
+ }
2671
+ }
2672
+ const result = {
2673
+ knownPeer,
2674
+ peerInfo,
2675
+ registeredPeerId
2676
+ };
2677
+ if (this.channelClient && this.settlementInfo?.supportedChains?.length && peerInfo.supportedChains?.length && peerInfo.settlementAddresses) {
2678
+ try {
2679
+ const negotiatedChain = negotiateSettlementChain(
2680
+ this.settlementInfo.supportedChains,
2681
+ peerInfo.supportedChains,
2682
+ this.settlementInfo.preferredTokens,
2683
+ peerInfo.preferredTokens
2684
+ );
2685
+ if (negotiatedChain) {
2686
+ const peerAddress = peerInfo.settlementAddresses[negotiatedChain];
2687
+ const tokenAddress = resolveTokenForChain(
2688
+ negotiatedChain,
2689
+ this.settlementInfo.preferredTokens,
2690
+ peerInfo.preferredTokens
2691
+ );
2692
+ const tokenNetwork = peerInfo.tokenNetworks?.[negotiatedChain];
2693
+ if (peerAddress) {
2694
+ console.log(
2695
+ `[Bootstrap] Negotiated ${negotiatedChain} with ${registeredPeerId} (lazy \u2014 channel deferred)`
2696
+ );
2697
+ result.negotiatedChain = negotiatedChain;
2698
+ result.settlementAddress = peerAddress;
2699
+ result.tokenAddress = tokenAddress;
2700
+ result.tokenNetwork = tokenNetwork;
2701
+ if (this.connectorAdmin) {
2702
+ await this.connectorAdmin.addPeer({
2703
+ id: registeredPeerId,
2704
+ url: peerInfo.btpEndpoint,
2705
+ authToken: "",
2706
+ routes: [{ prefix: peerInfo.ilpAddress }],
2707
+ settlement: {
2708
+ preference: negotiatedChain,
2709
+ ...peerAddress && { evmAddress: peerAddress },
2710
+ ...tokenAddress && { tokenAddress },
2711
+ ...tokenNetwork && { tokenNetworkAddress: tokenNetwork }
2712
+ }
2713
+ });
2714
+ }
2715
+ }
2716
+ }
2717
+ } catch (error) {
2718
+ const reason = error instanceof Error ? error.message : "Unknown error";
2719
+ console.warn(
2720
+ `[Bootstrap] Settlement failed for ${registeredPeerId}:`,
2721
+ reason
2722
+ );
2723
+ this.emit({
2724
+ type: "bootstrap:settlement-failed",
2725
+ peerId: registeredPeerId,
2726
+ reason
2727
+ });
2728
+ }
2729
+ }
2730
+ if (!this.ilpClient) {
2731
+ try {
2732
+ console.log(
2733
+ `[Bootstrap] Publishing our ILP info to ${knownPeer.relayUrl}...`
2734
+ );
2735
+ await this.publishOurInfo(knownPeer.relayUrl);
2736
+ } catch (error) {
2737
+ console.warn(
2738
+ `[Bootstrap] Failed to publish ILP info to ${knownPeer.relayUrl}:`,
2739
+ error instanceof Error ? error.message : "Unknown error"
2740
+ );
2741
+ }
2742
+ }
2743
+ return result;
2744
+ }
2745
+ /**
2746
+ * Announce own kind:10032 as paid ILP PREPARE (Phase 2).
2747
+ */
2748
+ async announceViaIlp(result) {
2749
+ if (!this.ilpClient || !this.toonEncoder) {
2750
+ return;
2751
+ }
2752
+ const ilpInfoEvent = buildIlpPeerInfoEvent(this.ownIlpInfo, this.secretKey);
2753
+ const toonBytes = this.toonEncoder(ilpInfoEvent);
2754
+ const base64Toon = Buffer.from(toonBytes).toString("base64");
2755
+ const amount = String(BigInt(toonBytes.length) * this.basePricePerByte);
2756
+ let ilpResult;
2757
+ if (this.claimSigner && result.channelId && this.ilpClient.sendIlpPacketWithClaim) {
2758
+ const claim = await this.claimSigner(result.channelId, BigInt(amount));
2759
+ ilpResult = await this.ilpClient.sendIlpPacketWithClaim(
2760
+ { destination: result.peerInfo.ilpAddress, amount, data: base64Toon },
2761
+ claim
2762
+ );
2763
+ } else {
2764
+ ilpResult = await this.ilpClient.sendIlpPacket({
2765
+ destination: result.peerInfo.ilpAddress,
2766
+ amount,
2767
+ data: base64Toon
2768
+ });
2769
+ }
2770
+ if (ilpResult.accepted) {
2771
+ console.log(
2772
+ `[Bootstrap] Announced to ${result.registeredPeerId} via ILP (eventId: ${ilpInfoEvent.id})`
2773
+ );
2774
+ this.emit({
2775
+ type: "bootstrap:announced",
2776
+ peerId: result.registeredPeerId,
2777
+ eventId: ilpInfoEvent.id,
2778
+ amount
2779
+ });
2780
+ } else {
2781
+ const reason = `${ilpResult.code} ${ilpResult.message}`;
2782
+ this.emit({
2783
+ type: "bootstrap:announce-failed",
2784
+ peerId: result.registeredPeerId,
2785
+ reason
2786
+ });
2787
+ console.warn(
2788
+ `[Bootstrap] Announce rejected by ${result.registeredPeerId}: ${reason}`
2789
+ );
2790
+ }
2791
+ }
2792
+ /**
2793
+ * Query a peer's relay for their kind:10032 ILP Peer Info event.
2794
+ * Uses direct WebSocket connection for reliable container-to-container communication.
2795
+ */
2796
+ async queryPeerInfo(knownPeer) {
2797
+ const filter = {
2798
+ kinds: [ILP_PEER_INFO_KIND],
2799
+ authors: [knownPeer.pubkey],
2800
+ limit: 1
2801
+ };
2802
+ console.log(`[Bootstrap] Query filter:`, JSON.stringify(filter));
2803
+ console.log(`[Bootstrap] Connecting to ${knownPeer.relayUrl}...`);
2804
+ return new Promise((resolve, reject) => {
2805
+ const events = [];
2806
+ const timeout = this.config.queryTimeout ?? 5e3;
2807
+ const ws = new WebSocket2(knownPeer.relayUrl);
2808
+ const subId = `bootstrap-${Date.now()}`;
2809
+ let resolved = false;
2810
+ const cleanup = () => {
2811
+ if (!resolved) {
2812
+ resolved = true;
2813
+ try {
2814
+ ws.close();
2815
+ } catch {
2816
+ }
2817
+ }
2818
+ };
2819
+ ws.on("open", () => {
2820
+ console.log(
2821
+ `[Bootstrap] Connected to ${knownPeer.relayUrl}, sending REQ`
2822
+ );
2823
+ ws.send(JSON.stringify(["REQ", subId, filter]));
2824
+ });
2825
+ ws.on("message", (data) => {
2826
+ let msg;
2827
+ try {
2828
+ msg = JSON.parse(data.toString());
2829
+ } catch {
2830
+ console.warn("[Bootstrap] Received malformed JSON from relay");
2831
+ return;
2832
+ }
2833
+ console.log(`[Bootstrap] Received message type: ${msg[0]}`);
2834
+ if (msg[0] === "EVENT" && msg[1] === subId) {
2835
+ let event;
2836
+ const rawEvent = msg[2];
2837
+ if (typeof rawEvent === "string") {
2838
+ try {
2839
+ const lines = rawEvent.trim().split("\n");
2840
+ const parsed = {};
2841
+ for (const line of lines) {
2842
+ const colonIndex = line.indexOf(":");
2843
+ if (colonIndex > 0) {
2844
+ const key = line.substring(0, colonIndex).trim();
2845
+ const value = line.substring(colonIndex + 1).trim();
2846
+ if (key.startsWith("tags[")) {
2847
+ continue;
2848
+ }
2849
+ if (value.startsWith('"') && value.endsWith('"')) {
2850
+ parsed[key] = JSON.parse(value);
2851
+ } else if (!isNaN(Number(value))) {
2852
+ parsed[key] = Number(value);
2853
+ } else {
2854
+ parsed[key] = value;
2855
+ }
2856
+ }
2857
+ }
2858
+ event = parsed;
2859
+ } catch (error) {
2860
+ console.warn(`[Bootstrap] Failed to parse TOON event:`, error);
2861
+ return;
2862
+ }
2863
+ } else if (typeof rawEvent === "object" && rawEvent !== null) {
2864
+ event = rawEvent;
2865
+ }
2866
+ if (event && typeof event["id"] === "string") {
2867
+ console.log(
2868
+ `[Bootstrap] Received event: ${event["id"].slice(0, 16)}...`
2869
+ );
2870
+ events.push(event);
2871
+ } else {
2872
+ console.warn(
2873
+ `[Bootstrap] Received EVENT message with invalid event data:`,
2874
+ msg
2875
+ );
2876
+ }
2877
+ } else if (msg[0] === "EOSE" && msg[1] === subId) {
2878
+ console.log(
2879
+ `[Bootstrap] EOSE received, found ${events.length} events`
2880
+ );
2881
+ cleanup();
2882
+ if (events.length === 0) {
2883
+ reject(
2884
+ new BootstrapError(
2885
+ `No kind:${ILP_PEER_INFO_KIND} event found for peer ${knownPeer.pubkey.slice(0, 16)}...`
2886
+ )
2887
+ );
2888
+ return;
2889
+ }
2890
+ const sortedEvents = events.sort(
2891
+ (a, b) => b.created_at - a.created_at
2892
+ );
2893
+ const mostRecent = sortedEvents[0];
2894
+ try {
2895
+ const peerInfo = parseIlpPeerInfo(
2896
+ mostRecent
2897
+ );
2898
+ resolve(peerInfo);
2899
+ } catch (error) {
2900
+ reject(
2901
+ new BootstrapError(
2902
+ `Failed to parse peer info`,
2903
+ error instanceof Error ? error : void 0
2904
+ )
2905
+ );
2906
+ }
2907
+ } else if (msg[0] === "NOTICE") {
2908
+ console.log(`[Bootstrap] Notice from relay: ${msg[1]}`);
2909
+ }
2910
+ });
2911
+ ws.on("error", (error) => {
2912
+ console.error(`[Bootstrap] WebSocket error:`, error.message);
2913
+ cleanup();
2914
+ reject(
2915
+ new BootstrapError(
2916
+ `Failed to connect to ${knownPeer.relayUrl}: ${error.message}`,
2917
+ error
2918
+ )
2919
+ );
2920
+ });
2921
+ ws.on("close", () => {
2922
+ console.log(`[Bootstrap] Connection closed`);
2923
+ if (!resolved) {
2924
+ cleanup();
2925
+ reject(
2926
+ new BootstrapError(
2927
+ `Connection closed before receiving events from ${knownPeer.relayUrl}`
2928
+ )
2929
+ );
2930
+ }
2931
+ });
2932
+ setTimeout(() => {
2933
+ if (resolved) return;
2934
+ console.log(`[Bootstrap] Query timeout after ${timeout}ms`);
2935
+ cleanup();
2936
+ if (events.length > 0) {
2937
+ const sortedEvents = events.sort(
2938
+ (a, b) => b.created_at - a.created_at
2939
+ );
2940
+ const mostRecent = sortedEvents[0];
2941
+ try {
2942
+ const peerInfo = parseIlpPeerInfo(
2943
+ mostRecent
2944
+ );
2945
+ resolve(peerInfo);
2946
+ } catch (error) {
2947
+ reject(
2948
+ new BootstrapError(
2949
+ `Failed to parse peer info`,
2950
+ error instanceof Error ? error : void 0
2951
+ )
2952
+ );
2953
+ }
2954
+ } else {
2955
+ reject(
2956
+ new BootstrapError(
2957
+ `Query timeout: No events received from ${knownPeer.relayUrl} after ${timeout}ms`
2958
+ )
2959
+ );
2960
+ }
2961
+ }, timeout);
2962
+ });
2963
+ }
2964
+ /**
2965
+ * Add a peer to the connector via Admin API.
2966
+ */
2967
+ async addPeerToConnector(knownPeer, peerInfo) {
2968
+ if (!this.connectorAdmin) {
2969
+ throw new BootstrapError("Connector admin client not set");
2970
+ }
2971
+ const peerId = `nostr-${knownPeer.pubkey.slice(0, 16)}`;
2972
+ await this.connectorAdmin.addPeer({
2973
+ id: peerId,
2974
+ url: peerInfo.btpEndpoint,
2975
+ authToken: "",
2976
+ // BTP doesn't need auth
2977
+ routes: [{ prefix: peerInfo.ilpAddress }]
2978
+ });
2979
+ }
2980
+ /**
2981
+ * Publish our own kind:10032 ILP Peer Info to a relay.
2982
+ */
2983
+ async publishOurInfo(relayUrl) {
2984
+ const event = buildIlpPeerInfoEvent(this.ownIlpInfo, this.secretKey);
2985
+ try {
2986
+ await this.pool.publish([relayUrl], event);
2987
+ } catch (error) {
2988
+ throw new BootstrapError(
2989
+ `Failed to publish ILP info to ${relayUrl}`,
2990
+ error instanceof Error ? error : void 0
2991
+ );
2992
+ }
2993
+ }
2994
+ /**
2995
+ * Query a peer's relay for other peers' kind:10032 events.
2996
+ *
2997
+ * Used after bootstrapping to discover additional peers
2998
+ * that have also published to the bootstrap node's relay.
2999
+ *
3000
+ * @param relayUrl - The relay URL to query
3001
+ * @param excludePubkeys - Pubkeys to exclude from results (e.g., our own, known peers)
3002
+ * @returns Map of pubkey to IlpPeerInfo for discovered peers
3003
+ */
3004
+ async discoverPeersViaRelay(relayUrl, excludePubkeys = []) {
3005
+ const excludeSet = /* @__PURE__ */ new Set([this.pubkey, ...excludePubkeys]);
3006
+ const filter = {
3007
+ kinds: [ILP_PEER_INFO_KIND]
3008
+ };
3009
+ try {
3010
+ const events = await this.pool.querySync([relayUrl], filter);
3011
+ const eventsByPubkey = /* @__PURE__ */ new Map();
3012
+ for (const event of events) {
3013
+ if (excludeSet.has(event.pubkey)) continue;
3014
+ const existing = eventsByPubkey.get(event.pubkey);
3015
+ if (!existing || event.created_at > existing.created_at) {
3016
+ eventsByPubkey.set(event.pubkey, event);
3017
+ }
3018
+ }
3019
+ const result = /* @__PURE__ */ new Map();
3020
+ for (const [pubkey, event] of eventsByPubkey) {
3021
+ try {
3022
+ const info = parseIlpPeerInfo(event);
3023
+ result.set(pubkey, info);
3024
+ } catch {
3025
+ }
3026
+ }
3027
+ return result;
3028
+ } catch (error) {
3029
+ throw new BootstrapError(
3030
+ `Failed to discover peers from ${relayUrl}`,
3031
+ error instanceof Error ? error : void 0
3032
+ );
3033
+ }
3034
+ }
3035
+ /**
3036
+ * Re-advertise own kind:10032 to all previously bootstrapped peers.
3037
+ *
3038
+ * Called after topology changes (addUpstreamPeer/removeUpstreamPeer) to
3039
+ * propagate updated ILP address lists to the network. Uses the same
3040
+ * ILP-first announcement path as the initial Phase 2 bootstrap.
3041
+ *
3042
+ * For non-ILP mode, publishes directly to each peer's relay URL.
3043
+ *
3044
+ * @param results - The bootstrap results from the initial bootstrap() call
3045
+ * @returns Number of peers successfully re-announced to
3046
+ */
3047
+ async republish(results) {
3048
+ if (results.length === 0) {
3049
+ return 0;
3050
+ }
3051
+ let successCount = 0;
3052
+ if (this.ilpClient && this.toonEncoder) {
3053
+ for (const result of results) {
3054
+ try {
3055
+ await this.announceViaIlp(result);
3056
+ successCount++;
3057
+ } catch (error) {
3058
+ const reason = error instanceof Error ? error.message : "Unknown error";
3059
+ this.emit({
3060
+ type: "bootstrap:announce-failed",
3061
+ peerId: result.registeredPeerId,
3062
+ reason: `republish: ${reason}`
3063
+ });
3064
+ console.warn(
3065
+ `[Bootstrap] Republish failed for ${result.registeredPeerId}:`,
3066
+ reason
3067
+ );
3068
+ }
3069
+ }
3070
+ } else {
3071
+ for (const result of results) {
3072
+ try {
3073
+ await this.publishOurInfo(result.knownPeer.relayUrl);
3074
+ successCount++;
3075
+ } catch (error) {
3076
+ console.warn(
3077
+ `[Bootstrap] Republish to ${result.knownPeer.relayUrl} failed:`,
3078
+ error instanceof Error ? error.message : "Unknown error"
3079
+ );
3080
+ }
3081
+ }
3082
+ }
3083
+ return successCount;
3084
+ }
3085
+ /**
3086
+ * Get our pubkey.
3087
+ */
3088
+ getPubkey() {
3089
+ return this.pubkey;
3090
+ }
3091
+ /**
3092
+ * Publish our ILP info to a specific relay.
3093
+ *
3094
+ * @param relayUrl - The relay URL to publish to (defaults to 'ws://localhost:7100')
3095
+ */
3096
+ async publishToRelay(relayUrl = "ws://localhost:7100") {
3097
+ await this.publishOurInfo(relayUrl);
3098
+ }
3099
+ };
3100
+ function createDiscoveryTracker(config) {
3101
+ const pubkey = getPublicKey4(config.secretKey);
3102
+ const excludedPubkeys = /* @__PURE__ */ new Set([pubkey]);
3103
+ let connectorAdmin;
3104
+ let _channelClient;
3105
+ let listeners = [];
3106
+ const discoveredPeers = /* @__PURE__ */ new Map();
3107
+ const peeredPubkeys = /* @__PURE__ */ new Set();
3108
+ const peerNegotiations = /* @__PURE__ */ new Map();
3109
+ const peerTimestamps = /* @__PURE__ */ new Map();
3110
+ function emit(event) {
3111
+ for (const listener of listeners) {
3112
+ try {
3113
+ listener(event);
3114
+ } catch {
3115
+ }
3116
+ }
3117
+ }
3118
+ function handleDeregistration(peerPubkey, peerId) {
3119
+ discoveredPeers.delete(peerPubkey);
3120
+ if (peeredPubkeys.has(peerPubkey)) {
3121
+ peeredPubkeys.delete(peerPubkey);
3122
+ if (connectorAdmin?.removePeer) {
3123
+ connectorAdmin.removePeer(peerId).then(() => {
3124
+ emit({
3125
+ type: "bootstrap:peer-deregistered",
3126
+ peerId,
3127
+ peerPubkey,
3128
+ reason: "empty-content"
3129
+ });
3130
+ }).catch((error) => {
3131
+ console.warn(
3132
+ "[DiscoveryTracker] Failed to deregister %s: %s",
3133
+ peerId,
3134
+ error instanceof Error ? error.message : "Unknown error"
3135
+ );
3136
+ });
3137
+ } else {
3138
+ emit({
3139
+ type: "bootstrap:peer-deregistered",
3140
+ peerId,
3141
+ peerPubkey,
3142
+ reason: "empty-content"
3143
+ });
3144
+ }
3145
+ }
3146
+ }
3147
+ function processDiscovery(event) {
3148
+ const peerId = `nostr-${event.pubkey.slice(0, 16)}`;
3149
+ let peerInfo;
3150
+ try {
3151
+ peerInfo = parseIlpPeerInfo(event);
3152
+ } catch {
3153
+ }
3154
+ if (!peerInfo || !peerInfo.ilpAddress || !event.content || event.content.trim() === "") {
3155
+ handleDeregistration(event.pubkey, peerId);
3156
+ return;
3157
+ }
3158
+ discoveredPeers.set(event.pubkey, {
3159
+ pubkey: event.pubkey,
3160
+ peerId,
3161
+ peerInfo,
3162
+ discoveredAt: event.created_at
3163
+ });
3164
+ emit({
3165
+ type: "bootstrap:peer-discovered",
3166
+ peerPubkey: event.pubkey,
3167
+ ilpAddress: peerInfo.ilpAddress
3168
+ });
3169
+ }
3170
+ const tracker = {
3171
+ processEvent(event) {
3172
+ if (event.kind !== ILP_PEER_INFO_KIND) return;
3173
+ if (excludedPubkeys.has(event.pubkey)) return;
3174
+ const lastSeen = peerTimestamps.get(event.pubkey) ?? 0;
3175
+ if (event.created_at <= lastSeen) return;
3176
+ peerTimestamps.set(event.pubkey, event.created_at);
3177
+ processDiscovery(event);
3178
+ },
3179
+ async peerWith(targetPubkey) {
3180
+ if (peeredPubkeys.has(targetPubkey)) {
3181
+ return;
3182
+ }
3183
+ const discovered = discoveredPeers.get(targetPubkey);
3184
+ if (!discovered) {
3185
+ throw new BootstrapError(
3186
+ `Peer ${targetPubkey.slice(0, 16)}... not discovered yet`
3187
+ );
3188
+ }
3189
+ if (!connectorAdmin) {
3190
+ throw new BootstrapError(
3191
+ "connectorAdmin must be set before calling peerWith()"
3192
+ );
3193
+ }
3194
+ const { peerId, peerInfo } = discovered;
3195
+ const admin = connectorAdmin;
3196
+ peeredPubkeys.add(targetPubkey);
3197
+ try {
3198
+ await admin.addPeer({
3199
+ id: peerId,
3200
+ url: peerInfo.btpEndpoint,
3201
+ authToken: "",
3202
+ routes: [{ prefix: peerInfo.ilpAddress }]
3203
+ });
3204
+ emit({
3205
+ type: "bootstrap:peer-registered",
3206
+ peerId,
3207
+ peerPubkey: targetPubkey,
3208
+ ilpAddress: peerInfo.ilpAddress
3209
+ });
3210
+ } catch (error) {
3211
+ peeredPubkeys.delete(targetPubkey);
3212
+ const reason = error instanceof Error ? error.message : "Unknown error";
3213
+ console.warn(
3214
+ "[DiscoveryTracker] Failed to register %s: %s",
3215
+ peerId,
3216
+ reason
3217
+ );
3218
+ emit({
3219
+ type: "bootstrap:settlement-failed",
3220
+ peerId,
3221
+ reason: `Registration failed: ${reason}`
3222
+ });
3223
+ return;
3224
+ }
3225
+ if (config.settlementInfo?.supportedChains?.length && peerInfo.supportedChains?.length && peerInfo.settlementAddresses) {
3226
+ try {
3227
+ const negotiatedChain = negotiateSettlementChain(
3228
+ config.settlementInfo.supportedChains,
3229
+ peerInfo.supportedChains,
3230
+ config.settlementInfo.preferredTokens,
3231
+ peerInfo.preferredTokens
3232
+ );
3233
+ if (negotiatedChain) {
3234
+ const peerAddress = peerInfo.settlementAddresses[negotiatedChain];
3235
+ const tokenAddress = resolveTokenForChain(
3236
+ negotiatedChain,
3237
+ config.settlementInfo.preferredTokens,
3238
+ peerInfo.preferredTokens
3239
+ );
3240
+ const tokenNetwork = peerInfo.tokenNetworks?.[negotiatedChain];
3241
+ if (peerAddress) {
3242
+ peerNegotiations.set(peerId, {
3243
+ chain: negotiatedChain,
3244
+ chainType: negotiatedChain.split(":")[0] ?? negotiatedChain,
3245
+ settlementAddress: peerAddress,
3246
+ tokenAddress,
3247
+ tokenNetwork
3248
+ });
3249
+ console.log(
3250
+ "[DiscoveryTracker] Negotiated %s with %s (lazy \u2014 channel deferred)",
3251
+ negotiatedChain,
3252
+ peerId
3253
+ );
3254
+ }
3255
+ }
3256
+ } catch (error) {
3257
+ const reason = error instanceof Error ? error.message : "Unknown error";
3258
+ console.warn(
3259
+ "[DiscoveryTracker] Settlement negotiation failed for %s: %s",
3260
+ peerId,
3261
+ reason
3262
+ );
3263
+ emit({
3264
+ type: "bootstrap:settlement-failed",
3265
+ peerId,
3266
+ reason
3267
+ });
3268
+ }
3269
+ }
3270
+ },
3271
+ getDiscoveredPeers() {
3272
+ return [...discoveredPeers.values()].filter(
3273
+ (p) => !peeredPubkeys.has(p.pubkey)
3274
+ );
3275
+ },
3276
+ getAllDiscoveredPeers() {
3277
+ return [...discoveredPeers.values()];
3278
+ },
3279
+ isPeered(targetPubkey) {
3280
+ return peeredPubkeys.has(targetPubkey);
3281
+ },
3282
+ getPeerCount() {
3283
+ return peeredPubkeys.size;
3284
+ },
3285
+ getDiscoveredCount() {
3286
+ return discoveredPeers.size;
3287
+ },
3288
+ on(listener) {
3289
+ listeners.push(listener);
3290
+ },
3291
+ off(listener) {
3292
+ listeners = listeners.filter((l) => l !== listener);
3293
+ },
3294
+ setConnectorAdmin(admin) {
3295
+ connectorAdmin = admin;
3296
+ },
3297
+ setChannelClient(client) {
3298
+ _channelClient = client;
3299
+ },
3300
+ getPeerNegotiation(peerId) {
3301
+ return peerNegotiations.get(peerId);
3302
+ },
3303
+ addExcludedPubkeys(pubkeys) {
3304
+ for (const pk of pubkeys) {
3305
+ excludedPubkeys.add(pk);
3306
+ }
3307
+ }
3308
+ };
3309
+ return tracker;
3310
+ }
3311
+ var ILP_TO_SEMANTIC = Object.freeze({
3312
+ T00: "internal_error",
3313
+ T04: "insufficient_funds",
3314
+ F00: "invalid_request",
3315
+ // F01 ("Invalid Packet" in ILP terms — emitted by the swap handler for
3316
+ // "Invalid gift wrap" / "Invalid amount") has NO dedicated entry in the
3317
+ // connector's REJECT_CODE_MAP (accepted semantics are: insufficient_funds,
3318
+ // expired, unreachable, invalid_request, invalid_amount,
3319
+ // insufficient_destination_amount, unexpected_payment, application_error,
3320
+ // internal_error, timeout). The closest faithful reason is `invalid_request`,
3321
+ // which the connector re-encodes to wire code F00. We map F01 EXPLICITLY
3322
+ // (rather than relying on the fallback below) so the F01 -> F00 normalization
3323
+ // is intentional and test-pinned, not a silent collapse that misleads callers
3324
+ // into thinking they hit a different failure class. See issue #86.
3325
+ F01: "invalid_request",
3326
+ F02: "unreachable",
3327
+ F03: "invalid_amount",
3328
+ F04: "insufficient_destination_amount",
3329
+ F06: "unexpected_payment",
3330
+ R00: "expired"
3331
+ });
3332
+ var MOCK_USDC_ADDRESS = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
3333
+ var CHAIN_PRESETS = {
3334
+ anvil: {
3335
+ name: "anvil",
3336
+ chainId: 31337,
3337
+ rpcUrl: "http://localhost:8545",
3338
+ usdcAddress: MOCK_USDC_ADDRESS,
3339
+ tokenNetworkAddress: "0xCafac3dD18aC6c6e92c921884f9E4176737C052c",
3340
+ registryAddress: "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512"
3341
+ },
3342
+ "arbitrum-sepolia": {
3343
+ name: "arbitrum-sepolia",
3344
+ chainId: 421614,
3345
+ rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc",
3346
+ usdcAddress: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
3347
+ tokenNetworkAddress: "0x91d62b1F7C5d1129A64EE3915c480DBF288B1cBa",
3348
+ registryAddress: ""
3349
+ },
3350
+ "arbitrum-one": {
3351
+ name: "arbitrum-one",
3352
+ chainId: 42161,
3353
+ rpcUrl: "https://arb1.arbitrum.io/rpc",
3354
+ usdcAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
3355
+ tokenNetworkAddress: "",
3356
+ registryAddress: ""
3357
+ },
3358
+ // Base Sepolia (public testnet) — TOON's deployed public-testnet settlement
3359
+ // environment (source of truth: e2e/testnets.json). USDC is the deployed test
3360
+ // token the TokenNetwork was opened against (NOT Circle's native testnet USDC,
3361
+ // which the channel would not recognise). Registry + TokenNetwork are live, so
3362
+ // this preset is settlement-complete: `--network testnet|devnet` settles here.
3363
+ "base-sepolia": {
3364
+ name: "base-sepolia",
3365
+ chainId: 84532,
3366
+ // The old `https://sepolia.base.org` is a stale-read load balancer: reads
3367
+ // work, but openChannel->setTotalDeposit fails with InvalidChannelState
3368
+ // (0xf806e9d9) because a follow-up read lands on a lagging replica. publicnode
3369
+ // is the working devnet/testnet default (source of truth: toon-meta
3370
+ // docs/deployment.md).
3371
+ rpcUrl: "https://base-sepolia-rpc.publicnode.com",
3372
+ // Post-2026-07-19 public-chain cutover addresses (source of truth: toon-meta
3373
+ // docs/deployment.md). USDC is a 6-decimal mock with an ungated mint; the
3374
+ // retired e2e deployment (18-decimal USDC 0xac806…, TokenNetwork 0x47616F4b…,
3375
+ // registry 0xb9516c…) is still on-chain but MUST NOT be used.
3376
+ usdcAddress: "0x49beE1Bca5d15Fb0963117923403F9498119a9Ce",
3377
+ tokenNetworkAddress: "0x1E95493fEF46707E034b4a1945f25a8C76A1823D",
3378
+ registryAddress: "0xcC9079adE929b168B54145f6d25262b64FAB9D5b"
3379
+ },
3380
+ // Base mainnet (public). USDC is Circle's native USDC on Base.
3381
+ // TOON TokenNetwork/registry not deployed yet → settlement relay-only.
3382
+ "base-mainnet": {
3383
+ name: "base-mainnet",
3384
+ chainId: 8453,
3385
+ rpcUrl: "https://mainnet.base.org",
3386
+ usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
3387
+ tokenNetworkAddress: "",
3388
+ registryAddress: ""
3389
+ }
3390
+ };
3391
+ var EVM_TIER = {
3392
+ mainnet: { primary: "base-mainnet", also: ["arbitrum-one"] },
3393
+ testnet: { primary: "base-sepolia", also: ["arbitrum-sepolia"] },
3394
+ // EVM has no public devnet → the public Sepolia testnets serve the devnet tier.
3395
+ devnet: { primary: "base-sepolia", also: ["arbitrum-sepolia"] }
3396
+ };
3397
+ var SOLANA_DEPLOYED_DEVNET = {
3398
+ rpcUrl: "https://api.devnet.solana.com",
3399
+ cluster: "devnet",
3400
+ // Post-2026-07-19 public-chain cutover (source of truth: toon-meta
3401
+ // docs/deployment.md). USDC mint authority is the faucet treasury
3402
+ // AEPoA5xT…; the pre-cutover self-hosted-validator values (mint
3403
+ // 9FtYCX…, program EdJxYPD…) are retired and MUST NOT be used.
3404
+ usdcMint: "xyc5J8MgKFiEN13PnfftdXxUzYH34FEvw1LCrFwN7in",
3405
+ programId: "2aEVJ8koKD8LTZrLRSGtAtU7LBt4e7QjjCgf1kzQ7Rip"
3406
+ };
3407
+ var SOLANA_TIER = {
3408
+ mainnet: {
3409
+ rpcUrl: "https://api.mainnet-beta.solana.com",
3410
+ cluster: "mainnet-beta",
3411
+ usdcMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
3412
+ programId: ""
3413
+ // TOON payment-channel program not deployed on mainnet
3414
+ },
3415
+ testnet: SOLANA_DEPLOYED_DEVNET,
3416
+ devnet: SOLANA_DEPLOYED_DEVNET
3417
+ };
3418
+ var MINA_DEPLOYED_DEVNET = {
3419
+ graphqlUrl: "https://api.minascan.io/node/devnet/v1/graphql",
3420
+ network: "devnet",
3421
+ // Post-2026-07-19 public-chain cutover (source of truth: toon-meta
3422
+ // docs/deployment.md). This is the CURRENT deployed PaymentChannel zkApp; the
3423
+ // previous address (B62qrH1As4…) is retired and MUST NOT be used. The channels
3424
+ // settle a custom USDC token, so the tokenId is required to read balances /
3425
+ // open channels against the right token.
3426
+ zkAppAddress: "B62qmgPhv2Xo6QVEtwjLja8UZJUtu8yapRFAR6gaoGtbM9zE5hG7Tkf",
3427
+ tokenId: "9497120696276615621907376728658022802954262638363646162765282600447713419198"
3428
+ };
3429
+ var MINA_TIER = {
3430
+ mainnet: {
3431
+ graphqlUrl: "https://api.minascan.io/node/mainnet/v1/graphql",
3432
+ network: "mainnet",
3433
+ zkAppAddress: ""
3434
+ // TOON payment-channel zkApp not deployed on mainnet
3435
+ },
3436
+ testnet: MINA_DEPLOYED_DEVNET,
3437
+ devnet: MINA_DEPLOYED_DEVNET
3438
+ };
3439
+ function evmSettlementComplete(p) {
3440
+ return p.registryAddress !== "" && p.tokenNetworkAddress !== "";
3441
+ }
3442
+ function evmClientId(preset) {
3443
+ const family = preset.name.split("-")[0] ?? preset.name;
3444
+ return `evm:${family}:${preset.chainId}`;
3445
+ }
3446
+ function resolveClientNetwork(network) {
3447
+ const supportedChains = [];
3448
+ const chainRpcUrls = {};
3449
+ const preferredTokens = {};
3450
+ const tokenNetworks = {};
3451
+ const status = {
3452
+ evm: "unconfigured",
3453
+ solana: "unconfigured",
3454
+ mina: "unconfigured"
3455
+ };
3456
+ const evm = CHAIN_PRESETS[EVM_TIER[network].primary];
3457
+ const evmId = evmClientId(evm);
3458
+ supportedChains.push(evmId);
3459
+ chainRpcUrls[evmId] = evm.rpcUrl;
3460
+ if (evm.usdcAddress) preferredTokens[evmId] = evm.usdcAddress;
3461
+ if (evmSettlementComplete(evm)) {
3462
+ tokenNetworks[evmId] = evm.tokenNetworkAddress;
3463
+ status.evm = "configured";
3464
+ }
3465
+ const sol = SOLANA_TIER[network];
3466
+ const solId = `solana:${sol.cluster}`;
3467
+ supportedChains.push(solId);
3468
+ chainRpcUrls[solId] = sol.rpcUrl;
3469
+ if (sol.usdcMint) preferredTokens[solId] = sol.usdcMint;
3470
+ let solanaChannel;
3471
+ if (sol.programId) {
3472
+ solanaChannel = {
3473
+ rpcUrl: sol.rpcUrl,
3474
+ programId: sol.programId,
3475
+ ...sol.usdcMint && { tokenMint: sol.usdcMint }
3476
+ };
3477
+ status.solana = "configured";
3478
+ }
3479
+ const mina = MINA_TIER[network];
3480
+ const minaId = `mina:${mina.network}`;
3481
+ supportedChains.push(minaId);
3482
+ chainRpcUrls[minaId] = mina.graphqlUrl;
3483
+ let minaChannel;
3484
+ if (mina.zkAppAddress) {
3485
+ minaChannel = {
3486
+ graphqlUrl: mina.graphqlUrl,
3487
+ zkAppAddress: mina.zkAppAddress,
3488
+ networkId: mina.network === "mainnet" ? "mainnet" : "devnet",
3489
+ ...mina.tokenId && { tokenId: mina.tokenId }
3490
+ };
3491
+ status.mina = "configured";
3492
+ }
3493
+ return {
3494
+ supportedChains,
3495
+ chainRpcUrls,
3496
+ preferredTokens,
3497
+ tokenNetworks,
3498
+ ...solanaChannel && { solanaChannel },
3499
+ ...minaChannel && { minaChannel },
3500
+ status
3501
+ };
3502
+ }
3503
+ function buildIlpPrepare(params) {
3504
+ return {
3505
+ destination: params.destination,
3506
+ amount: String(params.amount),
3507
+ data: Buffer.from(params.data).toString("base64"),
3508
+ ...params.expiresAt !== void 0 && {
3509
+ expiresAt: params.expiresAt.toISOString()
3510
+ }
3511
+ };
3512
+ }
3513
+
3514
+ // ../client/dist/chunk-OM3MHJHC.js
3515
+ var cachedO1js = null;
3516
+ var cachedPaymentChannel = null;
3517
+ var compiledContract = null;
3518
+ var runtimeOverride = null;
3519
+ async function loadMinaRuntime() {
3520
+ if (cachedO1js && cachedPaymentChannel) {
3521
+ return { o1js: cachedO1js, PaymentChannel: cachedPaymentChannel };
3522
+ }
3523
+ if (runtimeOverride) {
3524
+ const injected = await runtimeOverride();
3525
+ cachedO1js = injected.o1js;
3526
+ cachedPaymentChannel = injected.PaymentChannel;
3527
+ return injected;
3528
+ }
3529
+ const { createRequire } = await import("module");
3530
+ const nodePath = await import("path");
3531
+ const requireHere = createRequire(import.meta.url);
3532
+ const mzkPkgPath = requireHere.resolve(
3533
+ "@toon-protocol/mina-zkapp/package.json"
3534
+ );
3535
+ const requireFromMzk = createRequire(mzkPkgPath);
3536
+ const o1js = requireFromMzk("o1js");
3537
+ const mzkPkgJson = requireFromMzk(mzkPkgPath);
3538
+ const mzkDir = nodePath.dirname(mzkPkgPath);
3539
+ const mzkEntry = nodePath.join(mzkDir, mzkPkgJson.main ?? "dist/index.js");
3540
+ const mzk = requireFromMzk(mzkEntry);
3541
+ const PaymentChannel = mzk.PaymentChannel ?? mzk.default?.PaymentChannel;
3542
+ if (!PaymentChannel) {
3543
+ throw new Error(
3544
+ "@toon-protocol/mina-zkapp does not export PaymentChannel \u2014 cannot open a Mina channel"
3545
+ );
3546
+ }
3547
+ cachedO1js = o1js;
3548
+ cachedPaymentChannel = PaymentChannel;
3549
+ return { o1js, PaymentChannel };
3550
+ }
3551
+ async function getO1js() {
3552
+ return (await loadMinaRuntime()).o1js;
3553
+ }
3554
+ var compiledVerificationKeyHash;
3555
+ async function getCompiledPaymentChannel() {
3556
+ const { PaymentChannel } = await loadMinaRuntime();
3557
+ if (!compiledContract) {
3558
+ const compiled = await PaymentChannel.compile();
3559
+ compiledVerificationKeyHash = compiled?.verificationKey?.hash?.toString() ?? void 0;
3560
+ compiledContract = PaymentChannel;
3561
+ }
3562
+ return compiledContract;
3563
+ }
3564
+ function getCompiledVerificationKeyHash() {
3565
+ return compiledVerificationKeyHash;
3566
+ }
3567
+ var MINA_CHANNEL_STATE_OPEN = 1n;
3568
+ var MINA_CHANNEL_STATE_UNINITIALIZED = 0n;
3569
+ async function openMinaChannelOnChain(params) {
3570
+ const { Mina, PrivateKey, PublicKey, Field: Field2, AccountUpdate, fetchAccount } = await getO1js();
3571
+ const network = Mina.Network(params.graphqlUrl);
3572
+ Mina.setActiveInstance(network);
3573
+ const txFee = params.feeNanomina ?? 100000000n;
3574
+ const payerKeyBase58 = hexToMinaBase58PrivateKey(params.payerPrivateKey);
3575
+ const payerPrivateKey = PrivateKey.fromBase58(payerKeyBase58);
3576
+ const payerPublicKey = payerPrivateKey.toPublicKey();
3577
+ const zkAppPublicKey = PublicKey.fromBase58(params.zkAppAddress);
3578
+ const readChannelState = async () => {
3579
+ const res = await fetchAccount({ publicKey: zkAppPublicKey });
3580
+ if (res.error || !res.account) {
3581
+ throw new Error(
3582
+ `Mina zkApp account ${params.zkAppAddress} not found on-chain (${String(
3583
+ res.error
3584
+ )}) \u2014 deploy the PaymentChannel zkApp before opening a channel`
3585
+ );
3586
+ }
3587
+ const appState = res.account.zkapp?.appState;
3588
+ const raw = appState?.[3]?.toString() ?? "0";
3589
+ return BigInt(raw);
3590
+ };
3591
+ const readDepositTotal = async () => {
3592
+ const res = await fetchAccount({ publicKey: zkAppPublicKey });
3593
+ if (res.error || !res.account) {
3594
+ throw new Error(
3595
+ `Mina zkApp account ${params.zkAppAddress} not found on-chain (${String(
3596
+ res.error
3597
+ )}) \u2014 deploy the PaymentChannel zkApp before opening a channel`
3598
+ );
3599
+ }
3600
+ const appState = res.account.zkapp?.appState;
3601
+ const raw = appState?.[4]?.toString() ?? "0";
3602
+ return BigInt(raw);
3603
+ };
3604
+ const currentState = await readChannelState();
3605
+ await fetchAccount({ publicKey: payerPublicKey });
3606
+ let opened = false;
3607
+ let initTxHash;
3608
+ let zkApp;
3609
+ const getZkApp = async () => {
3610
+ if (!zkApp) {
3611
+ const PaymentChannel = await getCompiledPaymentChannel();
3612
+ zkApp = new PaymentChannel(zkAppPublicKey);
3613
+ }
3614
+ return zkApp;
3615
+ };
3616
+ if (currentState === MINA_CHANNEL_STATE_UNINITIALIZED) {
3617
+ const channel = await getZkApp();
3618
+ const participantA = payerPublicKey;
3619
+ const participantB = params.peerPublicKey ? PublicKey.fromBase58(params.peerPublicKey) : payerPublicKey;
3620
+ const nonce = Field2(0);
3621
+ const timeoutField = Field2((params.timeout ?? 86400n).toString());
3622
+ const tokenIdField = Field2(params.tokenId ?? "1");
3623
+ await fetchAccount({ publicKey: zkAppPublicKey });
3624
+ await fetchAccount({ publicKey: payerPublicKey });
3625
+ const initTx = await Mina.transaction(
3626
+ { sender: payerPublicKey, fee: Number(txFee) },
3627
+ async () => {
3628
+ await channel.initializeChannel(
3629
+ participantA,
3630
+ participantB,
3631
+ nonce,
3632
+ timeoutField,
3633
+ tokenIdField
3634
+ );
3635
+ }
3636
+ );
3637
+ await initTx.prove();
3638
+ const sentInit = await initTx.sign([payerPrivateKey]).send();
3639
+ initTxHash = sentInit.hash ?? void 0;
3640
+ opened = true;
3641
+ await sentInit.wait();
3642
+ await fetchAccount({ publicKey: zkAppPublicKey });
3643
+ await fetchAccount({ publicKey: payerPublicKey });
3644
+ } else if (currentState !== MINA_CHANNEL_STATE_OPEN) {
3645
+ throw new Error(
3646
+ `Mina channel ${params.zkAppAddress} is in state ${currentState} (not UNINITIALIZED/OPEN) \u2014 cannot open`
3647
+ );
3648
+ }
3649
+ let depositTxHash;
3650
+ if (params.deposit && params.deposit.amount > 0n) {
3651
+ const channel = await getZkApp();
3652
+ await fetchAccount({ publicKey: zkAppPublicKey });
3653
+ const amountField = Field2(params.deposit.amount.toString());
3654
+ const depositTx = await Mina.transaction(
3655
+ { sender: payerPublicKey, fee: Number(txFee) },
3656
+ async () => {
3657
+ await channel.deposit(amountField, payerPublicKey);
3658
+ }
3659
+ );
3660
+ await depositTx.prove();
3661
+ const sentDeposit = await depositTx.sign([payerPrivateKey]).send();
3662
+ depositTxHash = sentDeposit.hash ?? void 0;
3663
+ await sentDeposit.wait();
3664
+ await fetchAccount({ publicKey: zkAppPublicKey });
3665
+ await fetchAccount({ publicKey: payerPublicKey });
3666
+ }
3667
+ let finalState;
3668
+ try {
3669
+ finalState = Number(await readChannelState());
3670
+ } catch {
3671
+ finalState = opened ? Number(MINA_CHANNEL_STATE_OPEN) : Number(currentState);
3672
+ }
3673
+ if (opened && finalState === Number(MINA_CHANNEL_STATE_UNINITIALIZED)) {
3674
+ finalState = Number(MINA_CHANNEL_STATE_OPEN);
3675
+ }
3676
+ void AccountUpdate;
3677
+ let depositTotal;
3678
+ try {
3679
+ depositTotal = await readDepositTotal();
3680
+ } catch {
3681
+ depositTotal = 0n;
3682
+ }
3683
+ return {
3684
+ zkAppAddress: params.zkAppAddress,
3685
+ opened,
3686
+ initTxHash,
3687
+ depositTxHash,
3688
+ channelState: finalState,
3689
+ depositTotal
3690
+ };
3691
+ }
3692
+ var APPSTATE_CHANNEL_HASH = 0;
3693
+ var APPSTATE_CHANNEL_STATE = 3;
3694
+ var STATE_UNINITIALIZED = 0n;
3695
+ var STATE_OPEN = 1n;
3696
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3697
+ async function deployMinaChannelZkApp(params) {
3698
+ const { o1js } = await loadMinaRuntime();
3699
+ const { Mina, PrivateKey, AccountUpdate, fetchAccount } = o1js;
3700
+ const progress = params.onProgress ?? (() => {
3701
+ });
3702
+ const network = Mina.Network(params.graphqlUrl);
3703
+ Mina.setActiveInstance(network);
3704
+ const payerKeyBase58 = hexToMinaBase58PrivateKey(params.payerPrivateKey);
3705
+ const payerPrivateKey = PrivateKey.fromBase58(payerKeyBase58);
3706
+ const payerPublicKey = payerPrivateKey.toPublicKey();
3707
+ progress(
3708
+ "compiling the PaymentChannel circuit (one-time, can take 1-3 minutes)\u2026"
3709
+ );
3710
+ const PaymentChannel = await getCompiledPaymentChannel();
3711
+ const zkAppPrivateKey = PrivateKey.random();
3712
+ const zkAppPublicKey = zkAppPrivateKey.toPublicKey();
3713
+ const zkAppAddress = zkAppPublicKey.toBase58();
3714
+ const zkApp = new PaymentChannel(zkAppPublicKey);
3715
+ await fetchAccount({ publicKey: payerPublicKey });
3716
+ progress(
3717
+ `deploying a dedicated PaymentChannel zkApp ${zkAppAddress} (costs the 1 MINA account-creation fee + tx fee)\u2026`
3718
+ );
3719
+ const fee = Number(params.feeNanomina ?? 100000000n);
3720
+ const deployTx = await Mina.transaction(
3721
+ { sender: payerPublicKey, fee },
3722
+ async () => {
3723
+ AccountUpdate.fundNewAccount(payerPublicKey);
3724
+ await zkApp.deploy();
3725
+ }
3726
+ );
3727
+ await deployTx.prove();
3728
+ const sent = await deployTx.sign([payerPrivateKey, zkAppPrivateKey]).send();
3729
+ const deployTxHash = sent.hash ?? void 0;
3730
+ progress(
3731
+ `deploy tx sent${deployTxHash ? ` (${deployTxHash})` : ""} \u2014 waiting for inclusion (devnet blocks are ~3 minutes)\u2026`
3732
+ );
3733
+ const interval = params.pollIntervalMs ?? 15e3;
3734
+ const budget = params.pollTimeoutMs ?? 54e4;
3735
+ const started = Date.now();
3736
+ try {
3737
+ await sent.wait();
3738
+ } catch {
3739
+ }
3740
+ for (; ; ) {
3741
+ const res = await fetchAccount({ publicKey: zkAppPublicKey });
3742
+ if (!res.error && res.account) break;
3743
+ if (Date.now() - started > budget) {
3744
+ throw new Error(
3745
+ `Mina zkApp ${zkAppAddress} did not appear on-chain within ${Math.round(budget / 6e4)} minutes of the deploy tx${deployTxHash ? ` (${deployTxHash})` : ""} \u2014 check the tx on minascan before retrying (the zkApp key has been recorded)`
3746
+ );
3747
+ }
3748
+ await sleep(interval);
3749
+ }
3750
+ progress(`zkApp ${zkAppAddress} is on-chain (bare \u2014 initialize follows).`);
3751
+ return {
3752
+ zkAppAddress,
3753
+ zkAppPrivateKey: zkAppPrivateKey.toBase58(),
3754
+ feePayer: payerPublicKey.toBase58(),
3755
+ ...deployTxHash !== void 0 ? { deployTxHash } : {},
3756
+ ...getCompiledVerificationKeyHash() !== void 0 ? { vkHash: getCompiledVerificationKeyHash() } : {}
3757
+ };
3758
+ }
3759
+ async function ensureOwnedMinaZkApp(params) {
3760
+ const { o1js } = await loadMinaRuntime();
3761
+ const { Mina, PrivateKey, PublicKey, Field: Field2, Poseidon, fetchAccount } = o1js;
3762
+ const progress = params.onProgress ?? (() => {
3763
+ });
3764
+ const network = Mina.Network(params.graphqlUrl);
3765
+ Mina.setActiveInstance(network);
3766
+ const payerKeyBase58 = hexToMinaBase58PrivateKey(params.payerPrivateKey);
3767
+ const clientPublicKey = PrivateKey.fromBase58(payerKeyBase58).toPublicKey();
3768
+ const peerPublicKey = PublicKey.fromBase58(params.peerPublicKey);
3769
+ if (!Poseidon) {
3770
+ throw new Error(
3771
+ "the loaded o1js runtime does not expose Poseidon \u2014 cannot derive the pair hash"
3772
+ );
3773
+ }
3774
+ const expectedChannelHash = Poseidon.hash([
3775
+ clientPublicKey.x,
3776
+ peerPublicKey.x,
3777
+ Field2(0)
3778
+ ]).toString();
3779
+ const candidates = [];
3780
+ if (params.deployed?.zkAppAddress) {
3781
+ candidates.push({ address: params.deployed.zkAppAddress, ownRecord: true });
3782
+ }
3783
+ if (params.candidateZkAppAddress && params.candidateZkAppAddress !== params.deployed?.zkAppAddress) {
3784
+ candidates.push({
3785
+ address: params.candidateZkAppAddress,
3786
+ ownRecord: false
3787
+ });
3788
+ }
3789
+ for (const candidate of candidates) {
3790
+ let appState;
3791
+ try {
3792
+ const res = await fetchAccount({
3793
+ publicKey: PublicKey.fromBase58(candidate.address)
3794
+ });
3795
+ if (res.error || !res.account) continue;
3796
+ appState = res.account.zkapp?.appState;
3797
+ } catch {
3798
+ continue;
3799
+ }
3800
+ const channelHash = appState?.[APPSTATE_CHANNEL_HASH]?.toString() ?? "";
3801
+ const channelState = BigInt(
3802
+ appState?.[APPSTATE_CHANNEL_STATE]?.toString() ?? "0"
3803
+ );
3804
+ if (channelState === STATE_OPEN && channelHash === expectedChannelHash) {
3805
+ progress(`reusing our open Mina channel zkApp ${candidate.address}.`);
3806
+ return { zkAppAddress: candidate.address, deployed: false };
3807
+ }
3808
+ if (candidate.ownRecord && channelState === STATE_UNINITIALIZED) {
3809
+ progress(
3810
+ `reusing our recorded (uninitialized) Mina zkApp ${candidate.address}.`
3811
+ );
3812
+ return { zkAppAddress: candidate.address, deployed: false };
3813
+ }
3814
+ }
3815
+ const record = await deployMinaChannelZkApp(params);
3816
+ await params.onDeployed?.(record);
3817
+ return { zkAppAddress: record.zkAppAddress, deployed: true, record };
3818
+ }
3819
+
3820
+ export {
3821
+ ToonError,
3822
+ encodeEventToToon,
3823
+ decodeEventFromToon,
3824
+ keccak_256,
3825
+ secp256k1,
3826
+ schnorr,
3827
+ hexToBytes3 as hexToBytes,
3828
+ bigintToBytes32BE,
3829
+ concatBytes2 as concatBytes,
3830
+ balanceProofHashEvm,
3831
+ balanceProofHashSolana,
3832
+ balanceProofFieldsMina,
3833
+ recoverEvmSigner,
3834
+ ILP_PEER_INFO_KIND,
3835
+ parseIlpPeerInfo,
3836
+ isEventExpired,
3837
+ buildBlobStorageRequest,
3838
+ GenesisPeerLoader,
3839
+ base58Encode,
3840
+ base58Decode,
3841
+ hexToMinaBase58PrivateKey,
3842
+ BootstrapService,
3843
+ createDiscoveryTracker,
3844
+ resolveClientNetwork,
3845
+ buildIlpPrepare,
3846
+ openMinaChannelOnChain,
3847
+ deployMinaChannelZkApp,
3848
+ ensureOwnedMinaZkApp
3849
+ };
3850
+ /*! Bundled license information:
3851
+
3852
+ @noble/curves/abstract/weierstrass.js:
3853
+ @noble/curves/secp256k1.js:
3854
+ (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
3855
+ */
3856
+ //# sourceMappingURL=chunk-IYPIOSEF.js.map