@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.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import * as _toon_protocol_core from '@toon-protocol/core';
2
- import { IlpPeerInfo, IlpClient, IlpSendResult, NetworkFamilyStatus, ConnectorAdminClient, ConnectorChannelClient, OpenChannelParams, OpenChannelResult, ChannelState } from '@toon-protocol/core';
2
+ import { IlpPeerInfo, IlpSendResult, IlpClient, SwapPair, NetworkFamilyStatus, ConnectorAdminClient, ConnectorChannelClient, OpenChannelParams, OpenChannelResult, ChannelState } from '@toon-protocol/core';
3
3
  export { UI_RENDERER_KIND, UI_TAG, UiCoordinate, buildUiCoordinate, getUiCoordinate, parseUiCoordinate, selectLatestAddressable } from '@toon-protocol/core';
4
4
  import { NostrEvent, EventTemplate } from 'nostr-tools/pure';
5
- import { PrivateKeyAccount } from 'viem/accounts';
5
+ import { MinaSignerClientLike, SettlementBundle } from '@toon-protocol/sdk';
6
+ import { AccumulatedClaim } from '@toon-protocol/sdk/swap';
7
+ import { PrivateKeyAccount, Hex } from 'viem';
8
+ import { PrivateKeyAccount as PrivateKeyAccount$1 } from 'viem/accounts';
6
9
  export { A2uiDecision, ConsentDecision, ConsentRequest, DispatchGuardInfo, DispatchInput, GenerateContext, GeneratedRenderer, GenerativeDecision, GenerativeFallbackOptions, GenerativeFallbackRenderer, GenerativeFallbackResult, GuardedDispatchInput, IntentClassification, KindRegistry, MIME_A2UI, MIME_MCP_APP, McpUiDecision, NativeDecision, PublishBackOptions, RenderBranch, RenderDecision, RenderTrust, RendererGenerator, RendererPin, RendererPinStore, RendererPublisher, RendererSigner, ResolvedCoordinate, SwapApproval, SwapDecision, SwapRejection, SwapRejectionReason, UiResource, VerifyRendererInput, WidgetIntent, buildConsentRequest, buildRendererEventTemplate, classifyIntent, deterministicGenerator, extractUiResource, guardedRenderDispatch, isTrustDowngrade, publishBackCoordinate, renderDeterministicHtml, renderDispatch, resolveRendererMime, resolveUiCoordinate, resolveUiRenderer, verifyRendererTrust } from './render/index.js';
7
10
 
8
11
  /** One on-chain wallet token balance. `amount` is base-unit integer, decimal. */
