@toon-protocol/client-mcp 0.8.0 → 0.8.3

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.
@@ -6524,6 +6524,7 @@ import {
6524
6524
  import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
6525
6525
  import { toHex as toHex3 } from "viem";
6526
6526
  import { readFileSync, writeFileSync, existsSync } from "fs";
6527
+ import { createPublicClient as createPublicClient2, http as http2, defineChain as defineChain2 } from "viem";
6527
6528
  import { finalizeEvent as finalizeEvent22 } from "nostr-tools/pure";
6528
6529
  import { nip19 } from "nostr-tools";
6529
6530
  import { getPublicKey as getPublicKey32 } from "nostr-tools/pure";
@@ -8066,17 +8067,17 @@ function readDiscoveredIlpPeer(peer) {
8066
8067
  }
8067
8068
  function selectIlpTransport(peer, options = {}) {
8068
8069
  const needsDuplex = options.needsDuplex ?? false;
8069
- const http2 = peer.httpEndpoint?.trim() || void 0;
8070
+ const http3 = peer.httpEndpoint?.trim() || void 0;
8070
8071
  const btp = peer.btpEndpoint?.trim() || void 0;
8071
8072
  const canUpgrade = peer.supportsUpgrade === true;
8072
8073
  if (needsDuplex) {
8073
8074
  if (btp) return { kind: "btp", btpEndpoint: btp };
8074
- if (http2 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http2 };
8075
+ if (http3 && canUpgrade) return { kind: "http-upgradable", httpEndpoint: http3 };
8075
8076
  throw new Error(
8076
8077
  "Duplex transport required but peer exposes neither a btpEndpoint nor an upgradable httpEndpoint"
8077
8078
  );
8078
8079
  }
8079
- if (http2) return { kind: "http", httpEndpoint: http2, canUpgrade };
8080
+ if (http3) return { kind: "http", httpEndpoint: http3, canUpgrade };
8080
8081
  if (btp) return { kind: "btp", btpEndpoint: btp };
8081
8082
  throw new Error("Peer exposes neither an httpEndpoint nor a btpEndpoint");
8082
8083
  }
@@ -9870,6 +9871,18 @@ var ChannelManager = class {
9870
9871
  }
9871
9872
  return tracking.cumulativeAmount;
9872
9873
  }
9874
+ /**
9875
+ * Gets the on-chain deposit total (collateral locked at open / via deposits)
9876
+ * for a tracked channel, or `0n` when none was captured. The available
9877
+ * (spendable) balance is `depositTotal - cumulativeAmount`.
9878
+ */
9879
+ getDepositTotal(channelId) {
9880
+ const tracking = this.channels.get(channelId);
9881
+ if (!tracking) {
9882
+ throw new Error(`Channel "${channelId}" is not being tracked.`);
9883
+ }
9884
+ return tracking.depositTotal ?? 0n;
9885
+ }
9873
9886
  /**
9874
9887
  * Gets all tracked channel IDs.
9875
9888
  */
@@ -9924,6 +9937,88 @@ var JsonFileChannelStore = class {
9924
9937
  writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf-8");
9925
9938
  }
9926
9939
  };
