@toon-protocol/client 0.14.5 → 0.14.7

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
@@ -976,6 +976,8 @@ declare class ToonClient {
976
976
  */
977
977
  private minaPrivateKey?;
978
978
  private channelManager?;
979
+ /** Concrete on-chain client, kept so deposit/withdraw can reach chain methods. */
980
+ private onChainChannelClient?;
979
981
  private readonly peerNegotiations;
980
982
  /**
981
983
  * Creates a new ToonClient instance.
@@ -1226,6 +1228,18 @@ declare class ToonClient {
1226
1228
  * The available (spendable) balance is this minus the cumulative spent amount.
1227
1229
  */
1228
1230
  getChannelDepositTotal(channelId: string): bigint;
1231
+ /**
1232
+ * Deposit additional collateral into an open channel. `amount` is the delta to
1233
+ * add (base units, decimal string or bigint). The daemon signs its own tx; no
1234
+ * key material leaves the client. Reads the current tracked deposit, performs
1235
+ * the on-chain deposit, updates the tracked total, and returns the new total.
1236
+ * EVM is live; Solana/Mina deposit lands in a follow-up.
1237
+ */
1238
+ depositToChannel(channelId: string, amount: string | bigint): Promise<{
1239
+ channelId: string;
1240
+ txHash?: string;
1241
+ depositTotal: string;
1242
+ }>;
1229
1243
  /**
1230
1244
  * Read the on-chain settlement-token balance of this client's OWN wallet on
1231
1245
  * each configured chain (EVM token, Solana SPL, native MINA). A free read — no
@@ -2135,6 +2149,36 @@ declare class OnChainChannelClient implements ConnectorChannelClient {
2135
2149
  * 4. Deposit initial funds if specified
2136
2150
  */
2137
2151
  openChannel(params: OpenChannelParams): Promise<OpenChannelResult>;
2152
+ /**
2153
+ * Deposit additional collateral into an already-open channel. `amount` is the
2154
+ * DELTA to add (base units). Dispatches by the channel's cached chain context;
2155
+ * `currentDeposit` is the channel's current locked total (tracked off-chain by
2156
+ * the caller) — required for EVM, whose `setTotalDeposit` takes the new
2157
+ * cumulative total, not a delta. Returns the new on-chain deposit total.
2158
+ *
2159
+ * Non-custodial: the client deposits its OWN funds and signs its OWN tx.
2160
+ * EVM is live; Solana/Mina deposit extraction is a follow-up (PR B.1).
2161
+ */
2162
+ depositToChannel(channelId: string, amount: bigint, opts: {
2163
+ currentDeposit: bigint;
2164
+ }): Promise<{
2165
+ txHash?: string;
2166
+ depositTotal: bigint;
2167
+ }>;
2168
+ /**
2169
+ * Solana deposit: fire the standalone `deposit` instruction against the channel
2170
+ * vault. Incremental on-chain (the program adds `amount`), so the new total is
2171
+ * the caller-tracked current plus the delta. Requires the funded payer token
2172
+ * account (the funded ATA) from the Solana channel config.
2173
+ */
2174
+ private depositSolana;
2175
+ /**
2176
+ * EVM deposit: approve the token-network for the delta if the allowance is
2177
+ * short, then `setTotalDeposit(channelId, participant, current + delta)` —
2178
+ * the contract takes the new cumulative total, so we add the delta to the
2179
+ * caller-supplied current locked amount.
2180
+ */
2181
+ private depositEvm;
2138
2182
  /**
2139
2183
  * Opens a REAL on-chain Solana payment channel.
2140
2184
  *
@@ -2305,6 +2349,12 @@ declare class ChannelManager {
2305
2349
  * (spendable) balance is `depositTotal - cumulativeAmount`.
2306
2350
  */
2307
2351
  getDepositTotal(channelId: string): bigint;
2352
+ /**
2353
+ * Update the tracked on-chain deposit total after a successful deposit, so the
2354
+ * available balance (`depositTotal - cumulativeAmount`) reflects the new
2355
+ * collateral on the next read.
2356
+ */
2357
+ setDepositTotal(channelId: string, total: bigint): void;
2308
2358
  /**
2309
2359
  * Gets all tracked channel IDs.
2310
2360
  */
package/dist/index.js CHANGED
@@ -2035,29 +2035,44 @@ async function openSolanaChannel(params) {
2035
2035
  ]);
