@vultisig/cli 2.19.7 → 2.19.10
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 +47 -0
- package/dist/index.js +276 -223
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 2.19.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1076](https://github.com/vultisig/vultisig-sdk/pull/1076) [`5179edd`](https://github.com/vultisig/vultisig-sdk/commit/5179edd9eb25b392941f9649a455e92bfd5bf8b5) Thanks [@neavra](https://github.com/neavra)! - fix(chains): validate `chains --add <chain>` against the registry before persisting
|
|
8
|
+
|
|
9
|
+
An invalid `chains --add fakechain` correctly reported INVALID_CHAIN but still wrote
|
|
10
|
+
"fakechain" to the vault's chain list (chain resolution falls back to the raw user
|
|
11
|
+
string when the name doesn't match the registry). Every subsequent address-deriving
|
|
12
|
+
command then re-derived the bogus chain and dumped a stack trace to stderr until it was
|
|
13
|
+
manually removed. The `--add` path now validates against the supported-chain registry
|
|
14
|
+
first and fails closed — nothing is persisted for an unsupported chain.
|
|
15
|
+
|
|
16
|
+
- [#1127](https://github.com/vultisig/vultisig-sdk/pull/1127) [`dea1efa`](https://github.com/vultisig/vultisig-sdk/commit/dea1efae6fbd2975de4ac5a26b2e8210999a0f4f) Thanks [@neavra](https://github.com/neavra)! - fix(cli): honor VULTISIG_CONFIG_DIR for vault storage
|
|
17
|
+
|
|
18
|
+
The documented `VULTISIG_CONFIG_DIR` env var was a no-op for vault storage: the
|
|
19
|
+
CLI constructed the SDK without a storage override, so vaults, the active-vault
|
|
20
|
+
pointer and cache always resolved to `~/.vultisig` even when the var pointed
|
|
21
|
+
elsewhere — only `config.json` and the agent journal honored it, producing a
|
|
22
|
+
split-brain config location that broke CI/container isolation and multi-tenant
|
|
23
|
+
use. The CLI now roots SDK vault storage at `getConfigDir()` via a shared
|
|
24
|
+
`createVaultStorage()` helper. When the var is unset it falls back to
|
|
25
|
+
`~/.vultisig`, so the default location is unchanged.
|
|
26
|
+
|
|
27
|
+
- [#1126](https://github.com/vultisig/vultisig-sdk/pull/1126) [`6054ff5`](https://github.com/vultisig/vultisig-sdk/commit/6054ff599e4133c9853f31e8ca2413ab52f606fb) Thanks [@neavra](https://github.com/neavra)! - fix(mpc): keep keygen tracing off stdout so `-o json` output stays parseable
|
|
28
|
+
|
|
29
|
+
The DKLS and Schnorr keygen/reshare/key-import ceremonies logged progress
|
|
30
|
+
(session ids, raw wire messages, "keygen complete", …) to stdout via ungated
|
|
31
|
+
`console.log`. stdout is the machine channel for the CLI's `-o json` mode, so
|
|
32
|
+
the documented `create fast … -o json` agent flow produced unparseable stdout
|
|
33
|
+
(`JSON.parse(stdout)` failed on the leading garbage) and leaked MPC internals
|
|
34
|
+
into terminals and CI logs.
|
|
35
|
+
|
|
36
|
+
Route that tracing through a gated logger that writes to stderr only when
|
|
37
|
+
`VULTISIG_DEBUG=1`, so stdout carries only the final JSON envelope while
|
|
38
|
+
the debug output stays available to humans on demand. No keygen behavior
|
|
39
|
+
changes — only the log sink moves off stdout.
|
|
40
|
+
|
|
41
|
+
- [#1077](https://github.com/vultisig/vultisig-sdk/pull/1077) [`5e5494c`](https://github.com/vultisig/vultisig-sdk/commit/5e5494cf103ea5c17431b6a6231b30931eb004bb) Thanks [@neavra](https://github.com/neavra)! - Tolerate a corrupt `activeVaultId.json` at startup. A truncated or unparseable
|
|
42
|
+
active-vault pointer used to throw during CLI initialization, which broke every
|
|
43
|
+
command — including `vultisig vaults`, the one you run to recover. The pointer
|
|
44
|
+
read now fails open (treated as "no active vault") and self-heals by clearing
|
|
45
|
+
the bad pointer, so vaults still list with none marked active.
|
|
46
|
+
- Updated dependencies [[`280956f`](https://github.com/vultisig/vultisig-sdk/commit/280956f1743564ea271a03c4735f70151b63f161), [`90070f3`](https://github.com/vultisig/vultisig-sdk/commit/90070f39be011821f7508c7ff094025861dce040), [`0e3f86d`](https://github.com/vultisig/vultisig-sdk/commit/0e3f86db82ed086b1e200a6f83434a638f593c17), [`6054ff5`](https://github.com/vultisig/vultisig-sdk/commit/6054ff599e4133c9853f31e8ca2413ab52f606fb), [`b37e726`](https://github.com/vultisig/vultisig-sdk/commit/b37e7264db3291adca1cb366f1311446d6add439), [`1b2636b`](https://github.com/vultisig/vultisig-sdk/commit/1b2636b535736a711fc537a87d2f51090fe6342d), [`2c9d34e`](https://github.com/vultisig/vultisig-sdk/commit/2c9d34e0837f68d92769c7aefa566ffb1c0c52c7), [`ffc75a6`](https://github.com/vultisig/vultisig-sdk/commit/ffc75a6e76af699a78b0fc3411ab052ce5000c91), [`fc595a1`](https://github.com/vultisig/vultisig-sdk/commit/fc595a17cb4901af1dfeac2521b93bb75823068f), [`776c539`](https://github.com/vultisig/vultisig-sdk/commit/776c5398764314f140f18ab4f86a1801fe9fdfe6)]:
|
|
47
|
+
- @vultisig/sdk@2.19.10
|
|
48
|
+
- @vultisig/core-chain@2.24.2
|
|
49
|
+
|
|
3
50
|
## 2.19.7
|
|
4
51
|
|
|
5
52
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -5899,234 +5899,33 @@ async function executePortfolio(ctx2, options = {}) {
|
|
|
5899
5899
|
// src/commands/chains.ts
|
|
5900
5900
|
import { SUPPORTED_CHAINS } from "@vultisig/sdk";
|
|
5901
5901
|
import chalk3 from "chalk";
|
|
5902
|
-
async function executeChains(ctx2, options = {}) {
|
|
5903
|
-
const vault = await ctx2.ensureActiveVault();
|
|
5904
|
-
if (options.addAll) {
|
|
5905
|
-
const currentCount = vault.chains.length;
|
|
5906
|
-
const spinner = createSpinner(`Adding all ${SUPPORTED_CHAINS.length} supported chains...`);
|
|
5907
|
-
await vault.setChains([...SUPPORTED_CHAINS]);
|
|
5908
|
-
const addedCount = SUPPORTED_CHAINS.length - currentCount;
|
|
5909
|
-
spinner.succeed(`Added ${addedCount} chains (${SUPPORTED_CHAINS.length} total)`);
|
|
5910
|
-
if (isJsonOutput()) {
|
|
5911
|
-
outputJson({ chains: [...vault.chains], added: addedCount, total: SUPPORTED_CHAINS.length });
|
|
5912
|
-
return;
|
|
5913
|
-
}
|
|
5914
|
-
info(chalk3.gray("\nAll supported chains are now enabled."));
|
|
5915
|
-
return;
|
|
5916
|
-
}
|
|
5917
|
-
if (options.add) {
|
|
5918
|
-
const alreadyActive = vault.chains.includes(options.add);
|
|
5919
|
-
if (!alreadyActive) {
|
|
5920
|
-
await vault.addChain(options.add);
|
|
5921
|
-
}
|
|
5922
|
-
const address = await vault.address(options.add);
|
|
5923
|
-
if (isJsonOutput()) {
|
|
5924
|
-
outputJson({ chain: options.add, alreadyActive, address, chains: [...vault.chains] });
|
|
5925
|
-
return;
|
|
5926
|
-
}
|
|
5927
|
-
success(alreadyActive ? `
|
|
5928
|
-
Chain already active: ${options.add}` : `
|
|
5929
|
-
+ Added chain: ${options.add}`);
|
|
5930
|
-
info(`Address: ${address}`);
|
|
5931
|
-
} else if (options.remove) {
|
|
5932
|
-
await vault.removeChain(options.remove);
|
|
5933
|
-
if (isJsonOutput()) {
|
|
5934
|
-
outputJson({ chain: options.remove, removed: true, chains: [...vault.chains] });
|
|
5935
|
-
return;
|
|
5936
|
-
}
|
|
5937
|
-
success(`
|
|
5938
|
-
+ Removed chain: ${options.remove}`);
|
|
5939
|
-
} else {
|
|
5940
|
-
const chains = vault.chains;
|
|
5941
|
-
if (isJsonOutput()) {
|
|
5942
|
-
outputJson({ chains: [...chains] });
|
|
5943
|
-
return;
|
|
5944
|
-
}
|
|
5945
|
-
printResult(chalk3.cyan("\nActive Chains:\n"));
|
|
5946
|
-
chains.forEach((chain) => {
|
|
5947
|
-
printResult(` - ${chain}`);
|
|
5948
|
-
});
|
|
5949
|
-
info(chalk3.gray(`
|
|
5950
|
-
${chains.length} of ${SUPPORTED_CHAINS.length} chains enabled`));
|
|
5951
|
-
info(chalk3.gray("Use --add <chain>, --add-all, or --remove <chain>"));
|
|
5952
|
-
}
|
|
5953
|
-
}
|
|
5954
|
-
async function executeAddresses(ctx2) {
|
|
5955
|
-
const vault = await ctx2.ensureActiveVault();
|
|
5956
|
-
const spinner = createSpinner("Loading addresses...");
|
|
5957
|
-
const addresses = await vault.addresses();
|
|
5958
|
-
spinner.succeed("Addresses loaded");
|
|
5959
|
-
if (isJsonOutput()) {
|
|
5960
|
-
outputJson({ addresses });
|
|
5961
|
-
return;
|
|
5962
|
-
}
|
|
5963
|
-
displayAddresses(addresses);
|
|
5964
|
-
}
|
|
5965
5902
|
|
|
5966
|
-
// src/
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
await ctx2.ensureActiveVault();
|
|
5971
|
-
if (options.discover) {
|
|
5972
|
-
await discoverTokens(ctx2, options.chain);
|
|
5973
|
-
return;
|
|
5974
|
-
}
|
|
5975
|
-
if (options.add) {
|
|
5976
|
-
let symbol = options.symbol;
|
|
5977
|
-
let name = options.name;
|
|
5978
|
-
let decimals = options.decimals;
|
|
5979
|
-
const prompts = [];
|
|
5980
|
-
if (!symbol) {
|
|
5981
|
-
prompts.push({
|
|
5982
|
-
type: "input",
|
|
5983
|
-
name: "symbol",
|
|
5984
|
-
message: "Enter token symbol (e.g., USDT):",
|
|
5985
|
-
validate: (input) => input.trim() !== "" || "Symbol is required"
|
|
5986
|
-
});
|
|
5987
|
-
}
|
|
5988
|
-
if (!name) {
|
|
5989
|
-
prompts.push({
|
|
5990
|
-
type: "input",
|
|
5991
|
-
name: "name",
|
|
5992
|
-
message: "Enter token name (e.g., Tether USD):",
|
|
5993
|
-
validate: (input) => input.trim() !== "" || "Name is required"
|
|
5994
|
-
});
|
|
5995
|
-
}
|
|
5996
|
-
if (decimals === void 0) {
|
|
5997
|
-
prompts.push({
|
|
5998
|
-
type: "number",
|
|
5999
|
-
name: "decimals",
|
|
6000
|
-
message: "Enter token decimals:",
|
|
6001
|
-
default: 18,
|
|
6002
|
-
validate: (input) => input >= 0 || "Decimals must be non-negative"
|
|
6003
|
-
});
|
|
6004
|
-
}
|
|
6005
|
-
if (prompts.length > 0) {
|
|
6006
|
-
requireInteractive("Provide --symbol, --name, and --decimals flags for non-interactive token addition.");
|
|
6007
|
-
const answers = await inquirer3.prompt(prompts);
|
|
6008
|
-
symbol = symbol || answers.symbol?.trim();
|
|
6009
|
-
name = name || answers.name?.trim();
|
|
6010
|
-
decimals = decimals ?? answers.decimals;
|
|
6011
|
-
}
|
|
6012
|
-
await addToken(ctx2, {
|
|
6013
|
-
chain: options.chain,
|
|
6014
|
-
contractAddress: options.add,
|
|
6015
|
-
symbol,
|
|
6016
|
-
name,
|
|
6017
|
-
decimals
|
|
6018
|
-
});
|
|
6019
|
-
} else if (options.remove) {
|
|
6020
|
-
await removeToken(ctx2, options.chain, options.remove);
|
|
6021
|
-
} else {
|
|
6022
|
-
await listTokens(ctx2, options.chain);
|
|
6023
|
-
}
|
|
6024
|
-
}
|
|
6025
|
-
async function addToken(ctx2, options) {
|
|
6026
|
-
const vault = await ctx2.ensureActiveVault();
|
|
6027
|
-
await vault.addToken(options.chain, {
|
|
6028
|
-
id: `${options.chain}-${options.contractAddress}`,
|
|
6029
|
-
contractAddress: options.contractAddress,
|
|
6030
|
-
symbol: options.symbol,
|
|
6031
|
-
name: options.name,
|
|
6032
|
-
decimals: options.decimals,
|
|
6033
|
-
chainId: options.chain,
|
|
6034
|
-
isNative: false
|
|
6035
|
-
});
|
|
6036
|
-
success(`
|
|
6037
|
-
+ Added token ${options.symbol} on ${options.chain}`);
|
|
6038
|
-
}
|
|
6039
|
-
async function removeToken(ctx2, chain, tokenId) {
|
|
6040
|
-
const vault = await ctx2.ensureActiveVault();
|
|
6041
|
-
await vault.removeToken(chain, tokenId);
|
|
6042
|
-
success(`
|
|
6043
|
-
+ Removed token ${tokenId} from ${chain}`);
|
|
6044
|
-
}
|
|
6045
|
-
async function discoverTokens(ctx2, chain) {
|
|
6046
|
-
const vault = await ctx2.ensureActiveVault();
|
|
6047
|
-
const spinner = createSpinner(`Discovering tokens on ${chain}...`);
|
|
6048
|
-
let discovered;
|
|
5903
|
+
// src/core/active-vault.ts
|
|
5904
|
+
var ACTIVE_VAULT_ID_KEY = "activeVaultId";
|
|
5905
|
+
async function loadActiveVaultSafely(sdk) {
|
|
5906
|
+
let activeId;
|
|
6049
5907
|
try {
|
|
6050
|
-
|
|
5908
|
+
activeId = await sdk.storage.get(ACTIVE_VAULT_ID_KEY);
|
|
6051
5909
|
} catch (err) {
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
5910
|
+
process.stderr.write(
|
|
5911
|
+
`Warning: active vault pointer is unreadable and was ignored (no active vault). ${err?.message ?? ""}
|
|
5912
|
+
`
|
|
5913
|
+
);
|
|
5914
|
+
try {
|
|
5915
|
+
await sdk.setActiveVault(null);
|
|
5916
|
+
} catch {
|
|
6059
5917
|
}
|
|
6060
|
-
return;
|
|
6061
|
-
}
|
|
6062
|
-
const existingTokens = vault.getTokens(chain);
|
|
6063
|
-
const existingAddresses = new Set(existingTokens.map((t) => t.contractAddress ?? t.id));
|
|
6064
|
-
const newTokens = discovered.filter((d) => d.contractAddress && !existingAddresses.has(d.contractAddress));
|
|
6065
|
-
for (const d of newTokens) {
|
|
6066
|
-
await vault.addToken(chain, {
|
|
6067
|
-
id: d.contractAddress,
|
|
6068
|
-
symbol: d.ticker,
|
|
6069
|
-
name: d.ticker,
|
|
6070
|
-
decimals: d.decimals,
|
|
6071
|
-
contractAddress: d.contractAddress,
|
|
6072
|
-
chainId: chain,
|
|
6073
|
-
isNative: false
|
|
6074
|
-
});
|
|
5918
|
+
return { vault: null, corruptPointer: true };
|
|
6075
5919
|
}
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
if (isJsonOutput()) {
|
|
6079
|
-
outputJson({
|
|
6080
|
-
chain,
|
|
6081
|
-
discovered: newTokens.map((d) => ({
|
|
6082
|
-
symbol: d.ticker,
|
|
6083
|
-
contractAddress: d.contractAddress,
|
|
6084
|
-
decimals: d.decimals
|
|
6085
|
-
})),
|
|
6086
|
-
count: newTokens.length
|
|
6087
|
-
});
|
|
6088
|
-
return;
|
|
5920
|
+
if (activeId === null || activeId === void 0) {
|
|
5921
|
+
return { vault: null, corruptPointer: false };
|
|
6089
5922
|
}
|
|
6090
|
-
|
|
6091
|
-
printResult(` ${d.ticker} (${d.contractAddress})`);
|
|
6092
|
-
}
|
|
6093
|
-
info(chalk4.gray(`
|
|
6094
|
-
${allTokens.length} total token(s) tracked on ${chain}`));
|
|
5923
|
+
return { vault: await sdk.getVaultById(activeId), corruptPointer: false };
|
|
6095
5924
|
}
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
const spinner = createSpinner(`Loading tokens for ${chain}...`);
|
|
6099
|
-
const tokens = vault.getTokens(chain);
|
|
6100
|
-
spinner.succeed(`Tokens loaded for ${chain}`);
|
|
6101
|
-
if (isJsonOutput()) {
|
|
6102
|
-
outputJson({ chain, tokens: tokens || [] });
|
|
6103
|
-
return;
|
|
6104
|
-
}
|
|
6105
|
-
if (!tokens || tokens.length === 0) {
|
|
6106
|
-
warn(`
|
|
6107
|
-
No tokens configured for ${chain}`);
|
|
6108
|
-
info(chalk4.gray(`
|
|
6109
|
-
Use --add <contractAddress> to add a token`));
|
|
6110
|
-
} else {
|
|
6111
|
-
printResult(chalk4.cyan(`
|
|
6112
|
-
Tokens for ${chain}:
|
|
6113
|
-
`));
|
|
6114
|
-
const table = tokens.map((token) => ({
|
|
6115
|
-
Symbol: token.symbol,
|
|
6116
|
-
Name: token.name,
|
|
6117
|
-
Contract: token.contractAddress || "N/A",
|
|
6118
|
-
Decimals: token.decimals,
|
|
6119
|
-
Native: token.isNative ? "Yes" : "No"
|
|
6120
|
-
}));
|
|
6121
|
-
printTable(table);
|
|
6122
|
-
info(chalk4.gray(`
|
|
6123
|
-
Use --add <contractAddress> to add or --remove <tokenId> to remove`));
|
|
6124
|
-
}
|
|
5925
|
+
function shouldAutoSelectActiveVault(hasActiveVault, corruptPointer, vaultCount) {
|
|
5926
|
+
return !hasActiveVault && !corruptPointer && vaultCount > 0;
|
|
6125
5927
|
}
|
|
6126
5928
|
|
|
6127
|
-
// src/commands/transaction.ts
|
|
6128
|
-
import { Chain, Vultisig as Vultisig2 } from "@vultisig/sdk";
|
|
6129
|
-
|
|
6130
5929
|
// src/agent/broadcastJournal.ts
|
|
6131
5930
|
import { createHash } from "node:crypto";
|
|
6132
5931
|
import {
|
|
@@ -6703,7 +6502,242 @@ import { getConfigPath, loadConfig, saveConfig } from "@vultisig/client-shared";
|
|
|
6703
6502
|
// src/core/vault-discovery.ts
|
|
6704
6503
|
import { discoverVaultFiles, SEARCH_DIRS } from "@vultisig/client-shared";
|
|
6705
6504
|
|
|
6505
|
+
// src/commands/chains.ts
|
|
6506
|
+
async function executeChains(ctx2, options = {}) {
|
|
6507
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6508
|
+
if (options.addAll) {
|
|
6509
|
+
const currentCount = vault.chains.length;
|
|
6510
|
+
const spinner = createSpinner(`Adding all ${SUPPORTED_CHAINS.length} supported chains...`);
|
|
6511
|
+
await vault.setChains([...SUPPORTED_CHAINS]);
|
|
6512
|
+
const addedCount = SUPPORTED_CHAINS.length - currentCount;
|
|
6513
|
+
spinner.succeed(`Added ${addedCount} chains (${SUPPORTED_CHAINS.length} total)`);
|
|
6514
|
+
if (isJsonOutput()) {
|
|
6515
|
+
outputJson({ chains: [...vault.chains], added: addedCount, total: SUPPORTED_CHAINS.length });
|
|
6516
|
+
return;
|
|
6517
|
+
}
|
|
6518
|
+
info(chalk3.gray("\nAll supported chains are now enabled."));
|
|
6519
|
+
return;
|
|
6520
|
+
}
|
|
6521
|
+
if (options.add) {
|
|
6522
|
+
if (!SUPPORTED_CHAINS.includes(options.add)) {
|
|
6523
|
+
throw new InvalidChainError(
|
|
6524
|
+
`Unsupported chain: "${options.add}"`,
|
|
6525
|
+
'Run "vultisig chains" to see the supported chains, or check the spelling.',
|
|
6526
|
+
void 0,
|
|
6527
|
+
{ chain: String(options.add) }
|
|
6528
|
+
);
|
|
6529
|
+
}
|
|
6530
|
+
const alreadyActive = vault.chains.includes(options.add);
|
|
6531
|
+
if (!alreadyActive) {
|
|
6532
|
+
await vault.addChain(options.add);
|
|
6533
|
+
}
|
|
6534
|
+
const address = await vault.address(options.add);
|
|
6535
|
+
if (isJsonOutput()) {
|
|
6536
|
+
outputJson({ chain: options.add, alreadyActive, address, chains: [...vault.chains] });
|
|
6537
|
+
return;
|
|
6538
|
+
}
|
|
6539
|
+
success(alreadyActive ? `
|
|
6540
|
+
Chain already active: ${options.add}` : `
|
|
6541
|
+
+ Added chain: ${options.add}`);
|
|
6542
|
+
info(`Address: ${address}`);
|
|
6543
|
+
} else if (options.remove) {
|
|
6544
|
+
await vault.removeChain(options.remove);
|
|
6545
|
+
if (isJsonOutput()) {
|
|
6546
|
+
outputJson({ chain: options.remove, removed: true, chains: [...vault.chains] });
|
|
6547
|
+
return;
|
|
6548
|
+
}
|
|
6549
|
+
success(`
|
|
6550
|
+
+ Removed chain: ${options.remove}`);
|
|
6551
|
+
} else {
|
|
6552
|
+
const chains = vault.chains;
|
|
6553
|
+
if (isJsonOutput()) {
|
|
6554
|
+
outputJson({ chains: [...chains] });
|
|
6555
|
+
return;
|
|
6556
|
+
}
|
|
6557
|
+
printResult(chalk3.cyan("\nActive Chains:\n"));
|
|
6558
|
+
chains.forEach((chain) => {
|
|
6559
|
+
printResult(` - ${chain}`);
|
|
6560
|
+
});
|
|
6561
|
+
info(chalk3.gray(`
|
|
6562
|
+
${chains.length} of ${SUPPORTED_CHAINS.length} chains enabled`));
|
|
6563
|
+
info(chalk3.gray("Use --add <chain>, --add-all, or --remove <chain>"));
|
|
6564
|
+
}
|
|
6565
|
+
}
|
|
6566
|
+
async function executeAddresses(ctx2) {
|
|
6567
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6568
|
+
const spinner = createSpinner("Loading addresses...");
|
|
6569
|
+
const addresses = await vault.addresses();
|
|
6570
|
+
spinner.succeed("Addresses loaded");
|
|
6571
|
+
if (isJsonOutput()) {
|
|
6572
|
+
outputJson({ addresses });
|
|
6573
|
+
return;
|
|
6574
|
+
}
|
|
6575
|
+
displayAddresses(addresses);
|
|
6576
|
+
}
|
|
6577
|
+
|
|
6578
|
+
// src/commands/tokens.ts
|
|
6579
|
+
import chalk4 from "chalk";
|
|
6580
|
+
import inquirer3 from "inquirer";
|
|
6581
|
+
async function executeTokens(ctx2, options) {
|
|
6582
|
+
await ctx2.ensureActiveVault();
|
|
6583
|
+
if (options.discover) {
|
|
6584
|
+
await discoverTokens(ctx2, options.chain);
|
|
6585
|
+
return;
|
|
6586
|
+
}
|
|
6587
|
+
if (options.add) {
|
|
6588
|
+
let symbol = options.symbol;
|
|
6589
|
+
let name = options.name;
|
|
6590
|
+
let decimals = options.decimals;
|
|
6591
|
+
const prompts = [];
|
|
6592
|
+
if (!symbol) {
|
|
6593
|
+
prompts.push({
|
|
6594
|
+
type: "input",
|
|
6595
|
+
name: "symbol",
|
|
6596
|
+
message: "Enter token symbol (e.g., USDT):",
|
|
6597
|
+
validate: (input) => input.trim() !== "" || "Symbol is required"
|
|
6598
|
+
});
|
|
6599
|
+
}
|
|
6600
|
+
if (!name) {
|
|
6601
|
+
prompts.push({
|
|
6602
|
+
type: "input",
|
|
6603
|
+
name: "name",
|
|
6604
|
+
message: "Enter token name (e.g., Tether USD):",
|
|
6605
|
+
validate: (input) => input.trim() !== "" || "Name is required"
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
if (decimals === void 0) {
|
|
6609
|
+
prompts.push({
|
|
6610
|
+
type: "number",
|
|
6611
|
+
name: "decimals",
|
|
6612
|
+
message: "Enter token decimals:",
|
|
6613
|
+
default: 18,
|
|
6614
|
+
validate: (input) => input >= 0 || "Decimals must be non-negative"
|
|
6615
|
+
});
|
|
6616
|
+
}
|
|
6617
|
+
if (prompts.length > 0) {
|
|
6618
|
+
requireInteractive("Provide --symbol, --name, and --decimals flags for non-interactive token addition.");
|
|
6619
|
+
const answers = await inquirer3.prompt(prompts);
|
|
6620
|
+
symbol = symbol || answers.symbol?.trim();
|
|
6621
|
+
name = name || answers.name?.trim();
|
|
6622
|
+
decimals = decimals ?? answers.decimals;
|
|
6623
|
+
}
|
|
6624
|
+
await addToken(ctx2, {
|
|
6625
|
+
chain: options.chain,
|
|
6626
|
+
contractAddress: options.add,
|
|
6627
|
+
symbol,
|
|
6628
|
+
name,
|
|
6629
|
+
decimals
|
|
6630
|
+
});
|
|
6631
|
+
} else if (options.remove) {
|
|
6632
|
+
await removeToken(ctx2, options.chain, options.remove);
|
|
6633
|
+
} else {
|
|
6634
|
+
await listTokens(ctx2, options.chain);
|
|
6635
|
+
}
|
|
6636
|
+
}
|
|
6637
|
+
async function addToken(ctx2, options) {
|
|
6638
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6639
|
+
await vault.addToken(options.chain, {
|
|
6640
|
+
id: `${options.chain}-${options.contractAddress}`,
|
|
6641
|
+
contractAddress: options.contractAddress,
|
|
6642
|
+
symbol: options.symbol,
|
|
6643
|
+
name: options.name,
|
|
6644
|
+
decimals: options.decimals,
|
|
6645
|
+
chainId: options.chain,
|
|
6646
|
+
isNative: false
|
|
6647
|
+
});
|
|
6648
|
+
success(`
|
|
6649
|
+
+ Added token ${options.symbol} on ${options.chain}`);
|
|
6650
|
+
}
|
|
6651
|
+
async function removeToken(ctx2, chain, tokenId) {
|
|
6652
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6653
|
+
await vault.removeToken(chain, tokenId);
|
|
6654
|
+
success(`
|
|
6655
|
+
+ Removed token ${tokenId} from ${chain}`);
|
|
6656
|
+
}
|
|
6657
|
+
async function discoverTokens(ctx2, chain) {
|
|
6658
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6659
|
+
const spinner = createSpinner(`Discovering tokens on ${chain}...`);
|
|
6660
|
+
let discovered;
|
|
6661
|
+
try {
|
|
6662
|
+
discovered = await vault.discoverTokens(chain);
|
|
6663
|
+
} catch (err) {
|
|
6664
|
+
spinner.fail(`Token discovery failed for ${chain}`);
|
|
6665
|
+
throw err;
|
|
6666
|
+
}
|
|
6667
|
+
if (discovered.length === 0) {
|
|
6668
|
+
spinner.succeed(`No new tokens found on ${chain}`);
|
|
6669
|
+
if (isJsonOutput()) {
|
|
6670
|
+
outputJson({ chain, discovered: [], count: 0 });
|
|
6671
|
+
}
|
|
6672
|
+
return;
|
|
6673
|
+
}
|
|
6674
|
+
const existingTokens = vault.getTokens(chain);
|
|
6675
|
+
const existingAddresses = new Set(existingTokens.map((t) => t.contractAddress ?? t.id));
|
|
6676
|
+
const newTokens = discovered.filter((d) => d.contractAddress && !existingAddresses.has(d.contractAddress));
|
|
6677
|
+
for (const d of newTokens) {
|
|
6678
|
+
await vault.addToken(chain, {
|
|
6679
|
+
id: d.contractAddress,
|
|
6680
|
+
symbol: d.ticker,
|
|
6681
|
+
name: d.ticker,
|
|
6682
|
+
decimals: d.decimals,
|
|
6683
|
+
contractAddress: d.contractAddress,
|
|
6684
|
+
chainId: chain,
|
|
6685
|
+
isNative: false
|
|
6686
|
+
});
|
|
6687
|
+
}
|
|
6688
|
+
const allTokens = vault.getTokens(chain);
|
|
6689
|
+
spinner.succeed(`Discovered ${newTokens.length} new token(s) on ${chain}`);
|
|
6690
|
+
if (isJsonOutput()) {
|
|
6691
|
+
outputJson({
|
|
6692
|
+
chain,
|
|
6693
|
+
discovered: newTokens.map((d) => ({
|
|
6694
|
+
symbol: d.ticker,
|
|
6695
|
+
contractAddress: d.contractAddress,
|
|
6696
|
+
decimals: d.decimals
|
|
6697
|
+
})),
|
|
6698
|
+
count: newTokens.length
|
|
6699
|
+
});
|
|
6700
|
+
return;
|
|
6701
|
+
}
|
|
6702
|
+
for (const d of newTokens) {
|
|
6703
|
+
printResult(` ${d.ticker} (${d.contractAddress})`);
|
|
6704
|
+
}
|
|
6705
|
+
info(chalk4.gray(`
|
|
6706
|
+
${allTokens.length} total token(s) tracked on ${chain}`));
|
|
6707
|
+
}
|
|
6708
|
+
async function listTokens(ctx2, chain) {
|
|
6709
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6710
|
+
const spinner = createSpinner(`Loading tokens for ${chain}...`);
|
|
6711
|
+
const tokens = vault.getTokens(chain);
|
|
6712
|
+
spinner.succeed(`Tokens loaded for ${chain}`);
|
|
6713
|
+
if (isJsonOutput()) {
|
|
6714
|
+
outputJson({ chain, tokens: tokens || [] });
|
|
6715
|
+
return;
|
|
6716
|
+
}
|
|
6717
|
+
if (!tokens || tokens.length === 0) {
|
|
6718
|
+
warn(`
|
|
6719
|
+
No tokens configured for ${chain}`);
|
|
6720
|
+
info(chalk4.gray(`
|
|
6721
|
+
Use --add <contractAddress> to add a token`));
|
|
6722
|
+
} else {
|
|
6723
|
+
printResult(chalk4.cyan(`
|
|
6724
|
+
Tokens for ${chain}:
|
|
6725
|
+
`));
|
|
6726
|
+
const table = tokens.map((token) => ({
|
|
6727
|
+
Symbol: token.symbol,
|
|
6728
|
+
Name: token.name,
|
|
6729
|
+
Contract: token.contractAddress || "N/A",
|
|
6730
|
+
Decimals: token.decimals,
|
|
6731
|
+
Native: token.isNative ? "Yes" : "No"
|
|
6732
|
+
}));
|
|
6733
|
+
printTable(table);
|
|
6734
|
+
info(chalk4.gray(`
|
|
6735
|
+
Use --add <contractAddress> to add or --remove <tokenId> to remove`));
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
|
|
6706
6739
|
// src/commands/transaction.ts
|
|
6740
|
+
import { Chain, Vultisig as Vultisig2 } from "@vultisig/sdk";
|
|
6707
6741
|
async function executeSend(ctx2, params) {
|
|
6708
6742
|
const vault = await ctx2.ensureActiveVault();
|
|
6709
6743
|
if (!Object.values(Chain).includes(params.chain)) {
|
|
@@ -14534,7 +14568,7 @@ var cachedVersion = null;
|
|
|
14534
14568
|
function getVersion() {
|
|
14535
14569
|
if (cachedVersion) return cachedVersion;
|
|
14536
14570
|
if (true) {
|
|
14537
|
-
cachedVersion = "2.19.
|
|
14571
|
+
cachedVersion = "2.19.10";
|
|
14538
14572
|
return cachedVersion;
|
|
14539
14573
|
}
|
|
14540
14574
|
try {
|
|
@@ -16150,7 +16184,7 @@ Error: ${error2.message}`));
|
|
|
16150
16184
|
async loadAllVaults() {
|
|
16151
16185
|
const spinner = createSpinner2("Loading vaults...").start();
|
|
16152
16186
|
try {
|
|
16153
|
-
const activeVault = await this.ctx.sdk
|
|
16187
|
+
const { vault: activeVault, corruptPointer } = await loadActiveVaultSafely(this.ctx.sdk);
|
|
16154
16188
|
if (activeVault) {
|
|
16155
16189
|
this.ctx.addVault(activeVault);
|
|
16156
16190
|
await this.ctx.setActiveVault(activeVault);
|
|
@@ -16164,7 +16198,7 @@ Error: ${error2.message}`));
|
|
|
16164
16198
|
this.eventBuffer.setupVaultListeners(vault);
|
|
16165
16199
|
}
|
|
16166
16200
|
});
|
|
16167
|
-
if (
|
|
16201
|
+
if (shouldAutoSelectActiveVault(!!this.ctx.getActiveVault(), corruptPointer, this.ctx.getVaults().size)) {
|
|
16168
16202
|
const firstVault = this.ctx.getVaults().values().next().value;
|
|
16169
16203
|
await this.ctx.setActiveVault(firstVault);
|
|
16170
16204
|
}
|
|
@@ -16174,6 +16208,11 @@ Error: ${error2.message}`));
|
|
|
16174
16208
|
} else {
|
|
16175
16209
|
spinner.succeed("No vaults found");
|
|
16176
16210
|
}
|
|
16211
|
+
if (corruptPointer && !this.ctx.getActiveVault() && this.ctx.getVaults().size > 0) {
|
|
16212
|
+
console.log(
|
|
16213
|
+
chalk14.yellow('Active vault pointer was corrupt and has been reset. Use "vault <name>" to pick one.')
|
|
16214
|
+
);
|
|
16215
|
+
}
|
|
16177
16216
|
} catch (error2) {
|
|
16178
16217
|
if (this.ctx.getVaults().size > 0) {
|
|
16179
16218
|
spinner.succeed(`Loaded ${this.ctx.getVaults().size} vault(s)`);
|
|
@@ -16522,6 +16561,18 @@ complete -c vsig -n "__fish_seen_subcommand_from import export" -a "(__fish_comp
|
|
|
16522
16561
|
`.trim();
|
|
16523
16562
|
}
|
|
16524
16563
|
|
|
16564
|
+
// src/lib/config.ts
|
|
16565
|
+
import { FileStorage } from "@vultisig/sdk/node";
|
|
16566
|
+
import { homedir as homedir6 } from "os";
|
|
16567
|
+
import { join as join6 } from "path";
|
|
16568
|
+
function getConfigDir() {
|
|
16569
|
+
const override = process.env.VULTISIG_CONFIG_DIR?.trim();
|
|
16570
|
+
return override ? override : join6(homedir6(), ".vultisig");
|
|
16571
|
+
}
|
|
16572
|
+
function createVaultStorage() {
|
|
16573
|
+
return new FileStorage({ basePath: getConfigDir() });
|
|
16574
|
+
}
|
|
16575
|
+
|
|
16525
16576
|
// src/lib/errors.ts
|
|
16526
16577
|
import chalk15 from "chalk";
|
|
16527
16578
|
|
|
@@ -16596,6 +16647,7 @@ async function init(vaultOverride, unlockPassword, passwordTTL) {
|
|
|
16596
16647
|
const globalOptions = program.opts();
|
|
16597
16648
|
const serverEndpoints = resolveServerEndpoints(globalOptions);
|
|
16598
16649
|
const sdk = new Vultisig6({
|
|
16650
|
+
storage: createVaultStorage(),
|
|
16599
16651
|
onPasswordRequired: createPasswordCallback(),
|
|
16600
16652
|
...serverEndpoints ? { serverEndpoints } : {},
|
|
16601
16653
|
...passwordTTL !== void 0 ? { passwordCache: { defaultTTL: passwordTTL } } : {}
|
|
@@ -16609,7 +16661,7 @@ async function init(vaultOverride, unlockPassword, passwordTTL) {
|
|
|
16609
16661
|
throw new Error(`Vault not found: "${vaultSelector}"`);
|
|
16610
16662
|
}
|
|
16611
16663
|
} else {
|
|
16612
|
-
vault = await sdk.
|
|
16664
|
+
vault = (await loadActiveVaultSafely(sdk)).vault;
|
|
16613
16665
|
}
|
|
16614
16666
|
if (vault) {
|
|
16615
16667
|
await ctx.setActiveVault(vault);
|
|
@@ -17440,6 +17492,7 @@ program.command("schema", { hidden: true }).description("Output machine-readable
|
|
|
17440
17492
|
async function startInteractiveMode() {
|
|
17441
17493
|
const serverEndpoints = resolveServerEndpoints(parseServerEndpointOverridesFromArgv(process.argv.slice(2)));
|
|
17442
17494
|
const sdk = new Vultisig6({
|
|
17495
|
+
storage: createVaultStorage(),
|
|
17443
17496
|
onPasswordRequired: createPasswordCallback(),
|
|
17444
17497
|
...serverEndpoints ? { serverEndpoints } : {}
|
|
17445
17498
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.10",
|
|
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.2.17",
|
|
77
|
-
"@vultisig/core-chain": "^2.24.
|
|
77
|
+
"@vultisig/core-chain": "^2.24.2",
|
|
78
78
|
"@vultisig/rujira": "^52.0.0",
|
|
79
|
-
"@vultisig/sdk": "^2.19.
|
|
79
|
+
"@vultisig/sdk": "^2.19.10",
|
|
80
80
|
"chalk": "^5.6.2",
|
|
81
81
|
"cli-table3": "^0.6.5",
|
|
82
82
|
"commander": "^15.0.0",
|