9940
+ var ERC20_READ_ABI = [
9941
+ { name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "account", type: "address" }], outputs: [{ type: "uint256" }] },
9942
+ { name: "decimals", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint8" }] },
9943
+ { name: "symbol", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] }
9944
+ ];
9945
+ function parseEvmChainId(chainKey) {
9946
+ const parts = chainKey.split(":");
9947
+ const idStr = parts.length >= 3 ? parts[2] : parts[1];
9948
+ const id = Number.parseInt(idStr ?? "", 10);
9949
+ if (!Number.isFinite(id)) throw new Error(`Invalid EVM chain key "${chainKey}".`);
9950
+ return id;
9951
+ }
9952
+ async function readEvmTokenBalance(opts) {
9953
+ const chainId = parseEvmChainId(opts.chainKey);
9954
+ const client = createPublicClient2({
9955
+ transport: http2(opts.rpcUrl),
9956
+ chain: defineChain2({
9957
+ id: chainId,
9958
+ name: opts.chainKey,
9959
+ nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
9960
+ rpcUrls: { default: { http: [opts.rpcUrl] } }
9961
+ })
9962
+ });
9963
+ const token = opts.tokenAddress;
9964
+ const owner = opts.owner;
9965
+ const [amount, decimals, symbol] = await Promise.all([
9966
+ client.readContract({ address: token, abi: ERC20_READ_ABI, functionName: "balanceOf", args: [owner] }),
9967
+ client.readContract({ address: token, abi: ERC20_READ_ABI, functionName: "decimals" }).catch(() => void 0),
9968
+ client.readContract({ address: token, abi: ERC20_READ_ABI, functionName: "symbol" }).catch(() => void 0)
9969
+ ]);
9970
+ const out = { chain: "evm", address: opts.owner, amount: amount.toString() };
9971
+ if (typeof symbol === "string" && symbol) out.asset = symbol;
9972
+ if (decimals !== void 0) out.assetScale = Number(decimals);
9973
+ return out;
9974
+ }
9975
+ async function readSolanaTokenBalance(opts) {
9976
+ const fetchImpl = opts.fetchImpl ?? fetch;
9977
+ const res = await fetchImpl(opts.rpcUrl, {
9978
+ method: "POST",
9979
+ headers: { "content-type": "application/json" },
9980
+ body: JSON.stringify({
9981
+ jsonrpc: "2.0",
9982
+ id: 1,
9983
+ method: "getTokenAccountsByOwner",
9984
+ params: [opts.owner, { mint: opts.mint }, { encoding: "jsonParsed", commitment: "confirmed" }]
9985
+ })
9986
+ });
9987
+ if (!res.ok) throw new Error(`Solana RPC request failed: HTTP ${res.status}`);
9988
+ const json = await res.json();
9989
+ if (json.error) throw new Error(`Solana RPC error: ${json.error.message ?? "unknown"}`);
9990
+ let amount = 0n;
9991
+ let decimals;
9992
+ for (const acc of json.result?.value ?? []) {
9993
+ const ta = acc.account?.data?.parsed?.info?.tokenAmount;
9994
+ if (ta?.amount) amount += BigInt(ta.amount);
9995
+ if (ta?.decimals !== void 0) decimals = ta.decimals;
9996
+ }
9997
+ const out = { chain: "solana", address: opts.owner, amount: amount.toString() };
9998
+ if (decimals !== void 0) out.assetScale = decimals;
9999
+ return out;
10000
+ }
10001
+ async function readMinaBalance(opts) {
10002
+ const fetchImpl = opts.fetchImpl ?? fetch;
10003
+ const query = "query($pk:String!){account(publicKey:$pk){balance{total}}}";
10004
+ const res = await fetchImpl(opts.graphqlUrl, {
10005
+ method: "POST",
10006
+ headers: { "content-type": "application/json" },
10007
+ body: JSON.stringify({ query, variables: { pk: opts.owner } })
10008
+ });
10009
+ if (!res.ok) throw new Error(`Mina GraphQL request failed: HTTP ${res.status}`);
10010
+ const json = await res.json();
10011
+ if (json.errors && json.errors.length > 0) {
10012
+ throw new Error(`Mina GraphQL error: ${json.errors[0]?.message ?? "unknown"}`);
10013
+ }
10014
+ return {
10015
+ chain: "mina",
10016
+ address: opts.owner,
10017
+ amount: String(json.data?.account?.balance?.total ?? "0"),
10018
+ asset: "MINA",
10019
+ assetScale: 9
10020
+ };
10021
+ }
9927
10022
  var ARWEAVE_TX_ID_REGEX = /^[A-Za-z0-9_-]{43}$/;
9928
10023
  async function requestBlobStorage(client, secretKey, params) {
9929
10024
  const bid = params.bid ?? (params.ilpAmount !== void 0 ? String(params.ilpAmount) : void 0);
@@ -9992,8 +10087,8 @@ async function requestBlobStorage(client, secretKey, params) {
9992
10087
  };
9993
10088
  }