2036
2036
  let depositTxSignature;
2037
2037
  if (params.deposit && params.deposit.amount > 0n) {
2038
- const depositData = new Uint8Array(16);
2039
- depositData.set(IX_DEPOSIT, 0);
2040
- writeU64LE(depositData, 8, params.deposit.amount);
2041
- depositTxSignature = await buildAndSendTransaction(rpcUrl, payer, [
2042
- {
2043
- programId,
2044
- keys: [
2045
- { pubkey: payerPubkey, isSigner: true, isWritable: false },
2046
- {
2047
- pubkey: params.deposit.payerTokenAccount,
2048
- isSigner: false,
2049
- isWritable: true
2050
- },
2051
- { pubkey: vaultPDA, isSigner: false, isWritable: true },
2052
- { pubkey: channelPDA, isSigner: false, isWritable: true },
2053
- { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
2054
- ],
2055
- data: depositData
2056
- }
2057
- ]);
2038
+ ({ depositTxSignature } = await depositSolanaChannel({
2039
+ rpcUrl,
2040
+ programId,
2041
+ channelPDA,
2042
+ payerSeed,
2043
+ payerPubkey,
2044
+ payerTokenAccount: params.deposit.payerTokenAccount,
2045
+ amount: params.deposit.amount
2046
+ }));
2058
2047
  }
2059
2048
  return { channelPDA, opened: true, initTxSignature, depositTxSignature };
2060
2049
  }
2050
+ async function depositSolanaChannel(params) {
2051
+ const { rpcUrl, programId, channelPDA, payerSeed, payerPubkey, payerTokenAccount, amount } = params;
2052
+ if (amount <= 0n) throw new Error("Solana deposit amount must be positive.");
2053
+ const payer = {
2054
+ publicKey: padTo32(base58Decode(payerPubkey)),
2055
+ privateKey: payerSeed
2056
+ };
2057
+ const { pda: vaultPDA } = deriveVaultPDA(channelPDA, programId);
2058
+ const depositData = new Uint8Array(16);
2059
+ depositData.set(IX_DEPOSIT, 0);
2060
+ writeU64LE(depositData, 8, amount);
2061
+ const depositTxSignature = await buildAndSendTransaction(rpcUrl, payer, [
2062
+ {
2063
+ programId,
2064
+ keys: [
2065
+ { pubkey: payerPubkey, isSigner: true, isWritable: false },
2066
+ { pubkey: payerTokenAccount, isSigner: false, isWritable: true },
2067
+ { pubkey: vaultPDA, isSigner: false, isWritable: true },
2068
+ { pubkey: channelPDA, isSigner: false, isWritable: true },
2069
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
2070
+ ],
2071
+ data: depositData
2072
+ }
2073
+ ]);
2074
+ return { depositTxSignature };
2075
+ }
2061
2076
 
2062
2077
  // src/channel/mina-channel-open.ts
2063
2078
  import { hexToMinaBase58PrivateKey as hexToMinaBase58PrivateKey2 } from "@toon-protocol/core";
@@ -2410,6 +2425,101 @@ var OnChainChannelClient = class {
2410
2425
  if (chainPrefix === "mina") return this.openMinaChannel(params);
2411
2426
  return this.openEvmChannel(params);
2412
2427
  }