@@ -640,6 +643,63 @@ declare function requestBlobStorage(client: ToonClient, secretKey: Uint8Array, p
640
643
  */
641
644
  declare function extractArweaveTxId(base64Data: string): string;
642
645
 
646
+ /**
647
+ * Shared sender-side plumbing for sender-chosen execution conditions
648
+ * (toon-client#350; contract: connector `docs/local-delivery-fulfillment-contract.md`,
649
+ * connector#309; spec: toon-meta `docs/rolling-swap.md` §3).
650
+ *
651
+ * Both ILP transports (HTTP `POST /ilp` and BTP) take the SAME extended send
652
+ * params and map FULFILL/REJECT responses through the SAME verifier so the
653
+ * two paths cannot drift:
654
+ *
655
+ * - absent/all-zero `executionCondition` → legacy class: today's behavior,
656
+ * byte-for-byte (zero condition on the wire, no FULFILL verification);
657
+ * - non-zero `executionCondition` → sender-chosen: the condition goes on
658
+ * the PREPARE verbatim and the FULFILL's 32-byte fulfillment MUST hash
659
+ * back to it — a missing/malformed/mismatching preimage is surfaced as a
660
+ * FAILED result (never a silent accept, never retried).
661
+ */
662
+
663
+ /**
664
+ * Send parameters accepted by both ILP transports. Extends the
665
+ * `@toon-protocol/core` `IlpClient` param shape with the sender-chosen
666
+ * condition and an explicit expiry — plain `IlpClient` callers keep working
667
+ * unchanged (both extras are optional; omitting them is the legacy path).
668
+ */
669
+ interface IlpSendParams {
670
+ destination: string;
671
+ amount: string;
672
+ /** Base64 ILP `data` payload. */
673
+ data: string;
674
+ /** Transport timeout in ms; also the default expiry window. */
675
+ timeout?: number;
676
+ /**
677
+ * Sender-chosen 32-byte execution condition `C = sha256(P)` (spec R2).
678
+ * Absent or all-zero = legacy unverified packet (default — ordinary
679
+ * publish/upload writes MUST keep this default).
680
+ */
681
+ executionCondition?: Uint8Array;
682
+ /**
683
+ * Explicit PREPARE `expiresAt` (spec R7). Defaults to `now + timeout`,
684
+ * preserving pre-#350 behavior. Accepts a `Date` or an ISO 8601 string —
685
+ * `@toon-protocol/core` ≥2.1.0's `IlpClient` passes the string form.
686
+ */
687
+ expiresAt?: Date | string;
688
+ }
689
+ /**
690
+ * `IlpSendResult` plus the FULFILL preimage when a sender-chosen condition
691
+ * was verified. Only populated on the sender-chosen path so legacy result
692
+ * objects stay byte-identical.
693
+ */
694
+ interface IlpSendResultWithFulfillment extends IlpSendResult {
695
+ /** Base64 32-byte fulfillment preimage (verified: sha256 == condition). */
696
+ fulfillment?: string;
697
+ }
698
+ /** ILP code used for a client-side fulfillment-verification failure. */
699
+ declare const FULFILLMENT_MISMATCH_CODE = "F99";
700
+ /** Message for a client-side fulfillment-verification failure. */
701
+ declare const FULFILLMENT_MISMATCH_MESSAGE: string;
702
+
643
703
  interface BtpRuntimeClientConfig {
644
704
  btpUrl: string;
645
705
  peerId: string;
@@ -676,23 +736,22 @@ declare class BtpRuntimeClient implements IlpClient {
676
736
  /**
677
737
  * Sends an ILP packet via BTP with auto-reconnect on connection errors.
678
738
  * Satisfies IlpClient interface.
739
+ *
740
+ * `params` may carry a sender-chosen `executionCondition` and an explicit
741
+ * `expiresAt` (toon-client#350); omitting both is the legacy zero-condition
742
+ * path, unchanged. With a non-zero condition the FULFILL preimage is
743
+ * verified (`sha256(fulfillment) == condition`) and a mismatch is surfaced
744
+ * as a failed result — see `mapIlpResponse`.
679
745
  */
680
- sendIlpPacket(params: {
681
- destination: string;
682
- amount: string;
683
- data: string;
684
- timeout?: number;
685
- }): Promise<IlpSendResult>;
746
+ sendIlpPacket(params: IlpSendParams): Promise<IlpSendResult>;
686
747
  /**
687
748
  * Sends a balance proof claim via BTP protocol data, then sends an ILP packet.
688
749
  * Auto-reconnects on connection errors.
750
+ *
751
+ * Sender-chosen `executionCondition` / explicit `expiresAt` semantics are
752
+ * identical to {@link sendIlpPacket}.
689
753
  */
690
- sendIlpPacketWithClaim(params: {
691
- destination: string;
692
- amount: string;
693
- data: string;
694
- timeout?: number;
695
- }, claim: Record<string, unknown>): Promise<IlpSendResult>;
754
+ sendIlpPacketWithClaim(params: IlpSendParams, claim: Record<string, unknown>): Promise<IlpSendResult>;
696
755
  /**
697
756
  * Send a standalone `payment-channel-claim` BTP MESSAGE (no ILP packet
698
757
  * attached). The connector's ClaimReceiver consumes this fire-and-forget
@@ -701,6 +760,14 @@ declare class BtpRuntimeClient implements IlpClient {
701
760
  */
702
761
  sendClaimMessage(claim: Record<string, unknown>): Promise<void>;
703
762
  private _sendClaimMessageOnce;
763
+ /**
764
+ * Build the ILP PREPARE for a send, applying the sender-chosen condition /
765
+ * explicit expiry when provided (toon-client#350) and validating that a
766
+ * non-zero condition is exactly 32 bytes (the OER serializer would
767
+ * otherwise silently zero-fill it, downgrading the packet to the legacy
768
+ * unverified class).
769
+ */
770
+ private buildPrepare;
704
771
  /**
705
772
  * Single-attempt ILP packet send. Reconnects if not connected.
706
773
  */
@@ -792,25 +859,24 @@ declare class HttpIlpClient implements IlpClient {
792
859
  * Send an ILP PREPARE via `POST /ilp` WITHOUT a claim. The connector accepts
793
860
  * this only on free/zero-amount routes; paid writes must use
794
861
  * {@link sendIlpPacketWithClaim}. Satisfies the IlpClient interface.
862
+ *
863
+ * `params` may carry a sender-chosen `executionCondition` and an explicit
864
+ * `expiresAt` (toon-client#350); omitting both is the legacy zero-condition
865
+ * path, unchanged. With a non-zero condition the FULFILL preimage is
866
+ * verified (`sha256(fulfillment) == condition`) and a mismatch is surfaced
867
+ * as a failed result — see {@link mapIlpResponse}.
795
868
  */
796
- sendIlpPacket(params: {
797
- destination: string;
798
- amount: string;
799
- data: string;
800
- timeout?: number;
801
- }): Promise<IlpSendResult>;
869
+ sendIlpPacket(params: IlpSendParams): Promise<IlpSendResult>;
802
870
  /**
803
871
  * Send an ILP PREPARE via `POST /ilp` with the payment-channel claim attached
804
872
  * as the `ILP-Payment-Channel-Claim` header. `claim` is the SAME JSON object
805
873
  * the BTP path attaches as the `payment-channel-claim` protocolData entry —
806
874
  * we base64(JSON.stringify(claim)) it, byte-for-byte identical to BTP.
875
+ *
876
+ * Sender-chosen `executionCondition` / explicit `expiresAt` semantics are
877
+ * identical to {@link sendIlpPacket}.
807
878
  */
808
- sendIlpPacketWithClaim(params: {
809
- destination: string;
810
- amount: string;
811
- data: string;
812
- timeout?: number;
813
- }, claim: unknown): Promise<IlpSendResult>;
879
+ sendIlpPacketWithClaim(params: IlpSendParams, claim: unknown): Promise<IlpSendResult>;
814
880
  /**
815
881
  * Upgrade to a duplex BTP session over the SAME endpoint.
816
882
  *
@@ -838,6 +904,10 @@ declare class HttpIlpClient implements IlpClient {
838
904
  * Map a `200 OK` body (OER FULFILL/REJECT) to an IlpSendResult; map a non-2xx
839
905
  * to a transport error. Per the wire contract, ILP-level rejects arrive as a
840
906
  * 200 + REJECT body — only HTTP non-2xx means a transport-layer failure.
907
+ *
908
+ * When `sentCondition` is non-zero the FULFILL preimage is verified against
909
+ * it; a mismatch yields `accepted: false` (shared `mapIlpResponse` logic,
910
+ * identical to the BTP path).
841
911
  */
842
912
  private mapResponse;
843
913
  private mapTransportError;
@@ -1051,6 +1121,173 @@ declare function serializeHttpRequest(req: {
1051
1121
  */
1052
1122
  declare function parseHttpResponse(bytes: Uint8Array): Response;
1053
1123
 
1124
+ /**
1125
+ * The persisted receive-side watermark for one swap target channel: the
1126
+ * HIGHEST-NONCE verified chain-B claim per `(chain, channelId)` (toon-client
1127
+ * issue #352, rolling-swap spec toon-meta docs/rolling-swap.md §3.2/§9).
1128
+ *
1129
+ * Claims are cumulative balance proofs — a higher-nonce claim supersedes every
1130
+ * earlier one — so persisting only the winner per channel is lossless for
1131
+ * settlement: `buildSettlementTx` redeems exactly this claim. Superseded claims
1132
+ * are informational and dropped.
1133
+ */
1134
+ interface ReceivedClaimEntry {
1135
+ /** Target chain the claim settles on (`pair.to.chain`, e.g. `evm:base:8453`). */
1136
+ chain: string;
1137
+ /** Payment-channel id on the target chain (0x-hex for EVM, base58 otherwise). */
1138
+ channelId: string;
1139
+ /** Balance-proof nonce (strictly increasing per channel). */
1140
+ nonce: bigint;
1141
+ /** Cumulative transferred amount, target micro-units. */
1142
+ cumulativeAmount: bigint;
1143
+ /** Recipient address the claim pays (the sender's `chainRecipient`). */
1144
+ recipient: string;
1145
+ /** Swap peer's on-chain signer address the signature verified against. */
1146
+ swapSignerAddress: string;
1147
+ /** The verified signed claim bytes (chain-specific encoding). */
1148
+ claimBytes: Uint8Array;
1149
+ /** Optional swap-side claim id. */
1150
+ claimId?: string;
1151
+ /** The SwapPair the claim was priced against (settlement-time routing). */
1152
+ pair: SwapPair;
1153
+ /** Unix ms the winning claim was accepted off the wire. */
1154
+ receivedAt: number;
1155
+ /** Unix ms this entry was last advanced. */
1156
+ updatedAt: number;
1157
+ /** Unix ms of the last successful on-chain settlement submission. */
1158
+ settledAt?: number;
1159
+ /** Watermark nonce redeemed by that settlement (claims ≤ this are settled). */
1160
+ settledNonce?: bigint;
1161
+ /** Tx hash of the last settlement submission. */
1162
+ settleTxHash?: string;
1163
+ }
1164
+ /**
1165
+ * Persistence interface for received (chain-B) swap claims. Mirrors
1166
+ * {@link ChannelStore}'s sync surface; keyed by `(chain, channelId)`.
1167
+ */
1168
+ interface ReceivedClaimStore {
1169
+ save(entry: ReceivedClaimEntry): void;
1170
+ load(chain: string, channelId: string): ReceivedClaimEntry | undefined;
1171
+ list(): ReceivedClaimEntry[];
1172
+ delete(chain: string, channelId: string): void;
1173
+ }
1174
+ /**
1175
+ * JSON file-backed {@link ReceivedClaimStore}. Synchronous I/O to match the
1176
+ * `JsonFileChannelStore` pattern (`ChannelStore.ts`); the parent directory is
1177
+ * created on first save so a fresh daemon home works out of the box.
1178
+ */
1179
+ declare class JsonFileReceivedClaimStore implements ReceivedClaimStore {
1180
+ private readonly filePath;
1181
+ constructor(filePath: string);
1182
+ save(entry: ReceivedClaimEntry): void;
1183
+ load(chain: string, channelId: string): ReceivedClaimEntry | undefined;
1184
+ list(): ReceivedClaimEntry[];
1185
+ delete(chain: string, channelId: string): void;
1186
+ private readFile;
1187
+ private writeFile;
1188
+ }
1189
+ /**
1190
+ * In-memory {@link ReceivedClaimStore} for tests and path-less configs. NOT
1191
+ * restart-safe — a daemon should always be given a `JsonFileReceivedClaimStore`.
1192
+ */
1193
+ declare class InMemoryReceivedClaimStore implements ReceivedClaimStore {
1194
+ private readonly entries;
1195
+ save(entry: ReceivedClaimEntry): void;
1196
+ load(chain: string, channelId: string): ReceivedClaimEntry | undefined;
1197
+ list(): ReceivedClaimEntry[];
1198
+ delete(chain: string, channelId: string): void;
1199
+ }
1200
+
1201
+ /**
1202
+ * Receive-side swap settlement (toon-client#352): turn persisted
1203
+ * {@link ReceivedClaimEntry} watermarks into on-chain settlement submissions.
1204
+ *
1205
+ * Building is pure and chain-agnostic — `buildSettlementTx` (sdk) re-verifies
1206
+ * the stored claim's signature and produces one {@link SettlementBundle} per
1207
+ * `(chain, channelId)` with the FINAL watermark, so N received advances net to
1208
+ * one on-chain close per channel (spec §9). Submission is chain-gated:
1209
+ *
1210
+ * - **EVM** — implemented here ({@link submitEvmSettlement}): the bundle's
1211
+ * unsigned RLP is decoded for `to`/calldata, gas is estimated against the
1212
+ * configured RPC, and the tx is signed by the client's EVM account (the
1213
+ * claim recipient) and broadcast. Real submission is therefore env-gated on
1214
+ * `chainRpcUrls[chain]` — absent RPC config yields a built-not-submitted
1215
+ * result, never a throw.
1216
+ * - **Solana** — the bundle carries a serialized Message; a submission path is
1217
+ * not wired yet (follow-up under toon-meta#145).
1218
+ * - **Mina** — receive-side redemption needs a co-sign (`claimFromChannel`
1219
+ * takes `signatureA` AND `signatureB`) plus o1js proof generation; the
1220
+ * client has no receive-side co-sign path. Explicitly out of scope for #352
1221
+ * (documented gap; follow-up: toon-client#357).
1222
+ */
1223
+
1224
+ /** One per-channel settlement build outcome (result-shaped, never thrown). */
1225
+ interface SwapSettlementBuild {
1226
+ chain: string;
1227
+ channelId: string;
1228
+ /** The bundle, when the claim verified and the chain config sufficed. */
1229
+ bundle?: SettlementBundle;
1230
+ /** Why no bundle was produced (missing config, failed re-verification, …). */
1231
+ error?: {
1232
+ code: string;
1233
+ message: string;
1234
+ };
1235
+ }
1236
+ interface BuildSwapSettlementsParams {
1237
+ /** Persisted watermarks to settle (typically `store.list()`, filtered). */
1238
+ entries: readonly ReceivedClaimEntry[];
1239
+ /**
1240
+ * Per-chain settlement contract: EVM TokenNetwork address / Solana
1241
+ * programId, keyed by the FULL chain key (e.g. `evm:base:8453`). Matches the
1242
+ * daemon config's `tokenNetworks` map.
1243
+ */
1244
+ tokenNetworks?: Record<string, string>;
1245
+ /** Pre-loaded `mina-signer` client for `mina:*` re-verification. */
1246
+ minaSignerClient?: MinaSignerClientLike;
1247
+ }
1248
+ /** Rebuild the sdk `AccumulatedClaim` shape from a persisted entry. */
1249
+ declare function entryToAccumulatedClaim(entry: ReceivedClaimEntry): AccumulatedClaim;
1250
+ /**
1251
+ * Parse the numeric chain id off an `evm:{network}:{chainId}` / `evm:{chainId}`
1252
+ * chain key. Returns undefined for malformed keys (reported result-shaped).
1253
+ */
1254
+ declare function parseEvmChainId(chain: string): number | undefined;
1255
+ /**
1256
+ * Build one settlement bundle per persisted entry via the sdk's
1257
+ * `buildSettlementTx` (signature re-verified at settle time — a tampered
1258
+ * store never reaches a submission). Per-entry isolation: one bad channel
1259
+ * cannot block the others.
1260
+ */
1261
+ declare function buildSwapSettlements(params: BuildSwapSettlementsParams): SwapSettlementBuild[];
1262
+ interface SubmitEvmSettlementParams {
1263
+ /** JSON-RPC endpoint of the bundle's chain (`chainRpcUrls[bundle.chain]`). */
1264
+ rpcUrl: string;
1265
+ /** The claim recipient's EVM account (signs + pays gas for the redeem). */
1266
+ account: PrivateKeyAccount;
1267
+ /** Receipt wait bound, ms (default 60_000). */
1268
+ timeoutMs?: number;
1269
+ }
1270
+ interface SubmitEvmSettlementResult {
1271
+ txHash: string;
1272
+ /** Receipt status when the wait succeeded within the bound. */
1273
+ status?: 'success' | 'reverted';
1274
+ }
1275
+ /**
1276
+ * Decode the unsigned legacy-RLP tx a settlement bundle carries.
1277
+ * Layout (EIP-155 unsigned): [nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0].
1278
+ */
1279
+ declare function decodeEvmSettlementTx(bundle: SettlementBundle): {
1280
+ to: Hex;
1281
+ data: Hex;
1282
+ chainId: number;
1283
+ };
1284
+ /**
1285
+ * Sign + broadcast an EVM settlement bundle from the recipient's account.
1286
+ * Gas/nonce are read from the RPC; the tx is signed locally (non-custodial)
1287
+ * and sent as a raw transaction, then awaited to a receipt (bounded).
1288
+ */
1289
+ declare function submitEvmSettlement(bundle: SettlementBundle, params: SubmitEvmSettlementParams): Promise<SubmitEvmSettlementResult>;
1290
+
1054
1291
  /**
1055
1292
  * ToonClient - High-level client for interacting with TOON network.
1056
1293
  *
@@ -1254,6 +1491,14 @@ declare class ToonClient {
1254
1491
  * matching `destination`,
1255
1492
  * (c) neither -> throw MISSING_CLAIM.
1256
1493
  *
1494
+ * A caller may supply a sender-chosen 32-byte `executionCondition`
1495
+ * (`C = sha256(P)`, one fresh preimage per packet — toon-client#350,
1496
+ * rolling-swap spec §3 R1/R2) and an explicit `expiresAt` (R7). Both are
1497
+ * set on the wire by either transport (HTTP `POST /ilp` and BTP), and on
1498
+ * FULFILL the transport verifies `sha256(fulfillment) == condition` —
1499
+ * a mismatch comes back as `accepted: false` (code F99), never a silent
1500
+ * accept. Omitting them keeps today's zero-condition legacy packet.
1501
+ *
1257
1502
  * @throws {ToonClientError} INVALID_STATE / NO_ILP_TRANSPORT / MISSING_CLAIM
1258
1503
  */
1259
1504
  sendSwapPacket(params: {
@@ -1262,6 +1507,10 @@ declare class ToonClient {
1262
1507
  toonData: Uint8Array;
1263
1508
  timeout?: number;
1264
1509
  claim?: SignedBalanceProof;
1510
+ /** Sender-chosen 32-byte execution condition; absent/zero = legacy. */
1511
+ executionCondition?: Uint8Array;
1512
+ /** Explicit ILP expiry; defaults to `now + timeout` in the transport. */
1513
+ expiresAt?: Date;
1265
1514
  }): Promise<IlpSendResult>;
1266
1515
  /**
1267
1516
  * Build a BTP claim message from a pre-signed balance proof using the
@@ -1393,6 +1642,19 @@ declare class ToonClient {
1393
1642
  channelId: string;
1394
1643
  txHash?: string;
1395
1644
  }>;
1645
+ /**
1646
+ * Submit a receive-side swap settlement bundle on-chain (toon-client#352).
1647
+ * The bundle comes from the sdk's `buildSettlementTx` over persisted,
1648
+ * verified chain-B claims (`buildSwapSettlements`); this signs it with the
1649
+ * client's EVM account (the claim recipient) and broadcasts it.
1650
+ *
1651
+ * Env-gated seam: EVM only, and only when `chainRpcUrls[bundle.chain]` is
1652
+ * configured — otherwise this throws a clear config error and callers
1653
+ * surface a built-not-submitted result. Solana submission and the Mina
1654
+ * receive-side co-sign path are explicit follow-ups (see
1655
+ * swap/settle-received-claims.ts module doc).
1656
+ */
1657
+ settleSwapBundle(bundle: SettlementBundle): Promise<SubmitEvmSettlementResult>;
1396
1658
  /** Where a tracked channel sits in the withdraw journey. */
1397
1659
  getChannelCloseState(channelId: string): 'open' | 'closing' | 'settleable' | 'settled';
1398
1660
  getSettleableAt(channelId: string): bigint | undefined;
@@ -2075,7 +2337,7 @@ declare class EvmSigner {
2075
2337
  /** ChainSigner identifier — EVM address */
2076
2338
  get signerIdentifier(): string;
2077
2339
  /** Viem PrivateKeyAccount — usable with walletClient for on-chain transactions */
2078
- get account(): PrivateKeyAccount;
2340
+ get account(): PrivateKeyAccount$1;
2079
2341
  /**
2080
2342
  * Signs a balance proof using EIP-712 typed data.
2081
2343
  *
@@ -2674,6 +2936,105 @@ declare class ChannelManager {
2674
2936
  */
2675
2937
  declare function readMinaDepositTotal(graphqlUrl: string, zkAppAddress: string, fetchImpl?: typeof fetch): Promise<bigint>;
2676
2938
 
2939
+ /**
2940
+ * Receive-side swap-claim ingestion + verification (toon-client#352, part of
2941
+ * the rolling-swap epic toon-meta#145; spec: toon-meta docs/rolling-swap.md
2942
+ * §3.2/§9 dependency 1).
2943
+ *
2944
+ * The deployed client used to accept swapped-in chain-B claims blind: no
2945
+ * signature check, no watermark, no persistence — `buildSettlementTx` /
2946
+ * `verifyAccumulatedClaim` had zero call sites in this repo. This module is
2947
+ * the missing pipeline: every accumulated claim harvested from a swap stream
2948
+ * is VERIFIED at receipt time and, only if it passes, persisted as the
2949
+ * highest-nonce watermark for its `(chain, channelId)` in a
2950
+ * {@link ReceivedClaimStore}. A claim that fails verification is NEVER counted
2951
+ * as value received — failures are loud and result-shaped, not thrown.
2952
+ *
2953
+ * Verification order per claim (cheapest first, every check fail-closed):
2954
+ * 1. settlement metadata completeness — a claim missing any of channelId /
2955
+ * nonce / cumulativeAmount / recipient / swapSignerAddress cannot be
2956
+ * settled (`MISSING_SETTLEMENT_METADATA` later) and is bucketed `legacy`
2957
+ * (the pre-rename-peer path, #349) rather than rejected: the existing
2958
+ * loud swap-time warning stays the surface for those.
2959
+ * 2. chain consistency — the claim must settle on the session's target chain.
2960
+ * 3. recipient — must equal the session `chainRecipient` (EVM
2961
+ * case-insensitive), the anti-substitution check.
2962
+ * 4. advertised signer — when the caller supplies the maker's advertised
2963
+ * `swapSignerAddress` (kind:10032 discovery / operator config), the
2964
+ * claim's self-reported signer must match (`SWAP_SIGNER_MISMATCH`,
2965
+ * sdk 2.x vocabulary).
2966
+ * 5. signature — `verifyAccumulatedClaim` (sdk) against the expected signer:
2967
+ * the advertised address when given, else the claim's self-reported one
2968
+ * (which then still proves the claim is internally consistent and pins
2969
+ * the address the settlement tx will verify against on-chain).
2970
+ * 6. signer pinning — a claim may not silently rotate the signer of an
2971
+ * already-persisted watermark for the same channel.
2972
+ * 7. nonce/cumulative monotonicity vs the locally persisted watermark —
2973
+ * strictly increasing nonce AND cumulative; the cumulative advance must
2974
+ * cover this packet's `targetAmount` (an under-delivering advance means
2975
+ * the maker short-paid the packet).
2976
+ */
2977
+
2978
+ /** Why a claim was rejected at receipt time. Codes are stable API. */
2979
+ type ReceivedClaimRejectionCode = 'CHAIN_MISMATCH' | 'RECIPIENT_MISMATCH' | 'SWAP_SIGNER_MISMATCH' | 'SIGNER_MISMATCH' | 'SIGNATURE_INVALID' | 'MINA_VERIFICATION_UNSUPPORTED' | 'UNSUPPORTED_CHAIN' | 'NON_MONOTONIC_NONCE' | 'NON_MONOTONIC_CUMULATIVE' | 'CUMULATIVE_SHORTFALL' | 'MALFORMED_METADATA';
2980
+ interface ReceivedClaimRejection {
2981
+ claim: AccumulatedClaim;
2982
+ code: ReceivedClaimRejectionCode;
2983
+ message: string;
2984
+ }
2985
+ interface VerifiedReceivedClaim {
2986
+ claim: AccumulatedClaim;
2987
+ /** How far this claim advanced the persisted cumulative watermark. */
2988
+ watermarkAdvance: bigint;
2989
+ }
2990
+ interface IngestReceivedClaimsParams {
2991
+ /** Accumulated claims off a swap stream (`streamSwap().claims`), in order. */
2992
+ claims: readonly AccumulatedClaim[];
2993
+ /** The session's target chain (`pair.to.chain` of the requested swap). */
2994
+ expectedChain: string;
2995
+ /** The session's payout address on `expectedChain`. */
2996
+ chainRecipient: string;
2997
+ /**
2998
+ * The maker's ADVERTISED on-chain signer address for `expectedChain`
2999
+ * (kind:10032 discovery or operator-supplied). When set, a claim whose
3000
+ * self-reported `swapSignerAddress` differs is rejected with
3001
+ * `SWAP_SIGNER_MISMATCH` and the signature is verified against THIS address,
3002
+ * never the claim's own.
3003
+ */
3004
+ expectedSignerAddress?: string;
3005
+ /** Durable watermark store; verified claims are persisted here. */
3006
+ store: ReceivedClaimStore;
3007
+ /** Pre-loaded `mina-signer` client — required to verify `mina:*` claims. */
3008
+ minaSignerClient?: MinaSignerClientLike;
3009
+ /** Clock seam for tests. */
3010
+ now?: () => number;
3011
+ }
3012
+ interface IngestReceivedClaimsResult {
3013
+ /** Claims that passed every check and advanced a persisted watermark. */
3014
+ verified: VerifiedReceivedClaim[];
3015
+ /** Claims that failed verification. NEVER counted as value received. */
3016
+ rejected: ReceivedClaimRejection[];
3017
+ /**
3018
+ * Claims missing settlement metadata (pre-rename / legacy swap peer, #349).
3019
+ * Not verified, not persisted, surfaced through the existing swap-time
3020
+ * warning — behavior for legacy no-metadata swaps is unchanged.
3021
+ */
3022
+ legacy: AccumulatedClaim[];
3023
+ /** Total watermark advance across verified claims (target micro-units). */
3024
+ valueReceived: bigint;
3025
+ }
3026
+ /** True when the claim carries every settlement-context field. */
3027
+ declare function hasSettlementMetadata(claim: AccumulatedClaim): claim is AccumulatedClaim & Required<Pick<AccumulatedClaim, 'channelId' | 'nonce' | 'cumulativeAmount' | 'recipient' | 'swapSignerAddress'>>;
3028
+ /**
3029
+ * Verify a batch of received chain-B claims and persist the winning watermark
3030
+ * per `(chain, channelId)`. See the module doc for the check ladder.
3031
+ *
3032
+ * Result-shaped: never throws on a bad claim — it lands in `rejected` with a
3033
+ * stable code, and later claims are still processed (a channel's watermark
3034
+ * only advances through claims that verified).
3035
+ */
3036
+ declare function ingestReceivedClaims(params: IngestReceivedClaimsParams): IngestReceivedClaimsResult;
3037
+
2677
3038
  /**
2678
3039
  * Configuration options for retry behavior with exponential backoff.
2679
3040
  */
@@ -2809,6 +3170,56 @@ declare function parseFulfillHttpBytes(bytes: Uint8Array): ParsedFulfillHttp;
2809
3170
  */
2810
3171
  declare function parseFulfillHttp(base64Data: string): ParsedFulfillHttp;
2811
3172
 
3173
+ /**
3174
+ * Sender-chosen ILP execution conditions (toon-client#350, rolling-swap
3175
+ * prerequisite — toon-meta#145 §3 R1/R2).
3176
+ *
3177
+ * Contract (normative: connector `docs/local-delivery-fulfillment-contract.md`,
3178
+ * connector#309):
3179
+ * - An ABSENT or ALL-ZERO (32×0x00) `executionCondition` is the LEGACY
3180
+ * class: no hashlock, no verification — today's publish/upload writes.
3181
+ * - Any NON-ZERO condition is SENDER-CHOSEN: the sender mints a fresh
3182
+ * random 32-byte preimage `P` per packet, sets `C = sha256(P)` on the
3183
+ * PREPARE, and on FULFILL MUST verify that the returned fulfillment
3184
+ * hashes back to `C` — a missing/malformed/mismatching fulfillment is a
3185
+ * hard failure (the packet is counted failed, never silently accepted).
3186
+ *
3187
+ * Isomorphic: @noble/hashes only (no Buffer, no node:crypto).
3188
+ */
3189
+ /** Exact byte length of an ILP execution condition / fulfillment preimage. */
3190
+ declare const CONDITION_LENGTH = 32;
3191
+ /** A freshly minted per-packet hashlock: `condition = sha256(preimage)`. */
3192
+ interface ExecutionConditionPair {
3193
+ /** Random 32-byte preimage `P` — reveal is the commit act; never reuse. */
3194
+ preimage: Uint8Array;
3195
+ /** `C = sha256(P)` — goes on the PREPARE's `executionCondition`. */
3196
+ condition: Uint8Array;
3197
+ }
3198
+ /**
3199
+ * Mint a fresh random 32-byte preimage and its sha256 condition (spec R1).
3200
+ * Mint one PER PACKET: a reused preimage lets any observer of packet *i*
3201
+ * fulfill packet *i+1* without the sender's consent.
3202
+ */
3203
+ declare function mintExecutionCondition(): ExecutionConditionPair;
3204
+ /**
3205
+ * True when `condition` selects the LEGACY (unverified) class: absent or
3206
+ * all-zero. The OER wire treats absent and 32×0x00 identically.
3207
+ */
3208
+ declare function isZeroCondition(condition: Uint8Array | undefined): boolean;
3209
+ /**
3210
+ * Validate a caller-supplied execution condition before it goes on the wire.
3211
+ * @throws {Error} When the condition is not exactly 32 bytes — the OER
3212
+ * serializer would otherwise silently zero-fill it, downgrading a
3213
+ * sender-chosen packet to the legacy unverified class.
3214
+ */
3215
+ declare function assertValidCondition(condition: Uint8Array): void;
3216
+ /**
3217
+ * True iff `fulfillment` is exactly 32 bytes and `sha256(fulfillment)`
3218
+ * equals `condition` — the sender-side FULFILL check (spec R6's mirror).
3219
+ * Fail-closed: an undefined/short/long fulfillment never matches.
3220
+ */
3221
+ declare function fulfillmentMatchesCondition(fulfillment: Uint8Array | undefined, condition: Uint8Array): boolean;
3222
+
2812
3223
  /**
2813
3224
  * Settlement info produced by buildSettlementInfo().
2814
3225
  * Extends the core SettlementConfig shape with ilpAddress for client use.
@@ -3326,4 +3737,4 @@ declare function loadKeystore(path: string, password: string): string;
3326
3737
  */
3327
3738
  declare function writeKeystoreFile(path: string, keystore: EncryptedKeystore): void;
3328
3739
 
3329
- export { type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type ChainMetadata, type ChainSigner, ChannelFundingError, ChannelManager, type ClaimMessage, type ClaimResolver, ConnectorError, type DiscoveredIlpPeer, type EVMClaimMessage, type EncryptedKeystore, EvmSigner, type FaucetChain, type FundWalletOptions, type FundWalletResult, type H402FetchOptions, Http402Client, type Http402ClientConfig, HttpConnectorAdmin, type HttpConnectorAdminConfig, HttpIlpClient, type HttpIlpClientConfig, type HttpIlpClientFactory, HttpRuntimeClient, type HttpRuntimeClientConfig, ILP_CLAIM_HEADER, ILP_CLAIM_WRAPPED_HEADER, ILP_PEER_ID_HEADER, type IlpTransportChoice, KeyManager, type KeyManagerConfig, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PublishEventResult, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type ToonChannelAccept, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, ValidationError, type VaultData, type WalletBalance, type WalletBalanceSources, type WalletChainBalances, type WalletTokenAmount, applyDefaults, applyNetworkPresets, buildBackupEvent, buildBackupFilter, buildSettlementInfo, buildStoreWriteEnvelope, decryptMnemonic, defaultFaucetTimeout, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, extractArweaveTxId, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, httpEndpointToBtpUrl, importKeystore, isInsufficientGasError, isPrfSupported, loadKeystore, parseBackupPayload, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readEvmNativeBalance, readEvmTokenBalance, readMinaBalance, readMinaDepositTotal, readSolanaNativeBalance, readSolanaTokenBalance, readWalletBalances, requestBlobStorage, selectIlpTransport, serializeHttpRequest, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
3740
+ export { type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type BuildSwapSettlementsParams, CONDITION_LENGTH, type ChainMetadata, type ChainSigner, ChannelFundingError, ChannelManager, type ClaimMessage, type ClaimResolver, ConnectorError, type DiscoveredIlpPeer, type EVMClaimMessage, type EncryptedKeystore, EvmSigner, type ExecutionConditionPair, FULFILLMENT_MISMATCH_CODE, FULFILLMENT_MISMATCH_MESSAGE, type FaucetChain, type FundWalletOptions, type FundWalletResult, type H402FetchOptions, Http402Client, type Http402ClientConfig, HttpConnectorAdmin, type HttpConnectorAdminConfig, HttpIlpClient, type HttpIlpClientConfig, type HttpIlpClientFactory, HttpRuntimeClient, type HttpRuntimeClientConfig, ILP_CLAIM_HEADER, ILP_CLAIM_WRAPPED_HEADER, ILP_PEER_ID_HEADER, type IlpSendParams, type IlpSendResultWithFulfillment, type IlpTransportChoice, InMemoryReceivedClaimStore, type IngestReceivedClaimsParams, type IngestReceivedClaimsResult, JsonFileReceivedClaimStore, KeyManager, type KeyManagerConfig, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PublishEventResult, type ReceivedClaimEntry, type ReceivedClaimRejection, type ReceivedClaimRejectionCode, type ReceivedClaimStore, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type SubmitEvmSettlementParams, type SubmitEvmSettlementResult, type SwapSettlementBuild, type ToonChannelAccept, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, ValidationError, type VaultData, type VerifiedReceivedClaim, type WalletBalance, type WalletBalanceSources, type WalletChainBalances, type WalletTokenAmount, applyDefaults, applyNetworkPresets, assertValidCondition, buildBackupEvent, buildBackupFilter, buildSettlementInfo, buildStoreWriteEnvelope, buildSwapSettlements, decodeEvmSettlementTx, decryptMnemonic, defaultFaucetTimeout, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, entryToAccumulatedClaim, extractArweaveTxId, fulfillmentMatchesCondition, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, hasSettlementMetadata, httpEndpointToBtpUrl, importKeystore, ingestReceivedClaims, isInsufficientGasError, isPrfSupported, isZeroCondition, loadKeystore, mintExecutionCondition, parseBackupPayload, parseEvmChainId, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readEvmNativeBalance, readEvmTokenBalance, readMinaBalance, readMinaDepositTotal, readSolanaNativeBalance, readSolanaTokenBalance, readWalletBalances, requestBlobStorage, selectIlpTransport, serializeHttpRequest, submitEvmSettlement, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };