@toon-protocol/client 0.14.10 → 0.14.12

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
@@ -1264,6 +1264,21 @@ declare class ToonClient {
1264
1264
  }>;
1265
1265
  /** Where a tracked channel sits in the withdraw journey. */
1266
1266
  getChannelCloseState(channelId: string): 'open' | 'closing' | 'settleable' | 'settled';
1267
+ getSettleableAt(channelId: string): bigint | undefined;
1268
+ /**
1269
+ * Re-hydrate a RESUMED channel's on-chain deposit. Persisted channel state
1270
+ * omits `depositTotal`, so after a daemon restart the tracked deposit is `0`
1271
+ * and the wallet shows 0 spendable even though real collateral is locked
1272
+ * on-chain. Read the participant's `deposit` from the `participants` mapping
1273
+ * and update the tracked total so `depositTotal - cumulativeAmount` is right.
1274
+ * Best-effort by caller (await + catch); returns the on-chain deposit, or
1275
+ * `undefined` when it can't be read (no channel manager / on-chain client /
1276
+ * EVM address).
1277
+ */
1278
+ rehydrateChannelDeposit(channelId: string, opts: {
1279
+ chain: string;
1280
+ tokenNetworkAddress: string;
1281
+ }): Promise<bigint | undefined>;
1267
1282
  /**
1268
1283
  * Read the on-chain settlement-token balance of this client's OWN wallet on
1269
1284
  * each configured chain (EVM token, Solana SPL, native MINA). A free read — no
@@ -1358,6 +1373,26 @@ declare class ConnectorError extends ToonClientError {
1358
1373
  declare class ValidationError extends ToonClientError {
1359
1374
  constructor(message: string, cause?: Error);
1360
1375
  }
1376
+ /**
1377
+ * Thrown when the one-time on-chain payment-channel OPEN reverts because the
1378
+ * local settlement wallet has no native gas to pay for its own
1379
+ * approve/openChannel/setTotalDeposit transactions. This is the channel OPEN
1380
+ * only — per-write settlement rides ILP-over-HTTP and never spends gas. We
1381
+ * remap ONLY this case so callers get an actionable message (fund the wallet)
1382
+ * instead of the raw viem "...exceeds the balance of the account" string
1383
+ * (toon-meta#65). Retryable once the wallet is funded; the underlying viem/RPC
1384
+ * error is preserved as `cause`.
1385
+ */
1386
+ declare class ChannelFundingError extends ToonClientError {
1387
+ readonly retryable = true;
1388
+ constructor(message: string, cause?: Error);
1389
+ }
1390
+ /**
1391
+ * True when `err` (or any error in its nested `cause` chain) is an
1392
+ * insufficient-native-gas revert. viem wraps the node error one or more levels
1393
+ * deep, so the whole chain is flattened and scanned.
1394
+ */
1395
+ declare function isInsufficientGasError(err: unknown): boolean;
1361
1396
 
1362
1397
  /**
1363
1398
  * Configuration options for HttpRuntimeClient.
@@ -2238,6 +2273,23 @@ declare class OnChainChannelClient implements ConnectorChannelClient {
2238
2273
  }>;
2239
2274
  /** Read + destructure the EVM `channels(bytes32)` view. */
2240
2275
  private readEvmChannel;
2276
+ /**
2277
+ * Read a participant's on-chain channel state — `deposit` (locked collateral),
2278
+ * `nonce`, and `transferredAmount` — straight from the `participants` mapping.
2279
+ * Takes the chain + token-network explicitly so it works for a channel that
2280
+ * was RESUMED from disk (no in-memory `channelContext` yet), which is exactly
2281
+ * when the daemon needs to re-hydrate the deposit it doesn't persist.
2282
+ */
2283
+ readEvmParticipantState(opts: {
2284
+ chain: string;
2285
+ tokenNetworkAddress: string;
2286
+ channelId: string;
2287
+ participant: string;
2288
+ }): Promise<{
2289
+ deposit: bigint;
2290
+ nonce: bigint;
2291
+ transferredAmount: bigint;
2292
+ }>;
2241
2293
  /**
2242
2294
  * Opens a REAL on-chain Solana payment channel.
2243
2295
  *
@@ -2284,14 +2336,22 @@ declare class OnChainChannelClient implements ConnectorChannelClient {
2284
2336
  */
