@t2000/cli 5.4.0 → 5.5.1

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.js CHANGED
@@ -27808,6 +27808,7 @@ async function buildSendTx({
27808
27808
  });
27809
27809
  return tx;
27810
27810
  }
27811
+ init_token_registry();
27811
27812
  var SUI_PRICE_FALLBACK = 1;
27812
27813
  var _cachedSuiPrice = 0;
27813
27814
  var _priceLastFetched = 0;
@@ -27840,30 +27841,67 @@ async function fetchSuiPrice(client) {
27840
27841
  }
27841
27842
  return _cachedSuiPrice || SUI_PRICE_FALLBACK;
27842
27843
  }
27844
+ function safeNorm(coinType) {
27845
+ try {
27846
+ return normalizeStructTag(coinType);
27847
+ } catch {
27848
+ return coinType;
27849
+ }
27850
+ }
27851
+ var SUI_TYPE_NORM = safeNorm(SUPPORTED_ASSETS.SUI.type);
27852
+ var STABLE_BY_NORM = (() => {
27853
+ const m = {};
27854
+ for (const asset of STABLE_ASSETS) m[safeNorm(SUPPORTED_ASSETS[asset].type)] = asset;
27855
+ return m;
27856
+ })();
27843
27857
  async function queryBalance(client, address) {
27844
- const stableBalancePromises = STABLE_ASSETS.map(
27845
- (asset) => client.core.getBalance({ owner: address, coinType: SUPPORTED_ASSETS[asset].type }).then((b) => ({ asset, amount: Number(b.balance.balance) / 10 ** SUPPORTED_ASSETS[asset].decimals })).catch(() => ({ asset, amount: 0 }))
27846
- );
27847
- const [suiBalance, suiPriceUsd, ...stableResults] = await Promise.all([
27848
- client.core.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.SUI.type }),
27849
- fetchSuiPrice(client),
27850
- ...stableBalancePromises
27851
- ]);
27858
+ const held = [];
27859
+ let cursor;
27860
+ do {
27861
+ const page = await client.core.listBalances({ owner: address, cursor: cursor ?? void 0 });
27862
+ for (const b of page.balances) {
27863
+ const raw = BigInt(b.balance);
27864
+ if (raw > 0n) held.push({ coinType: b.coinType, raw });
27865
+ }
27866
+ cursor = page.hasNextPage ? page.cursor : null;
27867
+ } while (cursor);
27868
+ const suiPriceUsd = await fetchSuiPrice(client);
27852
27869
  const stables = {};
27870
+ for (const asset of STABLE_ASSETS) stables[asset] = 0;
27853
27871
  let totalStables = 0;
27854
- for (const { asset, amount } of stableResults) {
27855
- stables[asset] = amount;
27856
- totalStables += amount;
27872
+ let suiAmount = 0;
27873
+ const otherCoins = [];
27874
+ for (const { coinType, raw } of held) {
27875
+ const norm = safeNorm(coinType);
27876
+ if (norm === SUI_TYPE_NORM) {
27877
+ suiAmount = Number(raw) / Number(MIST_PER_SUI);
27878
+ } else if (STABLE_BY_NORM[norm]) {
27879
+ const asset = STABLE_BY_NORM[norm];
27880
+ const amount = Number(raw) / 10 ** SUPPORTED_ASSETS[asset].decimals;
27881
+ stables[asset] = amount;
27882
+ totalStables += amount;
27883
+ } else {
27884
+ otherCoins.push({ coinType, raw });
27885
+ }
27857
27886
  }
27858
- const suiAmount = Number(suiBalance.balance.balance) / Number(MIST_PER_SUI);
27887
+ const tokens = await Promise.all(
27888
+ otherCoins.map(async ({ coinType, raw }) => {
27889
+ const decimals = await resolveCoinDecimals(client, coinType);
27890
+ return {
27891
+ coinType,
27892
+ symbol: resolveSymbol(coinType),
27893
+ amount: Number(raw) / 10 ** decimals,
27894
+ usdValue: null
27895
+ };
27896
+ })
27897
+ );
27898
+ tokens.sort((a, b) => a.symbol.localeCompare(b.symbol));
27859
27899
  const suiUsdValue = suiAmount * suiPriceUsd;
27860
27900
  return {
27861
27901
  stables,
27862
27902
  available: totalStables,
27863
- sui: {
27864
- amount: suiAmount,
27865
- usdValue: suiUsdValue
27866
- },
27903
+ sui: { amount: suiAmount, usdValue: suiUsdValue },
27904
+ tokens,
27867
27905
  totalUsd: totalStables + suiUsdValue
27868
27906
  };
27869
27907
  }
