@vultisig/cli 2.21.1 → 2.22.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/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 2.22.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1583](https://github.com/vultisig/vultisig-sdk/pull/1583) [`028b3ce`](https://github.com/vultisig/vultisig-sdk/commit/028b3cec5e56e5ab41de5eeb66f6837af9e1dd27) Thanks [@Toby1009](https://github.com/Toby1009)! - Move every Sui read, simulation and broadcast off JSON-RPC.
8
+
9
+ Sui is retiring JSON-RPC: shutdown on Foundation mainnet full nodes began the
10
+ week of 2026-07-27 and full decommission (code removal) lands mid-October 2026,
11
+ after which no provider can serve it. This is a scheduled migration ahead of
12
+ that date, NOT a fix for a live outage — as of 2026-07-27 both
13
+ `sui-rpc.publicnode.com` and `fullnode.mainnet.sui.io` still answer JSON-RPC.
14
+
15
+ - `getSuiClient()` now returns a `SuiGrpcClient` pointed at
16
+ `https://fullnode.mainnet.sui.io:443` (gRPC-web over HTTPS).
17
+ - React Native uses `SuiGraphQLClient` against
18
+ `https://graphql.mainnet.sui.io/graphql` instead: grpc-web needs
19
+ `Response.body` streaming, which Hermes' fetch does not provide. Both clients
20
+ implement the same unified transport interface, so callsites are identical.
21
+ - Balance, coin metadata, coin listing, tx hash, tx status, broadcast and
22
+ keysign gas refinement moved to `getBalance` / `getCoinMetadata` / `listCoins`
23
+ / `simulateTransaction` / `getTransaction` / `executeTransaction`.
24
+ - The dependency-free `@vultisig/sdk` balance tools (`getSuiBalance`,
25
+ `getSuiTokenBalance`, `getSuiAllBalances`) now POST Sui GraphQL and follow the
26
+ paginated `balances` connection to completion, returning `tokens_unavailable`
27
+ rather than a silently truncated portfolio.
28
+
29
+ Broadcast-error classification follows the transport. A gRPC failure carries the
30
+ grpc-status NAME in `code` (not a JSON-RPC number) and a percent-encoded message,
31
+ so both classifiers were re-pointed:
32
+
33
+ - `isTransientBroadcastError` retries `UNAVAILABLE` / `DEADLINE_EXCEEDED` /
34
+ `RESOURCE_EXHAUSTED` and decodes the message before pattern-matching. A
35
+ grpc-web response is HTTP 200 with the real status in the trailer, so the
36
+ existing 5xx branch never saw a busy or restarting node.
37
+ - The CLI's permanent-vs-retryable gate matches `INVALID_ARGUMENT` instead of
38
+ the numeric `-32002`. Left unchanged, that gate would have gone dead and every
39
+ permanent Sui rejection would have been re-broadcast as if transient.
40
+
41
+ Breaking for direct consumers: `assertSuiTxSucceeded` now takes the unified
42
+ client's transaction result (`{ $kind, Transaction | FailedTransaction }`)
43
+ instead of a JSON-RPC effects object.
44
+
45
+ - Updated dependencies [[`4b14790`](https://github.com/vultisig/vultisig-sdk/commit/4b14790fb5f0fa5b9a58f6fe5575ad4c2bab3867), [`70f4583`](https://github.com/vultisig/vultisig-sdk/commit/70f4583a359f988460633b44046bf5811c9c0f74), [`98ec3bf`](https://github.com/vultisig/vultisig-sdk/commit/98ec3bfdcf0831df00ceec6618c796dbfa2c4d13), [`bb5b62c`](https://github.com/vultisig/vultisig-sdk/commit/bb5b62c60ca298d0aa98614e8c2b01eeef0d8bdb), [`d7fd8fd`](https://github.com/vultisig/vultisig-sdk/commit/d7fd8fd891d2bb9f007b3feff5b31cc961bae497), [`3cf9cdc`](https://github.com/vultisig/vultisig-sdk/commit/3cf9cdc14f0069f231f2ea0cede3cec155af95d5), [`f99133d`](https://github.com/vultisig/vultisig-sdk/commit/f99133dc7a99f44bbe78ba43fa59e7ec761c73e1), [`3cf9cdc`](https://github.com/vultisig/vultisig-sdk/commit/3cf9cdc14f0069f231f2ea0cede3cec155af95d5), [`6142529`](https://github.com/vultisig/vultisig-sdk/commit/6142529abc39bb548be8b1f32453f0207584c4e2), [`028b3ce`](https://github.com/vultisig/vultisig-sdk/commit/028b3cec5e56e5ab41de5eeb66f6837af9e1dd27), [`70f4583`](https://github.com/vultisig/vultisig-sdk/commit/70f4583a359f988460633b44046bf5811c9c0f74), [`e76ba9b`](https://github.com/vultisig/vultisig-sdk/commit/e76ba9ba78ec52f30f3678ef4acc933ef5712cdc), [`4777264`](https://github.com/vultisig/vultisig-sdk/commit/47772647b90336ae3297d208777523592f69dde4), [`89410fb`](https://github.com/vultisig/vultisig-sdk/commit/89410fbb0abf3ad05919fb38d1abc74a5acf9a6b), [`787e755`](https://github.com/vultisig/vultisig-sdk/commit/787e755d230d1e0fa012583d6edd8b7fa5aad88d)]:
46
+ - @vultisig/core-chain@2.29.0
47
+ - @vultisig/sdk@2.22.0
48
+ - @vultisig/rujira@55.0.0
49
+
3
50
  ## 2.21.1
4
51
 
5
52
  ### Patch Changes
package/dist/index.js CHANGED
@@ -5121,7 +5121,15 @@ var EVM_PERMANENT_BROADCAST_INPUT_RE = /failed to decode signed transaction|coul
5121
5121
  var UTXO_PERMANENT_BROADCAST_INPUT_RE = /\bTX decode failed\b/i;
5122
5122
  var SOLANA_PERMANENT_BROADCAST_INPUT_RE = /failed to deserialize(?: transaction)?|failed to sanitize|(?:transaction )?signature verification (?:failed|failure)|non-base58 character|invalid base58/i;
5123
5123
  var SUI_REQUIRED_FIELDS_GUARD_RE = /Sui broadcast requires JSON with "unsignedTx" and "signature" fields/i;
5124
- var SUI_PERMANENT_EXECUTION_MESSAGE_RE = /invalid (?:user )?signature|signature verification (?:failed|failure)|malformed transaction|invalid transaction (?:data|bytes)/i;
5124
+ var SUI_PERMANENT_GRPC_STATUS = "INVALID_ARGUMENT";
5125
+ var SUI_PERMANENT_EXECUTION_MESSAGE_RE = /invalid (?:user )?signature|signature verification (?:failed|failure)|malformed transaction|invalid transaction(?: (?:data|bytes))?\b/i;
5126
+ var decodeRpcDetails = (details) => {
5127
+ try {
5128
+ return decodeURIComponent(details);
5129
+ } catch {
5130
+ return details;
5131
+ }
5132
+ };
5125
5133
  var COSMOS_PERMANENT_SDK_CODES = {
5126
5134
  2: /tx parse error/i,
5127
5135
  4: /unauthorized|signature verification failed/i,
@@ -5151,7 +5159,8 @@ var permanentBroadcastInputClassifiers = {
5151
5159
  sui: (err, details) => {
5152
5160
  if (SUI_REQUIRED_FIELDS_GUARD_RE.test(details)) return true;
5153
5161
  const rpcCode = err.originalError?.code;
5154
- return rpcCode === -32002 && SUI_PERMANENT_EXECUTION_MESSAGE_RE.test(details);
5162
+ if (rpcCode !== SUI_PERMANENT_GRPC_STATUS) return false;
5163
+ return SUI_PERMANENT_EXECUTION_MESSAGE_RE.test(details) || SUI_PERMANENT_EXECUTION_MESSAGE_RE.test(decodeRpcDetails(details));
5155
5164
  },
5156
5165
  cosmos: (_err, details) => isCosmosPermanentBroadcastInput(details)
5157
5166
  };
@@ -11992,6 +12001,7 @@ var CLI_SIGNABLE_PREP_TOOLS = /* @__PURE__ */ new Set([
11992
12001
  "execute_send",
11993
12002
  "execute_contract_call"
11994
12003
  ]);
12004
+ var CLI_SIGNABLE_YIELD_TOOLS = /* @__PURE__ */ new Set(["yield_enter", "yield_exit"]);
11995
12005
  function asRecord(value) {
11996
12006
  if (typeof value === "string") {
11997
12007
  try {
@@ -12092,11 +12102,50 @@ function buildTxReadyFromToolOutput(toolName, output) {
12092
12102
  }
12093
12103
  return { __buildTx: true, chain: chainStr, chain_id: chainIdStr, ...action ? { action } : {}, tx: main };
12094
12104
  }
12105
+ function buildTxReadyFromYieldOutput(toolName, output) {
12106
+ if (!CLI_SIGNABLE_YIELD_TOOLS.has(toolName)) return null;
12107
+ const env = asRecord(output);
12108
+ if (!env) return null;
12109
+ if (env.status === "error" || "error" in env) return null;
12110
+ const chain = asChainString(env.chain);
12111
+ if (!chain) return null;
12112
+ const resolved = resolveChain(chain);
12113
+ if (!resolved || getChainKind4(resolved) !== "evm") return null;
12114
+ const chainStr = chain;
12115
+ const rawTxs = env.transactions;
12116
+ if (!Array.isArray(rawTxs) || rawTxs.length === 0) return null;
12117
+ const legs = [];
12118
+ for (const raw of rawTxs) {
12119
+ const legObj = asRecord(raw);
12120
+ if (!legObj) return null;
12121
+ if (legObj.status === "error" || "error" in legObj) return null;
12122
+ const leg = extractLeg(legObj);
12123
+ if (!leg) return null;
12124
+ legs.push(leg);
12125
+ }
12126
+ if (legs.length > 2) return null;
12127
+ const action = typeof env.action === "string" && env.action !== "" ? env.action : void 0;
12128
+ if (legs.length === 2) {
12129
+ const [approveLeg, mainLeg] = legs;
12130
+ return {
12131
+ __buildTx: true,
12132
+ chain: chainStr,
12133
+ ...action ? { action } : {},
12134
+ approvalTxArgs: { chain: chainStr, tx: approveLeg },
12135
+ txArgs: { chain: chainStr, tx: mainLeg }
12136
+ };
12137
+ }
12138
+ return { __buildTx: true, chain: chainStr, ...action ? { action } : {}, tx: legs[0] };
12139
+ }
12095
12140
  function deriveToolOutputCandidate(toolName, output) {
12096
12141
  if (CLI_SIGNABLE_FLAT_TOOLS.has(toolName)) {
12097
12142
  const payload = buildTxReadyFromToolOutput(toolName, output);
12098
12143
  return payload ? { payload, source: "flat", toolName } : null;
12099
12144
  }
12145
+ if (CLI_SIGNABLE_YIELD_TOOLS.has(toolName)) {
12146
+ const payload = buildTxReadyFromYieldOutput(toolName, output);
12147
+ return payload ? { payload, source: "yield", toolName } : null;
12148
+ }
12100
12149
  if (CLI_SIGNABLE_PREP_TOOLS.has(toolName)) {
12101
12150
  const env = asRecord(output);
12102
12151
  if (!env || env.status === "error" || "error" in env) return null;
@@ -12713,7 +12762,8 @@ var AgentClient = class {
12713
12762
  maybeSignToolOutput(status, toolName, output, callbacks, v1Type) {
12714
12763
  if (v1Type === "tool-output-error") return;
12715
12764
  if (status !== "done" || !toolName || !callbacks.onToolOutputTx) return;
12716
- if (!CLI_SIGNABLE_FLAT_TOOLS.has(toolName) && !CLI_SIGNABLE_PREP_TOOLS.has(toolName)) return;
12765
+ if (!CLI_SIGNABLE_FLAT_TOOLS.has(toolName) && !CLI_SIGNABLE_PREP_TOOLS.has(toolName) && !CLI_SIGNABLE_YIELD_TOOLS.has(toolName))
12766
+ return;
12717
12767
  const candidate = deriveToolOutputCandidate(toolName, output);
12718
12768
  if (!candidate) return;
12719
12769
  if (this.verbose)
@@ -15082,7 +15132,7 @@ var cachedVersion = null;
15082
15132
  function getVersion() {
15083
15133
  if (cachedVersion) return cachedVersion;
15084
15134
  if (true) {
15085
- cachedVersion = "2.21.1";
15135
+ cachedVersion = "2.22.0";
15086
15136
  return cachedVersion;
15087
15137
  }
15088
15138
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "2.21.1",
3
+ "version": "2.22.0",
4
4
  "description": "The self-custody MPC wallet CLI for AI coding agents (Claude Code, Cursor, OpenCode). Natural-language agent mode, 36+ chains, DKLS23 threshold signatures. Seedless.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74,9 +74,9 @@
74
74
  "@napi-rs/keyring": "^1.3.0",
75
75
  "@noble/hashes": "^2.2.0",
76
76
  "@vultisig/client-shared": "^0.3.0",
77
- "@vultisig/core-chain": "^2.28.0",
78
- "@vultisig/rujira": "^54.0.0",
79
- "@vultisig/sdk": "^2.21.1",
77
+ "@vultisig/core-chain": "^2.29.0",
78
+ "@vultisig/rujira": "^55.0.0",
79
+ "@vultisig/sdk": "^2.22.0",
80
80
  "chalk": "^5.6.2",
81
81
  "cli-table3": "^0.6.5",
82
82
  "commander": "^15.0.0",