@vultisig/cli 3.0.0 → 4.0.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 +33 -0
- package/dist/index.js +87 -13
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 4.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1608](https://github.com/vultisig/vultisig-sdk/pull/1608) [`791d344`](https://github.com/vultisig/vultisig-sdk/commit/791d344c2dacc289c9fb7fbcbc38488aeeb47542) Thanks [@neavra](https://github.com/neavra)! - Fix tracked token balance fetching and make token removal report the truth.
|
|
8
|
+
|
|
9
|
+
A token added with `tokens --add` is stored under an id of the form `<Chain>-<address>`. That id was passed to the RPC as if it were a contract address; the RPC rejected it, the throw was swallowed per-chain, and the **whole chain's balances disappeared** — native asset included — leaving only a `console.warn`. Balance lookups now resolve a stored token reference to its real contract address / chain-level asset id before both the per-coin and batched calls. What is written to the vault file is unchanged, and balance result keys still use the stored id.
|
|
10
|
+
|
|
11
|
+
**Behavior change — `tokens --remove` now fails when nothing was removed.** Removal previously matched on an exact id comparison, so removing by symbol (or by contract address for a token added under the prefixed id form) matched nothing while the command still printed `Removed token …` and exited 0. Removal now goes through the shared token resolver, and a reference that matches no tracked token raises the existing not-found error and exits **5** (`RESOURCE_NOT_FOUND`) instead of exiting 0. A script that removed an untracked token and relied on a zero exit will now see a failure. Removal by symbol and by contract address, which previously silently no-op'd, now work.
|
|
12
|
+
|
|
13
|
+
**Behavior change — the agent `vault_coin remove` tool reports per-coin outcomes.** It previously returned `removed: true` unconditionally; it now returns the SDK's actual result, so the model is told when a coin was not tracked. Batch removals return `{ chain, tokenId, removed }` per coin rather than `{ chain, tokenId }`.
|
|
14
|
+
|
|
15
|
+
**Breaking SDK API change — `VaultBase.removeToken` now returns `Promise<boolean>` instead of `Promise<void>`.** It resolves to `true` when a tracked token was removed and persisted, and `false` when the reference matched nothing. Consumers with callbacks, interfaces, or overrides typed to the previous `Promise<void>` signature must update those types.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#1642](https://github.com/vultisig/vultisig-sdk/pull/1642) [`ac5becb`](https://github.com/vultisig/vultisig-sdk/commit/ac5becb7939bc8c6b45d04cd00067e0d2caf6297) Thanks [@neavra](https://github.com/neavra)! - Show the user-visible memo and XRP destination tag from the signable transaction payload in both send dry-run and pre-signing confirmation previews, with terminal-safe dry-run rendering.
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [[`b9f81af`](https://github.com/vultisig/vultisig-sdk/commit/b9f81af9065a5c0bfc2f86f8fb20aa51e670ab77), [`c0e260f`](https://github.com/vultisig/vultisig-sdk/commit/c0e260f89d159d14b170384864b24b101b23dfb0), [`2ef8f3f`](https://github.com/vultisig/vultisig-sdk/commit/2ef8f3f42f5d44673568b39a91c42bd0fe410311), [`791d344`](https://github.com/vultisig/vultisig-sdk/commit/791d344c2dacc289c9fb7fbcbc38488aeeb47542)]:
|
|
22
|
+
- @vultisig/core-chain@2.31.0
|
|
23
|
+
- @vultisig/sdk@4.0.0
|
|
24
|
+
- @vultisig/client-shared@0.3.2
|
|
25
|
+
- @vultisig/rujira@59.0.0
|
|
26
|
+
|
|
27
|
+
## 3.1.0
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [[`645e291`](https://github.com/vultisig/vultisig-sdk/commit/645e2917aa1b6cd58c5599ddb32b1c89fa73e20e), [`9436de6`](https://github.com/vultisig/vultisig-sdk/commit/9436de627b4d123d7f9bb76e4981722cd84266d1)]:
|
|
32
|
+
- @vultisig/core-chain@2.30.0
|
|
33
|
+
- @vultisig/sdk@3.1.0
|
|
34
|
+
- @vultisig/rujira@58.0.0
|
|
35
|
+
|
|
3
36
|
## 3.0.0
|
|
4
37
|
|
|
5
38
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -5828,6 +5828,12 @@ import { fiatCurrencies, fiatCurrencyNameRecord as fiatCurrencyNameRecord2 } fro
|
|
|
5828
5828
|
// src/ui.ts
|
|
5829
5829
|
import { fiatCurrencyNameRecord, fromChainAmountExact, Vultisig } from "@vultisig/sdk";
|
|
5830
5830
|
import chalk2 from "chalk";
|
|
5831
|
+
var escapeTerminalControls = (value) => Array.from(value, (character) => {
|
|
5832
|
+
if (character === "\\") return "\\\\";
|
|
5833
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
5834
|
+
const isTerminalControl = codePoint <= 31 || codePoint === 127 || codePoint >= 128 && codePoint <= 159;
|
|
5835
|
+
return isTerminalControl ? `\\x${codePoint.toString(16).padStart(2, "0").toUpperCase()}` : character;
|
|
5836
|
+
}).join("");
|
|
5831
5837
|
function displayBalance(chain, balance, _raw = false) {
|
|
5832
5838
|
printResult(chalk2.cyan(`
|
|
5833
5839
|
${chain} Balance:`));
|
|
@@ -5933,7 +5939,7 @@ Estimated gas: ${JSON.stringify(gas, bigIntReplacer2, 2)}`));
|
|
|
5933
5939
|
printResult(` Amount: ${amount} ${symbol}`);
|
|
5934
5940
|
printResult(` Chain: ${chain}`);
|
|
5935
5941
|
if (memo) {
|
|
5936
|
-
printResult(` Memo: ${memo}`);
|
|
5942
|
+
printResult(` Memo: ${escapeTerminalControls(memo)}`);
|
|
5937
5943
|
}
|
|
5938
5944
|
if (destinationTag !== void 0) {
|
|
5939
5945
|
printResult(` Destination tag: ${destinationTag}`);
|
|
@@ -6244,7 +6250,8 @@ var EthereumL2Chain = {
|
|
|
6244
6250
|
Blast: "Blast",
|
|
6245
6251
|
Optimism: "Optimism",
|
|
6246
6252
|
Zksync: "Zksync",
|
|
6247
|
-
Mantle: "Mantle"
|
|
6253
|
+
Mantle: "Mantle",
|
|
6254
|
+
Robinhood: "Robinhood"
|
|
6248
6255
|
};
|
|
6249
6256
|
var EvmChain = {
|
|
6250
6257
|
...EthereumL2Chain,
|
|
@@ -6323,6 +6330,7 @@ var chainKindRecord = {
|
|
|
6323
6330
|
[EvmChain.Mantle]: "evm",
|
|
6324
6331
|
[EvmChain.Hyperliquid]: "evm",
|
|
6325
6332
|
[EvmChain.Sei]: "evm",
|
|
6333
|
+
[EvmChain.Robinhood]: "evm",
|
|
6326
6334
|
[UtxoChain.Bitcoin]: "utxo",
|
|
6327
6335
|
[UtxoChain.BitcoinCash]: "utxo",
|
|
6328
6336
|
[UtxoChain.Litecoin]: "utxo",
|
|
@@ -7296,7 +7304,10 @@ async function addToken(ctx2, options) {
|
|
|
7296
7304
|
}
|
|
7297
7305
|
async function removeToken(ctx2, chain, tokenId) {
|
|
7298
7306
|
const vault = await ctx2.ensureActiveVault();
|
|
7299
|
-
await vault.removeToken(chain, tokenId);
|
|
7307
|
+
const removed = await vault.removeToken(chain, tokenId);
|
|
7308
|
+
if (!removed) {
|
|
7309
|
+
throw new TokenNotFoundError(`Token "${tokenId}" not found on ${chain}`);
|
|
7310
|
+
}
|
|
7300
7311
|
success(`
|
|
7301
7312
|
+ Removed token ${tokenId} from ${chain}`);
|
|
7302
7313
|
}
|
|
@@ -7411,8 +7422,57 @@ var normalizeRippleDestination = (address) => {
|
|
|
7411
7422
|
return { address: value };
|
|
7412
7423
|
};
|
|
7413
7424
|
|
|
7425
|
+
// ../../packages/core/mpc/dist/keysign/error.js
|
|
7426
|
+
var BuildKeysignPayloadError = class extends Error {
|
|
7427
|
+
type;
|
|
7428
|
+
constructor(type, message = type) {
|
|
7429
|
+
super(message);
|
|
7430
|
+
this.type = type;
|
|
7431
|
+
this.name = "BuildKeysignPayloadError";
|
|
7432
|
+
}
|
|
7433
|
+
};
|
|
7434
|
+
|
|
7435
|
+
// ../../packages/core/mpc/dist/keysign/utils/rippleDestinationTag.js
|
|
7436
|
+
var maxRippleDestinationTag = 4294967295;
|
|
7437
|
+
var getLegacyDestinationTag = (memo) => {
|
|
7438
|
+
if (!memo || !/^(0|[1-9]\d*)$/.test(memo))
|
|
7439
|
+
return void 0;
|
|
7440
|
+
const destinationTag = Number(memo);
|
|
7441
|
+
return destinationTag <= maxRippleDestinationTag ? destinationTag : void 0;
|
|
7442
|
+
};
|
|
7443
|
+
var validateDestinationTag = (destinationTag) => {
|
|
7444
|
+
if (!Number.isInteger(destinationTag) || destinationTag < 0 || destinationTag > maxRippleDestinationTag) {
|
|
7445
|
+
throw new BuildKeysignPayloadError("ripple-destination-tag-invalid", `Invalid XRP destination tag: expected an integer between 0 and ${maxRippleDestinationTag}`);
|
|
7446
|
+
}
|
|
7447
|
+
return destinationTag;
|
|
7448
|
+
};
|
|
7449
|
+
var resolveDestinationTag = ({ destinationTag, memo }) => {
|
|
7450
|
+
if (destinationTag !== void 0)
|
|
7451
|
+
return validateDestinationTag(destinationTag);
|
|
7452
|
+
return getLegacyDestinationTag(memo);
|
|
7453
|
+
};
|
|
7454
|
+
|
|
7414
7455
|
// src/commands/transaction.ts
|
|
7415
7456
|
import { Chain as Chain4, Vultisig as Vultisig2 } from "@vultisig/sdk";
|
|
7457
|
+
var getSendPreviewDetails = (chain, keysignPayload) => {
|
|
7458
|
+
let memo = keysignPayload.memo || void 0;
|
|
7459
|
+
if (chain !== Chain4.Ripple) {
|
|
7460
|
+
return { memo, destinationTag: void 0 };
|
|
7461
|
+
}
|
|
7462
|
+
const rippleSpecific = keysignPayload.blockchainSpecific;
|
|
7463
|
+
if (rippleSpecific.case !== "rippleSpecific") {
|
|
7464
|
+
throw new Error("Ripple send payload is missing Ripple-specific data");
|
|
7465
|
+
}
|
|
7466
|
+
const destinationTag = resolveDestinationTag({
|
|
7467
|
+
destinationTag: rippleSpecific.value.destinationTag,
|
|
7468
|
+
memo
|
|
7469
|
+
});
|
|
7470
|
+
const legacyMemoDestinationTag = getLegacyDestinationTag(memo);
|
|
7471
|
+
if (legacyMemoDestinationTag !== void 0 && legacyMemoDestinationTag === destinationTag) {
|
|
7472
|
+
memo = void 0;
|
|
7473
|
+
}
|
|
7474
|
+
return { memo, destinationTag };
|
|
7475
|
+
};
|
|
7416
7476
|
async function executeSend(ctx2, params) {
|
|
7417
7477
|
const vault = await ctx2.ensureActiveVault();
|
|
7418
7478
|
if (!Object.values(Chain4).includes(params.chain)) {
|
|
@@ -7424,9 +7484,13 @@ async function executeSend(ctx2, params) {
|
|
|
7424
7484
|
}
|
|
7425
7485
|
return sendTransaction(vault, params);
|
|
7426
7486
|
}
|
|
7427
|
-
async function previewDryRun(vault, params, dryResult, to
|
|
7487
|
+
async function previewDryRun(vault, params, dryResult, to) {
|
|
7428
7488
|
const balance = await vault.balance(params.chain, params.tokenId);
|
|
7429
7489
|
const hasInsufficientBalance = parseFloat(dryResult.total) > parseFloat(balance.formattedAmount);
|
|
7490
|
+
const { memo: previewMemo, destinationTag: payloadDestinationTag } = getSendPreviewDetails(
|
|
7491
|
+
params.chain,
|
|
7492
|
+
dryResult.keysignPayload
|
|
7493
|
+
);
|
|
7430
7494
|
const isTokenSend = balance.tokenId !== void 0;
|
|
7431
7495
|
const feeBalance = isTokenSend ? await vault.balance(params.chain).catch(() => void 0) : void 0;
|
|
7432
7496
|
const warnings = [];
|
|
@@ -7450,7 +7514,8 @@ async function previewDryRun(vault, params, dryResult, to, destinationTag) {
|
|
|
7450
7514
|
feeSymbol: dryResult.feeSymbol,
|
|
7451
7515
|
total: dryResult.total,
|
|
7452
7516
|
balance: balance.formattedAmount,
|
|
7453
|
-
destinationTag,
|
|
7517
|
+
destinationTag: payloadDestinationTag,
|
|
7518
|
+
...previewMemo ? { memo: previewMemo } : {},
|
|
7454
7519
|
...warnings.length > 0 ? { warning: warnings.join(". ") } : {}
|
|
7455
7520
|
};
|
|
7456
7521
|
if (isJsonOutput()) {
|
|
@@ -7463,6 +7528,7 @@ Dry-run preview:`);
|
|
|
7463
7528
|
info(` To: ${result.to}`);
|
|
7464
7529
|
info(` Amount: ${result.amount} ${result.symbol}`);
|
|
7465
7530
|
if (result.destinationTag !== void 0) info(` Destination tag: ${result.destinationTag}`);
|
|
7531
|
+
if (result.memo) info(` Memo: ${escapeTerminalControls(result.memo)}`);
|
|
7466
7532
|
info(` Fee: ${result.fee} ${result.feeSymbol}`);
|
|
7467
7533
|
info(` Total: ${result.total} ${result.symbol}`);
|
|
7468
7534
|
info(` Balance: ${result.balance} ${result.symbol}`);
|
|
@@ -7497,7 +7563,7 @@ async function sendTransaction(vault, params) {
|
|
|
7497
7563
|
prepareSpinner.succeed("Transaction prepared");
|
|
7498
7564
|
if (!dryResult.dryRun) throw new Error("unreachable");
|
|
7499
7565
|
if (params.dryRun) {
|
|
7500
|
-
return previewDryRun(vault, params, dryResult, to
|
|
7566
|
+
return previewDryRun(vault, params, dryResult, to);
|
|
7501
7567
|
}
|
|
7502
7568
|
let gas;
|
|
7503
7569
|
try {
|
|
@@ -7508,14 +7574,15 @@ async function sendTransaction(vault, params) {
|
|
|
7508
7574
|
const balance = await vault.balance(params.chain, params.tokenId);
|
|
7509
7575
|
if (!isJsonOutput()) {
|
|
7510
7576
|
const address = await vault.address(params.chain);
|
|
7577
|
+
const preview = getSendPreviewDetails(params.chain, dryResult.keysignPayload);
|
|
7511
7578
|
displayTransactionPreview(
|
|
7512
7579
|
address,
|
|
7513
7580
|
to,
|
|
7514
7581
|
dryResult.total,
|
|
7515
7582
|
balance.symbol,
|
|
7516
7583
|
params.chain,
|
|
7517
|
-
|
|
7518
|
-
destinationTag,
|
|
7584
|
+
preview.memo,
|
|
7585
|
+
preview.destinationTag,
|
|
7519
7586
|
gas
|
|
7520
7587
|
);
|
|
7521
7588
|
}
|
|
@@ -11028,8 +11095,8 @@ var AgentExecutor = class {
|
|
|
11028
11095
|
`vault_coin remove: missing contract_address for ${t.ticker || t.symbol || "coin"} on ${t.chain}`
|
|
11029
11096
|
);
|
|
11030
11097
|
}
|
|
11031
|
-
await this.vault.removeToken(chain2, tokenId2);
|
|
11032
|
-
results.push({ chain: chain2.toString(), tokenId: tokenId2 });
|
|
11098
|
+
const removed2 = await this.vault.removeToken(chain2, tokenId2);
|
|
11099
|
+
results.push({ chain: chain2.toString(), tokenId: tokenId2, removed: removed2 });
|
|
11033
11100
|
}
|
|
11034
11101
|
return { removed: results };
|
|
11035
11102
|
}
|
|
@@ -11040,8 +11107,8 @@ var AgentExecutor = class {
|
|
|
11040
11107
|
if (!tokenId) {
|
|
11041
11108
|
throw new Error(`vault_coin remove: missing contract_address for coin on ${chainName}`);
|
|
11042
11109
|
}
|
|
11043
|
-
await this.vault.removeToken(chain, tokenId);
|
|
11044
|
-
return { chain: chain.toString(), removed
|
|
11110
|
+
const removed = await this.vault.removeToken(chain, tokenId);
|
|
11111
|
+
return { chain: chain.toString(), removed };
|
|
11045
11112
|
}
|
|
11046
11113
|
async removeChain(_toolCallId, input) {
|
|
11047
11114
|
return this.runTool("remove_chain", () => this.removeChainImpl(input));
|
|
@@ -14883,6 +14950,13 @@ function summarizeData(data) {
|
|
|
14883
14950
|
return `tx: ${data.tx_hash.slice(0, 12)}...`;
|
|
14884
14951
|
}
|
|
14885
14952
|
if (data.added) return "added";
|
|
14953
|
+
if (Array.isArray(data.removed)) {
|
|
14954
|
+
const entries = data.removed;
|
|
14955
|
+
const removed = entries.filter((entry) => entry.removed).length;
|
|
14956
|
+
if (removed === 0) return "not tracked";
|
|
14957
|
+
return removed === entries.length ? "removed" : `removed ${removed}/${entries.length}`;
|
|
14958
|
+
}
|
|
14959
|
+
if (data.removed === false) return "not tracked";
|
|
14886
14960
|
if (data.removed) return "removed";
|
|
14887
14961
|
if (data.message) return data.message;
|
|
14888
14962
|
return "";
|
|
@@ -15271,7 +15345,7 @@ var cachedVersion = null;
|
|
|
15271
15345
|
function getVersion() {
|
|
15272
15346
|
if (cachedVersion) return cachedVersion;
|
|
15273
15347
|
if (true) {
|
|
15274
|
-
cachedVersion = "
|
|
15348
|
+
cachedVersion = "4.0.0";
|
|
15275
15349
|
return cachedVersion;
|
|
15276
15350
|
}
|
|
15277
15351
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.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": {
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"@cosmjs/stargate": "^0.39.0",
|
|
74
74
|
"@napi-rs/keyring": "^1.3.0",
|
|
75
75
|
"@noble/hashes": "^2.2.0",
|
|
76
|
-
"@vultisig/client-shared": "^0.3.
|
|
77
|
-
"@vultisig/core-chain": "^2.
|
|
78
|
-
"@vultisig/rujira": "^
|
|
79
|
-
"@vultisig/sdk": "^
|
|
76
|
+
"@vultisig/client-shared": "^0.3.2",
|
|
77
|
+
"@vultisig/core-chain": "^2.31.0",
|
|
78
|
+
"@vultisig/rujira": "^59.0.0",
|
|
79
|
+
"@vultisig/sdk": "^4.0.0",
|
|
80
80
|
"chalk": "^5.6.2",
|
|
81
81
|
"cli-table3": "^0.6.5",
|
|
82
82
|
"commander": "^15.0.0",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"@types/node": "^26.1.1",
|
|
95
95
|
"@types/tabtab": "^3.0.4",
|
|
96
96
|
"@types/ws": "^8.18.1",
|
|
97
|
+
"@vultisig/core-mpc": "^1.16.0",
|
|
97
98
|
"esbuild": "^0.28.1",
|
|
98
99
|
"ethers": "^6.17.0",
|
|
99
100
|
"node-pty": "^1.1.0",
|