9994
10089
  function extractArweaveTxId(base64Data) {
9995
- const http2 = parseFulfillHttp(base64Data);
9996
- if (!http2.isHttp) {
10090
+ const http3 = parseFulfillHttp(base64Data);
10091
+ if (!http3.isHttp) {
9997
10092
  const legacy = decodeUtf8(fromBase64(base64Data));
9998
10093
  if (!ARWEAVE_TX_ID_REGEX.test(legacy)) {
9999
10094
  throw new Error(
@@ -10002,18 +10097,18 @@ function extractArweaveTxId(base64Data) {
10002
10097
  }
10003
10098
  return legacy;
10004
10099
  }
10005
- if (http2.status < 200 || http2.status >= 300) {
10006
- const detail = http2.body ? ` - ${http2.body}` : "";
10100
+ if (http3.status < 200 || http3.status >= 300) {
10101
+ const detail = http3.body ? ` - ${http3.body}` : "";
10007
10102
  throw new Error(
10008
- `Blob upload failed: DVM returned HTTP ${http2.status} ${http2.statusText}`.trimEnd() + detail
10103
+ `Blob upload failed: DVM returned HTTP ${http3.status} ${http3.statusText}`.trimEnd() + detail
10009
10104
  );
10010
10105
  }
10011
10106
  let parsed;
10012
10107
  try {
10013
- parsed = JSON.parse(http2.body);
10108
+ parsed = JSON.parse(http3.body);
10014
10109
  } catch {
10015
10110
  throw new Error(
10016
- `Blob upload response body was not valid JSON: "${http2.body}"`
10111
+ `Blob upload response body was not valid JSON: "${http3.body}"`
10017
10112
  );
10018
10113
  }
10019
10114
  const body = parsed;
@@ -10031,7 +10126,7 @@ function extractArweaveTxId(base64Data) {
10031
10126
  }
10032
10127
  }
10033
10128
  throw new Error(
10034
- `Blob upload response did not contain a valid Arweave tx ID: "${http2.body}"`
10129
+ `Blob upload response did not contain a valid Arweave tx ID: "${http3.body}"`
10035
10130
  );
10036
10131
  }
10037
10132
  var Http402Client = class {
@@ -10904,6 +10999,59 @@ var ToonClient = class {
10904
10999
  if (!this.channelManager) throw new Error("ChannelManager not initialized");
10905
11000
  return this.channelManager.getCumulativeAmount(channelId);
10906
11001
  }
11002
+ /**
11003
+ * Gets the on-chain deposit total (locked collateral) for a tracked channel.
11004
+ * The available (spendable) balance is this minus the cumulative spent amount.
11005
+ */
11006
+ getChannelDepositTotal(channelId) {
11007
+ if (!this.channelManager) throw new Error("ChannelManager not initialized");
11008
+ return this.channelManager.getDepositTotal(channelId);
11009
+ }
11010
+ /**
11011
+ * Read the on-chain settlement-token balance of this client's OWN wallet on
11012
+ * each configured chain (EVM token, Solana SPL, native MINA). A free read — no
11013
+ * signing, no payment. Best-effort per chain: a chain whose config is absent or
11014
+ * whose RPC read fails is omitted rather than failing the whole result, so the
11015
+ * wallet view degrades gracefully. Available after `start()` (Solana/Mina keys
11016
+ * are derived there).
11017
+ */
11018
+ async getBalances() {
11019
+ const out = [];
11020
+ const evmAddress = this.getEvmAddress();
11021
+ const rpcUrls = this.config.chainRpcUrls;
11022
+ const tokens = this.config.preferredTokens;
11023
+ if (evmAddress && rpcUrls && tokens) {
11024
+ const chainKeys = this.config.supportedChains ?? Object.keys(rpcUrls);
11025
+ const chainKey = chainKeys.find((c) => c.startsWith("evm") && rpcUrls[c] && tokens[c]);
11026
+ const rpcUrl = chainKey ? rpcUrls[chainKey] : void 0;
11027
+ const tokenAddress = chainKey ? tokens[chainKey] : void 0;
11028
+ if (chainKey && rpcUrl && tokenAddress) {
11029
+ try {
11030
+ out.push(await readEvmTokenBalance({ rpcUrl, chainKey, tokenAddress, owner: evmAddress }));
11031
+ } catch {
11032
+ }
11033
+ }
11034
+ }
11035
+ const solAddress = this.getSolanaAddress();
11036
+ const sol = this.config.solanaChannel;
11037
+ if (solAddress && sol?.rpcUrl && sol.tokenMint) {
11038
+ try {
11039
+ out.push(
11040
+ await readSolanaTokenBalance({ rpcUrl: sol.rpcUrl, mint: sol.tokenMint, owner: solAddress })
11041
+ );
11042
+ } catch {
11043
+ }
11044
+ }
11045
+ const minaAddress = this.getMinaAddress();
11046
+ const mina = this.config.minaChannel;
11047
+ if (minaAddress && mina?.graphqlUrl) {
11048
+ try {
11049
+ out.push(await readMinaBalance({ graphqlUrl: mina.graphqlUrl, owner: minaAddress }));
11050
+ } catch {
11051
+ }
11052
+ }
11053
+ return out;
11054
+ }
10907
11055
  /**
10908
11056
  * Resolves an ILP destination address to a peer ID.
10909
11057
  * Convention: destination "g.toon.peer1" → peerId "peer1" (last segment).
@@ -12027,6 +12175,9 @@ var ControlClient = class {
12027
12175
  channels() {
12028
12176
  return this.request("GET", "/channels");
12029
12177
  }
12178
+ balances() {
12179
+ return this.request("GET", "/balances");
12180
+ }
12030
12181
  swap(body) {
12031
12182
  return this.request("POST", "/swap", body);
12032
12183
  }
@@ -12232,4 +12383,4 @@ export {
12232
12383
  @scure/bip32/lib/esm/index.js:
12233
12384
  (*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
12234
12385
  */
12235
- //# sourceMappingURL=chunk-UEP6PFZN.js.map
12386
+ //# sourceMappingURL=chunk-ZVFLRFXS.js.map