@toon-protocol/client 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -153,7 +153,7 @@ async function deriveSolanaKey(seed, accountIndex = 0) {
153
153
  const { ed25519: ed255194 } = await import("@noble/curves/ed25519.js");
154
154
  const encoder = new TextEncoder();
155
155
  let I = hmac(sha512, encoder.encode("ed25519 seed"), seed);
156
- let key = I.slice(0, 32);
156
+ let key2 = I.slice(0, 32);
157
157
  let chainCode = I.slice(32);
158
158
  const indices = [
159
159
  2147483692,
@@ -168,18 +168,18 @@ async function deriveSolanaKey(seed, accountIndex = 0) {
168
168
  for (const index of indices) {
169
169
  const data = new Uint8Array(37);
170
170
  data[0] = 0;
171
- data.set(key, 1);
171
+ data.set(key2, 1);
172
172
  data[33] = index >>> 24 & 255;
173
173
  data[34] = index >>> 16 & 255;
174
174
  data[35] = index >>> 8 & 255;
175
175
  data[36] = index & 255;
176
176
  I = hmac(sha512, chainCode, data);
177
- key = I.slice(0, 32);
177
+ key2 = I.slice(0, 32);
178
178
  chainCode = I.slice(32);
179
179
  }
180
- const publicKeyBytes = ed255194.getPublicKey(key);
180
+ const publicKeyBytes = ed255194.getPublicKey(key2);
181
181
  const keypair = new Uint8Array(64);
182
- keypair.set(key, 0);
182
+ keypair.set(key2, 0);
183
183
  keypair.set(publicKeyBytes, 32);
184
184
  const publicKey = toBase58(publicKeyBytes);
185
185
  return { secretKey: keypair, publicKey };
@@ -894,9 +894,13 @@ function deserializeIlpPacket(buf) {
894
894
  }
895
895
  function deserializeIlpFulfill(buf) {
896
896
  let offset = 1;
897
+ if (buf.length < offset + 32) {
898
+ throw new Error("Buffer underflow reading FULFILL fulfillment");
899
+ }
900
+ const fulfillment = buf.slice(offset, offset + 32);
897
901
  offset += 32;
898
902
  const { value: data } = decodeVarOctetString(buf, offset);
899
- return { type: ILPPacketType.FULFILL, data };
903
+ return { type: ILPPacketType.FULFILL, fulfillment, data };
900
904
  }
901
905
  function deserializeIlpReject(buf) {
902
906
  let offset = 1;
@@ -1207,8 +1211,10 @@ var IsomorphicBtpClient = class {
1207
1211
  this.pendingRequests.delete(id);
1208
1212
  if (json["type"] === "FULFILL") {
1209
1213
  const responseData = json["data"] ? this.base64ToUint8Array(json["data"]) : new Uint8Array(0);
1214
+ const fulfillment = json["fulfillment"] ? this.base64ToUint8Array(json["fulfillment"]) : new Uint8Array(32);
1210
1215
  pending.resolve({
1211
1216
  type: ILPPacketType.FULFILL,
1217
+ fulfillment,
1212
1218
  data: responseData
1213
1219
  });
1214
1220
  } else {
@@ -1269,6 +1275,74 @@ var IsomorphicBtpClient = class {
1269
1275
  }
1270
1276
  };
1271
1277
 
1278
+ // src/utils/condition.ts
1279
+ import { sha256 } from "@noble/hashes/sha2.js";
1280
+ import { randomBytes } from "@noble/hashes/utils.js";
1281
+ var CONDITION_LENGTH = 32;
1282
+ function mintExecutionCondition() {
1283
+ const preimage = randomBytes(CONDITION_LENGTH);
1284
+ return { preimage, condition: sha256(preimage) };
1285
+ }
1286
+ function isZeroCondition(condition) {
1287
+ if (condition === void 0) return true;
1288
+ for (const byte of condition) {
1289
+ if (byte !== 0) return false;
1290
+ }
1291
+ return true;
1292
+ }
1293
+ function assertValidCondition(condition) {
1294
+ if (condition.length !== CONDITION_LENGTH) {
1295
+ throw new Error(
1296
+ `executionCondition must be exactly ${CONDITION_LENGTH} bytes, got ${condition.length}`
1297
+ );
1298
+ }
1299
+ }
1300
+ function fulfillmentMatchesCondition(fulfillment, condition) {
1301
+ if (fulfillment === void 0 || fulfillment.length !== CONDITION_LENGTH) {
1302
+ return false;
1303
+ }
1304
+ const digest = sha256(fulfillment);
1305
+ for (let i = 0; i < CONDITION_LENGTH; i++) {
1306
+ if (digest[i] !== condition[i]) return false;
1307
+ }
1308
+ return true;
1309
+ }
1310
+
1311
+ // src/adapters/ilp-send.ts
1312
+ function resolveExpiresAt(expiresAt, timeoutMs) {
1313
+ if (expiresAt === void 0) return new Date(Date.now() + timeoutMs);
1314
+ return expiresAt instanceof Date ? new Date(expiresAt.getTime()) : new Date(expiresAt);
1315
+ }
1316
+ var FULFILLMENT_MISMATCH_CODE = "F99";
1317
+ var FULFILLMENT_MISMATCH_MESSAGE = "FULFILL fulfillment does not match execution condition (sha256(fulfillment) != executionCondition) \u2014 packet counted failed";
1318
+ function mapIlpResponse(packet, sentCondition) {
1319
+ if (packet.type === ILPPacketType.FULFILL) {
1320
+ const dataField = packet.data.length > 0 ? { data: toBase64(packet.data) } : {};
1321
+ if (sentCondition === void 0 || isZeroCondition(sentCondition)) {
1322
+ return { accepted: true, ...dataField };
1323
+ }
1324
+ if (!fulfillmentMatchesCondition(packet.fulfillment, sentCondition)) {
1325
+ return {
1326
+ accepted: false,
1327
+ code: FULFILLMENT_MISMATCH_CODE,
1328
+ message: FULFILLMENT_MISMATCH_MESSAGE,
1329
+ ...dataField
1330
+ };
1331
+ }
1332
+ return {
1333
+ accepted: true,
1334
+ fulfillment: toBase64(packet.fulfillment),
1335
+ ...dataField
1336
+ };
1337
+ }
1338
+ return {
1339
+ accepted: false,
1340
+ code: packet.code,
1341
+ message: packet.message,
1342
+ ...packet.data.length > 0 ? { data: toBase64(packet.data) } : {}
1343
+ };
1344
+ }
1345
+
1272
1346
  // src/adapters/BtpRuntimeClient.ts
1273
1347
  function isConnectionError(error) {
1274
1348
  const msg = error.message.toLowerCase();
@@ -1324,6 +1398,12 @@ var BtpRuntimeClient = class {
1324
1398
  /**
1325
1399
  * Sends an ILP packet via BTP with auto-reconnect on connection errors.
1326
1400
  * Satisfies IlpClient interface.
1401
+ *
1402
+ * `params` may carry a sender-chosen `executionCondition` and an explicit
1403
+ * `expiresAt` (toon-client#350); omitting both is the legacy zero-condition
1404
+ * path, unchanged. With a non-zero condition the FULFILL preimage is
1405
+ * verified (`sha256(fulfillment) == condition`) and a mismatch is surfaced
1406
+ * as a failed result — see `mapIlpResponse`.
1327
1407
  */
1328
1408
  async sendIlpPacket(params) {
1329
1409
  return withRetry(() => this._sendIlpPacketOnce(params), {
@@ -1339,6 +1419,9 @@ var BtpRuntimeClient = class {
1339
1419
  /**
1340
1420
  * Sends a balance proof claim via BTP protocol data, then sends an ILP packet.
1341
1421
  * Auto-reconnects on connection errors.
1422
+ *
1423
+ * Sender-chosen `executionCondition` / explicit `expiresAt` semantics are
1424
+ * identical to {@link sendIlpPacket}.
1342
1425
  */
1343
1426
  async sendIlpPacketWithClaim(params, claim) {
1344
1427
  return withRetry(() => this._sendIlpPacketWithClaimOnce(params, claim), {
@@ -1381,6 +1464,30 @@ var BtpRuntimeClient = class {
1381
1464
  encodeUtf8(JSON.stringify(claim))
1382
1465
  );
1383
1466
  }
1467
+ /**
1468
+ * Build the ILP PREPARE for a send, applying the sender-chosen condition /
1469
+ * explicit expiry when provided (toon-client#350) and validating that a
1470
+ * non-zero condition is exactly 32 bytes (the OER serializer would
1471
+ * otherwise silently zero-fill it, downgrading the packet to the legacy
1472
+ * unverified class).
1473
+ */
1474
+ buildPrepare(params) {
1475
+ const condition = params.executionCondition;
1476
+ if (condition !== void 0 && !isZeroCondition(condition)) {
1477
+ assertValidCondition(condition);
1478
+ }
1479
+ return {
1480
+ prepare: {
1481
+ type: 12,
1482
+ amount: BigInt(params.amount),
1483
+ destination: params.destination,
1484
+ executionCondition: condition ?? new Uint8Array(32),
1485
+ expiresAt: resolveExpiresAt(params.expiresAt, params.timeout ?? 3e4),
1486
+ data: fromBase64(params.data)
1487
+ },
1488
+ condition
1489
+ };
1490
+ }
1384
1491
  /**
1385
1492
  * Single-attempt ILP packet send. Reconnects if not connected.
1386
1493
  */
@@ -1388,26 +1495,9 @@ var BtpRuntimeClient = class {
1388
1495
  if (!this._isConnected) {
1389
1496
  await this.reconnect();
1390
1497
  }
1391
- const response = await this.btpClient.sendPacket({
1392
- type: 12,
1393
- amount: BigInt(params.amount),
1394
- destination: params.destination,
1395
- executionCondition: new Uint8Array(32),
1396
- expiresAt: new Date(Date.now() + (params.timeout ?? 3e4)),
1397
- data: fromBase64(params.data)
1398
- });
1399
- if (response.type === ILPPacketType.FULFILL) {
1400
- return {
1401
- accepted: true,
1402
- data: response.data.length > 0 ? toBase64(response.data) : void 0
1403
- };
1404
- }
1405
- return {
1406
- accepted: false,
1407
- code: response.code,
1408
- message: response.message,
1409
- data: response.data.length > 0 ? toBase64(response.data) : void 0
1410
- };
1498
+ const { prepare, condition } = this.buildPrepare(params);
1499
+ const response = await this.btpClient.sendPacket(prepare);
1500
+ return mapIlpResponse(response, condition);
1411
1501
  }
1412
1502
  /**
1413
1503
  * Single-attempt claim + ILP packet send. Reconnects if not connected.
@@ -1426,29 +1516,9 @@ var BtpRuntimeClient = class {
1426
1516
  data: encodeUtf8(JSON.stringify(claim))
1427
1517
  }
1428
1518
  ];
1429
- const response = await this.btpClient.sendPacket(
1430
- {
1431
- type: 12,
1432
- amount: BigInt(params.amount),
1433
- destination: params.destination,
1434
- executionCondition: new Uint8Array(32),
1435
- expiresAt: new Date(Date.now() + (params.timeout ?? 3e4)),
1436
- data: fromBase64(params.data)
1437
- },
1438
- protocolData
1439
- );
1440
- if (response.type === ILPPacketType.FULFILL) {
1441
- return {
1442
- accepted: true,
1443
- data: response.data.length > 0 ? toBase64(response.data) : void 0
1444
- };
1445
- }
1446
- return {
1447
- accepted: false,
1448
- code: response.code,
1449
- message: response.message,
1450
- data: response.data.length > 0 ? toBase64(response.data) : void 0
1451
- };
1519
+ const { prepare, condition } = this.buildPrepare(params);
1520
+ const response = await this.btpClient.sendPacket(prepare, protocolData);
1521
+ return mapIlpResponse(response, condition);
1452
1522
  }
1453
1523
  };
1454
1524
 
@@ -1480,6 +1550,12 @@ var HttpIlpClient = class {
1480
1550
  * Send an ILP PREPARE via `POST /ilp` WITHOUT a claim. The connector accepts
1481
1551
  * this only on free/zero-amount routes; paid writes must use
1482
1552
  * {@link sendIlpPacketWithClaim}. Satisfies the IlpClient interface.
1553
+ *
1554
+ * `params` may carry a sender-chosen `executionCondition` and an explicit
1555
+ * `expiresAt` (toon-client#350); omitting both is the legacy zero-condition
1556
+ * path, unchanged. With a non-zero condition the FULFILL preimage is
1557
+ * verified (`sha256(fulfillment) == condition`) and a mismatch is surfaced
1558
+ * as a failed result — see {@link mapIlpResponse}.
1483
1559
  */
1484
1560
  async sendIlpPacket(params) {
1485
1561
  return withRetry(() => this.postPrepare(params), {
@@ -1494,6 +1570,9 @@ var HttpIlpClient = class {
1494
1570
  * as the `ILP-Payment-Channel-Claim` header. `claim` is the SAME JSON object
1495
1571
  * the BTP path attaches as the `payment-channel-claim` protocolData entry —
1496
1572
  * we base64(JSON.stringify(claim)) it, byte-for-byte identical to BTP.
1573
+ *
1574
+ * Sender-chosen `executionCondition` / explicit `expiresAt` semantics are
1575
+ * identical to {@link sendIlpPacket}.
1497
1576
  */
1498
1577
  async sendIlpPacketWithClaim(params, claim) {
1499
1578
  return withRetry(() => this.postPrepare(params, claim), {
@@ -1546,12 +1625,16 @@ var HttpIlpClient = class {
1546
1625
  */
1547
1626
  async postPrepare(params, claim) {
1548
1627
  const requestTimeout = params.timeout ?? this.timeout;
1628
+ const condition = params.executionCondition;
1629
+ if (condition !== void 0 && !isZeroCondition(condition)) {
1630
+ assertValidCondition(condition);
1631
+ }
1549
1632
  const prepare = serializeIlpPrepare({
1550
1633
  type: ILPPacketType.PREPARE,
1551
1634
  amount: BigInt(params.amount),
1552
1635
  destination: params.destination,
1553
- executionCondition: new Uint8Array(32),
1554
- expiresAt: new Date(Date.now() + requestTimeout),
1636
+ executionCondition: condition ?? new Uint8Array(32),
1637
+ expiresAt: resolveExpiresAt(params.expiresAt, requestTimeout),
1555
1638
  data: fromBase64(params.data)
1556
1639
  });
1557
1640
  const headers = {
@@ -1574,7 +1657,7 @@ var HttpIlpClient = class {
1574
1657
  signal: controller.signal
1575
1658
  });
1576
1659
  clearTimeout(timeoutId);
1577
- return await this.mapResponse(response);
1660
+ return await this.mapResponse(response, condition);
1578
1661
  } catch (error) {
1579
1662
  clearTimeout(timeoutId);
1580
1663
  throw this.mapTransportError(error, requestTimeout);
@@ -1584,26 +1667,18 @@ var HttpIlpClient = class {
1584
1667
  * Map a `200 OK` body (OER FULFILL/REJECT) to an IlpSendResult; map a non-2xx
1585
1668
  * to a transport error. Per the wire contract, ILP-level rejects arrive as a
1586
1669
  * 200 + REJECT body — only HTTP non-2xx means a transport-layer failure.
1670
+ *
1671
+ * When `sentCondition` is non-zero the FULFILL preimage is verified against
1672
+ * it; a mismatch yields `accepted: false` (shared `mapIlpResponse` logic,
1673
+ * identical to the BTP path).
1587
1674
  */
1588
- async mapResponse(response) {
1675
+ async mapResponse(response, sentCondition) {
1589
1676
  if (response.ok) {
1590
1677
  const buf = new Uint8Array(await response.arrayBuffer());
1591
1678
  if (buf.length === 0) {
1592
1679
  throw new ConnectorError("Empty 200 body from /ilp (expected OER ILP response)");
1593
1680
  }
1594
- const ilp = deserializeIlpPacket(buf);
1595
- if (ilp.type === ILPPacketType.FULFILL) {
1596
- return {
1597
- accepted: true,
1598
- data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
1599
- };
1600
- }
1601
- return {
1602
- accepted: false,
1603
- code: ilp.code,
1604
- message: ilp.message,
1605
- data: ilp.data.length > 0 ? toBase64(ilp.data) : void 0
1606
- };
1681
+ return mapIlpResponse(deserializeIlpPacket(buf), sentCondition);
1607
1682
  }
1608
1683
  const body = await response.text().catch(() => "");
1609
1684
  const detail = body ? `: ${body}` : "";
@@ -1663,17 +1738,17 @@ function readDiscoveredIlpPeer(peer) {
1663
1738
  }
1664
1739
  function selectIlpTransport(peer, options = {}) {
1665
1740
  const needsDuplex = options.needsDuplex ?? false;
1666
- const http3 = peer.httpEndpoint?.trim() || void 0;
1741
+ const http4 = peer.httpEndpoint?.trim() || void 0;
1667
1742
  const btp = peer.btpEndpoint?.trim() || void 0;
1668
1743
  const canUpgrade = peer.supportsUpgrade === true;
1669
1744
  if (needsDuplex) {
1670
1745
  if (btp) return { kind: "btp", btpEndpoint: btp };
1671
- if (http3 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http3 };
1746
+ if (http4 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http4 };
1672
1747
  throw new Error(
1673
1748
  "Duplex transport required but peer exposes neither a btpEndpoint nor an upgradable httpEndpoint"
1674
1749
  );
1675
1750
  }
1676
- if (http3) return { kind: "http", httpEndpoint: http3, canUpgrade };
1751
+ if (http4) return { kind: "http", httpEndpoint: http4, canUpgrade };
1677
1752
  if (btp) return { kind: "btp", btpEndpoint: btp };
1678
1753
  throw new Error("Peer exposes neither an httpEndpoint nor a btpEndpoint");
1679
1754
  }
@@ -1692,7 +1767,7 @@ import { base58Encode as base58Encode2 } from "@toon-protocol/core";
1692
1767
 
1693
1768
  // src/channel/solana-payment-channel.ts
1694
1769
  import { ed25519 } from "@noble/curves/ed25519.js";
1695
- import { sha256 } from "@noble/hashes/sha2.js";
1770
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1696
1771
  import { base58Encode, base58Decode } from "@toon-protocol/core";
1697
1772
  var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
1698
1773
  var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
@@ -1781,7 +1856,7 @@ function findProgramAddress(seeds, programId) {
1781
1856
  input.set(programId, offset);
1782
1857
  offset += programId.length;
1783
1858
  input.set(PDA_MARKER, offset);
1784
- const hash = sha256(input);
1859
+ const hash = sha2562(input);
1785
1860
  if (!isOnCurve(hash)) return { pda: hash, bump };
1786
1861
  }
1787
1862
  throw new Error("Could not find a viable PDA bump seed");
@@ -1894,13 +1969,13 @@ async function buildAndSendTransaction(rpcUrl, feePayer, instructions, additiona
1894
1969
  isWritable: true
1895
1970
  });
1896
1971
  for (const ix of instructions) {
1897
- for (const key of ix.keys) {
1898
- const existing = accountMap.get(key.pubkey);
1972
+ for (const key2 of ix.keys) {
1973
+ const existing = accountMap.get(key2.pubkey);
1899
1974
  if (existing) {
1900
- existing.isSigner = existing.isSigner || key.isSigner;
1901
- existing.isWritable = existing.isWritable || key.isWritable;
1975
+ existing.isSigner = existing.isSigner || key2.isSigner;
1976
+ existing.isWritable = existing.isWritable || key2.isWritable;
1902
1977
  } else {
1903
- accountMap.set(key.pubkey, { ...key });
1978
+ accountMap.set(key2.pubkey, { ...key2 });
1904
1979
  }
1905
1980
  }
1906
1981
  if (!accountMap.has(ix.programId)) {
@@ -3234,7 +3309,7 @@ var SolanaSigner = class {
3234
3309
 
3235
3310
  // src/signing/mina-signer.ts
3236
3311
  import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey3 } from "@toon-protocol/core";
3237
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
3312
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
3238
3313
  import { bytesToHex } from "@noble/hashes/utils.js";
3239
3314
 
3240
3315
  // src/channel/mina-payment-channel.ts
@@ -3365,7 +3440,7 @@ var DEFAULT_MINA_TOKEN_ID = "MINA";
3365
3440
  var MINA_CLAIM_NETWORK = "devnet";
3366
3441
  function deriveMinaSalt(zkAppAddress, nonce) {
3367
3442
  const digestHex = bytesToHex(
3368
- sha2562(new TextEncoder().encode(`mina-pc-salt:${zkAppAddress}:${nonce}`))
3443
+ sha2563(new TextEncoder().encode(`mina-pc-salt:${zkAppAddress}:${nonce}`))
3369
3444
  );
3370
3445
  const salt = BigInt("0x" + digestHex.slice(0, 60));
3371
3446
  return salt === 0n ? 1n : salt;
@@ -4196,8 +4271,8 @@ async function requestBlobStorage(client, secretKey, params) {
4196
4271
  };
4197
4272
  }
4198
4273
  function extractArweaveTxId(base64Data) {
4199
- const http3 = parseFulfillHttp(base64Data);
4200
- if (!http3.isHttp) {
4274
+ const http4 = parseFulfillHttp(base64Data);
4275
+ if (!http4.isHttp) {
4201
4276
  const legacy = decodeUtf8(fromBase64(base64Data));
4202
4277
  if (!ARWEAVE_TX_ID_REGEX.test(legacy)) {
4203
4278
  throw new Error(
@@ -4206,18 +4281,18 @@ function extractArweaveTxId(base64Data) {
4206
4281
  }
4207
4282
  return legacy;
4208
4283
  }
4209
- if (http3.status < 200 || http3.status >= 300) {
4210
- const detail = http3.body ? ` - ${http3.body}` : "";
4284
+ if (http4.status < 200 || http4.status >= 300) {
4285
+ const detail = http4.body ? ` - ${http4.body}` : "";
4211
4286
  throw new Error(
4212
- `Blob upload failed: DVM returned HTTP ${http3.status} ${http3.statusText}`.trimEnd() + detail
4287
+ `Blob upload failed: DVM returned HTTP ${http4.status} ${http4.statusText}`.trimEnd() + detail
4213
4288
  );
4214
4289
  }
4215
4290
  let parsed;
4216
4291
  try {
4217
- parsed = JSON.parse(http3.body);
4292
+ parsed = JSON.parse(http4.body);
4218
4293
  } catch {
4219
4294
  throw new Error(
4220
- `Blob upload response body was not valid JSON: "${http3.body}"`
4295
+ `Blob upload response body was not valid JSON: "${http4.body}"`
4221
4296
  );
4222
4297
  }
4223
4298
  const body = parsed;
@@ -4235,7 +4310,7 @@ function extractArweaveTxId(base64Data) {
4235
4310
  }
4236
4311
  }
4237
4312
  throw new Error(
4238
- `Blob upload response did not contain a valid Arweave tx ID: "${http3.body}"`
4313
+ `Blob upload response did not contain a valid Arweave tx ID: "${http4.body}"`
4239
4314
  );
4240
4315
  }
4241
4316
 
@@ -4490,6 +4565,172 @@ function parseHttpResponse(bytes) {
4490
4565
  );
4491
4566
  }
4492
4567
 
4568
+ // src/swap/settle-received-claims.ts
4569
+ import {
4570
+ buildSettlementTx,
4571
+ SettlementTxError
4572
+ } from "@toon-protocol/sdk";
4573
+ import {
4574
+ createPublicClient as createPublicClient3,
4575
+ defineChain as defineChain3,
4576
+ fromRlp,
4577
+ http as http3
4578
+ } from "viem";
4579
+ function entryToAccumulatedClaim(entry) {
4580
+ return {
4581
+ packetIndex: 0,
4582
+ sourceAmount: 0n,
4583
+ targetAmount: entry.cumulativeAmount,
4584
+ claimBytes: entry.claimBytes,
4585
+ swapEphemeralPubkey: "",
4586
+ ...entry.claimId !== void 0 ? { claimId: entry.claimId } : {},
4587
+ pair: entry.pair,
4588
+ receivedAt: entry.receivedAt,
4589
+ channelId: entry.channelId,
4590
+ nonce: entry.nonce.toString(),
4591
+ cumulativeAmount: entry.cumulativeAmount.toString(),
4592
+ recipient: entry.recipient,
4593
+ swapSignerAddress: entry.swapSignerAddress
4594
+ };
4595
+ }
4596
+ function parseEvmChainId2(chain) {
4597
+ const parts = chain.split(":");
4598
+ const raw = parts.length >= 3 ? parts[2] : parts[1];
4599
+ const chainId = Number.parseInt(raw ?? "", 10);
4600
+ return Number.isInteger(chainId) && chainId > 0 ? chainId : void 0;
4601
+ }
4602
+ function buildSwapSettlements(params) {
4603
+ return params.entries.map((entry) => {
4604
+ const base = { chain: entry.chain, channelId: entry.channelId };
4605
+ const signer = { address: entry.swapSignerAddress };
4606
+ const contract = params.tokenNetworks?.[entry.chain];
4607
+ if (entry.chain.startsWith("evm")) {
4608
+ const chainId = parseEvmChainId2(entry.chain);
4609
+ if (!contract || chainId === void 0) {
4610
+ return {
4611
+ ...base,
4612
+ error: {
4613
+ code: "MISSING_CHAIN_CONFIG",
4614
+ message: `EVM settlement for ${entry.chain} needs tokenNetworks["${entry.chain}"] (TokenNetwork contract) and a numeric chain id in the chain key.`
4615
+ }
4616
+ };
4617
+ }
4618
+ signer.contractAddress = contract;
4619
+ signer.chainId = chainId;
4620
+ } else if (entry.chain.startsWith("solana")) {
4621
+ if (!contract) {
4622
+ return {
4623
+ ...base,
4624
+ error: {
4625
+ code: "MISSING_CHAIN_CONFIG",
4626
+ message: `Solana settlement for ${entry.chain} needs tokenNetworks["${entry.chain}"] (programId).`
4627
+ }
4628
+ };
4629
+ }
4630
+ signer.programId = contract;
4631
+ }
4632
+ try {
4633
+ const result = buildSettlementTx({
4634
+ claims: [entryToAccumulatedClaim(entry)],
4635
+ signers: { [entry.chain]: signer },
4636
+ recipients: { [entry.chain]: entry.recipient },
4637
+ ...params.minaSignerClient ? { minaSignerClient: params.minaSignerClient } : {}
4638
+ });
4639
+ const firstRejected = result.rejected[0];
4640
+ if (firstRejected) {
4641
+ return {
4642
+ ...base,
4643
+ error: {
4644
+ code: firstRejected.reason,
4645
+ message: firstRejected.details ?? `stored claim for ${entry.chain}/${entry.channelId} failed settlement re-verification`
4646
+ }
4647
+ };
4648
+ }
4649
+ const bundle = result.bundles[0];
4650
+ if (!bundle) {
4651
+ return {
4652
+ ...base,
4653
+ error: {
4654
+ code: "NO_BUNDLE",
4655
+ message: `buildSettlementTx produced no bundle for ${entry.chain}/${entry.channelId}`
4656
+ }
4657
+ };
4658
+ }
4659
+ return { ...base, bundle };
4660
+ } catch (err) {
4661
+ const code = err instanceof SettlementTxError ? err.code : "BUILD_FAILED";
4662
+ return {
4663
+ ...base,
4664
+ error: {
4665
+ code,
4666
+ message: err instanceof Error ? err.message : String(err)
4667
+ }
4668
+ };
4669
+ }
4670
+ });
4671
+ }
4672
+ function decodeEvmSettlementTx(bundle) {
4673
+ const fields = fromRlp(bundle.unsignedTxBytes, "hex");
4674
+ if (!Array.isArray(fields) || fields.length !== 9) {
4675
+ throw new Error(
4676
+ `settlement bundle RLP is not a 9-field unsigned EVM tx (got ${Array.isArray(fields) ? fields.length : typeof fields})`
4677
+ );
4678
+ }
4679
+ const to = fields[3];
4680
+ const data = fields[5];
4681
+ const chainIdHex = fields[6];
4682
+ const chainId = Number.parseInt(chainIdHex === "0x" ? "0x0" : chainIdHex, 16);
4683
+ if (typeof to !== "string" || to.length !== 42) {
4684
+ throw new Error(`settlement tx "to" is not a 20-byte address: ${String(to)}`);
4685
+ }
4686
+ return { to, data: data === "0x" ? "0x" : data, chainId };
4687
+ }
4688
+ async function submitEvmSettlement(bundle, params) {
4689
+ if (bundle.chainKind !== "evm") {
4690
+ throw new Error(
4691
+ `submitEvmSettlement only submits evm bundles (got ${bundle.chainKind} for ${bundle.chain})`
4692
+ );
4693
+ }
4694
+ const { to, data, chainId } = decodeEvmSettlementTx(bundle);
4695
+ const chain = defineChain3({
4696
+ id: chainId,
4697
+ name: bundle.chain,
4698
+ nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
4699
+ rpcUrls: { default: { http: [params.rpcUrl] } }
4700
+ });
4701
+ const publicClient = createPublicClient3({ chain, transport: http3(params.rpcUrl) });
4702
+ const [nonce, gasPrice, gas] = await Promise.all([
4703
+ publicClient.getTransactionCount({
4704
+ address: params.account.address,
4705
+ blockTag: "pending"
4706
+ }),
4707
+ publicClient.getGasPrice(),
4708
+ publicClient.estimateGas({ account: params.account.address, to, data })
4709
+ ]);
4710
+ const signed = await params.account.signTransaction({
4711
+ type: "legacy",
4712
+ chainId,
4713
+ nonce,
4714
+ gasPrice,
4715
+ gas,
4716
+ to,
4717
+ value: 0n,
4718
+ data
4719
+ });
4720
+ const txHash = await publicClient.sendRawTransaction({
4721
+ serializedTransaction: signed
4722
+ });
4723
+ try {
4724
+ const receipt = await publicClient.waitForTransactionReceipt({
4725
+ hash: txHash,
4726
+ timeout: params.timeoutMs ?? 6e4
4727
+ });
4728
+ return { txHash, status: receipt.status };
4729
+ } catch {
4730
+ return { txHash };
4731
+ }
4732
+ }
4733
+
4493
4734
  // src/ToonClient.ts
4494
4735
  var ToonClient = class {
4495
4736
  config;
@@ -4897,6 +5138,14 @@ var ToonClient = class {
4897
5138
  * matching `destination`,
4898
5139
  * (c) neither -> throw MISSING_CLAIM.
4899
5140
  *
5141
+ * A caller may supply a sender-chosen 32-byte `executionCondition`
5142
+ * (`C = sha256(P)`, one fresh preimage per packet — toon-client#350,
5143
+ * rolling-swap spec §3 R1/R2) and an explicit `expiresAt` (R7). Both are
5144
+ * set on the wire by either transport (HTTP `POST /ilp` and BTP), and on
5145
+ * FULFILL the transport verifies `sha256(fulfillment) == condition` —
5146
+ * a mismatch comes back as `accepted: false` (code F99), never a silent
5147
+ * accept. Omitting them keeps today's zero-condition legacy packet.
5148
+ *
4900
5149
  * @throws {ToonClientError} INVALID_STATE / NO_ILP_TRANSPORT / MISSING_CLAIM
4901
5150
  */
4902
5151
  async sendSwapPacket(params) {
@@ -4917,7 +5166,9 @@ var ToonClient = class {
4917
5166
  destination: params.destination,
4918
5167
  amount: String(params.amount),
4919
5168
  data: toBase64(params.toonData),
4920
- timeout: params.timeout ?? 3e4
5169
+ timeout: params.timeout ?? 3e4,
5170
+ ...params.executionCondition ? { executionCondition: params.executionCondition } : {},
5171
+ ...params.expiresAt ? { expiresAt: params.expiresAt } : {}
4921
5172
  },
4922
5173
  claimMessage
4923
5174
  );
@@ -5196,6 +5447,38 @@ var ToonClient = class {
5196
5447
  this.channelManager.setChannelSettled(channelId, nowSec);
5197
5448
  return { channelId, ...r.txHash ? { txHash: r.txHash } : {} };
5198
5449
  }
5450
+ /**
5451
+ * Submit a receive-side swap settlement bundle on-chain (toon-client#352).
5452
+ * The bundle comes from the sdk's `buildSettlementTx` over persisted,
5453
+ * verified chain-B claims (`buildSwapSettlements`); this signs it with the
5454
+ * client's EVM account (the claim recipient) and broadcasts it.
5455
+ *
5456
+ * Env-gated seam: EVM only, and only when `chainRpcUrls[bundle.chain]` is
5457
+ * configured — otherwise this throws a clear config error and callers
5458
+ * surface a built-not-submitted result. Solana submission and the Mina
5459
+ * receive-side co-sign path are explicit follow-ups (see
5460
+ * swap/settle-received-claims.ts module doc).
5461
+ */
5462
+ async settleSwapBundle(bundle) {
5463
+ if (bundle.chainKind !== "evm") {
5464
+ throw new Error(
5465
+ `Swap settlement submission for ${bundle.chainKind} (${bundle.chain}) is not wired yet \u2014 EVM only today.`
5466
+ );
5467
+ }
5468
+ const rpcUrl = this.config.chainRpcUrls?.[bundle.chain];
5469
+ if (!rpcUrl) {
5470
+ throw new Error(
5471
+ `No RPC URL configured for chain "${bundle.chain}" \u2014 add it to chainRpcUrls to enable swap settlement submission.`
5472
+ );
5473
+ }
5474
+ if (!this.evmSigner) {
5475
+ throw new Error("EVM signer not configured (no evmPrivateKey/mnemonic).");
5476
+ }
5477
+ return submitEvmSettlement(bundle, {
5478
+ rpcUrl,
5479
+ account: this.evmSigner.account
5480
+ });
5481
+ }
5199
5482
  /** Where a tracked channel sits in the withdraw journey. */
5200
5483
  getChannelCloseState(channelId) {
5201
5484
  if (!this.channelManager) throw new Error("ChannelManager not initialized");
@@ -5794,6 +6077,238 @@ var HttpConnectorAdmin = class {
5794
6077
  }
5795
6078
  };
5796
6079
 
6080
+ // src/channel/ReceivedClaimStore.ts
6081
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync } from "fs";
6082
+ import { dirname } from "path";
6083
+ function key(chain, channelId) {
6084
+ return `${chain}|${channelId}`;
6085
+ }
6086
+ var JsonFileReceivedClaimStore = class {
6087
+ filePath;
6088
+ constructor(filePath) {
6089
+ this.filePath = filePath;
6090
+ }
6091
+ save(entry) {
6092
+ const data = this.readFile();
6093
+ data[key(entry.chain, entry.channelId)] = {
6094
+ chain: entry.chain,
6095
+ channelId: entry.channelId,
6096
+ nonce: entry.nonce.toString(),
6097
+ cumulativeAmount: entry.cumulativeAmount.toString(),
6098
+ recipient: entry.recipient,
6099
+ swapSignerAddress: entry.swapSignerAddress,
6100
+ claimBytes: Buffer.from(entry.claimBytes).toString("base64"),
6101
+ ...entry.claimId !== void 0 ? { claimId: entry.claimId } : {},
6102
+ pair: entry.pair,
6103
+ receivedAt: entry.receivedAt,
6104
+ updatedAt: entry.updatedAt,
6105
+ ...entry.settledAt !== void 0 ? { settledAt: entry.settledAt } : {},
6106
+ ...entry.settledNonce !== void 0 ? { settledNonce: entry.settledNonce.toString() } : {},
6107
+ ...entry.settleTxHash !== void 0 ? { settleTxHash: entry.settleTxHash } : {}
6108
+ };
6109
+ this.writeFile(data);
6110
+ }
6111
+ load(chain, channelId) {
6112
+ const entry = this.readFile()[key(chain, channelId)];
6113
+ return entry ? fromJson(entry) : void 0;
6114
+ }
6115
+ list() {
6116
+ return Object.values(this.readFile()).map(fromJson);
6117
+ }
6118
+ delete(chain, channelId) {
6119
+ const data = this.readFile();
6120
+ const { [key(chain, channelId)]: _, ...rest } = data;
6121
+ this.writeFile(rest);
6122
+ }
6123
+ readFile() {
6124
+ if (!existsSync2(this.filePath)) {
6125
+ return {};
6126
+ }
6127
+ const raw = readFileSync2(this.filePath, "utf-8");
6128
+ return JSON.parse(raw);
6129
+ }
6130
+ writeFile(data) {
6131
+ mkdirSync(dirname(this.filePath), { recursive: true });
6132
+ writeFileSync2(this.filePath, JSON.stringify(data, null, 2), "utf-8");
6133
+ }
6134
+ };
6135
+ var InMemoryReceivedClaimStore = class {
6136
+ entries = /* @__PURE__ */ new Map();
6137
+ save(entry) {
6138
+ this.entries.set(key(entry.chain, entry.channelId), { ...entry });
6139
+ }
6140
+ load(chain, channelId) {
6141
+ const entry = this.entries.get(key(chain, channelId));
6142
+ return entry ? { ...entry } : void 0;
6143
+ }
6144
+ list() {
6145
+ return [...this.entries.values()].map((e) => ({ ...e }));
6146
+ }
6147
+ delete(chain, channelId) {
6148
+ this.entries.delete(key(chain, channelId));
6149
+ }
6150
+ };
6151
+ function fromJson(entry) {
6152
+ return {
6153
+ chain: entry.chain,
6154
+ channelId: entry.channelId,
6155
+ nonce: BigInt(entry.nonce),
6156
+ cumulativeAmount: BigInt(entry.cumulativeAmount),
6157
+ recipient: entry.recipient,
6158
+ swapSignerAddress: entry.swapSignerAddress,
6159
+ claimBytes: new Uint8Array(Buffer.from(entry.claimBytes, "base64")),
6160
+ ...entry.claimId !== void 0 ? { claimId: entry.claimId } : {},
6161
+ pair: entry.pair,
6162
+ receivedAt: entry.receivedAt,
6163
+ updatedAt: entry.updatedAt,
6164
+ ...entry.settledAt !== void 0 ? { settledAt: entry.settledAt } : {},
6165
+ ...entry.settledNonce !== void 0 ? { settledNonce: BigInt(entry.settledNonce) } : {},
6166
+ ...entry.settleTxHash !== void 0 ? { settleTxHash: entry.settleTxHash } : {}
6167
+ };
6168
+ }
6169
+
6170
+ // src/swap/received-claims.ts
6171
+ import {
6172
+ verifyAccumulatedClaim
6173
+ } from "@toon-protocol/sdk";
6174
+ function hasSettlementMetadata(claim) {
6175
+ return claim.channelId !== void 0 && claim.nonce !== void 0 && claim.cumulativeAmount !== void 0 && claim.recipient !== void 0 && claim.swapSignerAddress !== void 0;
6176
+ }
6177
+ function sameAddress(chain, a, b) {
6178
+ return chain.startsWith("evm") ? a.toLowerCase() === b.toLowerCase() : a === b;
6179
+ }
6180
+ function signatureRejectionCode(reason) {
6181
+ if (reason.startsWith("SIGNER_MISMATCH")) return "SIGNER_MISMATCH";
6182
+ if (reason.startsWith("MINA_VERIFICATION_UNSUPPORTED"))
6183
+ return "MINA_VERIFICATION_UNSUPPORTED";
6184
+ if (reason.startsWith("UNSUPPORTED_CHAIN")) return "UNSUPPORTED_CHAIN";
6185
+ return "SIGNATURE_INVALID";
6186
+ }
6187
+ function ingestReceivedClaims(params) {
6188
+ const now = params.now ?? Date.now;
6189
+ const verified = [];
6190
+ const rejected = [];
6191
+ const legacy = [];
6192
+ let valueReceived = 0n;
6193
+ const watermarks = /* @__PURE__ */ new Map();
6194
+ const reject = (claim, code, message) => {
6195
+ rejected.push({ claim, code, message });
6196
+ };
6197
+ for (const claim of params.claims) {
6198
+ if (!hasSettlementMetadata(claim)) {
6199
+ legacy.push(claim);
6200
+ continue;
6201
+ }
6202
+ const chain = claim.pair.to.chain;
6203
+ if (chain !== params.expectedChain) {
6204
+ reject(
6205
+ claim,
6206
+ "CHAIN_MISMATCH",
6207
+ `claim settles on "${chain}", session expected "${params.expectedChain}"`
6208
+ );
6209
+ continue;
6210
+ }
6211
+ if (!sameAddress(chain, claim.recipient, params.chainRecipient)) {
6212
+ reject(
6213
+ claim,
6214
+ "RECIPIENT_MISMATCH",
6215
+ `claim recipient "${claim.recipient}" is not the session chainRecipient "${params.chainRecipient}"`
6216
+ );
6217
+ continue;
6218
+ }
6219
+ if (params.expectedSignerAddress !== void 0 && !sameAddress(chain, claim.swapSignerAddress, params.expectedSignerAddress)) {
6220
+ reject(
6221
+ claim,
6222
+ "SWAP_SIGNER_MISMATCH",
6223
+ `claim swapSignerAddress "${claim.swapSignerAddress}" does not match the maker's advertised signer "${params.expectedSignerAddress}"`
6224
+ );
6225
+ continue;
6226
+ }
6227
+ const expectedSigner = params.expectedSignerAddress ?? claim.swapSignerAddress;
6228
+ const sig = verifyAccumulatedClaim(
6229
+ claim,
6230
+ { address: expectedSigner },
6231
+ params.minaSignerClient
6232
+ );
6233
+ if (!sig.valid) {
6234
+ reject(claim, signatureRejectionCode(sig.reason), sig.reason);
6235
+ continue;
6236
+ }
6237
+ let nonce;
6238
+ let cumulativeAmount;
6239
+ try {
6240
+ nonce = BigInt(claim.nonce);
6241
+ cumulativeAmount = BigInt(claim.cumulativeAmount);
6242
+ } catch {
6243
+ reject(
6244
+ claim,
6245
+ "MALFORMED_METADATA",
6246
+ `nonce "${claim.nonce}" / cumulativeAmount "${claim.cumulativeAmount}" are not decimal integers`
6247
+ );
6248
+ continue;
6249
+ }
6250
+ const wmKey = `${chain}|${claim.channelId}`;
6251
+ const watermark = watermarks.get(wmKey) ?? params.store.load(chain, claim.channelId);
6252
+ if (watermark) {
6253
+ if (!sameAddress(chain, watermark.swapSignerAddress, expectedSigner)) {
6254
+ reject(
6255
+ claim,
6256
+ "SWAP_SIGNER_MISMATCH",
6257
+ `channel ${claim.channelId} watermark was signed by "${watermark.swapSignerAddress}"; a claim signed by "${expectedSigner}" may not rotate it`
6258
+ );
6259
+ continue;
6260
+ }
6261
+ if (nonce <= watermark.nonce) {
6262
+ reject(
6263
+ claim,
6264
+ "NON_MONOTONIC_NONCE",
6265
+ `nonce ${nonce} does not advance the persisted watermark nonce ${watermark.nonce} for channel ${claim.channelId}`
6266
+ );
6267
+ continue;
6268
+ }
6269
+ if (cumulativeAmount <= watermark.cumulativeAmount) {
6270
+ reject(
6271
+ claim,
6272
+ "NON_MONOTONIC_CUMULATIVE",
6273
+ `cumulativeAmount ${cumulativeAmount} does not advance the persisted watermark ${watermark.cumulativeAmount} for channel ${claim.channelId}`
6274
+ );
6275
+ continue;
6276
+ }
6277
+ }
6278
+ const advance = cumulativeAmount - (watermark?.cumulativeAmount ?? 0n);
6279
+ if (advance < claim.targetAmount) {
6280
+ reject(
6281
+ claim,
6282
+ "CUMULATIVE_SHORTFALL",
6283
+ `cumulative advance ${advance} is less than the packet's targetAmount ${claim.targetAmount} for channel ${claim.channelId}`
6284
+ );
6285
+ continue;
6286
+ }
6287
+ const entry = {
6288
+ chain,
6289
+ channelId: claim.channelId,
6290
+ nonce,
6291
+ cumulativeAmount,
6292
+ recipient: claim.recipient,
6293
+ swapSignerAddress: expectedSigner,
6294
+ claimBytes: claim.claimBytes,
6295
+ ...claim.claimId !== void 0 ? { claimId: claim.claimId } : {},
6296
+ pair: claim.pair,
6297
+ receivedAt: claim.receivedAt,
6298
+ updatedAt: now(),
6299
+ // Settlement bookkeeping survives watermark advances.
6300
+ ...watermark?.settledAt !== void 0 ? { settledAt: watermark.settledAt } : {},
6301
+ ...watermark?.settledNonce !== void 0 ? { settledNonce: watermark.settledNonce } : {},
6302
+ ...watermark?.settleTxHash !== void 0 ? { settleTxHash: watermark.settleTxHash } : {}
6303
+ };
6304
+ params.store.save(entry);
6305
+ watermarks.set(wmKey, entry);
6306
+ verified.push({ claim, watermarkAdvance: advance });
6307
+ valueReceived += advance;
6308
+ }
6309
+ return { verified, rejected, legacy, valueReceived };
6310
+ }
6311
+
5797
6312
  // src/faucet.ts
5798
6313
  function defaultFaucetTimeout(chain) {
5799
6314
  return chain === "mina" ? 12e4 : 3e4;
@@ -6771,9 +7286,9 @@ import {
6771
7286
  scryptSync,
6772
7287
  createCipheriv,
6773
7288
  createDecipheriv,
6774
- randomBytes
7289
+ randomBytes as randomBytes2
6775
7290
  } from "crypto";
6776
- import { writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
7291
+ import { writeFileSync as writeFileSync3, readFileSync as readFileSync3 } from "fs";
6777
7292
  var SCRYPT_N = 2 ** 17;
6778
7293
  var SCRYPT_R = 8;
6779
7294
  var SCRYPT_P = 1;
@@ -6798,16 +7313,16 @@ function encryptMnemonic2(mnemonic, password) {
6798
7313
  if (typeof password !== "string" || password.length === 0) {
6799
7314
  throw new Error("encryptMnemonic: password must be a non-empty string");
6800
7315
  }
6801
- const salt = randomBytes(SALT_LEN);
6802
- const iv = randomBytes(IV_LEN);
6803
- const key = scryptSync(password, salt, SCRYPT_KEY_LEN, {
7316
+ const salt = randomBytes2(SALT_LEN);
7317
+ const iv = randomBytes2(IV_LEN);
7318
+ const key2 = scryptSync(password, salt, SCRYPT_KEY_LEN, {
6804
7319
  N: SCRYPT_N,
6805
7320
  r: SCRYPT_R,
6806
7321
  p: SCRYPT_P,
6807
7322
  maxmem: SCRYPT_MAXMEM
6808
7323
  });
6809
7324
  try {
6810
- const cipher = createCipheriv("aes-256-gcm", key, iv, {
7325
+ const cipher = createCipheriv("aes-256-gcm", key2, iv, {
6811
7326
  authTagLength: AUTH_TAG_LEN
6812
7327
  });
6813
7328
  const ciphertext = Buffer.concat([
@@ -6823,7 +7338,7 @@ function encryptMnemonic2(mnemonic, password) {
6823
7338
  version: 1
6824
7339
  };
6825
7340
  } finally {
6826
- key.fill(0);
7341
+ key2.fill(0);
6827
7342
  }
6828
7343
  }
6829
7344
  function decryptMnemonic2(encrypted, password) {
@@ -6838,14 +7353,14 @@ function decryptMnemonic2(encrypted, password) {
6838
7353
  const iv = Buffer.from(encrypted.iv, "base64");
6839
7354
  const ciphertext = Buffer.from(encrypted.ciphertext, "base64");
6840
7355
  const tag = Buffer.from(encrypted.tag, "base64");
6841
- const key = scryptSync(password, salt, SCRYPT_KEY_LEN, {
7356
+ const key2 = scryptSync(password, salt, SCRYPT_KEY_LEN, {
6842
7357
  N: SCRYPT_N,
6843
7358
  r: SCRYPT_R,
6844
7359
  p: SCRYPT_P,
6845
7360
  maxmem: SCRYPT_MAXMEM
6846
7361
  });
6847
7362
  try {
6848
- const decipher = createDecipheriv("aes-256-gcm", key, iv, {
7363
+ const decipher = createDecipheriv("aes-256-gcm", key2, iv, {
6849
7364
  authTagLength: AUTH_TAG_LEN
6850
7365
  });
6851
7366
  decipher.setAuthTag(tag);
@@ -6861,7 +7376,7 @@ function decryptMnemonic2(encrypted, password) {
6861
7376
  );
6862
7377
  }
6863
7378
  } finally {
6864
- key.fill(0);
7379
+ key2.fill(0);
6865
7380
  }
6866
7381
  }
6867
7382
  function generateKeystore(path, password) {
@@ -6884,7 +7399,7 @@ function importKeystore(path, mnemonic, password) {
6884
7399
  }
6885
7400
  function loadKeystore(path, password) {
6886
7401
  assertNode();
6887
- const raw = readFileSync2(path, "utf8");
7402
+ const raw = readFileSync3(path, "utf8");
6888
7403
  let parsed;
6889
7404
  try {
6890
7405
  parsed = JSON.parse(raw);
@@ -6895,17 +7410,20 @@ function loadKeystore(path, password) {
6895
7410
  }
6896
7411
  function writeKeystoreFile(path, keystore) {
6897
7412
  assertNode();
6898
- writeFileSync2(path, JSON.stringify(keystore, null, 2), {
7413
+ writeFileSync3(path, JSON.stringify(keystore, null, 2), {
6899
7414
  encoding: "utf8",
6900
7415
  mode: 384
6901
7416
  });
6902
7417
  }
6903
7418
  export {
6904
7419
  BtpRuntimeClient,
7420
+ CONDITION_LENGTH,
6905
7421
  ChannelFundingError,
6906
7422
  ChannelManager,
6907
7423
  ConnectorError,
6908
7424
  EvmSigner,
7425
+ FULFILLMENT_MISMATCH_CODE,
7426
+ FULFILLMENT_MISMATCH_MESSAGE,
6909
7427
  GenerativeFallbackRenderer,
6910
7428
  Http402Client,
6911
7429
  HttpConnectorAdmin,
@@ -6914,6 +7432,8 @@ export {
6914
7432
  ILP_CLAIM_HEADER,
6915
7433
  ILP_CLAIM_WRAPPED_HEADER,
6916
7434
  ILP_PEER_ID_HEADER,
7435
+ InMemoryReceivedClaimStore,
7436
+ JsonFileReceivedClaimStore,
6917
7437
  KeyManager,
6918
7438
  KindRegistry,
6919
7439
  MIME_A2UI,
@@ -6930,14 +7450,17 @@ export {
6930
7450
  ValidationError,
6931
7451
  applyDefaults,
6932
7452
  applyNetworkPresets,
7453
+ assertValidCondition,
6933
7454
  buildBackupEvent,
6934
7455
  buildBackupFilter,
6935
7456
  buildConsentRequest,
6936
7457
  buildRendererEventTemplate,
6937
7458
  buildSettlementInfo,
6938
7459
  buildStoreWriteEnvelope,
7460
+ buildSwapSettlements,
6939
7461
  buildUiCoordinate,
6940
7462
  classifyIntent,
7463
+ decodeEvmSettlementTx,
6941
7464
  decryptMnemonic2 as decryptMnemonic,
6942
7465
  defaultFaucetTimeout,
6943
7466
  deriveFromNsec,
@@ -6945,8 +7468,10 @@ export {
6945
7468
  deriveNostrKeyFromMnemonic,
6946
7469
  deterministicGenerator,
6947
7470
  encryptMnemonic2 as encryptMnemonic,
7471
+ entryToAccumulatedClaim,
6948
7472
  extractArweaveTxId,
6949
7473
  extractUiResource,
7474
+ fulfillmentMatchesCondition,
6950
7475
  fundWallet,
6951
7476
  generateKeystore,
6952
7477
  generateMnemonic,
@@ -6954,13 +7479,18 @@ export {
6954
7479
  getNetworkStatus,
6955
7480
  getUiCoordinate,
6956
7481
  guardedRenderDispatch,
7482
+ hasSettlementMetadata,
6957
7483
  httpEndpointToBtpUrl,
6958
7484
  importKeystore,
7485
+ ingestReceivedClaims,
6959
7486
  isInsufficientGasError,
6960
7487
  isPrfSupported,
6961
7488
  isTrustDowngrade,
7489
+ isZeroCondition,
6962
7490
  loadKeystore,
7491
+ mintExecutionCondition,
6963
7492
  parseBackupPayload,
7493
+ parseEvmChainId2 as parseEvmChainId,
6964
7494
  parseFulfillHttp,
6965
7495
  parseFulfillHttpBytes,
6966
7496
  parseHttpResponse,
@@ -6986,6 +7516,7 @@ export {
6986
7516
  selectIlpTransport,
6987
7517
  selectLatestAddressable,
6988
7518
  serializeHttpRequest,
7519
+ submitEvmSettlement,
6989
7520
  validateConfig,
6990
7521
  validateMnemonic,
6991
7522
  verifyRendererTrust,