@vultisig/cli 2.23.0 → 3.1.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 +70 -0
- package/dist/index.js +128 -133
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,75 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 3.1.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`645e291`](https://github.com/vultisig/vultisig-sdk/commit/645e2917aa1b6cd58c5599ddb32b1c89fa73e20e), [`9436de6`](https://github.com/vultisig/vultisig-sdk/commit/9436de627b4d123d7f9bb76e4981722cd84266d1)]:
|
|
8
|
+
- @vultisig/core-chain@2.30.0
|
|
9
|
+
- @vultisig/sdk@3.1.0
|
|
10
|
+
- @vultisig/rujira@58.0.0
|
|
11
|
+
|
|
12
|
+
## 3.0.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- [#1606](https://github.com/vultisig/vultisig-sdk/pull/1606) [`c593ba0`](https://github.com/vultisig/vultisig-sdk/commit/c593ba0693f6a02402aac0912a97d9e36e8efad0) Thanks [@neavra](https://github.com/neavra)! - Make token references resolve consistently across the vault and CLI surfaces.
|
|
17
|
+
|
|
18
|
+
**`@vultisig/sdk` — consumer-visible behaviour change on `send`, `swap` and `balance`:**
|
|
19
|
+
|
|
20
|
+
- A token reference (the `symbol` on `send`/`swap`, the `tokenId` on `balance`)
|
|
21
|
+
now resolves by contract address / stored vault token id as well as by symbol
|
|
22
|
+
or well-known ticker, through one shared resolver. Previously `send` matched
|
|
23
|
+
by symbol only while `balance` treated the same value as a raw contract
|
|
24
|
+
address, so no single value worked on both paths and an ERC-20 send could not
|
|
25
|
+
be built at all.
|
|
26
|
+
- The change is additive. Symbol/ticker is still matched first and the vault's
|
|
27
|
+
own tokens still shadow the well-known registry, so every reference that
|
|
28
|
+
resolved before resolves to the same token and produces the same signed
|
|
29
|
+
payload. Only references that previously threw now resolve. A reference
|
|
30
|
+
matching nothing is still passed through to the balance layer untouched.
|
|
31
|
+
- `send({ dryRun: true })` gains `feeSymbol` and reports the network fee in the
|
|
32
|
+
chain's native asset. For a token send, `fee` was previously formatted with
|
|
33
|
+
the token's decimals and `total` was amount + fee — both meaningless when the
|
|
34
|
+
fee is paid in a different asset. `total` is now denominated in the asset
|
|
35
|
+
being sent. Native sends are unaffected.
|
|
36
|
+
- A `Balance` for a token is labelled by the same resolution. Previously the
|
|
37
|
+
token was found by an exact match against the vault's stored token id, so a
|
|
38
|
+
well-known token the vault does not track — or one added with an id that is
|
|
39
|
+
not its bare contract address — fell through to a default of 18 decimals with
|
|
40
|
+
the raw id as `symbol`. `formatBalance` now resolves the same way everything
|
|
41
|
+
else does; a token in no registry still falls back as before.
|
|
42
|
+
|
|
43
|
+
**`@vultisig/cli`:**
|
|
44
|
+
|
|
45
|
+
- `send --token` works with either a contract address or a symbol, and its
|
|
46
|
+
dry-run preview quotes the fee in the native asset. The preview also warns
|
|
47
|
+
separately when the native balance cannot cover the fee — a token send draws
|
|
48
|
+
its fee from a different balance than the one `total` is checked against.
|
|
49
|
+
- `portfolio`'s total now equals the sum of the breakdown printed under it, with
|
|
50
|
+
each held token itemized as its own row (`chainBalances[].tokens`).
|
|
51
|
+
- `balance <chain> --tokens` returns token balances instead of silently
|
|
52
|
+
ignoring the flag; without the flag the output is unchanged.
|
|
53
|
+
- `tokens --discover` documents that it saves discovered tokens to the vault.
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
- [#1174](https://github.com/vultisig/vultisig-sdk/pull/1174) [`0d73d9f`](https://github.com/vultisig/vultisig-sdk/commit/0d73d9f5d08b10e52b9461678d7d700afba52e01) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Fix CLI shell completion so vault suggestions read the SDK's real storage layout and honor `VULTISIG_CONFIG_DIR`.
|
|
58
|
+
|
|
59
|
+
- [#1163](https://github.com/vultisig/vultisig-sdk/pull/1163) [`286e342`](https://github.com/vultisig/vultisig-sdk/commit/286e342962e8fa63525c8de25bed84295fd468cd) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Promote THOR/Maya swap-memo parsing into the public SDK API and update the CLI executor to consume the shared helper.
|
|
60
|
+
|
|
61
|
+
- [#1165](https://github.com/vultisig/vultisig-sdk/pull/1165) [`f3fd265`](https://github.com/vultisig/vultisig-sdk/commit/f3fd2654b8d90f5d5aaa3c578fcd5fad752203d3) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Re-export the RN-safe `parseChain`, `parseTicker`, and `knownContracts` helpers from `@vultisig/sdk/platforms/react-native` so mobile consumers can use the SDK's canonical public helpers without maintaining local copies or reaching into non-RN entrypoints.
|
|
62
|
+
|
|
63
|
+
- [#1171](https://github.com/vultisig/vultisig-sdk/pull/1171) [`a24771a`](https://github.com/vultisig/vultisig-sdk/commit/a24771afba7c210423c586f9492d3531cdcd47f5) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Make the SDK's default Node/Electron `FileStorage` honor `VULTISIG_CONFIG_DIR` so default vault storage stays co-located with the CLI config, credentials, cache, and broadcast journal paths.
|
|
64
|
+
|
|
65
|
+
- [#1168](https://github.com/vultisig/vultisig-sdk/pull/1168) [`e40aab2`](https://github.com/vultisig/vultisig-sdk/commit/e40aab24e02c46fd2c3fe95873b14aad4fd2fe6d) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Consolidate `VULTISIG_CONFIG_DIR` resolution into a shared helper so empty or whitespace-only overrides consistently fall back to the default config directory across credentials, config storage, token cache, and broadcast journal paths.
|
|
66
|
+
|
|
67
|
+
- Updated dependencies [[`8061f30`](https://github.com/vultisig/vultisig-sdk/commit/8061f3072cc299196894b3c118bf7046eff8a004), [`4c76c50`](https://github.com/vultisig/vultisig-sdk/commit/4c76c507df970c6bbb1542c72a7ab0e06d039e65), [`bb752e2`](https://github.com/vultisig/vultisig-sdk/commit/bb752e25dc318488a72d9b6b7aa8d484c568dbaa), [`0d73d9f`](https://github.com/vultisig/vultisig-sdk/commit/0d73d9f5d08b10e52b9461678d7d700afba52e01), [`ec4aac7`](https://github.com/vultisig/vultisig-sdk/commit/ec4aac78e96db00cae283fe8a506983a30c42412), [`286e342`](https://github.com/vultisig/vultisig-sdk/commit/286e342962e8fa63525c8de25bed84295fd468cd), [`c593ba0`](https://github.com/vultisig/vultisig-sdk/commit/c593ba0693f6a02402aac0912a97d9e36e8efad0), [`d1ed4bb`](https://github.com/vultisig/vultisig-sdk/commit/d1ed4bbd459bfed006cf9f319d9e39356ffe25b9), [`648d932`](https://github.com/vultisig/vultisig-sdk/commit/648d932b7e3c6f3c30ff7007f3c4e4387879ba38), [`f3fd265`](https://github.com/vultisig/vultisig-sdk/commit/f3fd2654b8d90f5d5aaa3c578fcd5fad752203d3), [`a24771a`](https://github.com/vultisig/vultisig-sdk/commit/a24771afba7c210423c586f9492d3531cdcd47f5), [`6763ddb`](https://github.com/vultisig/vultisig-sdk/commit/6763ddbd382bd71cdf9f24bbd3bde0116a694906), [`e40aab2`](https://github.com/vultisig/vultisig-sdk/commit/e40aab24e02c46fd2c3fe95873b14aad4fd2fe6d), [`259837f`](https://github.com/vultisig/vultisig-sdk/commit/259837f482717624d6422797e088a9341d4f1a23)]:
|
|
68
|
+
- @vultisig/core-chain@2.29.2
|
|
69
|
+
- @vultisig/sdk@3.0.0
|
|
70
|
+
- @vultisig/client-shared@0.3.1
|
|
71
|
+
- @vultisig/rujira@57.0.0
|
|
72
|
+
|
|
3
73
|
## 2.23.0
|
|
4
74
|
|
|
5
75
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -5855,12 +5855,20 @@ function displayPortfolio(portfolio, currency, _raw = false) {
|
|
|
5855
5855
|
printResult(chalk2.cyan("| ") + chalk2.bold.green(totalDisplay) + chalk2.cyan(" |"));
|
|
5856
5856
|
printResult(chalk2.cyan("+----------------------------------------+\n"));
|
|
5857
5857
|
printResult(chalk2.bold("Chain Breakdown:\n"));
|
|
5858
|
-
const table = portfolio.chainBalances.
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5858
|
+
const table = portfolio.chainBalances.flatMap(({ chain, balance, value, tokens }) => [
|
|
5859
|
+
{
|
|
5860
|
+
Chain: chain,
|
|
5861
|
+
Amount: balance.formattedAmount,
|
|
5862
|
+
Symbol: balance.symbol,
|
|
5863
|
+
Value: value ? `${value.amount} ${value.currency.toUpperCase()}` : "N/A"
|
|
5864
|
+
},
|
|
5865
|
+
...(tokens ?? []).map((token) => ({
|
|
5866
|
+
Chain: chain,
|
|
5867
|
+
Amount: token.balance?.formattedAmount ?? "-",
|
|
5868
|
+
Symbol: token.balance?.symbol ?? token.tokenId,
|
|
5869
|
+
Value: `${token.value.amount} ${token.value.currency.toUpperCase()}`
|
|
5870
|
+
}))
|
|
5871
|
+
]);
|
|
5864
5872
|
printTable(table);
|
|
5865
5873
|
}
|
|
5866
5874
|
function displayAddresses(addresses) {
|
|
@@ -6085,6 +6093,16 @@ async function executeBalance(ctx2, options = {}) {
|
|
|
6085
6093
|
const spinner = createSpinner("Loading balances...");
|
|
6086
6094
|
const raw = options.raw ?? false;
|
|
6087
6095
|
if (options.chain) {
|
|
6096
|
+
if (options.includeTokens) {
|
|
6097
|
+
const balances = await vault.balances([options.chain], true);
|
|
6098
|
+
spinner.succeed("Balances loaded");
|
|
6099
|
+
if (isJsonOutput()) {
|
|
6100
|
+
outputJson({ chain: options.chain, balances });
|
|
6101
|
+
return;
|
|
6102
|
+
}
|
|
6103
|
+
displayBalancesTable(balances, raw);
|
|
6104
|
+
return;
|
|
6105
|
+
}
|
|
6088
6106
|
const balance = await vault.balance(options.chain);
|
|
6089
6107
|
spinner.succeed("Balance loaded");
|
|
6090
6108
|
if (isJsonOutput()) {
|
|
@@ -6115,7 +6133,6 @@ async function executePortfolio(ctx2, options = {}) {
|
|
|
6115
6133
|
}
|
|
6116
6134
|
const currencyName = fiatCurrencyNameRecord2[currency];
|
|
6117
6135
|
const spinner = createSpinner(`Loading portfolio in ${currencyName}...`);
|
|
6118
|
-
const totalValue = await vault.getTotalValue(currency);
|
|
6119
6136
|
const chains = vault.chains;
|
|
6120
6137
|
const results = await Promise.all(
|
|
6121
6138
|
chains.map(async (chain) => {
|
|
@@ -6125,12 +6142,34 @@ async function executePortfolio(ctx2, options = {}) {
|
|
|
6125
6142
|
} catch (err) {
|
|
6126
6143
|
return { failure: { chain, stage: "balance", error: conciseError(err) } };
|
|
6127
6144
|
}
|
|
6145
|
+
let values;
|
|
6128
6146
|
try {
|
|
6129
|
-
|
|
6130
|
-
return { entry: { chain, balance, value } };
|
|
6147
|
+
values = await vault.getValues(chain, currency);
|
|
6131
6148
|
} catch (err) {
|
|
6132
6149
|
return { entry: { chain, balance }, failure: { chain, stage: "value", error: conciseError(err) } };
|
|
6133
6150
|
}
|
|
6151
|
+
const { native, ...tokenValues } = values;
|
|
6152
|
+
if (!native) {
|
|
6153
|
+
try {
|
|
6154
|
+
const retried = await vault.getValue(chain, void 0, currency);
|
|
6155
|
+
return { entry: { chain, balance, value: retried, tokens: await withAmounts(tokenValues) } };
|
|
6156
|
+
} catch (err) {
|
|
6157
|
+
return {
|
|
6158
|
+
entry: { chain, balance, tokens: await withAmounts(tokenValues) },
|
|
6159
|
+
failure: { chain, stage: "value", error: conciseError(err) }
|
|
6160
|
+
};
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
return { entry: { chain, balance, value: native, tokens: await withAmounts(tokenValues) } };
|
|
6164
|
+
async function withAmounts(byTokenId) {
|
|
6165
|
+
return Promise.all(
|
|
6166
|
+
Object.entries(byTokenId).map(async ([tokenId, value]) => ({
|
|
6167
|
+
tokenId,
|
|
6168
|
+
value,
|
|
6169
|
+
balance: await vault.balance(chain, tokenId).catch(() => void 0)
|
|
6170
|
+
}))
|
|
6171
|
+
);
|
|
6172
|
+
}
|
|
6134
6173
|
})
|
|
6135
6174
|
);
|
|
6136
6175
|
const chainBalances = [];
|
|
@@ -6147,6 +6186,11 @@ async function executePortfolio(ctx2, options = {}) {
|
|
|
6147
6186
|
["Check your internet connection", "Retry in a few moments"]
|
|
6148
6187
|
);
|
|
6149
6188
|
}
|
|
6189
|
+
const total = chainBalances.reduce(
|
|
6190
|
+
(sum, entry) => sum + parseFloat(entry.value?.amount ?? "0") + (entry.tokens ?? []).reduce((tokenSum, token) => tokenSum + parseFloat(token.value.amount), 0),
|
|
6191
|
+
0
|
|
6192
|
+
);
|
|
6193
|
+
const totalValue = { amount: total.toFixed(2), currency, lastUpdated: Date.now() };
|
|
6150
6194
|
const portfolio = { totalValue, chainBalances };
|
|
6151
6195
|
spinner.succeed("Portfolio loaded");
|
|
6152
6196
|
if (isJsonOutput()) {
|
|
@@ -6324,8 +6368,8 @@ import {
|
|
|
6324
6368
|
writeFileSync,
|
|
6325
6369
|
writeSync
|
|
6326
6370
|
} from "node:fs";
|
|
6327
|
-
import { homedir } from "node:os";
|
|
6328
6371
|
import { dirname, join } from "node:path";
|
|
6372
|
+
import { getVultisigConfigDir } from "@vultisig/client-shared";
|
|
6329
6373
|
|
|
6330
6374
|
// src/agent/agentErrors.ts
|
|
6331
6375
|
import { VaultError as VaultError2, VaultErrorCode as VaultErrorCode2, VaultImportError as VaultImportError2, VaultImportErrorCode as VaultImportErrorCode2 } from "@vultisig/sdk";
|
|
@@ -6560,8 +6604,7 @@ function nowMs() {
|
|
|
6560
6604
|
function journalPath() {
|
|
6561
6605
|
const explicit = process.env.VULTISIG_BROADCAST_JOURNAL_PATH;
|
|
6562
6606
|
if (explicit && explicit.trim()) return explicit;
|
|
6563
|
-
|
|
6564
|
-
return join(dir, "broadcasts.jsonl");
|
|
6607
|
+
return join(getVultisigConfigDir(), "broadcasts.jsonl");
|
|
6565
6608
|
}
|
|
6566
6609
|
function normalize(v, canonicalizeEmptyCalldata = false) {
|
|
6567
6610
|
const normalized = (v ?? "").trim().toLowerCase();
|
|
@@ -7289,7 +7332,7 @@ async function discoverTokens(ctx2, chain) {
|
|
|
7289
7332
|
});
|
|
7290
7333
|
}
|
|
7291
7334
|
const allTokens = vault.getTokens(chain);
|
|
7292
|
-
spinner.succeed(`
|
|
7335
|
+
spinner.succeed(`Now tracking ${newTokens.length} new token(s) on ${chain}`);
|
|
7293
7336
|
if (isJsonOutput()) {
|
|
7294
7337
|
outputJson({
|
|
7295
7338
|
chain,
|
|
@@ -7306,6 +7349,9 @@ async function discoverTokens(ctx2, chain) {
|
|
|
7306
7349
|
printResult(` ${d.ticker} (${d.contractAddress})`);
|
|
7307
7350
|
}
|
|
7308
7351
|
info(chalk4.gray(`
|
|
7352
|
+
Saved to this vault \u2014 tracked tokens count toward portfolio and balance --tokens.`));
|
|
7353
|
+
info(chalk4.gray(`Use --remove <tokenId> to stop tracking one.`));
|
|
7354
|
+
info(chalk4.gray(`
|
|
7309
7355
|
${allTokens.length} total token(s) tracked on ${chain}`));
|
|
7310
7356
|
}
|
|
7311
7357
|
async function listTokens(ctx2, chain) {
|
|
@@ -7378,6 +7424,51 @@ async function executeSend(ctx2, params) {
|
|
|
7378
7424
|
}
|
|
7379
7425
|
return sendTransaction(vault, params);
|
|
7380
7426
|
}
|
|
7427
|
+
async function previewDryRun(vault, params, dryResult, to, destinationTag) {
|
|
7428
|
+
const balance = await vault.balance(params.chain, params.tokenId);
|
|
7429
|
+
const hasInsufficientBalance = parseFloat(dryResult.total) > parseFloat(balance.formattedAmount);
|
|
7430
|
+
const isTokenSend = balance.tokenId !== void 0;
|
|
7431
|
+
const feeBalance = isTokenSend ? await vault.balance(params.chain).catch(() => void 0) : void 0;
|
|
7432
|
+
const warnings = [];
|
|
7433
|
+
if (hasInsufficientBalance) {
|
|
7434
|
+
warnings.push(`Insufficient balance: you have ${balance.formattedAmount} ${balance.symbol}`);
|
|
7435
|
+
}
|
|
7436
|
+
if (isTokenSend && feeBalance === void 0) {
|
|
7437
|
+
warnings.push(`Could not check your ${dryResult.feeSymbol} balance for the network fee`);
|
|
7438
|
+
} else if (feeBalance && parseFloat(dryResult.fee) > parseFloat(feeBalance.formattedAmount)) {
|
|
7439
|
+
warnings.push(
|
|
7440
|
+
`Insufficient ${dryResult.feeSymbol} for the network fee: you have ${feeBalance.formattedAmount} ${dryResult.feeSymbol}, the fee is ${dryResult.fee}`
|
|
7441
|
+
);
|
|
7442
|
+
}
|
|
7443
|
+
const result = {
|
|
7444
|
+
dryRun: true,
|
|
7445
|
+
chain: params.chain,
|
|
7446
|
+
to,
|
|
7447
|
+
amount: params.amount,
|
|
7448
|
+
symbol: balance.symbol,
|
|
7449
|
+
fee: dryResult.fee,
|
|
7450
|
+
feeSymbol: dryResult.feeSymbol,
|
|
7451
|
+
total: dryResult.total,
|
|
7452
|
+
balance: balance.formattedAmount,
|
|
7453
|
+
destinationTag,
|
|
7454
|
+
...warnings.length > 0 ? { warning: warnings.join(". ") } : {}
|
|
7455
|
+
};
|
|
7456
|
+
if (isJsonOutput()) {
|
|
7457
|
+
outputJson(result);
|
|
7458
|
+
return result;
|
|
7459
|
+
}
|
|
7460
|
+
info(`
|
|
7461
|
+
Dry-run preview:`);
|
|
7462
|
+
info(` Chain: ${result.chain}`);
|
|
7463
|
+
info(` To: ${result.to}`);
|
|
7464
|
+
info(` Amount: ${result.amount} ${result.symbol}`);
|
|
7465
|
+
if (result.destinationTag !== void 0) info(` Destination tag: ${result.destinationTag}`);
|
|
7466
|
+
info(` Fee: ${result.fee} ${result.feeSymbol}`);
|
|
7467
|
+
info(` Total: ${result.total} ${result.symbol}`);
|
|
7468
|
+
info(` Balance: ${result.balance} ${result.symbol}`);
|
|
7469
|
+
if (result.warning) warn(` Warning: ${result.warning}`);
|
|
7470
|
+
return result;
|
|
7471
|
+
}
|
|
7381
7472
|
async function sendTransaction(vault, params) {
|
|
7382
7473
|
if (!params.dryRun && !params.yes && isNonInteractive()) {
|
|
7383
7474
|
throw new ConfirmationRequiredError(
|
|
@@ -7406,37 +7497,7 @@ async function sendTransaction(vault, params) {
|
|
|
7406
7497
|
prepareSpinner.succeed("Transaction prepared");
|
|
7407
7498
|
if (!dryResult.dryRun) throw new Error("unreachable");
|
|
7408
7499
|
if (params.dryRun) {
|
|
7409
|
-
|
|
7410
|
-
const hasInsufficientBalance = parseFloat(dryResult.total) > parseFloat(balance2.formattedAmount);
|
|
7411
|
-
const result = {
|
|
7412
|
-
dryRun: true,
|
|
7413
|
-
chain: params.chain,
|
|
7414
|
-
to,
|
|
7415
|
-
amount: params.amount,
|
|
7416
|
-
symbol: balance2.symbol,
|
|
7417
|
-
fee: dryResult.fee,
|
|
7418
|
-
total: dryResult.total,
|
|
7419
|
-
balance: balance2.formattedAmount,
|
|
7420
|
-
destinationTag
|
|
7421
|
-
};
|
|
7422
|
-
if (hasInsufficientBalance) {
|
|
7423
|
-
result.warning = `Insufficient balance: you have ${balance2.formattedAmount} ${balance2.symbol}`;
|
|
7424
|
-
}
|
|
7425
|
-
if (isJsonOutput()) {
|
|
7426
|
-
outputJson(result);
|
|
7427
|
-
} else {
|
|
7428
|
-
info(`
|
|
7429
|
-
Dry-run preview:`);
|
|
7430
|
-
info(` Chain: ${result.chain}`);
|
|
7431
|
-
info(` To: ${result.to}`);
|
|
7432
|
-
info(` Amount: ${result.amount} ${result.symbol}`);
|
|
7433
|
-
if (result.destinationTag !== void 0) info(` Destination tag: ${result.destinationTag}`);
|
|
7434
|
-
info(` Fee: ${result.fee} ${result.symbol}`);
|
|
7435
|
-
info(` Total: ${result.total} ${result.symbol}`);
|
|
7436
|
-
info(` Balance: ${result.balance} ${result.symbol}`);
|
|
7437
|
-
if (result.warning) warn(` Warning: ${result.warning}`);
|
|
7438
|
-
}
|
|
7439
|
-
return result;
|
|
7500
|
+
return previewDryRun(vault, params, dryResult, to, destinationTag);
|
|
7440
7501
|
}
|
|
7441
7502
|
let gas;
|
|
7442
7503
|
try {
|
|
@@ -10358,6 +10419,7 @@ import {
|
|
|
10358
10419
|
Chain as Chain11,
|
|
10359
10420
|
chainFeeCoin,
|
|
10360
10421
|
getChainKind as getChainKind3,
|
|
10422
|
+
parseThorSwapMemo,
|
|
10361
10423
|
resolveChainReference,
|
|
10362
10424
|
VaultError as VaultError3,
|
|
10363
10425
|
VaultErrorCode as VaultErrorCode3,
|
|
@@ -10367,7 +10429,7 @@ import {
|
|
|
10367
10429
|
// src/core/VaultStateStore.ts
|
|
10368
10430
|
import * as fs3 from "node:fs";
|
|
10369
10431
|
import * as path3 from "node:path";
|
|
10370
|
-
import { getVultisigConfigDir } from "@vultisig/client-shared";
|
|
10432
|
+
import { getVultisigConfigDir as getVultisigConfigDir2 } from "@vultisig/client-shared";
|
|
10371
10433
|
var LOCK_STALE_MS = 6e4;
|
|
10372
10434
|
var LOCK_RETRY_INIT_MS = 100;
|
|
10373
10435
|
var LOCK_MAX_WAIT_MS = 3e4;
|
|
@@ -10379,7 +10441,7 @@ var VaultStateStore = class {
|
|
|
10379
10441
|
if (!safeId) {
|
|
10380
10442
|
throw new Error("Invalid vaultId: must contain alphanumeric characters");
|
|
10381
10443
|
}
|
|
10382
|
-
this.baseDir = path3.join(
|
|
10444
|
+
this.baseDir = path3.join(getVultisigConfigDir2(), "vault-state", safeId);
|
|
10383
10445
|
fs3.mkdirSync(this.baseDir, { recursive: true });
|
|
10384
10446
|
}
|
|
10385
10447
|
// -------------------------------------------------------------------------
|
|
@@ -10520,45 +10582,6 @@ function sleep2(ms) {
|
|
|
10520
10582
|
}
|
|
10521
10583
|
|
|
10522
10584
|
// src/agent/executor.ts
|
|
10523
|
-
var THOR_MEMO_CHAIN_TO_ENUM = {
|
|
10524
|
-
BTC: Chain11.Bitcoin,
|
|
10525
|
-
ETH: Chain11.Ethereum,
|
|
10526
|
-
BSC: Chain11.BSC,
|
|
10527
|
-
AVAX: Chain11.Avalanche,
|
|
10528
|
-
BASE: Chain11.Base,
|
|
10529
|
-
// L2 — THORChain routinely quotes Base destinations (PR #439 review finding 1)
|
|
10530
|
-
ARB: Chain11.Arbitrum,
|
|
10531
|
-
// L1-via-bridge path (PR #439 review finding 1)
|
|
10532
|
-
BCH: Chain11.BitcoinCash,
|
|
10533
|
-
LTC: Chain11.Litecoin,
|
|
10534
|
-
DOGE: Chain11.Dogecoin,
|
|
10535
|
-
GAIA: Chain11.Cosmos,
|
|
10536
|
-
THOR: Chain11.THORChain,
|
|
10537
|
-
RUNE: Chain11.THORChain,
|
|
10538
|
-
XRP: Chain11.Ripple,
|
|
10539
|
-
DASH: Chain11.Dash,
|
|
10540
|
-
ZEC: Chain11.Zcash,
|
|
10541
|
-
MAYA: Chain11.MayaChain,
|
|
10542
|
-
CACAO: Chain11.MayaChain
|
|
10543
|
-
};
|
|
10544
|
-
var THOR_MEMO_ASSET_SHORTCUTS = {
|
|
10545
|
-
b: "BTC.BTC",
|
|
10546
|
-
e: "ETH.ETH",
|
|
10547
|
-
s: "BSC.BNB",
|
|
10548
|
-
a: "AVAX.AVAX",
|
|
10549
|
-
c: "BCH.BCH",
|
|
10550
|
-
l: "LTC.LTC",
|
|
10551
|
-
d: "DOGE.DOGE",
|
|
10552
|
-
g: "GAIA.ATOM",
|
|
10553
|
-
r: "THOR.RUNE",
|
|
10554
|
-
x: "XRP.XRP",
|
|
10555
|
-
cacao: "MAYA.CACAO",
|
|
10556
|
-
dash: "DASH.DASH",
|
|
10557
|
-
zec: "ZEC.ZEC"
|
|
10558
|
-
// BASE / ARB don't have documented single-letter shortcuts; THORChain
|
|
10559
|
-
// emits these as the full CHAIN.ASSET form in memos. Listed in
|
|
10560
|
-
// THOR_MEMO_CHAIN_TO_ENUM only.
|
|
10561
|
-
};
|
|
10562
10585
|
var EVM_CHAINS = /* @__PURE__ */ new Set([
|
|
10563
10586
|
"Ethereum",
|
|
10564
10587
|
"BSC",
|
|
@@ -11219,13 +11242,7 @@ var AgentExecutor = class {
|
|
|
11219
11242
|
const txArgs = serverTxData?.txArgs ?? {};
|
|
11220
11243
|
const memo = typeof txArgs.memo === "string" ? txArgs.memo : "";
|
|
11221
11244
|
const parsed = parseThorSwapMemo(memo);
|
|
11222
|
-
const toChain =
|
|
11223
|
-
if (!toChain) {
|
|
11224
|
-
throw new VaultError3(
|
|
11225
|
-
VaultErrorCode3.UnsupportedChain,
|
|
11226
|
-
`signThorMsgDepositSwap: unsupported destination chain code '${parsed.destChainCode}' in memo '${memo}'.`
|
|
11227
|
-
);
|
|
11228
|
-
}
|
|
11245
|
+
const toChain = parsed.toChain;
|
|
11229
11246
|
const vaultDestAddress = await this.vault.address(toChain);
|
|
11230
11247
|
const normalizeForCompare = (addr) => EVM_CHAINS.has(toChain) ? addr.toLowerCase() : addr;
|
|
11231
11248
|
if (parsed.destAddress && normalizeForCompare(parsed.destAddress) !== normalizeForCompare(vaultDestAddress)) {
|
|
@@ -12034,31 +12051,6 @@ function parseNonEvmEnvelope(serverTxData, chain) {
|
|
|
12034
12051
|
const memo = typeof txArgs.memo === "string" && txArgs.memo.length > 0 ? txArgs.memo : void 0;
|
|
12035
12052
|
return { chain, to, amount: amountDecimal, symbol, memo };
|
|
12036
12053
|
}
|
|
12037
|
-
function parseThorSwapMemo(memo) {
|
|
12038
|
-
if (!memo.startsWith("=:")) {
|
|
12039
|
-
throw new VaultError3(
|
|
12040
|
-
VaultErrorCode3.NotImplemented,
|
|
12041
|
-
`parseThorSwapMemo: only swap memos (=:CHAIN.ASSET:DEST...) supported on this path; got memo='${memo}'. LP memos (+:/-:) route through signThorMsgDepositLp; loan / validator ops out of scope.`
|
|
12042
|
-
);
|
|
12043
|
-
}
|
|
12044
|
-
const memoBody = memo.slice(2);
|
|
12045
|
-
const parts = memoBody.split(":");
|
|
12046
|
-
let chainAsset = parts[0];
|
|
12047
|
-
if (chainAsset && !chainAsset.includes(".")) {
|
|
12048
|
-
const expanded = THOR_MEMO_ASSET_SHORTCUTS[chainAsset.toLowerCase()];
|
|
12049
|
-
if (expanded) chainAsset = expanded;
|
|
12050
|
-
}
|
|
12051
|
-
if (!chainAsset || !chainAsset.includes(".")) {
|
|
12052
|
-
throw new VaultError3(
|
|
12053
|
-
VaultErrorCode3.InvalidConfig,
|
|
12054
|
-
`parseThorSwapMemo: malformed swap memo '${memo}': missing CHAIN.ASSET in first segment.`
|
|
12055
|
-
);
|
|
12056
|
-
}
|
|
12057
|
-
const [destChainCode, destAssetRaw] = chainAsset.split(".");
|
|
12058
|
-
const destAsset = destAssetRaw?.split("-")[0] ?? "";
|
|
12059
|
-
const destAddress = typeof parts[1] === "string" ? parts[1] : "";
|
|
12060
|
-
return { destChainCode, destAsset, destAddress };
|
|
12061
|
-
}
|
|
12062
12054
|
function resolveChainId(chainId) {
|
|
12063
12055
|
return resolveChainReference(chainId) ?? null;
|
|
12064
12056
|
}
|
|
@@ -13495,13 +13487,13 @@ import {
|
|
|
13495
13487
|
statSync as statSync3,
|
|
13496
13488
|
writeFileSync as writeFileSync3
|
|
13497
13489
|
} from "node:fs";
|
|
13498
|
-
import { homedir
|
|
13490
|
+
import { homedir } from "node:os";
|
|
13499
13491
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
13500
13492
|
var LOCK_RETRY_MS = 25;
|
|
13501
13493
|
var LOCK_MAX_WAIT_MS2 = 5e3;
|
|
13502
13494
|
var LOCK_STALE_MS2 = 3e4;
|
|
13503
13495
|
function getTokenCachePath() {
|
|
13504
|
-
const dir = process.env.VULTISIG_CONFIG_DIR ?? join3(
|
|
13496
|
+
const dir = process.env.VULTISIG_CONFIG_DIR ?? join3(homedir(), ".vultisig");
|
|
13505
13497
|
return join3(dir, "agent-tokens.json");
|
|
13506
13498
|
}
|
|
13507
13499
|
function tokenCacheKey(scope) {
|
|
@@ -15271,7 +15263,7 @@ function formatDate(iso) {
|
|
|
15271
15263
|
}
|
|
15272
15264
|
|
|
15273
15265
|
// src/lib/version.ts
|
|
15274
|
-
import { getVultisigConfigDir as
|
|
15266
|
+
import { getVultisigConfigDir as getVultisigConfigDir3 } from "@vultisig/client-shared";
|
|
15275
15267
|
import chalk11 from "chalk";
|
|
15276
15268
|
import { existsSync as existsSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
15277
15269
|
import { join as join4 } from "path";
|
|
@@ -15279,7 +15271,7 @@ var cachedVersion = null;
|
|
|
15279
15271
|
function getVersion() {
|
|
15280
15272
|
if (cachedVersion) return cachedVersion;
|
|
15281
15273
|
if (true) {
|
|
15282
|
-
cachedVersion = "
|
|
15274
|
+
cachedVersion = "3.1.0";
|
|
15283
15275
|
return cachedVersion;
|
|
15284
15276
|
}
|
|
15285
15277
|
try {
|
|
@@ -15292,7 +15284,7 @@ function getVersion() {
|
|
|
15292
15284
|
return cachedVersion;
|
|
15293
15285
|
}
|
|
15294
15286
|
}
|
|
15295
|
-
var CACHE_DIR = join4(
|
|
15287
|
+
var CACHE_DIR = join4(getVultisigConfigDir3(), "cache");
|
|
15296
15288
|
var VERSION_CACHE_FILE = join4(CACHE_DIR, "version-check.json");
|
|
15297
15289
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
15298
15290
|
function readVersionCache() {
|
|
@@ -15376,7 +15368,7 @@ function formatVersionShort() {
|
|
|
15376
15368
|
}
|
|
15377
15369
|
function formatVersionDetailed() {
|
|
15378
15370
|
const lines = [];
|
|
15379
|
-
const configDir =
|
|
15371
|
+
const configDir = getVultisigConfigDir3();
|
|
15380
15372
|
lines.push(chalk11.bold(`Vultisig CLI v${getVersion()}`));
|
|
15381
15373
|
lines.push("");
|
|
15382
15374
|
lines.push(` Node.js: ${process.version}`);
|
|
@@ -16816,10 +16808,10 @@ Error: ${error2.message}`));
|
|
|
16816
16808
|
};
|
|
16817
16809
|
|
|
16818
16810
|
// src/lib/completion.ts
|
|
16811
|
+
import { getVultisigConfigDir as getVultisigConfigDir4 } from "@vultisig/client-shared";
|
|
16819
16812
|
import { SUPPORTED_CHAINS as SUPPORTED_CHAINS2 } from "@vultisig/sdk";
|
|
16820
16813
|
import { program } from "commander";
|
|
16821
16814
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync5 } from "fs";
|
|
16822
|
-
import { homedir as homedir3 } from "os";
|
|
16823
16815
|
import { join as join5 } from "path";
|
|
16824
16816
|
var tabtab = null;
|
|
16825
16817
|
async function getTabtab() {
|
|
@@ -16843,7 +16835,7 @@ function getChains() {
|
|
|
16843
16835
|
}
|
|
16844
16836
|
function getVaultNames() {
|
|
16845
16837
|
try {
|
|
16846
|
-
const vaultDir =
|
|
16838
|
+
const vaultDir = getVultisigConfigDir4();
|
|
16847
16839
|
if (!existsSync3(vaultDir)) return [];
|
|
16848
16840
|
const files = readdirSync(vaultDir);
|
|
16849
16841
|
const names = [];
|
|
@@ -16851,9 +16843,10 @@ function getVaultNames() {
|
|
|
16851
16843
|
if (file.startsWith("vault:") && file.endsWith(".json")) {
|
|
16852
16844
|
try {
|
|
16853
16845
|
const content = readFileSync5(join5(vaultDir, file), "utf-8");
|
|
16854
|
-
const
|
|
16855
|
-
|
|
16856
|
-
if (vault
|
|
16846
|
+
const parsed = JSON.parse(content);
|
|
16847
|
+
const vault = parsed?.value ?? parsed;
|
|
16848
|
+
if (vault?.name) names.push(vault.name);
|
|
16849
|
+
if (vault?.id) names.push(vault.id);
|
|
16857
16850
|
} catch {
|
|
16858
16851
|
}
|
|
16859
16852
|
}
|
|
@@ -17095,12 +17088,10 @@ complete -c vsig -n "__fish_seen_subcommand_from import export" -a "(__fish_comp
|
|
|
17095
17088
|
}
|
|
17096
17089
|
|
|
17097
17090
|
// src/lib/config.ts
|
|
17091
|
+
import { getVultisigConfigDir as getVultisigConfigDir5 } from "@vultisig/client-shared";
|
|
17098
17092
|
import { FileStorage } from "@vultisig/sdk/node";
|
|
17099
|
-
import { homedir as homedir4 } from "os";
|
|
17100
|
-
import { join as join6 } from "path";
|
|
17101
17093
|
function getConfigDir() {
|
|
17102
|
-
|
|
17103
|
-
return override ? override : join6(homedir4(), ".vultisig");
|
|
17094
|
+
return getVultisigConfigDir5();
|
|
17104
17095
|
}
|
|
17105
17096
|
function createVaultStorage() {
|
|
17106
17097
|
return new FileStorage({ basePath: getConfigDir() });
|
|
@@ -17658,9 +17649,13 @@ program2.command("delete [vault]").description("Delete a vault from local storag
|
|
|
17658
17649
|
});
|
|
17659
17650
|
})
|
|
17660
17651
|
);
|
|
17661
|
-
program2.command("tokens <chain>").description("List and manage tokens for a chain").option("--add <contractAddress>", "Add a token by contract address").option("--remove <tokenId>", "Remove a token by ID").option("--discover", "
|
|
17652
|
+
program2.command("tokens <chain>").description("List and manage tokens for a chain").option("--add <contractAddress>", "Add a token by contract address").option("--remove <tokenId>", "Remove a token by ID").option("--discover", "Find tokens with balances on the chain and save them to this vault").addHelpText(
|
|
17662
17653
|
"after",
|
|
17663
17654
|
`
|
|
17655
|
+
--discover writes to the vault: every token it finds is saved to the tracked
|
|
17656
|
+
list, so it also changes what portfolio and balance --tokens report. Use
|
|
17657
|
+
--remove <tokenId> to stop tracking one.
|
|
17658
|
+
|
|
17664
17659
|
Examples:
|
|
17665
17660
|
vultisig tokens Ethereum
|
|
17666
17661
|
vultisig tokens Ethereum --discover --output json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.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.1",
|
|
77
|
+
"@vultisig/core-chain": "^2.30.0",
|
|
78
|
+
"@vultisig/rujira": "^58.0.0",
|
|
79
|
+
"@vultisig/sdk": "^3.1.0",
|
|
80
80
|
"chalk": "^5.6.2",
|
|
81
81
|
"cli-table3": "^0.6.5",
|
|
82
82
|
"commander": "^15.0.0",
|