@toon-protocol/client 0.19.0 → 0.20.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 +170 -7
- package/dist/index.js +177 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { UI_RENDERER_KIND, UI_TAG, UiCoordinate, buildUiCoordinate, getUiCoordin
|
|
|
4
4
|
import { NostrEvent, EventTemplate } from 'nostr-tools/pure';
|
|
5
5
|
import { MinaSignerClientLike, SettlementBundle } from '@toon-protocol/sdk';
|
|
6
6
|
import { AccumulatedClaim } from '@toon-protocol/sdk/swap';
|
|
7
|
-
import { PrivateKeyAccount, Hex } from 'viem';
|
|
7
|
+
import { PrivateKeyAccount, Hex, Address } from 'viem';
|
|
8
8
|
import { PrivateKeyAccount as PrivateKeyAccount$1 } from 'viem/accounts';
|
|
9
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';
|
|
10
10
|
|
|
@@ -1262,6 +1262,21 @@ interface BuildSwapSettlementsParams {
|
|
|
1262
1262
|
tokenNetworks?: Record<string, string>;
|
|
1263
1263
|
/** Pre-loaded `mina-signer` client for `mina:*` re-verification. */
|
|
1264
1264
|
minaSignerClient?: MinaSignerClientLike;
|
|
1265
|
+
/**
|
|
1266
|
+
* Re-verify the stored claim's signature at settle time (defense in depth
|
|
1267
|
+
* over the store file). Default `true` — the published **v2** sdk
|
|
1268
|
+
* (`@toon-protocol/sdk@^3`, connector#324 finding #1) verifies EVM claims
|
|
1269
|
+
* against the **v2** EIP-712 domain-separated balance-proof digest, the SAME
|
|
1270
|
+
* digest the receive-side used (`ingestReceivedClaims`). Reconstructing that
|
|
1271
|
+
* EIP-712 domain needs `chainId` + `verifyingContract`, which this builder
|
|
1272
|
+
* threads into the sdk signer config from `tokenNetworks` (for EVM claims) —
|
|
1273
|
+
* so a claim verified at receipt re-verifies correctly here.
|
|
1274
|
+
*
|
|
1275
|
+
* Set `false` only to skip the settle-time re-verify entirely (e.g. when the
|
|
1276
|
+
* receive-side verify is treated as the sole authoritative gate); the sdk is
|
|
1277
|
+
* then used only to BUILD the settlement calldata.
|
|
1278
|
+
*/
|
|
1279
|
+
verifySignatures?: boolean;
|
|
1265
1280
|
}
|
|
1266
1281
|
/** Rebuild the sdk `AccumulatedClaim` shape from a persisted entry. */
|
|
1267
1282
|
declare function entryToAccumulatedClaim(entry: ReceivedClaimEntry): AccumulatedClaim;
|
|
@@ -3017,10 +3032,15 @@ declare function readMinaChannelState(graphqlUrl: string, zkAppAddress: string,
|
|
|
3017
3032
|
* `swapSignerAddress` (kind:10032 discovery / operator config), the
|
|
3018
3033
|
* claim's self-reported signer must match (`SWAP_SIGNER_MISMATCH`,
|
|
3019
3034
|
* sdk 2.x vocabulary).
|
|
3020
|
-
* 5. signature —
|
|
3021
|
-
*
|
|
3022
|
-
*
|
|
3023
|
-
*
|
|
3035
|
+
* 5. signature — against the expected signer (advertised address when given,
|
|
3036
|
+
* else the claim's self-reported one). EVM claims verify against the
|
|
3037
|
+
* **v2 EIP-712 domain-separated** balance-proof digest
|
|
3038
|
+
* (`verifyEvmClaimSignature`, connector#324 finding #1) — the digest binds
|
|
3039
|
+
* `chainId` + `verifyingContract`, so `tokenNetworks[chain]` (the
|
|
3040
|
+
* RollingSwapChannel address) and a numeric chain id are REQUIRED (an EVM
|
|
3041
|
+
* claim without them is rejected `MISSING_CHAIN_CONFIG`, fail-closed).
|
|
3042
|
+
* Solana/Mina keep the sdk `verifyAccumulatedClaim` path (their domain is
|
|
3043
|
+
* folded into the message).
|
|
3024
3044
|
* 6. signer pinning — a claim may not silently rotate the signer of an
|
|
3025
3045
|
* already-persisted watermark for the same channel.
|
|
3026
3046
|
* 7. nonce/cumulative monotonicity vs the locally persisted watermark —
|
|
@@ -3030,7 +3050,7 @@ declare function readMinaChannelState(graphqlUrl: string, zkAppAddress: string,
|
|
|
3030
3050
|
*/
|
|
3031
3051
|
|
|
3032
3052
|
/** Why a claim was rejected at receipt time. Codes are stable API. */
|
|
3033
|
-
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';
|
|
3053
|
+
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' | 'MISSING_CHAIN_CONFIG' | 'MALFORMED_METADATA';
|
|
3034
3054
|
interface ReceivedClaimRejection {
|
|
3035
3055
|
claim: AccumulatedClaim;
|
|
3036
3056
|
code: ReceivedClaimRejectionCode;
|
|
@@ -3056,6 +3076,21 @@ interface IngestReceivedClaimsParams {
|
|
|
3056
3076
|
* never the claim's own.
|
|
3057
3077
|
*/
|
|
3058
3078
|
expectedSignerAddress?: string;
|
|
3079
|
+
/**
|
|
3080
|
+
* Per-chain settlement contract addresses (the deployed `RollingSwapChannel`
|
|
3081
|
+
* / `verifyingContract`), keyed by the FULL chain key (e.g. `evm:base:8453`).
|
|
3082
|
+
* Matches the daemon config's `tokenNetworks` map and what
|
|
3083
|
+
* `buildSwapSettlements` already threads on the submit side.
|
|
3084
|
+
*
|
|
3085
|
+
* REQUIRED for EVM claims under the v2 EIP-712 digest (connector#324 finding
|
|
3086
|
+
* #1): the claim signature is domain-separated over `(chainId,
|
|
3087
|
+
* verifyingContract)`, so an EVM claim whose chain key lacks a `tokenNetworks`
|
|
3088
|
+
* entry (or a numeric chain id) is rejected `MISSING_CHAIN_CONFIG` — it cannot
|
|
3089
|
+
* be verified fail-closed without the domain. Supplied by the connector/swap
|
|
3090
|
+
* session context (the RollingSwapChannel the client settles against). Unused
|
|
3091
|
+
* for Solana/Mina claims, which fold their domain into the message itself.
|
|
3092
|
+
*/
|
|
3093
|
+
tokenNetworks?: Record<string, string>;
|
|
3059
3094
|
/** Durable watermark store; verified claims are persisted here. */
|
|
3060
3095
|
store: ReceivedClaimStore;
|
|
3061
3096
|
/** Pre-loaded `mina-signer` client — required to verify `mina:*` claims. */
|
|
@@ -3089,6 +3124,134 @@ declare function hasSettlementMetadata(claim: AccumulatedClaim): claim is Accumu
|
|
|
3089
3124
|
*/
|
|
3090
3125
|
declare function ingestReceivedClaims(params: IngestReceivedClaimsParams): IngestReceivedClaimsResult;
|
|
3091
3126
|
|
|
3127
|
+
/**
|
|
3128
|
+
* EVM rolling-swap **v2** balance-proof claim digest (EIP-712 domain-separated).
|
|
3129
|
+
*
|
|
3130
|
+
* Refs connector#324 **finding #1** / connector#325 (canonical spec:
|
|
3131
|
+
* `docs/rolling-swap-v2-digest-spec.md`). This is the client's byte-for-byte
|
|
3132
|
+
* conformance anchor for the v2 migration.
|
|
3133
|
+
*
|
|
3134
|
+
* ## Why this exists in the client
|
|
3135
|
+
*
|
|
3136
|
+
* The v1 digest that shipped in `@toon-protocol/core` `balanceProofHashEvm`
|
|
3137
|
+
* (imported transitively by the sdk's `verifyAccumulatedClaim` /
|
|
3138
|
+
* `buildSettlementTx`, which is what this repo used to lean on) was
|
|
3139
|
+
*
|
|
3140
|
+
* keccak256( channelId(32) || cumulativeAmount(32BE)
|
|
3141
|
+
* || nonce(32BE) || recipient(20) )
|
|
3142
|
+
*
|
|
3143
|
+
* — it bound **neither** `chainId` **nor** the settling contract address, so a
|
|
3144
|
+
* signer-signed claim redeemed on one (chain, deployment) could be replayed
|
|
3145
|
+
* verbatim on another for the same tuple (cross-chain / cross-deployment
|
|
3146
|
+
* replay). v2 folds `chainId` **and** `verifyingContract` into the signed
|
|
3147
|
+
* preimage via a standard **EIP-712** typed-data domain, so a signature is
|
|
3148
|
+
* valid on **exactly one `(chainId, contract)` pair**, and the `version="2"`
|
|
3149
|
+
* string makes the cutover fail-closed (a v1 raw-keccak sig can never validate
|
|
3150
|
+
* as v2 and vice-versa).
|
|
3151
|
+
*
|
|
3152
|
+
* ## Lockstep dependency
|
|
3153
|
+
*
|
|
3154
|
+
* The canonical v2 digest util lives in `@toon-protocol/core`
|
|
3155
|
+
* (`balanceProofHashEvm` → EIP-712) + `@toon-protocol/sdk`
|
|
3156
|
+
* (`verifyAccumulatedClaim` / `buildSettlementTx`). Those packages migrate in
|
|
3157
|
+
* lockstep (connector#324 release order: core/sdk → swap → client). Until a v2
|
|
3158
|
+
* core/sdk is published, this module is the client's own v2 digest so the
|
|
3159
|
+
* receive-side verify (see {@link file://./received-claims.ts}) is already
|
|
3160
|
+
* domain-separated and the golden-vector conformance test
|
|
3161
|
+
* (`evm-claim-digest.test.ts`) pins the exact literals from the spec. When the
|
|
3162
|
+
* v2 core/sdk ships, the recompute here should delegate to it (or be asserted
|
|
3163
|
+
* byte-identical to it) — the golden-vector test stays as the shared fixture.
|
|
3164
|
+
*
|
|
3165
|
+
* The signer leg (`swap` `EvmPaymentChannelSigner.signBalanceProof`) MUST also
|
|
3166
|
+
* move to this same EIP-712 preimage and now REQUIRES `chainId` +
|
|
3167
|
+
* `verifyingContract` inputs it did not take before.
|
|
3168
|
+
*/
|
|
3169
|
+
|
|
3170
|
+
/** EIP-712 domain `name` for the RollingSwapChannel (spec §2.1). */
|
|
3171
|
+
declare const ROLLING_SWAP_DOMAIN_NAME: "RollingSwapChannel";
|
|
3172
|
+
/** EIP-712 domain `version` — `"2"` is the domain-separated migration. */
|
|
3173
|
+
declare const ROLLING_SWAP_DOMAIN_VERSION: "2";
|
|
3174
|
+
/**
|
|
3175
|
+
* `keccak256("ClaimBalanceProof(bytes32 channelId,uint256 cumulativeAmount,uint256 nonce,address recipient)")`.
|
|
3176
|
+
* Pinned from the spec; asserted in `evm-claim-digest.test.ts`.
|
|
3177
|
+
*/
|
|
3178
|
+
declare const CLAIM_TYPEHASH: "0xa0c8262c1a8615f7674d3af796b14d19672d3634f89c6093502ab35c0afe2d91";
|
|
3179
|
+
/**
|
|
3180
|
+
* `keccak256("CooperativeClose(bytes32 channelId,uint256 cumulativeAmount,uint256 nonce)")`.
|
|
3181
|
+
* Pinned from the spec; asserted in `evm-claim-digest.test.ts`.
|
|
3182
|
+
*/
|
|
3183
|
+
declare const COOP_CLOSE_TYPEHASH: "0xa5753389755fea51cd5016d7b02b508ac03f2e822d9a7ee345ec45b36574ff9f";
|
|
3184
|
+
/** The two chain-context inputs v2 adds over v1 (the domain binding). */
|
|
3185
|
+
interface EvmClaimDomainContext {
|
|
3186
|
+
/** Settlement chain id (`block.chainid` on-chain). e.g. `8453` for Base. */
|
|
3187
|
+
chainId: number;
|
|
3188
|
+
/** Deployed `RollingSwapChannel` address (`address(this)` / EIP-712 `verifyingContract`). */
|
|
3189
|
+
verifyingContract: string;
|
|
3190
|
+
}
|
|
3191
|
+
/** Fields of the `ClaimBalanceProof` message (the balance-proof claim leg). */
|
|
3192
|
+
interface EvmClaimMessage {
|
|
3193
|
+
/** Channel id, 0x-prefixed 32-byte hex. */
|
|
3194
|
+
channelId: string;
|
|
3195
|
+
/** Cumulative transferred amount (target micro-units). */
|
|
3196
|
+
cumulativeAmount: bigint;
|
|
3197
|
+
/** Monotonic balance-proof nonce. */
|
|
3198
|
+
nonce: bigint;
|
|
3199
|
+
/** Recipient (the claim payout address), 0x-prefixed 20-byte hex. */
|
|
3200
|
+
recipient: string;
|
|
3201
|
+
}
|
|
3202
|
+
/** Fields of the `CooperativeClose` message (recipient close-ack leg). */
|
|
3203
|
+
interface EvmCooperativeCloseMessage {
|
|
3204
|
+
channelId: string;
|
|
3205
|
+
cumulativeAmount: bigint;
|
|
3206
|
+
nonce: bigint;
|
|
3207
|
+
}
|
|
3208
|
+
/**
|
|
3209
|
+
* The v2 EIP-712 claim digest — `keccak256(0x1901 || domainSeparator ||
|
|
3210
|
+
* hashStruct(ClaimBalanceProof))` — that the on-chain `updateBalance` verifier
|
|
3211
|
+
* (and the swap signer) produce. This is what a received claim's signature must
|
|
3212
|
+
* recover against.
|
|
3213
|
+
*/
|
|
3214
|
+
declare function evmClaimDigest(ctx: EvmClaimDomainContext, message: EvmClaimMessage): Hex;
|
|
3215
|
+
/**
|
|
3216
|
+
* The v2 EIP-712 cooperative-close digest — same domain as the claim, distinct
|
|
3217
|
+
* type hash — that a recipient's close-ack signature must recover against.
|
|
3218
|
+
*/
|
|
3219
|
+
declare function evmCooperativeCloseDigest(ctx: EvmClaimDomainContext, message: EvmCooperativeCloseMessage): Hex;
|
|
3220
|
+
/** A 65-byte `r || s || v` signature, as 0x-hex or raw bytes. */
|
|
3221
|
+
type ClaimSignature = Hex | Uint8Array;
|
|
3222
|
+
/**
|
|
3223
|
+
* Recover the EVM address that signed a v2 claim digest. Uses the same
|
|
3224
|
+
* `@noble/curves` secp256k1 recovery + keccak address derivation as the sdk's
|
|
3225
|
+
* on-chain-matching `recoverEvmSignerAddress`, over the **v2** EIP-712 digest.
|
|
3226
|
+
* Enforces the same 65-byte `r||s||v`, `v ∈ {27,28}` envelope the on-chain OZ
|
|
3227
|
+
* `ECDSA.recover` accepts (fail-closed on a malformed signature).
|
|
3228
|
+
*
|
|
3229
|
+
* @returns the recovered address (lowercase 0x-hex).
|
|
3230
|
+
* @throws if the signature is not 65 bytes or `v` is not 27/28.
|
|
3231
|
+
*/
|
|
3232
|
+
declare function recoverEvmClaimSigner(ctx: EvmClaimDomainContext, message: EvmClaimMessage, signature: ClaimSignature): Address;
|
|
3233
|
+
/** Result of {@link verifyEvmClaimSignature}. Mirrors the sdk verify shape. */
|
|
3234
|
+
type EvmClaimVerifyResult = {
|
|
3235
|
+
valid: true;
|
|
3236
|
+
recovered: Address;
|
|
3237
|
+
} | {
|
|
3238
|
+
valid: false;
|
|
3239
|
+
reason: string;
|
|
3240
|
+
};
|
|
3241
|
+
/**
|
|
3242
|
+
* Verify a received EVM balance-proof claim: recover the v2-digest signer and
|
|
3243
|
+
* check it equals `expectedSigner` (case-insensitive, per EVM address rules).
|
|
3244
|
+
*
|
|
3245
|
+
* Result-shaped — never throws; a malformed signature or a mismatch is a
|
|
3246
|
+
* `{ valid: false, reason }` so the receive ladder can bucket it fail-closed.
|
|
3247
|
+
*/
|
|
3248
|
+
declare function verifyEvmClaimSignature(params: {
|
|
3249
|
+
ctx: EvmClaimDomainContext;
|
|
3250
|
+
message: EvmClaimMessage;
|
|
3251
|
+
signature: ClaimSignature;
|
|
3252
|
+
expectedSigner: string;
|
|
3253
|
+
}): EvmClaimVerifyResult;
|
|
3254
|
+
|
|
3092
3255
|
/**
|
|
3093
3256
|
* Per-packet preimage retention (toon-client#360, rolling-swap epic
|
|
3094
3257
|
* toon-meta#145 — spec `docs/rolling-swap.md` §3 R1 / §3.2 leg-B reveal).
|
|
@@ -4175,4 +4338,4 @@ declare function loadKeystore(path: string, password: string): string;
|
|
|
4175
4338
|
*/
|
|
4176
4339
|
declare function writeKeystoreFile(path: string, keystore: EncryptedKeystore): void;
|
|
4177
4340
|
|
|
4178
|
-
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, InMemoryPreimageRetentionStore, InMemoryReceivedClaimStore, type IngestAndRevealParams, type IngestAndRevealResult, type IngestReceivedClaimsParams, type IngestReceivedClaimsResult, JsonFileReceivedClaimStore, KeyManager, type KeyManagerConfig, MINA_CHANNEL_STATE, type MinaChannelStateReader, type MinaClaimMessage, type MinaClaimSubmitArgs, type MinaClaimSubmitter, type MinaCoSignInputs, type MinaCoSignedClaim, type MinaDepositReader, type MinaOnChainChannelState, type MinaSettlementContext, MinaSettlementError, type MinaSettlementErrorCode, type MinaSettlementResult, type MinaSignaturePair, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PreimageRetentionStore, type PublishEventResult, type ReceivedClaimEntry, type ReceivedClaimRejection, type ReceivedClaimRejectionCode, type ReceivedClaimStore, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetainedPreimage, type RetryOptions, type RevealDecision, type RevealFn, type RevealResult, type RevealedClaim, type RolledBackClaim, 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, buildMinaCoSignedClaim, buildSettlementInfo, buildStoreWriteEnvelope, buildSwapSettlements, createO1jsMinaClaimSubmitter, decodeEvmSettlementTx, decryptMnemonic, defaultFaucetTimeout, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, entryToAccumulatedClaim, extractArweaveTxId, fulfillmentMatchesCondition, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, hasSettlementMetadata, httpEndpointToBtpUrl, importKeystore, ingestAndReveal, ingestReceivedClaims, isInsufficientGasError, isPrfSupported, isZeroCondition, loadKeystore, mintExecutionCondition, parseBackupPayload, parseEvmChainId, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readEvmNativeBalance, readEvmTokenBalance, readMinaBalance, readMinaChannelState, readMinaDepositTotal, readSolanaNativeBalance, readSolanaTokenBalance, readWalletBalances, requestBlobStorage, selectIlpTransport, serializeHttpRequest, submitEvmSettlement, submitMinaSettlement, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
|
|
4341
|
+
export { type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type BuildSwapSettlementsParams, CLAIM_TYPEHASH, CONDITION_LENGTH, COOP_CLOSE_TYPEHASH, type ChainMetadata, type ChainSigner, ChannelFundingError, ChannelManager, type ClaimMessage, type ClaimResolver, type ClaimSignature, ConnectorError, type DiscoveredIlpPeer, type EVMClaimMessage, type EncryptedKeystore, type EvmClaimDomainContext, type EvmClaimMessage, type EvmClaimVerifyResult, type EvmCooperativeCloseMessage, 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, InMemoryPreimageRetentionStore, InMemoryReceivedClaimStore, type IngestAndRevealParams, type IngestAndRevealResult, type IngestReceivedClaimsParams, type IngestReceivedClaimsResult, JsonFileReceivedClaimStore, KeyManager, type KeyManagerConfig, MINA_CHANNEL_STATE, type MinaChannelStateReader, type MinaClaimMessage, type MinaClaimSubmitArgs, type MinaClaimSubmitter, type MinaCoSignInputs, type MinaCoSignedClaim, type MinaDepositReader, type MinaOnChainChannelState, type MinaSettlementContext, MinaSettlementError, type MinaSettlementErrorCode, type MinaSettlementResult, type MinaSignaturePair, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PreimageRetentionStore, type PublishEventResult, ROLLING_SWAP_DOMAIN_NAME, ROLLING_SWAP_DOMAIN_VERSION, type ReceivedClaimEntry, type ReceivedClaimRejection, type ReceivedClaimRejectionCode, type ReceivedClaimStore, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetainedPreimage, type RetryOptions, type RevealDecision, type RevealFn, type RevealResult, type RevealedClaim, type RolledBackClaim, 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, buildMinaCoSignedClaim, buildSettlementInfo, buildStoreWriteEnvelope, buildSwapSettlements, createO1jsMinaClaimSubmitter, decodeEvmSettlementTx, decryptMnemonic, defaultFaucetTimeout, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, entryToAccumulatedClaim, evmClaimDigest, evmCooperativeCloseDigest, extractArweaveTxId, fulfillmentMatchesCondition, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, hasSettlementMetadata, httpEndpointToBtpUrl, importKeystore, ingestAndReveal, ingestReceivedClaims, isInsufficientGasError, isPrfSupported, isZeroCondition, loadKeystore, mintExecutionCondition, parseBackupPayload, parseEvmChainId, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readEvmNativeBalance, readEvmTokenBalance, readMinaBalance, readMinaChannelState, readMinaDepositTotal, readSolanaNativeBalance, readSolanaTokenBalance, readWalletBalances, recoverEvmClaimSigner, requestBlobStorage, selectIlpTransport, serializeHttpRequest, submitEvmSettlement, submitMinaSettlement, validateConfig, validateMnemonic, verifyEvmClaimSignature, withRetry, writeKeystoreFile };
|
package/dist/index.js
CHANGED
|
@@ -4677,6 +4677,7 @@ function buildSwapSettlements(params) {
|
|
|
4677
4677
|
claims: [entryToAccumulatedClaim(entry)],
|
|
4678
4678
|
signers: { [entry.chain]: signer },
|
|
4679
4679
|
recipients: { [entry.chain]: entry.recipient },
|
|
4680
|
+
...params.verifySignatures !== void 0 ? { verifySignatures: params.verifySignatures } : {},
|
|
4680
4681
|
...params.minaSignerClient ? { minaSignerClient: params.minaSignerClient } : {}
|
|
4681
4682
|
});
|
|
4682
4683
|
const firstRejected = result.rejected[0];
|
|
@@ -4724,7 +4725,9 @@ function decodeEvmSettlementTx(bundle) {
|
|
|
4724
4725
|
const chainIdHex = fields[6];
|
|
4725
4726
|
const chainId = Number.parseInt(chainIdHex === "0x" ? "0x0" : chainIdHex, 16);
|
|
4726
4727
|
if (typeof to !== "string" || to.length !== 42) {
|
|
4727
|
-
throw new Error(
|
|
4728
|
+
throw new Error(
|
|
4729
|
+
`settlement tx "to" is not a 20-byte address: ${String(to)}`
|
|
4730
|
+
);
|
|
4728
4731
|
}
|
|
4729
4732
|
return { to, data: data === "0x" ? "0x" : data, chainId };
|
|
4730
4733
|
}
|
|
@@ -4741,7 +4744,10 @@ async function submitEvmSettlement(bundle, params) {
|
|
|
4741
4744
|
nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
|
|
4742
4745
|
rpcUrls: { default: { http: [params.rpcUrl] } }
|
|
4743
4746
|
});
|
|
4744
|
-
const publicClient = createPublicClient3({
|
|
4747
|
+
const publicClient = createPublicClient3({
|
|
4748
|
+
chain,
|
|
4749
|
+
transport: http3(params.rpcUrl)
|
|
4750
|
+
});
|
|
4745
4751
|
const [nonce, gasPrice, gas] = await Promise.all([
|
|
4746
4752
|
publicClient.getTransactionCount({
|
|
4747
4753
|
address: params.account.address,
|
|
@@ -6463,6 +6469,116 @@ function fromJson(entry) {
|
|
|
6463
6469
|
import {
|
|
6464
6470
|
verifyAccumulatedClaim
|
|
6465
6471
|
} from "@toon-protocol/sdk";
|
|
6472
|
+
|
|
6473
|
+
// src/swap/evm-claim-digest.ts
|
|
6474
|
+
import {
|
|
6475
|
+
hashTypedData
|
|
6476
|
+
} from "viem";
|
|
6477
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
6478
|
+
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
6479
|
+
import { hexToBytes, bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
|
|
6480
|
+
var ROLLING_SWAP_DOMAIN_NAME = "RollingSwapChannel";
|
|
6481
|
+
var ROLLING_SWAP_DOMAIN_VERSION = "2";
|
|
6482
|
+
var CLAIM_TYPEHASH = "0xa0c8262c1a8615f7674d3af796b14d19672d3634f89c6093502ab35c0afe2d91";
|
|
6483
|
+
var COOP_CLOSE_TYPEHASH = "0xa5753389755fea51cd5016d7b02b508ac03f2e822d9a7ee345ec45b36574ff9f";
|
|
6484
|
+
var CLAIM_TYPES = {
|
|
6485
|
+
ClaimBalanceProof: [
|
|
6486
|
+
{ name: "channelId", type: "bytes32" },
|
|
6487
|
+
{ name: "cumulativeAmount", type: "uint256" },
|
|
6488
|
+
{ name: "nonce", type: "uint256" },
|
|
6489
|
+
{ name: "recipient", type: "address" }
|
|
6490
|
+
]
|
|
6491
|
+
};
|
|
6492
|
+
var COOP_CLOSE_TYPES = {
|
|
6493
|
+
CooperativeClose: [
|
|
6494
|
+
{ name: "channelId", type: "bytes32" },
|
|
6495
|
+
{ name: "cumulativeAmount", type: "uint256" },
|
|
6496
|
+
{ name: "nonce", type: "uint256" }
|
|
6497
|
+
]
|
|
6498
|
+
};
|
|
6499
|
+
function normalizeAddress(addr) {
|
|
6500
|
+
return addr.toLowerCase();
|
|
6501
|
+
}
|
|
6502
|
+
function domainOf(ctx) {
|
|
6503
|
+
return {
|
|
6504
|
+
name: ROLLING_SWAP_DOMAIN_NAME,
|
|
6505
|
+
version: ROLLING_SWAP_DOMAIN_VERSION,
|
|
6506
|
+
chainId: ctx.chainId,
|
|
6507
|
+
verifyingContract: normalizeAddress(ctx.verifyingContract)
|
|
6508
|
+
};
|
|
6509
|
+
}
|
|
6510
|
+
function evmClaimDigest(ctx, message) {
|
|
6511
|
+
return hashTypedData({
|
|
6512
|
+
domain: domainOf(ctx),
|
|
6513
|
+
types: CLAIM_TYPES,
|
|
6514
|
+
primaryType: "ClaimBalanceProof",
|
|
6515
|
+
message: {
|
|
6516
|
+
channelId: message.channelId,
|
|
6517
|
+
cumulativeAmount: message.cumulativeAmount,
|
|
6518
|
+
nonce: message.nonce,
|
|
6519
|
+
recipient: normalizeAddress(message.recipient)
|
|
6520
|
+
}
|
|
6521
|
+
});
|
|
6522
|
+
}
|
|
6523
|
+
function evmCooperativeCloseDigest(ctx, message) {
|
|
6524
|
+
return hashTypedData({
|
|
6525
|
+
domain: domainOf(ctx),
|
|
6526
|
+
types: COOP_CLOSE_TYPES,
|
|
6527
|
+
primaryType: "CooperativeClose",
|
|
6528
|
+
message: {
|
|
6529
|
+
channelId: message.channelId,
|
|
6530
|
+
cumulativeAmount: message.cumulativeAmount,
|
|
6531
|
+
nonce: message.nonce
|
|
6532
|
+
}
|
|
6533
|
+
});
|
|
6534
|
+
}
|
|
6535
|
+
var SIG_BYTES = 65;
|
|
6536
|
+
function signatureToBytes(sig) {
|
|
6537
|
+
if (typeof sig !== "string") return sig;
|
|
6538
|
+
const hex = sig.startsWith("0x") ? sig.slice(2) : sig;
|
|
6539
|
+
return hexToBytes(hex);
|
|
6540
|
+
}
|
|
6541
|
+
function recoverEvmClaimSigner(ctx, message, signature) {
|
|
6542
|
+
const bytes = signatureToBytes(signature);
|
|
6543
|
+
if (bytes.length !== SIG_BYTES) {
|
|
6544
|
+
throw new Error(
|
|
6545
|
+
`EVM signature must be 65 bytes (r||s||v), got ${bytes.length}`
|
|
6546
|
+
);
|
|
6547
|
+
}
|
|
6548
|
+
const v = bytes[64];
|
|
6549
|
+
if (v !== 27 && v !== 28) {
|
|
6550
|
+
throw new Error(`EVM signature v must be 27 or 28, got ${v}`);
|
|
6551
|
+
}
|
|
6552
|
+
const digest = evmClaimDigest(ctx, message).slice(2);
|
|
6553
|
+
const recovered = secp256k1.Signature.fromBytes(bytes.slice(0, 64), "compact").addRecoveryBit(v - 27).recoverPublicKey(hexToBytes(digest));
|
|
6554
|
+
const uncompressed = recovered.toBytes(false);
|
|
6555
|
+
const addrHash = keccak_256(uncompressed.slice(1));
|
|
6556
|
+
return `0x${bytesToHex2(addrHash.slice(-20))}`;
|
|
6557
|
+
}
|
|
6558
|
+
function verifyEvmClaimSignature(params) {
|
|
6559
|
+
let recovered;
|
|
6560
|
+
try {
|
|
6561
|
+
recovered = recoverEvmClaimSigner(
|
|
6562
|
+
params.ctx,
|
|
6563
|
+
params.message,
|
|
6564
|
+
params.signature
|
|
6565
|
+
);
|
|
6566
|
+
} catch (err) {
|
|
6567
|
+
return {
|
|
6568
|
+
valid: false,
|
|
6569
|
+
reason: `SIGNATURE_INVALID: ${err instanceof Error ? err.message : String(err)}`
|
|
6570
|
+
};
|
|
6571
|
+
}
|
|
6572
|
+
if (recovered.toLowerCase() !== params.expectedSigner.toLowerCase()) {
|
|
6573
|
+
return {
|
|
6574
|
+
valid: false,
|
|
6575
|
+
reason: `SIGNER_MISMATCH: recovered ${recovered}, expected ${params.expectedSigner}`
|
|
6576
|
+
};
|
|
6577
|
+
}
|
|
6578
|
+
return { valid: true, recovered };
|
|
6579
|
+
}
|
|
6580
|
+
|
|
6581
|
+
// src/swap/received-claims.ts
|
|
6466
6582
|
function hasSettlementMetadata(claim) {
|
|
6467
6583
|
return claim.channelId !== void 0 && claim.nonce !== void 0 && claim.cumulativeAmount !== void 0 && claim.recipient !== void 0 && claim.swapSignerAddress !== void 0;
|
|
6468
6584
|
}
|
|
@@ -6517,11 +6633,49 @@ function ingestReceivedClaims(params) {
|
|
|
6517
6633
|
continue;
|
|
6518
6634
|
}
|
|
6519
6635
|
const expectedSigner = params.expectedSignerAddress ?? claim.swapSignerAddress;
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
params.
|
|
6524
|
-
|
|
6636
|
+
let sig;
|
|
6637
|
+
if (chain.startsWith("evm")) {
|
|
6638
|
+
const chainId = parseEvmChainId2(chain);
|
|
6639
|
+
const verifyingContract = params.tokenNetworks?.[chain];
|
|
6640
|
+
if (chainId === void 0 || !verifyingContract) {
|
|
6641
|
+
reject(
|
|
6642
|
+
claim,
|
|
6643
|
+
"MISSING_CHAIN_CONFIG",
|
|
6644
|
+
`EVM v2 balance-proof verification for ${chain} needs a numeric chain id in the chain key AND tokenNetworks["${chain}"] (the RollingSwapChannel / verifyingContract) to reconstruct the EIP-712 domain; supply it from the connector/swap session context.`
|
|
6645
|
+
);
|
|
6646
|
+
continue;
|
|
6647
|
+
}
|
|
6648
|
+
let msgNonce;
|
|
6649
|
+
let msgCumulative;
|
|
6650
|
+
try {
|
|
6651
|
+
msgNonce = BigInt(claim.nonce);
|
|
6652
|
+
msgCumulative = BigInt(claim.cumulativeAmount);
|
|
6653
|
+
} catch {
|
|
6654
|
+
reject(
|
|
6655
|
+
claim,
|
|
6656
|
+
"MALFORMED_METADATA",
|
|
6657
|
+
`nonce "${claim.nonce}" / cumulativeAmount "${claim.cumulativeAmount}" are not decimal integers`
|
|
6658
|
+
);
|
|
6659
|
+
continue;
|
|
6660
|
+
}
|
|
6661
|
+
sig = verifyEvmClaimSignature({
|
|
6662
|
+
ctx: { chainId, verifyingContract },
|
|
6663
|
+
message: {
|
|
6664
|
+
channelId: claim.channelId,
|
|
6665
|
+
cumulativeAmount: msgCumulative,
|
|
6666
|
+
nonce: msgNonce,
|
|
6667
|
+
recipient: claim.recipient
|
|
6668
|
+
},
|
|
6669
|
+
signature: claim.claimBytes,
|
|
6670
|
+
expectedSigner
|
|
6671
|
+
});
|
|
6672
|
+
} else {
|
|
6673
|
+
sig = verifyAccumulatedClaim(
|
|
6674
|
+
claim,
|
|
6675
|
+
{ address: expectedSigner },
|
|
6676
|
+
params.minaSignerClient
|
|
6677
|
+
);
|
|
6678
|
+
}
|
|
6525
6679
|
if (!sig.valid) {
|
|
6526
6680
|
reject(claim, signatureRejectionCode(sig.reason), sig.reason);
|
|
6527
6681
|
continue;
|
|
@@ -6889,14 +7043,14 @@ function fromBase642(b64) {
|
|
|
6889
7043
|
}
|
|
6890
7044
|
return bytes;
|
|
6891
7045
|
}
|
|
6892
|
-
function
|
|
7046
|
+
function hexToBytes2(hex) {
|
|
6893
7047
|
const bytes = new Uint8Array(hex.length / 2);
|
|
6894
7048
|
for (let i = 0; i < hex.length; i += 2) {
|
|
6895
7049
|
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
6896
7050
|
}
|
|
6897
7051
|
return bytes;
|
|
6898
7052
|
}
|
|
6899
|
-
function
|
|
7053
|
+
function bytesToHex3(bytes) {
|
|
6900
7054
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
6901
7055
|
}
|
|
6902
7056
|
|
|
@@ -7228,7 +7382,7 @@ var KeyManager = class {
|
|
|
7228
7382
|
const mnemonic = generateMnemonic();
|
|
7229
7383
|
const identity = await deriveFullIdentity(mnemonic);
|
|
7230
7384
|
const prfSalt = crypto.getRandomValues(new Uint8Array(32));
|
|
7231
|
-
const userIdBytes =
|
|
7385
|
+
const userIdBytes = hexToBytes2(identity.nostr.pubkey);
|
|
7232
7386
|
const registration = await registerPasskey({
|
|
7233
7387
|
rpId: this.config.rpId,
|
|
7234
7388
|
rpName: this.config.rpName,
|
|
@@ -7270,7 +7424,7 @@ var KeyManager = class {
|
|
|
7270
7424
|
"Passkey did not return a userHandle. Cannot determine Nostr pubkey for recovery."
|
|
7271
7425
|
);
|
|
7272
7426
|
}
|
|
7273
|
-
const pubkey =
|
|
7427
|
+
const pubkey = bytesToHex3(discovery.userHandle);
|
|
7274
7428
|
const vault = await fetchBackupFromRelays(pubkey, this.config.relayUrls);
|
|
7275
7429
|
if (!vault) {
|
|
7276
7430
|
throw new Error(
|
|
@@ -7308,7 +7462,7 @@ var KeyManager = class {
|
|
|
7308
7462
|
}
|
|
7309
7463
|
const identity = await deriveFullIdentity(mnemonic);
|
|
7310
7464
|
const prfSalt = crypto.getRandomValues(new Uint8Array(32));
|
|
7311
|
-
const userIdBytes =
|
|
7465
|
+
const userIdBytes = hexToBytes2(identity.nostr.pubkey);
|
|
7312
7466
|
const registration = await registerPasskey({
|
|
7313
7467
|
rpId: this.config.rpId,
|
|
7314
7468
|
rpName: this.config.rpName,
|
|
@@ -7339,7 +7493,7 @@ var KeyManager = class {
|
|
|
7339
7493
|
const identity = deriveFromNsec(secretKey);
|
|
7340
7494
|
if (isPrfSupported()) {
|
|
7341
7495
|
const prfSalt = crypto.getRandomValues(new Uint8Array(32));
|
|
7342
|
-
const userIdBytes =
|
|
7496
|
+
const userIdBytes = hexToBytes2(identity.nostr.pubkey);
|
|
7343
7497
|
try {
|
|
7344
7498
|
const registration = await registerPasskey({
|
|
7345
7499
|
rpId: this.config.rpId,
|
|
@@ -7350,7 +7504,7 @@ var KeyManager = class {
|
|
|
7350
7504
|
});
|
|
7351
7505
|
const kek = await deriveKek(registration.prfOutput);
|
|
7352
7506
|
const credIdHash = await hashCredentialId(registration.credentialId);
|
|
7353
|
-
const hexKey =
|
|
7507
|
+
const hexKey = bytesToHex3(secretKey);
|
|
7354
7508
|
this.vault = await createVault(hexKey, kek, credIdHash, prfSalt);
|
|
7355
7509
|
this.activeCredentialIdHash = credIdHash;
|
|
7356
7510
|
await this.saveToLocalStorage();
|
|
@@ -7369,7 +7523,7 @@ var KeyManager = class {
|
|
|
7369
7523
|
throw new Error("No active identity \u2014 call create() or recover() first");
|
|
7370
7524
|
}
|
|
7371
7525
|
const prfSalt = crypto.getRandomValues(new Uint8Array(32));
|
|
7372
|
-
const userIdBytes =
|
|
7526
|
+
const userIdBytes = hexToBytes2(this.identity.nostr.pubkey);
|
|
7373
7527
|
const registration = await registerPasskey({
|
|
7374
7528
|
rpId: this.config.rpId,
|
|
7375
7529
|
rpName: this.config.rpName,
|
|
@@ -7799,7 +7953,9 @@ function writeKeystoreFile(path, keystore) {
|
|
|
7799
7953
|
}
|
|
7800
7954
|
export {
|
|
7801
7955
|
BtpRuntimeClient,
|
|
7956
|
+
CLAIM_TYPEHASH,
|
|
7802
7957
|
CONDITION_LENGTH,
|
|
7958
|
+
COOP_CLOSE_TYPEHASH,
|
|
7803
7959
|
ChannelFundingError,
|
|
7804
7960
|
ChannelManager,
|
|
7805
7961
|
ConnectorError,
|
|
@@ -7826,6 +7982,8 @@ export {
|
|
|
7826
7982
|
MinaSigner,
|
|
7827
7983
|
NetworkError,
|
|
7828
7984
|
OnChainChannelClient,
|
|
7985
|
+
ROLLING_SWAP_DOMAIN_NAME,
|
|
7986
|
+
ROLLING_SWAP_DOMAIN_VERSION,
|
|
7829
7987
|
RendererPinStore,
|
|
7830
7988
|
SolanaSigner,
|
|
7831
7989
|
ToonClient,
|
|
@@ -7856,6 +8014,8 @@ export {
|
|
|
7856
8014
|
deterministicGenerator,
|
|
7857
8015
|
encryptMnemonic2 as encryptMnemonic,
|
|
7858
8016
|
entryToAccumulatedClaim,
|
|
8017
|
+
evmClaimDigest,
|
|
8018
|
+
evmCooperativeCloseDigest,
|
|
7859
8019
|
extractArweaveTxId,
|
|
7860
8020
|
extractUiResource,
|
|
7861
8021
|
fulfillmentMatchesCondition,
|
|
@@ -7896,6 +8056,7 @@ export {
|
|
|
7896
8056
|
readSolanaNativeBalance,
|
|
7897
8057
|
readSolanaTokenBalance,
|
|
7898
8058
|
readWalletBalances,
|
|
8059
|
+
recoverEvmClaimSigner,
|
|
7899
8060
|
renderDeterministicHtml,
|
|
7900
8061
|
renderDispatch,
|
|
7901
8062
|
requestBlobStorage,
|
|
@@ -7909,6 +8070,7 @@ export {
|
|
|
7909
8070
|
submitMinaSettlement,
|
|
7910
8071
|
validateConfig,
|
|
7911
8072
|
validateMnemonic,
|
|
8073
|
+
verifyEvmClaimSignature,
|
|
7912
8074
|
verifyRendererTrust,
|
|
7913
8075
|
withRetry,
|
|
7914
8076
|
writeKeystoreFile
|