2285
2337
  private openMinaChannel;
2286
2338
  /**
2287
- * Opens an EVM payment channel on-chain.
2339
+ * Opens an EVM payment channel on-chain, remapping the one-time
2340
+ * insufficient-native-gas revert into an actionable {@link ChannelFundingError}
2341
+ * so callers surface "fund the wallet" instead of the raw viem
2342
+ * "...exceeds the balance of the account" string (toon-meta#65). Only the gas
2343
+ * case is remapped; every other error propagates unchanged.
2344
+ */
2345
+ private openEvmChannel;
2346
+ /**
2347
+ * Raw EVM channel-open (no gas-error remapping — see {@link openEvmChannel}).
2288
2348
  *
2289
2349
  * 1. Approve token spend if needed
2290
2350
  * 2. Call TokenNetwork.openChannel()
2291
2351
  * 3. Extract channelId from ChannelOpened event
2292
2352
  * 4. Deposit initial funds if specified
2293
2353
  */
2294
- private openEvmChannel;
2354
+ private openEvmChannelUnchecked;
2295
2355
  /**
2296
2356
  * Gets the current state of a payment channel from on-chain data.
2297
2357
  */
@@ -3519,4 +3579,4 @@ declare function loadKeystore(path: string, password: string): string;
3519
3579
  */
3520
3580
  declare function writeKeystoreFile(path: string, keystore: EncryptedKeystore): void;
3521
3581
 
3522
- export { type BackupPayload, type BalanceProofParams, BtpRuntimeClient, type BtpRuntimeClientConfig, type ChainMetadata, type ChainSigner, 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, type InteractionResultContent, KeyManager, type KeyManagerConfig, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PetDvmProvider, type PetInteractionEventData, type PetInteractionRequestParams, type PetInteractionResultData, type PetListing, type PetListingFilterOptions, type PetListingParams, type PetPurchaseRequestParams, type ProofStatus, type PublishEventResult, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type StatValues, type ToonChannelAccept, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, type UnsignedNostrEvent, ValidationError, type VaultData, applyDefaults, applyNetworkPresets, buildBackupEvent, buildBackupFilter, buildPetInteractionRequest, buildPetListingEvent, buildPetPurchaseRequest, buildSettlementInfo, buildStoreWriteEnvelope, decryptMnemonic, defaultFaucetTimeout, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, filterPetDvmProviders, filterPetListings, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, httpEndpointToBtpUrl, importKeystore, isPrfSupported, loadKeystore, parseBackupPayload, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parsePetInteractionEvent, parsePetInteractionResult, parsePetListing, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readMinaDepositTotal, requestBlobStorage, selectIlpTransport, serializeHttpRequest, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
3582
+ 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, type InteractionResultContent, KeyManager, type KeyManagerConfig, type MinaClaimMessage, type MinaDepositReader, MinaSigner, type MinaSignerOptions, NetworkError, OnChainChannelClient, type OnChainChannelClientConfig, type ParsedFulfillHttp, type ParsedX402Challenge, type PasskeyInfo, type PetDvmProvider, type PetInteractionEventData, type PetInteractionRequestParams, type PetInteractionResultData, type PetListing, type PetListingFilterOptions, type PetListingParams, type PetPurchaseRequestParams, type ProofStatus, type PublishEventResult, type RequestBlobStorageParams, type RequestBlobStorageResult, type RetryOptions, type SelectIlpTransportOptions, type SignedBalanceProof, type SolanaChannelClientOptions, type SolanaClaimMessage, SolanaSigner, type StatValues, type ToonChannelAccept, ToonClient, type ToonClientConfig, ToonClientError, type ToonIdentity, type ToonSigners, type ToonStartResult, type UnsignedNostrEvent, ValidationError, type VaultData, applyDefaults, applyNetworkPresets, buildBackupEvent, buildBackupFilter, buildPetInteractionRequest, buildPetListingEvent, buildPetPurchaseRequest, buildSettlementInfo, buildStoreWriteEnvelope, decryptMnemonic, defaultFaucetTimeout, deriveFromNsec, deriveFullIdentity, deriveNostrKeyFromMnemonic, encryptMnemonic, filterPetDvmProviders, filterPetListings, fundWallet, generateKeystore, generateMnemonic, generateRandomIdentity, getNetworkStatus, httpEndpointToBtpUrl, importKeystore, isInsufficientGasError, isPrfSupported, loadKeystore, parseBackupPayload, parseFulfillHttp, parseFulfillHttpBytes, parseHttpResponse, parsePetInteractionEvent, parsePetInteractionResult, parsePetListing, parseX402Body, parseX402Challenge, proxyIlpEndpoint, readDiscoveredIlpPeer, readMinaDepositTotal, requestBlobStorage, selectIlpTransport, serializeHttpRequest, validateConfig, validateMnemonic, withRetry, writeKeystoreFile };
package/dist/index.js CHANGED
@@ -80,6 +80,29 @@ var PeerAlreadyExistsError = class extends ToonClientError {
80
80
  this.name = "PeerAlreadyExistsError";
81
81
  }