@@ -28029,7 +28067,7 @@ var TX_NODE_FRAGMENT = `
28029
28067
  }
28030
28068
  `;
28031
28069
  var HISTORY_QUERY = `query History($address: SuiAddress!, $last: Int!) {
28032
- transactions(last: $last, filter: { sentAddress: $address }) {
28070
+ transactions(last: $last, filter: { affectedAddress: $address }) {
28033
28071
  nodes {${TX_NODE_FRAGMENT}}
28034
28072
  }
28035
28073
  }`;
@@ -28099,7 +28137,9 @@ function buildRecord(args) {
28099
28137
  return { digest, action, label, legs, amount, asset, recipient, direction, timestamp: timestampMs, gasCost };
28100
28138
  }
28101
28139
  init_token_registry();
28102
- var SUI_MAINNET_URL = "https://fullnode.mainnet.sui.io:443";
28140
+ var RESOLVE_NAME_QUERY = `query ResolveSuins($name: String!) {
28141
+ address(name: $name) { address }
28142
+ }`;
28103
28143
  var SUI_ADDRESS_REGEX = /^0x[a-fA-F0-9]{1,64}$/i;
28104
28144
  var SUINS_NAME_REGEX = /^[a-z0-9-]+(\.[a-z0-9-]+)*\.sui$/;