2428
+ /**
2429
+ * Deposit additional collateral into an already-open channel. `amount` is the
2430
+ * DELTA to add (base units). Dispatches by the channel's cached chain context;
2431
+ * `currentDeposit` is the channel's current locked total (tracked off-chain by
2432
+ * the caller) — required for EVM, whose `setTotalDeposit` takes the new
2433
+ * cumulative total, not a delta. Returns the new on-chain deposit total.
2434
+ *
2435
+ * Non-custodial: the client deposits its OWN funds and signs its OWN tx.
2436
+ * EVM is live; Solana/Mina deposit extraction is a follow-up (PR B.1).
2437
+ */
2438
+ async depositToChannel(channelId, amount, opts) {
2439
+ if (amount <= 0n) throw new Error("Deposit amount must be positive.");
2440
+ const ctx = this.channelContext.get(channelId);
2441
+ if (!ctx) {
2442
+ throw new Error(
2443
+ `No on-chain context for channel "${channelId}" \u2014 it must be opened by this client first.`
2444
+ );
2445
+ }
2446
+ const chainPrefix = ctx.chain.split(":")[0];
2447
+ if (chainPrefix === "solana") {
2448
+ return this.depositSolana(channelId, amount, opts.currentDeposit);
2449
+ }
2450
+ if (chainPrefix === "mina") {
2451
+ throw new Error("Deposit on mina is not yet supported (EVM + Solana today; Mina follow-up).");
2452
+ }
2453
+ return this.depositEvm(channelId, amount, opts.currentDeposit, ctx);
2454
+ }
2455
+ /**
2456
+ * Solana deposit: fire the standalone `deposit` instruction against the channel
2457
+ * vault. Incremental on-chain (the program adds `amount`), so the new total is
2458
+ * the caller-tracked current plus the delta. Requires the funded payer token
2459
+ * account (the funded ATA) from the Solana channel config.
2460
+ */
2461
+ async depositSolana(channelId, amount, currentDeposit) {
2462
+ if (!this.solanaConfig) {
2463
+ throw new Error("Solana channel config not set \u2014 cannot deposit.");
2464
+ }
2465
+ const cfg = this.solanaConfig;
2466
+ const payerTokenAccount = cfg.deposit?.payerTokenAccount;
2467
+ if (!payerTokenAccount) {
2468
+ throw new Error(
2469
+ "Solana deposit requires solanaConfig.deposit.payerTokenAccount (the funded SPL token account)."
2470
+ );
2471
+ }
2472
+ const payerSeed = cfg.keypair.slice(0, 32);
2473
+ const payerPubkey = base58Encode2(new Uint8Array(ed255192.getPublicKey(payerSeed)));
2474
+ const { depositTxSignature } = await depositSolanaChannel({
2475
+ rpcUrl: cfg.rpcUrl,
2476
+ programId: cfg.programId,
2477
+ channelPDA: channelId,
2478
+ payerSeed,
2479
+ payerPubkey,
2480
+ payerTokenAccount,
2481
+ amount
2482
+ });
2483
+ return { txHash: depositTxSignature, depositTotal: currentDeposit + amount };
2484
+ }
2485
+ /**
2486
+ * EVM deposit: approve the token-network for the delta if the allowance is
2487
+ * short, then `setTotalDeposit(channelId, participant, current + delta)` —
2488
+ * the contract takes the new cumulative total, so we add the delta to the
2489
+ * caller-supplied current locked amount.
2490
+ */
2491
+ async depositEvm(channelId, amount, currentDeposit, ctx) {
2492
+ const { publicClient, walletClient } = this.createClients(ctx.chain);
2493
+ const tokenNetworkAddr = ctx.tokenNetworkAddress;
2494
+ const myAddress = this.evmSigner.address;
2495
+ const newTotal = currentDeposit + amount;
2496
+ if (ctx.tokenAddress) {
2497
+ const tokenAddr = ctx.tokenAddress;
2498
+ const allowance = await publicClient.readContract({
2499
+ address: tokenAddr,
2500
+ abi: ERC20_ABI,
2501
+ functionName: "allowance",
2502
+ args: [myAddress, tokenNetworkAddr]
2503
+ });
2504
+ if (allowance < amount) {
2505
+ const approveHash = await walletClient.writeContract({
2506
+ address: tokenAddr,
2507
+ abi: ERC20_ABI,
2508
+ functionName: "approve",
2509
+ args: [tokenNetworkAddr, maxUint256]
2510
+ });
2511
+ await publicClient.waitForTransactionReceipt({ hash: approveHash });
2512
+ }
2513
+ }
2514
+ const depositHash = await walletClient.writeContract({
2515
+ address: tokenNetworkAddr,
2516
+ abi: TOKEN_NETWORK_ABI,
2517
+ functionName: "setTotalDeposit",
2518
+ args: [channelId, myAddress, newTotal]
2519
+ });
2520
+ await publicClient.waitForTransactionReceipt({ hash: depositHash });
2521
+ return { txHash: depositHash, depositTotal: newTotal };
2522
+ }
2413
2523
  /**
2414
2524
  * Opens a REAL on-chain Solana payment channel.
2415
2525
  *
@@ -2611,7 +2721,8 @@ var OnChainChannelClient = class {
2611
2721
  }
2612
2722
  this.channelContext.set(channelId, {
2613
2723
  chain,
2614
- tokenNetworkAddress: tokenNetwork
2724
+ tokenNetworkAddress: tokenNetwork,
2725
+ ...params.token ? { tokenAddress: params.token } : {}
2615
2726
  });
2616
2727
  if (deposit > 0n) {
2617
2728
  const depositHash = await walletClient.writeContract({
@@ -3501,6 +3612,18 @@ var ChannelManager = class {
3501
3612
  }
3502
3613
  return tracking.depositTotal ?? 0n;
3503
3614
  }
3615
+ /**
3616
+ * Update the tracked on-chain deposit total after a successful deposit, so the
3617
+ * available balance (`depositTotal - cumulativeAmount`) reflects the new
3618
+ * collateral on the next read.
3619
+ */
3620
+ setDepositTotal(channelId, total) {
3621
+ const tracking = this.channels.get(channelId);
3622
+ if (!tracking) {
3623
+ throw new Error(`Channel "${channelId}" is not being tracked.`);
3624
+ }
3625
+ tracking.depositTotal = total;
3626
+ }
3504
3627
  /**
3505
3628
  * Gets all tracked channel IDs.
3506
3629
  */