82
82
  };
83
+ var ChannelFundingError = class extends ToonClientError {
84
+ retryable = true;
85
+ constructor(message, cause) {
86
+ super(message, "CHANNEL_FUNDING", cause);
87
+ this.name = "ChannelFundingError";
88
+ }
89
+ };
90
+ var INSUFFICIENT_GAS_MARKERS = [
91
+ "exceeds the balance of the account",
92
+ "insufficient funds for gas",
93
+ "insufficient funds for intrinsic transaction cost",
94
+ "insufficient funds for transfer"
95
+ ];
96
+ function isInsufficientGasError(err) {
97
+ const parts = [];
98
+ let cur = err;
99
+ for (let i = 0; i < 10 && cur != null; i++) {
100
+ parts.push(cur instanceof Error ? cur.message : String(cur));
101
+ cur = cur instanceof Error ? cur.cause : void 0;
102
+ }
103
+ const text = parts.join(" | ").toLowerCase();
104
+ return INSUFFICIENT_GAS_MARKERS.some((m) => text.includes(m));
105
+ }
83
106
 
84
107
  // src/keys/KeyDerivation.ts
85
108
  import { generateSecretKey, getPublicKey } from "nostr-tools/pure";
@@ -2300,6 +2323,17 @@ var TOKEN_NETWORK_ABI = [
2300
2323
  { name: "participant2", type: "address" }
2301
2324
  ]
2302
2325
  },
2326
+ {
2327
+ name: "participants",
2328
+ type: "function",
2329
+ stateMutability: "view",
2330
+ inputs: [{ type: "bytes32" }, { type: "address" }],
2331
+ outputs: [
2332
+ { name: "deposit", type: "uint256" },
2333
+ { name: "nonce", type: "uint256" },
2334
+ { name: "transferredAmount", type: "uint256" }
2335
+ ]
2336
+ },
2303
2337
  {
2304
2338
  name: "ChannelOpened",
2305
2339
  type: "event",
@@ -2631,6 +2665,23 @@ var OnChainChannelClient = class {
2631
2665
  });
2632
2666
  return { settlementTimeout: res[0], state: Number(res[1]), closedAt: res[2] };
2633
2667
  }