28105
28145
  var InvalidAddressError = class extends Error {
@@ -28136,38 +28176,22 @@ async function resolveSuinsViaRpc(rawName, ctx = {}) {
28136
28176
  if (!SUINS_NAME_REGEX.test(name)) {
28137
28177
  throw new InvalidAddressError(rawName);
28138
28178
  }
28139
- const url = ctx.suiRpcUrl || SUI_MAINNET_URL;
28179
+ const gql = getSuiGraphQLClient();
28140
28180
  let res;
28141
28181
  try {
28142
- res = await fetch(url, {
28143
- method: "POST",
28144
- headers: { "Content-Type": "application/json" },
28145
- body: JSON.stringify({
28146
- jsonrpc: "2.0",
28147
- id: 1,
28148
- method: "suix_resolveNameServiceAddress",
28149
- params: [name]
28150
- }),
28151
- signal: ctx.signal ?? AbortSignal.timeout(8e3)
28182
+ res = await gql.query({
28183
+ query: RESOLVE_NAME_QUERY,
28184
+ variables: { name },
28185
+ signal: ctx.signal
28152
28186
  });
28153
28187
  } catch (err) {
28154
28188
  const msg = err instanceof Error ? err.message : String(err);
28155
28189
  throw new SuinsRpcError(name, msg);
28156
28190
  }
28157
- if (!res.ok) {
28158
- throw new SuinsRpcError(name, `HTTP ${res.status}`);
28159
- }
28160
- let body;
28161
- try {
28162
- body = await res.json();
28163
- } catch (err) {
28164
- const msg = err instanceof Error ? err.message : String(err);
28165
- throw new SuinsRpcError(name, `JSON parse failed: ${msg}`);
28166
- }
28167
- if (body.error) {
28168
- throw new SuinsRpcError(name, body.error.message);
28191
+ if (res.errors?.length) {
28192
+ throw new SuinsRpcError(name, res.errors.map((e) => e.message ?? "unknown error").join("; "));
28169
28193
  }
28170
- return body.result ?? null;
28194
+ return res.data?.address?.address ?? null;
28171
28195
  }
28172
28196
  init_errors();
28173
28197
  var DEFAULT_CONFIG_DIR = join2(homedir(), ".t2000");
@@ -31333,8 +31357,11 @@ function registerFund(program3) {
31333
31357
 
31334
31358
  // src/commands/balance.ts
31335
31359
  var import_picocolors3 = __toESM(require_picocolors(), 1);
31360
+ function formatTokenAmount(n) {
31361
+ return n.toLocaleString("en-US", { maximumFractionDigits: 6, useGrouping: false });
31362
+ }
31336
31363
  function registerBalance(program3) {
31337
- program3.command("balance").description("Show stablecoin + SUI holdings (USDC, USDsui, SUI; wallet only)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
31364
+ program3.command("balance").description("Show all wallet holdings \u2014 USDC / USDsui / SUI (USD-priced) + any other tokens (amount-only)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
31338
31365
  try {
31339
31366
  const agent = await withAgent({ keyPath: opts.key });
31340
31367
  const bal = await agent.balance();
@@ -31343,6 +31370,7 @@ function registerBalance(program3) {
31343
31370
  available: bal.available,
31344
31371
  stables: bal.stables,
31345
31372
  sui: bal.sui,
31373
+ tokens: bal.tokens,
31346
31374
  totalUsd: bal.totalUsd
31347
31375
  });
31348
31376
  return;
@@ -31358,14 +31386,25 @@ function registerBalance(program3) {
31358
31386
  printKeyValue(label, formatUsd(amount));
31359
31387
  }
31360
31388
  }
31361
- if (bal.sui && bal.sui.usdValue >= 1e-3) {
31389
+ if (bal.sui && bal.sui.amount > 0) {
31362
31390
  printKeyValue(
31363
31391
  "SUI",
31364
- `${formatUsd(bal.sui.usdValue)} ${import_picocolors3.default.dim(`(${bal.sui.amount.toFixed(4)} SUI \u2014 for swaps)`)}`
31392
+ `${formatUsd(bal.sui.usdValue)} ${import_picocolors3.default.dim(`(${bal.sui.amount.toFixed(4)} SUI \xB7 gas)`)}`
31365
31393
  );
31366
31394
  }
31395
+ const tokens = bal.tokens ?? [];
31396
+ for (const t of tokens) {
31397
+ printKeyValue(t.symbol.padEnd(8), import_picocolors3.default.dim(formatTokenAmount(t.amount)));
31398
+ }
31367
31399
  printSeparator();
31368
- printKeyValue("Wallet total", formatUsd(bal.totalUsd));
31400
+ printKeyValue("Wallet total", `${formatUsd(bal.totalUsd)} ${import_picocolors3.default.dim("(priced holdings)")}`);
31401
+ if (tokens.length > 0) {
31402
+ printLine(
31403
+ import_picocolors3.default.dim(
31404
+ ` + ${tokens.length} token${tokens.length === 1 ? "" : "s"} above with no USD price \u2014 not counted in the total`
31405
+ )
31406
+ );
31407
+ }
31369
31408
  printBlank();
31370
31409
  } catch (error) {
31371
31410
  handleError(error);
@@ -31399,9 +31438,9 @@ function printTxSummary(tx) {
31399
31438
  const label = ACTION_LABELS[tx.action] ?? `\u{1F4E6} ${tx.action}`;
31400
31439
  const time = tx.timestamp ? relativeTime(tx.timestamp) : "";
31401
31440
  const amount = formatAmount(tx);
31402
- const recipient = tx.recipient ? import_picocolors4.default.dim(`\u2192 ${truncateAddress(tx.recipient)}`) : "";
31441
+ const direction = tx.direction === "in" ? import_picocolors4.default.green("\u2190 received") : tx.recipient ? import_picocolors4.default.dim(`\u2192 ${truncateAddress(tx.recipient)}`) : "";
31403
31442
  const link = import_picocolors4.default.dim(explorerUrl(tx.digest));
31404
- printLine(`${label} ${amount} ${recipient}`);
31443
+ printLine(`${label} ${amount} ${direction}`);
31405
31444
  printLine(` ${import_picocolors4.default.dim(truncateAddress(tx.digest))} ${import_picocolors4.default.dim(time)}`);
31406
31445
  printLine(` ${link}`);
31407
31446
  }
@@ -31411,6 +31450,7 @@ function printTxDetail(tx) {
31411
31450
  printKeyValue("Type", label);
31412
31451
  printKeyValue("Digest", tx.digest);
31413
31452
  if (tx.amount) printKeyValue("Amount", `${tx.amount.toFixed(tx.amount < 0.01 ? 6 : 4)} ${tx.asset ?? ""}`);
31453
+ if (tx.direction) printKeyValue("Direction", tx.direction === "in" ? "Received" : "Sent");
31414
31454
  if (tx.recipient) printKeyValue("Recipient", tx.recipient);
31415
31455
  if (tx.timestamp) {
31416
31456
  printKeyValue("Time", `${new Date(tx.timestamp).toLocaleString()} (${relativeTime(tx.timestamp)})`);
@@ -32350,7 +32390,7 @@ function registerMcpStart(parent) {
32350
32390
  parent.command("start", { isDefault: true }).description("Start MCP server (stdio transport \u2014 for AI client integration)").option("--key <path>", "Custom wallet path (default ~/.t2000/wallet.key)").action(async (opts) => {
32351
32391
  let mod2;
32352
32392
  try {
32353
- mod2 = await import("./dist-O4WYNOSR.js");
32393
+ mod2 = await import("./dist-OMYCTHXH.js");
32354
32394
  } catch {
32355
32395
  console.error("MCP server not installed. Run:\n npm install -g @t2000/mcp");
32356
32396
  process.exit(1);