@@ -4029,6 +4152,8 @@ var ToonClient = class {
4029
4152
  */
4030
4153
  minaPrivateKey;
4031
4154
  channelManager;
4155
+ /** Concrete on-chain client, kept so deposit/withdraw can reach chain methods. */
4156
+ onChainChannelClient;
4032
4157
  peerNegotiations = /* @__PURE__ */ new Map();
4033
4158
  /**
4034
4159
  * Creates a new ToonClient instance.
@@ -4222,6 +4347,7 @@ var ToonClient = class {
4222
4347
  }
4223
4348
  }
4224
4349
  if (this.channelManager && initialization.onChainChannelClient) {
4350
+ this.onChainChannelClient = initialization.onChainChannelClient;
4225
4351
  this.channelManager.setChannelClient(
4226
4352
  initialization.onChainChannelClient
4227
4353
  );
@@ -4638,6 +4764,31 @@ var ToonClient = class {
4638
4764
  if (!this.channelManager) throw new Error("ChannelManager not initialized");
4639
4765
  return this.channelManager.getDepositTotal(channelId);
4640
4766
  }
4767
+ /**
4768
+ * Deposit additional collateral into an open channel. `amount` is the delta to
4769
+ * add (base units, decimal string or bigint). The daemon signs its own tx; no
4770
+ * key material leaves the client. Reads the current tracked deposit, performs
4771
+ * the on-chain deposit, updates the tracked total, and returns the new total.
4772
+ * EVM is live; Solana/Mina deposit lands in a follow-up.
4773
+ */
4774
+ async depositToChannel(channelId, amount) {
4775
+ if (!this.channelManager) throw new Error("ChannelManager not initialized");
4776
+ if (!this.onChainChannelClient) {
4777
+ throw new Error("On-chain channel client not configured (no chainRpcUrls).");
4778
+ }
4779
+ const delta = BigInt(amount);
4780
+ if (delta <= 0n) throw new Error("Deposit amount must be positive.");
4781
+ const currentDeposit = this.channelManager.getDepositTotal(channelId);
4782
+ const result = await this.onChainChannelClient.depositToChannel(channelId, delta, {
4783
+ currentDeposit
4784
+ });
4785
+ this.channelManager.setDepositTotal(channelId, result.depositTotal);
4786
+ return {
4787
+ channelId,
4788
+ ...result.txHash ? { txHash: result.txHash } : {},
4789
+ depositTotal: result.depositTotal.toString()
4790
+ };
4791
+ }
4641
4792
  /**
4642
4793
  * Read the on-chain settlement-token balance of this client's OWN wallet on
4643
4794
  * each configured chain (EVM token, Solana SPL, native MINA). A free read — no