2668
+ /**
2669
+ * Read a participant's on-chain channel state — `deposit` (locked collateral),
2670
+ * `nonce`, and `transferredAmount` — straight from the `participants` mapping.
2671
+ * Takes the chain + token-network explicitly so it works for a channel that
2672
+ * was RESUMED from disk (no in-memory `channelContext` yet), which is exactly
2673
+ * when the daemon needs to re-hydrate the deposit it doesn't persist.
2674
+ */
2675
+ async readEvmParticipantState(opts) {
2676
+ const { publicClient } = this.createClients(opts.chain);
2677
+ const res = await publicClient.readContract({
2678
+ address: opts.tokenNetworkAddress,
2679
+ abi: TOKEN_NETWORK_ABI,
2680
+ functionName: "participants",
2681
+ args: [opts.channelId, opts.participant]
2682
+ });
2683
+ return { deposit: res[0], nonce: res[1], transferredAmount: res[2] };
2684
+ }
2634
2685
  /**
2635
2686
  * Opens a REAL on-chain Solana payment channel.
2636
2687
  *
@@ -2762,14 +2813,33 @@ var OnChainChannelClient = class {
2762
2813
  };
2763
2814
  }
2764
2815
  /**
2765
- * Opens an EVM payment channel on-chain.
2816
+ * Opens an EVM payment channel on-chain, remapping the one-time
2817
+ * insufficient-native-gas revert into an actionable {@link ChannelFundingError}
2818
+ * so callers surface "fund the wallet" instead of the raw viem
2819
+ * "...exceeds the balance of the account" string (toon-meta#65). Only the gas
2820
+ * case is remapped; every other error propagates unchanged.
2821
+ */
2822
+ async openEvmChannel(params) {
2823
+ try {
2824
+ return await this.openEvmChannelUnchecked(params);
2825
+ } catch (err) {
2826
+ if (!isInsufficientGasError(err)) throw err;
2827
+ const chainFamily = params.chain.split(":")[0] || params.chain;
2828
+ throw new ChannelFundingError(
2829
+ `Settlement wallet ${this.evmSigner.address} has no gas on ${chainFamily} to open a payment channel. Run toon_fund_wallet (or fund the wallet) and retry.`,
2830
+ err instanceof Error ? err : void 0
2831
+ );
2832
+ }
2833
+ }
2834
+ /**
2835
+ * Raw EVM channel-open (no gas-error remapping — see {@link openEvmChannel}).
2766
2836
  *
2767
2837
  * 1. Approve token spend if needed
2768
2838
  * 2. Call TokenNetwork.openChannel()
2769
2839
  * 3. Extract channelId from ChannelOpened event
2770
2840
  * 4. Deposit initial funds if specified
2771
2841
  */
2772
- async openEvmChannel(params) {
2842
+ async openEvmChannelUnchecked(params) {
2773
2843
  const {
2774
2844
  chain,
2775
2845
  tokenNetwork,
@@ -5010,6 +5080,33 @@ var ToonClient = class {
5010
5080
  if (!this.channelManager) throw new Error("ChannelManager not initialized");
5011
5081
  return this.channelManager.getChannelCloseState(channelId);
5012
5082
  }
5083
+ getSettleableAt(channelId) {
5084
+ if (!this.channelManager) throw new Error("ChannelManager not initialized");
5085
+ return this.channelManager.getSettleableAt(channelId);
5086
+ }
5087
+ /**
5088
+ * Re-hydrate a RESUMED channel's on-chain deposit. Persisted channel state
5089
+ * omits `depositTotal`, so after a daemon restart the tracked deposit is `0`
5090
+ * and the wallet shows 0 spendable even though real collateral is locked
5091
+ * on-chain. Read the participant's `deposit` from the `participants` mapping
5092
+ * and update the tracked total so `depositTotal - cumulativeAmount` is right.
5093
+ * Best-effort by caller (await + catch); returns the on-chain deposit, or
5094
+ * `undefined` when it can't be read (no channel manager / on-chain client /
5095
+ * EVM address).
5096
+ */
5097
+ async rehydrateChannelDeposit(channelId, opts) {
5098
+ if (!this.channelManager || !this.onChainChannelClient) return void 0;
5099
+ const participant = this.getEvmAddress();
5100
+ if (!participant) return void 0;
5101
+ const { deposit } = await this.onChainChannelClient.readEvmParticipantState({
5102
+ chain: opts.chain,
5103
+ tokenNetworkAddress: opts.tokenNetworkAddress,
5104
+ channelId,
5105
+ participant
5106
+ });
5107
+ this.channelManager.setDepositTotal(channelId, deposit);
5108
+ return deposit;
5109
+ }
5013
5110
  /**
5014
5111
  * Read the on-chain settlement-token balance of this client's OWN wallet on
5015
5112
  * each configured chain (EVM token, Solana SPL, native MINA). A free read — no
@@ -7045,6 +7142,7 @@ function writeKeystoreFile(path, keystore) {
7045
7142
  }
7046
7143
  export {
7047
7144
  BtpRuntimeClient,
7145
+ ChannelFundingError,
7048
7146
  ChannelManager,
7049
7147
  ConnectorError,
7050
7148
  EvmSigner,
@@ -7102,6 +7200,7 @@ export {
7102
7200
  guardedRenderDispatch,
7103
7201
  httpEndpointToBtpUrl,
7104
7202
  importKeystore,
7203
+ isInsufficientGasError,
7105
7204
  isPrfSupported,
7106
7205
  isTrustDowngrade,
7107
7206
  loadKeystore,