@vultisig/cli 5.1.0 → 6.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 +41 -0
- package/README.md +22 -0
- package/dist/index.js +586 -170
- package/package.json +7 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 6.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#2218](https://github.com/vultisig/vultisig-sdk/pull/2218) [`d043dc4`](https://github.com/vultisig/vultisig-sdk/commit/d043dc43d9fe33a3160c2739150fd6294f0e7eff) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Unify the workspace on the coordinated Noble/Scure v2 stack and align related workspace peer dependency ranges.
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- [#2024](https://github.com/vultisig/vultisig-sdk/pull/2024) [`821c8a7`](https://github.com/vultisig/vultisig-sdk/commit/821c8a73dd7d3aee55eaca59c22adc1ce8dae2f2) Thanks [@neavra](https://github.com/neavra)! - Label XRP spendable-vs-total balance. `getRippleNativeBalanceDetail` exposes the `{ total, spendable, reserve }` breakdown of a native XRP balance (the existing resolvers keep returning the spendable number, so no consumer changes meaning). SDK `Balance` gains optional `totalAmount`/`reserveAmount` fields, populated for native XRP. The CLI labels the spendable headline and prints the locked reserve for XRP balances; all other chains render unchanged.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#2176](https://github.com/vultisig/vultisig-sdk/pull/2176) [`d2edffd`](https://github.com/vultisig/vultisig-sdk/commit/d2edffd98730daa474d0c2f35a305d5277e3eb15) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Export a canonical typed parser for backend `tx_ready` and execute-prep envelopes, and migrate the CLI's non-EVM and THOR/Maya execution routing to that shared contract.
|
|
16
|
+
|
|
17
|
+
- [#1736](https://github.com/vultisig/vultisig-sdk/pull/1736) [`b58da97`](https://github.com/vultisig/vultisig-sdk/commit/b58da972a3830eb11449401d97ae6b5e62189501) Thanks [@neavra](https://github.com/neavra)! - Fix agent send consent summaries so token tickers, chains, and contract details render exactly once; strip negated routed-chain phrases without leaving a dangling "not" and strip ASCII-ellipsis truncated contract copies like the Unicode form.
|
|
18
|
+
|
|
19
|
+
- [#1760](https://github.com/vultisig/vultisig-sdk/pull/1760) [`9759c64`](https://github.com/vultisig/vultisig-sdk/commit/9759c6429225afe0ee96a8b51aff6b79026e1b8b) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Preserve optional `priceProviderId` on `discoverTokens()` results so downstream consumers can price newly discovered tokens without app-local metadata backfills.
|
|
20
|
+
|
|
21
|
+
- [#1870](https://github.com/vultisig/vultisig-sdk/pull/1870) [`3e37e69`](https://github.com/vultisig/vultisig-sdk/commit/3e37e69fdc60d63cb53a2ef7c74b01aa930b27e1) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Add a public `pollTxStatusUntilFinal` helper to `@vultisig/sdk` and reuse it across SDK/CLI transaction finality polling paths.
|
|
22
|
+
|
|
23
|
+
- [#2018](https://github.com/vultisig/vultisig-sdk/pull/2018) [`3163f30`](https://github.com/vultisig/vultisig-sdk/commit/3163f30ed91dad7c9e8f860c6d4dbb6e61899be8) Thanks [@neavra](https://github.com/neavra)! - The aggregate `balance` and `portfolio` views now say they only cover the vault's enabled chains. When the enabled set is a strict subset of the SDK-supported chains, the human output appends a hint pointing at `vultisig balance <chain>` and `vultisig chains --add <chain>`, and JSON mode carries the same text in a dedicated `scopeHint` field (omitted when every supported chain is enabled). The balances/portfolio payloads and the scoped `balance <chain>` path are unchanged.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [[`d043dc4`](https://github.com/vultisig/vultisig-sdk/commit/d043dc43d9fe33a3160c2739150fd6294f0e7eff), [`d2edffd`](https://github.com/vultisig/vultisig-sdk/commit/d2edffd98730daa474d0c2f35a305d5277e3eb15), [`9759c64`](https://github.com/vultisig/vultisig-sdk/commit/9759c6429225afe0ee96a8b51aff6b79026e1b8b), [`eccbc25`](https://github.com/vultisig/vultisig-sdk/commit/eccbc25a1fd61fb9eb03494afb0d5ceb6977be8c), [`bd44426`](https://github.com/vultisig/vultisig-sdk/commit/bd44426fe80b160d8c9a0a866e3cbb759bf781ba), [`dd82325`](https://github.com/vultisig/vultisig-sdk/commit/dd82325ee2f5700429178cb513b338dac27aa281), [`e6375ee`](https://github.com/vultisig/vultisig-sdk/commit/e6375ee8a4d77035b4ae8dae01184b2100ac8ca7), [`e2be3d4`](https://github.com/vultisig/vultisig-sdk/commit/e2be3d41214b988c3b917538e26dbe1e123725de), [`f170bdd`](https://github.com/vultisig/vultisig-sdk/commit/f170bdddafd80d892cd35a050cf8f5393776a6a0), [`6c535ae`](https://github.com/vultisig/vultisig-sdk/commit/6c535ae3aed1c376d2e1bbbeb100e8b5c21c8929), [`5bf33f2`](https://github.com/vultisig/vultisig-sdk/commit/5bf33f264c90ec4055d2c12e90222bec9aea501b), [`3203589`](https://github.com/vultisig/vultisig-sdk/commit/3203589af5da361dfc51695aad4fef77afa2d78e), [`3e37e69`](https://github.com/vultisig/vultisig-sdk/commit/3e37e69fdc60d63cb53a2ef7c74b01aa930b27e1), [`4c30666`](https://github.com/vultisig/vultisig-sdk/commit/4c306668690f798ff4fb9094cf16dd26eaafa8e7), [`1672265`](https://github.com/vultisig/vultisig-sdk/commit/16722657dcefafff32744a7673c277e403e62a77), [`2faf1a2`](https://github.com/vultisig/vultisig-sdk/commit/2faf1a2b833b1fc0f10a02ad2c8bec50ef4b1f57), [`beaca3c`](https://github.com/vultisig/vultisig-sdk/commit/beaca3c086679a8b87592fb69ca30a0a9d1877db), [`5500717`](https://github.com/vultisig/vultisig-sdk/commit/5500717036e760ed81d4880c66bda559d37331cd), [`d04f246`](https://github.com/vultisig/vultisig-sdk/commit/d04f246a992f3256e4fe7151e5319003d8ae267a), [`da2ea4e`](https://github.com/vultisig/vultisig-sdk/commit/da2ea4e1ae00f17cfec3d27da4fff2e6cb5b1190), [`821c8a7`](https://github.com/vultisig/vultisig-sdk/commit/821c8a73dd7d3aee55eaca59c22adc1ce8dae2f2)]:
|
|
26
|
+
- @vultisig/core-chain@4.0.0
|
|
27
|
+
- @vultisig/sdk@6.0.0
|
|
28
|
+
- @vultisig/rujira@70.0.0
|
|
29
|
+
- @vultisig/client-shared@0.3.5
|
|
30
|
+
|
|
31
|
+
## 5.2.0
|
|
32
|
+
|
|
33
|
+
### Minor Changes
|
|
34
|
+
|
|
35
|
+
- [#1719](https://github.com/vultisig/vultisig-sdk/pull/1719) [`ac213ac`](https://github.com/vultisig/vultisig-sdk/commit/ac213ac23f49e0d3ea3ad1cb10a055f28c921469) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Add direct unsigned CLI preparation commands for contract calls, IBC, SPL, TRC-20, Jetton, Sui tokens, Polkadot assets, Cosmos staking, and CW-20 transfers.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [[`397c2b6`](https://github.com/vultisig/vultisig-sdk/commit/397c2b6629fdc7002d55bd95bb8585dce78de416), [`df144e9`](https://github.com/vultisig/vultisig-sdk/commit/df144e9e21c2fb64e73efcf12ac35c958dbf1c7b), [`7d6a014`](https://github.com/vultisig/vultisig-sdk/commit/7d6a01440fd0b855356cce81469b5b5a91665862)]:
|
|
40
|
+
- @vultisig/sdk@5.2.0
|
|
41
|
+
- @vultisig/core-chain@3.0.0
|
|
42
|
+
- @vultisig/rujira@69.0.0
|
|
43
|
+
|
|
3
44
|
## 5.1.0
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -367,6 +367,28 @@ Swap quotes and previews show your VULT discount tier when affiliate fees are ap
|
|
|
367
367
|
| `sign` | Sign pre-hashed bytes for custom transactions |
|
|
368
368
|
| `broadcast` | Broadcast a pre-signed raw transaction |
|
|
369
369
|
| `tx-status <chain> <txHash>` | Check transaction confirmation status |
|
|
370
|
+
| `prep <helper>` | Build an unsigned SDK transaction payload |
|
|
371
|
+
|
|
372
|
+
#### Unsigned transaction preparation
|
|
373
|
+
|
|
374
|
+
`vultisig prep` exposes the SDK's specialized transaction builders directly. These commands only build unsigned
|
|
375
|
+
payloads: they never sign or broadcast. Identity-dependent helpers use the active vault's public identity by default;
|
|
376
|
+
isolated tooling can pass the same non-secret fields with `--identity <json>`.
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
vultisig prep contract-call Ethereum <contractAddress> approve --sender <senderAddress> --abi '[{"type":"function","name":"approve","inputs":[{"type":"address","name":"spender"},{"type":"uint256","name":"amount"}]}]' --args '["<spenderAddress>","1000000"]'
|
|
380
|
+
vultisig prep ibc-transfer Osmosis <sourceAddress> <receiverAddress> uosmo 1000000 --to-chain Cosmos
|
|
381
|
+
vultisig prep spl-transfer <mint> <from> <to> 1000000 6
|
|
382
|
+
vultisig prep trc20-transfer <contract> <from> <to> 1000000
|
|
383
|
+
vultisig prep jetton-transfer <recipient> <senderJettonWallet> 1000000 5
|
|
384
|
+
vultisig prep sui-token-transfer <coinType> <from> <to> 1000000 --decimals 6 --ticker USDC
|
|
385
|
+
vultisig prep polkadot-asset-send 1984 <from> <to> 1000000
|
|
386
|
+
vultisig prep cosmos-staking delegate <delegator> <validator> 5000000 uosmo
|
|
387
|
+
vultisig prep cw20-transfer osmo <contract> <recipient> 1000000 <sender>
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
Run `vultisig prep <helper> --help` for the complete optional parameter set. JSON mode returns
|
|
391
|
+
`{ helper, unsigned: true, result }` inside the standard versioned success envelope.
|
|
370
392
|
|
|
371
393
|
#### Transaction Status
|
|
372
394
|
|
package/dist/index.js
CHANGED
|
@@ -2506,7 +2506,7 @@ var init_toBytes = __esm({
|
|
|
2506
2506
|
}
|
|
2507
2507
|
});
|
|
2508
2508
|
|
|
2509
|
-
// ../../node_modules/@noble/hashes/esm/_u64.js
|
|
2509
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/_u64.js
|
|
2510
2510
|
function fromBig(n, le = false) {
|
|
2511
2511
|
if (le)
|
|
2512
2512
|
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
@@ -2524,7 +2524,7 @@ function split(lst, le = false) {
|
|
|
2524
2524
|
}
|
|
2525
2525
|
var U32_MASK64, _32n, rotlSH, rotlSL, rotlBH, rotlBL;
|
|
2526
2526
|
var init_u64 = __esm({
|
|
2527
|
-
"../../node_modules/@noble/hashes/esm/_u64.js"() {
|
|
2527
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/_u64.js"() {
|
|
2528
2528
|
U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
2529
2529
|
_32n = /* @__PURE__ */ BigInt(32);
|
|
2530
2530
|
rotlSH = (h, l, s) => h << s | l >>> 32 - s;
|
|
@@ -2534,16 +2534,16 @@ var init_u64 = __esm({
|
|
|
2534
2534
|
}
|
|
2535
2535
|
});
|
|
2536
2536
|
|
|
2537
|
-
// ../../node_modules/@noble/hashes/esm/cryptoNode.js
|
|
2537
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/cryptoNode.js
|
|
2538
2538
|
import * as nc from "node:crypto";
|
|
2539
2539
|
var crypto2;
|
|
2540
2540
|
var init_cryptoNode = __esm({
|
|
2541
|
-
"../../node_modules/@noble/hashes/esm/cryptoNode.js"() {
|
|
2541
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/cryptoNode.js"() {
|
|
2542
2542
|
crypto2 = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && "randomBytes" in nc ? nc : void 0;
|
|
2543
2543
|
}
|
|
2544
2544
|
});
|
|
2545
2545
|
|
|
2546
|
-
// ../../node_modules/@noble/hashes/esm/utils.js
|
|
2546
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/utils.js
|
|
2547
2547
|
function isBytes(a) {
|
|
2548
2548
|
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
2549
2549
|
}
|
|
@@ -2644,7 +2644,7 @@ function randomBytes2(bytesLength = 32) {
|
|
|
2644
2644
|
}
|
|
2645
2645
|
var isLE, swap32IfBE, Hash;
|
|
2646
2646
|
var init_utils2 = __esm({
|
|
2647
|
-
"../../node_modules/@noble/hashes/esm/utils.js"() {
|
|
2647
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/utils.js"() {
|
|
2648
2648
|
init_cryptoNode();
|
|
2649
2649
|
isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
2650
2650
|
swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
@@ -2653,7 +2653,7 @@ var init_utils2 = __esm({
|
|
|
2653
2653
|
}
|
|
2654
2654
|
});
|
|
2655
2655
|
|
|
2656
|
-
// ../../node_modules/@noble/hashes/esm/sha3.js
|
|
2656
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/sha3.js
|
|
2657
2657
|
function keccakP(s, rounds = 24) {
|
|
2658
2658
|
const B = new Uint32Array(5 * 2);
|
|
2659
2659
|
for (let round = 24 - rounds; round < 24; round++) {
|
|
@@ -2696,7 +2696,7 @@ function keccakP(s, rounds = 24) {
|
|
|
2696
2696
|
}
|
|
2697
2697
|
var _0n, _1n, _2n, _7n, _256n, _0x71n, SHA3_PI, SHA3_ROTL, _SHA3_IOTA, IOTAS, SHA3_IOTA_H, SHA3_IOTA_L, rotlH, rotlL, Keccak, gen, keccak_256;
|
|
2698
2698
|
var init_sha3 = __esm({
|
|
2699
|
-
"../../node_modules/@noble/hashes/esm/sha3.js"() {
|
|
2699
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/sha3.js"() {
|
|
2700
2700
|
init_u64();
|
|
2701
2701
|
init_utils2();
|
|
2702
2702
|
_0n = BigInt(0);
|
|
@@ -3852,10 +3852,10 @@ var init_decodeAbiParameters = __esm({
|
|
|
3852
3852
|
});
|
|
3853
3853
|
|
|
3854
3854
|
// ../../node_modules/viem/_esm/utils/stringify.js
|
|
3855
|
-
var
|
|
3855
|
+
var stringify2;
|
|
3856
3856
|
var init_stringify = __esm({
|
|
3857
3857
|
"../../node_modules/viem/_esm/utils/stringify.js"() {
|
|
3858
|
-
|
|
3858
|
+
stringify2 = (value, replacer, space) => JSON.stringify(value, (key, value_) => {
|
|
3859
3859
|
const value2 = typeof value_ === "bigint" ? value_.toString() : value_;
|
|
3860
3860
|
return typeof replacer === "function" ? replacer(key, value2) : value2;
|
|
3861
3861
|
}, space);
|
|
@@ -3895,7 +3895,7 @@ var init_Value = __esm({
|
|
|
3895
3895
|
}
|
|
3896
3896
|
});
|
|
3897
3897
|
|
|
3898
|
-
// ../../node_modules/@noble/hashes/esm/_md.js
|
|
3898
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/_md.js
|
|
3899
3899
|
function setBigUint64(view, byteOffset, value, isLE2) {
|
|
3900
3900
|
if (typeof view.setBigUint64 === "function")
|
|
3901
3901
|
return view.setBigUint64(byteOffset, value, isLE2);
|
|
@@ -3916,7 +3916,7 @@ function Maj(a, b, c) {
|
|
|
3916
3916
|
}
|
|
3917
3917
|
var HashMD, SHA256_IV;
|
|
3918
3918
|
var init_md = __esm({
|
|
3919
|
-
"../../node_modules/@noble/hashes/esm/_md.js"() {
|
|
3919
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/_md.js"() {
|
|
3920
3920
|
init_utils2();
|
|
3921
3921
|
HashMD = class extends Hash {
|
|
3922
3922
|
constructor(blockLen, outputLen, padOffset, isLE2) {
|
|
@@ -4021,10 +4021,10 @@ var init_md = __esm({
|
|
|
4021
4021
|
}
|
|
4022
4022
|
});
|
|
4023
4023
|
|
|
4024
|
-
// ../../node_modules/@noble/hashes/esm/sha2.js
|
|
4024
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/sha2.js
|
|
4025
4025
|
var SHA256_K, SHA256_W, SHA256, sha256;
|
|
4026
4026
|
var init_sha2 = __esm({
|
|
4027
|
-
"../../node_modules/@noble/hashes/esm/sha2.js"() {
|
|
4027
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/sha2.js"() {
|
|
4028
4028
|
init_md();
|
|
4029
4029
|
init_utils2();
|
|
4030
4030
|
SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
@@ -4168,10 +4168,10 @@ var init_sha2 = __esm({
|
|
|
4168
4168
|
}
|
|
4169
4169
|
});
|
|
4170
4170
|
|
|
4171
|
-
// ../../node_modules/@noble/hashes/esm/hmac.js
|
|
4171
|
+
// ../../node_modules/viem/node_modules/@noble/hashes/esm/hmac.js
|
|
4172
4172
|
var HMAC, hmac;
|
|
4173
4173
|
var init_hmac = __esm({
|
|
4174
|
-
"../../node_modules/@noble/hashes/esm/hmac.js"() {
|
|
4174
|
+
"../../node_modules/viem/node_modules/@noble/hashes/esm/hmac.js"() {
|
|
4175
4175
|
init_utils2();
|
|
4176
4176
|
HMAC = class extends Hash {
|
|
4177
4177
|
constructor(hash2, _key) {
|
|
@@ -9104,7 +9104,7 @@ x ${classified.message}`);
|
|
|
9104
9104
|
}
|
|
9105
9105
|
|
|
9106
9106
|
// src/commands/balance.ts
|
|
9107
|
-
import { fiatCurrencies, fiatCurrencyNameRecord as fiatCurrencyNameRecord2 } from "@vultisig/sdk";
|
|
9107
|
+
import { fiatCurrencies, fiatCurrencyNameRecord as fiatCurrencyNameRecord2, SUPPORTED_CHAINS } from "@vultisig/sdk";
|
|
9108
9108
|
|
|
9109
9109
|
// src/ui.ts
|
|
9110
9110
|
import { fiatCurrencyNameRecord, fromChainAmountExact, Vultisig } from "@vultisig/sdk";
|
|
@@ -9115,10 +9115,19 @@ var escapeTerminalControls = (value) => Array.from(value, (character) => {
|
|
|
9115
9115
|
const isTerminalControl = codePoint <= 31 || codePoint === 127 || codePoint >= 128 && codePoint <= 159;
|
|
9116
9116
|
return isTerminalControl ? `\\x${codePoint.toString(16).padStart(2, "0").toUpperCase()}` : character;
|
|
9117
9117
|
}).join("");
|
|
9118
|
+
var hasLockedReserve = (balance) => balance.reserveAmount !== void 0 && balance.reserveAmount !== "0" && balance.totalAmount !== void 0;
|
|
9119
|
+
var formatAmountCell = (balance) => hasLockedReserve(balance) ? `${balance.formattedAmount} (spendable)` : balance.formattedAmount;
|
|
9118
9120
|
function displayBalance(chain, balance, _raw = false) {
|
|
9119
9121
|
printResult(chalk2.cyan(`
|
|
9120
9122
|
${chain} Balance:`));
|
|
9121
|
-
printResult(
|
|
9123
|
+
printResult(
|
|
9124
|
+
` Amount: ${balance.formattedAmount} ${balance.symbol}${hasLockedReserve(balance) ? " (spendable)" : ""}`
|
|
9125
|
+
);
|
|
9126
|
+
if (hasLockedReserve(balance) && balance.totalAmount !== void 0) {
|
|
9127
|
+
const reserve = formatBalanceAmount(balance.reserveAmount, balance.decimals);
|
|
9128
|
+
const total = formatBalanceAmount(balance.totalAmount, balance.decimals);
|
|
9129
|
+
printResult(` Reserve: ${reserve} ${balance.symbol} locked (${total} ${balance.symbol} total on ledger)`);
|
|
9130
|
+
}
|
|
9122
9131
|
if (balance.fiatValue && balance.fiatCurrency) {
|
|
9123
9132
|
printResult(` Value: ${balance.fiatValue.toFixed(2)} ${balance.fiatCurrency}`);
|
|
9124
9133
|
}
|
|
@@ -9127,7 +9136,7 @@ function displayBalancesTable(balances, _raw = false) {
|
|
|
9127
9136
|
printResult(chalk2.cyan("\nPortfolio Balances:\n"));
|
|
9128
9137
|
const tableData = Object.entries(balances).map(([chain, balance]) => ({
|
|
9129
9138
|
Chain: chain,
|
|
9130
|
-
Amount: balance
|
|
9139
|
+
Amount: formatAmountCell(balance),
|
|
9131
9140
|
Symbol: balance.symbol,
|
|
9132
9141
|
Value: balance.fiatValue && balance.fiatCurrency ? `${balance.fiatValue.toFixed(2)} ${balance.fiatCurrency}` : "N/A"
|
|
9133
9142
|
}));
|
|
@@ -9145,7 +9154,7 @@ function displayPortfolio(portfolio, currency, _raw = false) {
|
|
|
9145
9154
|
const table = portfolio.chainBalances.flatMap(({ chain, balance, value, tokens }) => [
|
|
9146
9155
|
{
|
|
9147
9156
|
Chain: chain,
|
|
9148
|
-
Amount: balance
|
|
9157
|
+
Amount: formatAmountCell(balance),
|
|
9149
9158
|
Symbol: balance.symbol,
|
|
9150
9159
|
Value: value ? `${value.amount} ${value.currency.toUpperCase()}` : "N/A"
|
|
9151
9160
|
},
|
|
@@ -9257,7 +9266,7 @@ async function confirmTransaction() {
|
|
|
9257
9266
|
function setupVaultEvents(vault) {
|
|
9258
9267
|
vault.on("balanceUpdated", ({ chain, balance, tokenId }) => {
|
|
9259
9268
|
const asset = tokenId ? `${balance.symbol} token` : balance.symbol;
|
|
9260
|
-
info(chalk2.blue(`i Balance updated for ${chain} (${asset}): ${balance
|
|
9269
|
+
info(chalk2.blue(`i Balance updated for ${chain} (${asset}): ${formatAmountCell(balance)}`));
|
|
9261
9270
|
});
|
|
9262
9271
|
vault.on("transactionBroadcast", ({ chain, txHash }) => {
|
|
9263
9272
|
info(chalk2.green(`+ Transaction broadcast on ${chain}`));
|
|
@@ -9292,6 +9301,14 @@ function formatBigintAmount(amount, decimals) {
|
|
|
9292
9301
|
const trimmed = fraction.replace(/0+$/, "");
|
|
9293
9302
|
return trimmed ? `${whole}.${trimmed}` : whole;
|
|
9294
9303
|
}
|
|
9304
|
+
function formatBalanceAmount(amount, decimals) {
|
|
9305
|
+
if (!amount || amount === "0") return "0";
|
|
9306
|
+
try {
|
|
9307
|
+
return formatBigintAmount(BigInt(amount), decimals);
|
|
9308
|
+
} catch {
|
|
9309
|
+
return amount;
|
|
9310
|
+
}
|
|
9311
|
+
}
|
|
9295
9312
|
function displaySwapPreview(quote, fromAmount, fromSymbol, toSymbol, options) {
|
|
9296
9313
|
const estimatedOutputFormatted = formatBigintAmount(quote.estimatedOutput, options.toDecimals);
|
|
9297
9314
|
printResult(chalk2.cyan("\nSwap Preview:"));
|
|
@@ -9371,6 +9388,13 @@ async function confirmSwap() {
|
|
|
9371
9388
|
}
|
|
9372
9389
|
|
|
9373
9390
|
// src/commands/balance.ts
|
|
9391
|
+
function buildScopeHint(enabledChains) {
|
|
9392
|
+
const supportedCount = SUPPORTED_CHAINS.length;
|
|
9393
|
+
const enabledSupportedCount = new Set(enabledChains.filter((chain) => SUPPORTED_CHAINS.includes(chain))).size;
|
|
9394
|
+
if (enabledSupportedCount >= supportedCount) return void 0;
|
|
9395
|
+
const noun = enabledSupportedCount === 1 ? "chain" : "chains";
|
|
9396
|
+
return `Showing the vault's ${enabledSupportedCount} enabled ${noun} of ${supportedCount} supported. Funds on other chains won't appear here \u2014 run \`vultisig balance <chain>\` to check one, or \`vultisig chains --add <chain>\` to include it.`;
|
|
9397
|
+
}
|
|
9374
9398
|
function conciseError(err) {
|
|
9375
9399
|
const message = err instanceof Error ? err.message : String(err);
|
|
9376
9400
|
return message.split("\n")[0].trim() || "Unknown error";
|
|
@@ -9400,11 +9424,14 @@ async function executeBalance(ctx2, options = {}) {
|
|
|
9400
9424
|
} else {
|
|
9401
9425
|
const balances = await vault.balances(void 0, options.includeTokens);
|
|
9402
9426
|
spinner.succeed("Balances loaded");
|
|
9427
|
+
const scopeHint = buildScopeHint(vault.chains);
|
|
9403
9428
|
if (isJsonOutput()) {
|
|
9404
|
-
outputJson({ balances });
|
|
9429
|
+
outputJson({ balances, scopeHint });
|
|
9405
9430
|
return;
|
|
9406
9431
|
}
|
|
9407
9432
|
displayBalancesTable(balances, raw);
|
|
9433
|
+
if (scopeHint) info(`
|
|
9434
|
+
${scopeHint}`);
|
|
9408
9435
|
}
|
|
9409
9436
|
}
|
|
9410
9437
|
async function executePortfolio(ctx2, options = {}) {
|
|
@@ -9480,11 +9507,14 @@ async function executePortfolio(ctx2, options = {}) {
|
|
|
9480
9507
|
const totalValue = { amount: total.toFixed(2), currency, lastUpdated: Date.now() };
|
|
9481
9508
|
const portfolio = { totalValue, chainBalances };
|
|
9482
9509
|
spinner.succeed("Portfolio loaded");
|
|
9510
|
+
const scopeHint = buildScopeHint(chains);
|
|
9483
9511
|
if (isJsonOutput()) {
|
|
9484
|
-
outputJson({ portfolio, currency, failures });
|
|
9512
|
+
outputJson({ portfolio, currency, failures, scopeHint });
|
|
9485
9513
|
return;
|
|
9486
9514
|
}
|
|
9487
9515
|
displayPortfolio(portfolio, currency, options.raw ?? false);
|
|
9516
|
+
if (scopeHint) info(`
|
|
9517
|
+
${scopeHint}`);
|
|
9488
9518
|
if (failures.length > 0) {
|
|
9489
9519
|
warn(`
|
|
9490
9520
|
Warning: ${failures.length} chain(s) failed to load fully:`);
|
|
@@ -9495,7 +9525,7 @@ Warning: ${failures.length} chain(s) failed to load fully:`);
|
|
|
9495
9525
|
}
|
|
9496
9526
|
|
|
9497
9527
|
// src/commands/chains.ts
|
|
9498
|
-
import { SUPPORTED_CHAINS } from "@vultisig/sdk";
|
|
9528
|
+
import { SUPPORTED_CHAINS as SUPPORTED_CHAINS2 } from "@vultisig/sdk";
|
|
9499
9529
|
import chalk3 from "chalk";
|
|
9500
9530
|
|
|
9501
9531
|
// src/core/active-vault.ts
|
|
@@ -10332,19 +10362,19 @@ async function executeChains(ctx2, options = {}) {
|
|
|
10332
10362
|
const vault = await ctx2.ensureActiveVault();
|
|
10333
10363
|
if (options.addAll) {
|
|
10334
10364
|
const currentCount = vault.chains.length;
|
|
10335
|
-
const spinner = createSpinner(`Adding all ${
|
|
10336
|
-
await vault.setChains([...
|
|
10337
|
-
const addedCount =
|
|
10338
|
-
spinner.succeed(`Added ${addedCount} chains (${
|
|
10365
|
+
const spinner = createSpinner(`Adding all ${SUPPORTED_CHAINS2.length} supported chains...`);
|
|
10366
|
+
await vault.setChains([...SUPPORTED_CHAINS2]);
|
|
10367
|
+
const addedCount = SUPPORTED_CHAINS2.length - currentCount;
|
|
10368
|
+
spinner.succeed(`Added ${addedCount} chains (${SUPPORTED_CHAINS2.length} total)`);
|
|
10339
10369
|
if (isJsonOutput()) {
|
|
10340
|
-
outputJson({ chains: [...vault.chains], added: addedCount, total:
|
|
10370
|
+
outputJson({ chains: [...vault.chains], added: addedCount, total: SUPPORTED_CHAINS2.length });
|
|
10341
10371
|
return;
|
|
10342
10372
|
}
|
|
10343
10373
|
info(chalk3.gray("\nAll supported chains are now enabled."));
|
|
10344
10374
|
return;
|
|
10345
10375
|
}
|
|
10346
10376
|
if (options.add) {
|
|
10347
|
-
if (!
|
|
10377
|
+
if (!SUPPORTED_CHAINS2.includes(options.add)) {
|
|
10348
10378
|
throw new InvalidChainError(
|
|
10349
10379
|
`Unsupported chain: "${options.add}"`,
|
|
10350
10380
|
'Run "vultisig chains" to see the supported chains, or check the spelling.',
|
|
@@ -10384,7 +10414,7 @@ Chain already active: ${options.add}` : `
|
|
|
10384
10414
|
printResult(` - ${chain}`);
|
|
10385
10415
|
});
|
|
10386
10416
|
info(chalk3.gray(`
|
|
10387
|
-
${chains.length} of ${
|
|
10417
|
+
${chains.length} of ${SUPPORTED_CHAINS2.length} chains enabled`));
|
|
10388
10418
|
info(chalk3.gray("Use --add <chain>, --add-all, or --remove <chain>"));
|
|
10389
10419
|
}
|
|
10390
10420
|
}
|
|
@@ -10836,6 +10866,307 @@ async function sendTransaction(vault, params) {
|
|
|
10836
10866
|
}
|
|
10837
10867
|
}
|
|
10838
10868
|
|
|
10869
|
+
// src/commands/prep.ts
|
|
10870
|
+
import {
|
|
10871
|
+
assertSafeDestination,
|
|
10872
|
+
buildCw20TransferMsg,
|
|
10873
|
+
buildDelegateMsg,
|
|
10874
|
+
buildRedelegateMsg,
|
|
10875
|
+
buildSplTransfer,
|
|
10876
|
+
buildUndelegateMsg,
|
|
10877
|
+
buildWithdrawRewardsMsg,
|
|
10878
|
+
prepareContractCallTxFromKeys,
|
|
10879
|
+
prepareIbcTransfer,
|
|
10880
|
+
prepareJettonTransferTxFromKeys,
|
|
10881
|
+
preparePolkadotAssetSend,
|
|
10882
|
+
prepareSuiTokenTransferFromKeys,
|
|
10883
|
+
prepareTrc20TransferFromKeys
|
|
10884
|
+
} from "@vultisig/sdk";
|
|
10885
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10886
|
+
var parseJson = (raw, label) => {
|
|
10887
|
+
try {
|
|
10888
|
+
return JSON.parse(raw);
|
|
10889
|
+
} catch (error2) {
|
|
10890
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
10891
|
+
throw new InvalidInputError(`Invalid ${label} JSON: ${message}`);
|
|
10892
|
+
}
|
|
10893
|
+
};
|
|
10894
|
+
var parseJsonArray = (raw, label) => {
|
|
10895
|
+
const value = parseJson(raw, label);
|
|
10896
|
+
if (!Array.isArray(value)) {
|
|
10897
|
+
throw new InvalidInputError(`${label} must be a JSON array`);
|
|
10898
|
+
}
|
|
10899
|
+
return value;
|
|
10900
|
+
};
|
|
10901
|
+
var MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
|
10902
|
+
var assertLosslessJsonNumberLexemes = (raw, label) => {
|
|
10903
|
+
let inString = false;
|
|
10904
|
+
let escaped = false;
|
|
10905
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
10906
|
+
const character = raw[index];
|
|
10907
|
+
if (inString) {
|
|
10908
|
+
if (escaped) {
|
|
10909
|
+
escaped = false;
|
|
10910
|
+
} else if (character === "\\") {
|
|
10911
|
+
escaped = true;
|
|
10912
|
+
} else if (character === '"') {
|
|
10913
|
+
inString = false;
|
|
10914
|
+
}
|
|
10915
|
+
continue;
|
|
10916
|
+
}
|
|
10917
|
+
if (character === '"') {
|
|
10918
|
+
inString = true;
|
|
10919
|
+
continue;
|
|
10920
|
+
}
|
|
10921
|
+
if (character !== "-" && (character < "0" || character > "9")) continue;
|
|
10922
|
+
const match = raw.slice(index).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/);
|
|
10923
|
+
if (match === null) continue;
|
|
10924
|
+
const lexeme = match[0];
|
|
10925
|
+
if (/[.eE]/.test(lexeme) || BigInt(lexeme) > MAX_SAFE_INTEGER || BigInt(lexeme) < -MAX_SAFE_INTEGER) {
|
|
10926
|
+
throw new InvalidInputError(
|
|
10927
|
+
`${label} numeric values must be safe base-10 integer literals; pass ABI integers as decimal strings`
|
|
10928
|
+
);
|
|
10929
|
+
}
|
|
10930
|
+
index += lexeme.length - 1;
|
|
10931
|
+
}
|
|
10932
|
+
};
|
|
10933
|
+
var parseLosslessJsonArray = (raw, label) => {
|
|
10934
|
+
assertLosslessJsonNumberLexemes(raw, label);
|
|
10935
|
+
const value = parseJsonArray(raw, label);
|
|
10936
|
+
return value;
|
|
10937
|
+
};
|
|
10938
|
+
var parseDecimalBigInt = (raw, label) => {
|
|
10939
|
+
if (!/^-?\d+$/.test(raw)) {
|
|
10940
|
+
throw new InvalidInputError(`${label} must be a base-10 integer string`);
|
|
10941
|
+
}
|
|
10942
|
+
return BigInt(raw);
|
|
10943
|
+
};
|
|
10944
|
+
var parseInteger = (raw, label) => {
|
|
10945
|
+
if (!/^-?\d+$/.test(raw)) {
|
|
10946
|
+
throw new InvalidInputError(`${label} must be an integer`);
|
|
10947
|
+
}
|
|
10948
|
+
const value = Number(raw);
|
|
10949
|
+
if (!Number.isSafeInteger(value)) {
|
|
10950
|
+
throw new InvalidInputError(`${label} must be a safe integer`);
|
|
10951
|
+
}
|
|
10952
|
+
return value;
|
|
10953
|
+
};
|
|
10954
|
+
var parseOptionalInteger = (raw, label) => raw === void 0 ? void 0 : parseInteger(raw, label);
|
|
10955
|
+
var parseIdentity = (raw) => {
|
|
10956
|
+
const value = parseJson(raw, "identity");
|
|
10957
|
+
if (!isRecord(value)) {
|
|
10958
|
+
throw new InvalidInputError("identity must be a JSON object");
|
|
10959
|
+
}
|
|
10960
|
+
const requiredStrings = ["ecdsaPublicKey", "eddsaPublicKey", "hexChainCode", "localPartyId", "libType"];
|
|
10961
|
+
for (const field of requiredStrings) {
|
|
10962
|
+
if (typeof value[field] !== "string" || value[field].length === 0) {
|
|
10963
|
+
throw new InvalidInputError(`identity.${field} must be a non-empty string`);
|
|
10964
|
+
}
|
|
10965
|
+
}
|
|
10966
|
+
if (!["GG20", "DKLS", "KeyImport"].includes(value.libType)) {
|
|
10967
|
+
throw new InvalidInputError("identity.libType must be GG20, DKLS, or KeyImport");
|
|
10968
|
+
}
|
|
10969
|
+
if (value.chainPublicKeys !== void 0 && !isRecord(value.chainPublicKeys)) {
|
|
10970
|
+
throw new InvalidInputError("identity.chainPublicKeys must be a JSON object when provided");
|
|
10971
|
+
}
|
|
10972
|
+
return value;
|
|
10973
|
+
};
|
|
10974
|
+
var identityFromVault = (vault) => ({
|
|
10975
|
+
ecdsaPublicKey: vault.publicKeys.ecdsa,
|
|
10976
|
+
eddsaPublicKey: vault.publicKeys.eddsa,
|
|
10977
|
+
hexChainCode: vault.hexChainCode,
|
|
10978
|
+
localPartyId: vault.localPartyId,
|
|
10979
|
+
libType: vault.libType,
|
|
10980
|
+
publicKeyMldsa: vault.publicKeyMldsa,
|
|
10981
|
+
chainPublicKeys: vault.data.chainPublicKeys
|
|
10982
|
+
});
|
|
10983
|
+
var resolveIdentity = (vault, rawIdentity) => {
|
|
10984
|
+
if (rawIdentity !== void 0) return parseIdentity(rawIdentity);
|
|
10985
|
+
if (vault !== void 0) return identityFromVault(vault);
|
|
10986
|
+
throw new InvalidInputError("An active vault or --identity JSON is required");
|
|
10987
|
+
};
|
|
10988
|
+
var stringify = (value) => JSON.stringify(value, (_key, item) => typeof item === "bigint" ? item.toString() : item, 2);
|
|
10989
|
+
var emitPrepResult = (helper, result) => {
|
|
10990
|
+
const output = { helper, unsigned: true, result };
|
|
10991
|
+
if (isJsonOutput()) {
|
|
10992
|
+
outputJson(output);
|
|
10993
|
+
} else {
|
|
10994
|
+
printResult(stringify(output));
|
|
10995
|
+
}
|
|
10996
|
+
};
|
|
10997
|
+
async function executePrepContractCall(vault, chain, contractAddress, functionName, options) {
|
|
10998
|
+
const value = options.value === void 0 ? void 0 : parseDecimalBigInt(options.value, "value");
|
|
10999
|
+
if (value !== void 0 && value > 0n) {
|
|
11000
|
+
assertSafeDestination(chain, contractAddress);
|
|
11001
|
+
}
|
|
11002
|
+
const feeSettings = options.gasLimit !== void 0 || options.maxPriorityFeePerGas !== void 0 ? {
|
|
11003
|
+
gasLimit: parseDecimalBigInt(options.gasLimit ?? "", "gas-limit"),
|
|
11004
|
+
maxPriorityFeePerGas: parseDecimalBigInt(options.maxPriorityFeePerGas ?? "", "max-priority-fee-per-gas")
|
|
11005
|
+
} : void 0;
|
|
11006
|
+
const result = await prepareContractCallTxFromKeys(resolveIdentity(vault, options.identity), {
|
|
11007
|
+
chain,
|
|
11008
|
+
contractAddress,
|
|
11009
|
+
abi: parseJsonArray(options.abi, "abi"),
|
|
11010
|
+
functionName,
|
|
11011
|
+
args: options.args === void 0 ? void 0 : parseLosslessJsonArray(options.args, "args"),
|
|
11012
|
+
value,
|
|
11013
|
+
senderAddress: options.sender,
|
|
11014
|
+
feeSettings
|
|
11015
|
+
});
|
|
11016
|
+
emitPrepResult("contract-call", result);
|
|
11017
|
+
}
|
|
11018
|
+
function executePrepIbcTransfer(fromChain, fromAddress, toAddress, denom, amount, options) {
|
|
11019
|
+
const result = prepareIbcTransfer({
|
|
11020
|
+
fromChain,
|
|
11021
|
+
fromAddress,
|
|
11022
|
+
toAddress,
|
|
11023
|
+
denom,
|
|
11024
|
+
amount,
|
|
11025
|
+
toChainId: options.toChain,
|
|
11026
|
+
sourceChannel: options.sourceChannel,
|
|
11027
|
+
timeoutHeight: options.timeoutHeight,
|
|
11028
|
+
timeoutTimestamp: options.timeoutTimestamp,
|
|
11029
|
+
accountNumber: options.accountNumber,
|
|
11030
|
+
sequence: options.sequence,
|
|
11031
|
+
memo: options.memo,
|
|
11032
|
+
nowMs: parseOptionalInteger(options.nowMs, "now-ms")
|
|
11033
|
+
});
|
|
11034
|
+
emitPrepResult("ibc-transfer", result);
|
|
11035
|
+
}
|
|
11036
|
+
function executePrepSplTransfer(mint, from, to, amount, decimals, options) {
|
|
11037
|
+
assertSafeDestination("Solana", to);
|
|
11038
|
+
const result = buildSplTransfer({
|
|
11039
|
+
mint,
|
|
11040
|
+
from,
|
|
11041
|
+
to,
|
|
11042
|
+
amount: parseDecimalBigInt(amount, "amount"),
|
|
11043
|
+
decimals: parseInteger(decimals, "decimals"),
|
|
11044
|
+
isToken2022: options.token2022
|
|
11045
|
+
});
|
|
11046
|
+
emitPrepResult("spl-transfer", result);
|
|
11047
|
+
}
|
|
11048
|
+
function executePrepTrc20Transfer(contractAddress, from, to, amount, options) {
|
|
11049
|
+
const result = prepareTrc20TransferFromKeys({
|
|
11050
|
+
contractAddress,
|
|
11051
|
+
from,
|
|
11052
|
+
to,
|
|
11053
|
+
amount,
|
|
11054
|
+
memo: options.memo,
|
|
11055
|
+
feeLimitSun: options.feeLimitSun
|
|
11056
|
+
});
|
|
11057
|
+
emitPrepResult("trc20-transfer", result);
|
|
11058
|
+
}
|
|
11059
|
+
function executePrepJettonTransfer(vault, receiver, jettonWalletAddress, amount, seqno, options) {
|
|
11060
|
+
const built = prepareJettonTransferTxFromKeys(resolveIdentity(vault, options.identity), {
|
|
11061
|
+
receiver,
|
|
11062
|
+
jettonWalletAddress,
|
|
11063
|
+
amount: parseDecimalBigInt(amount, "amount"),
|
|
11064
|
+
seqno: parseInteger(seqno, "seqno"),
|
|
11065
|
+
memo: options.memo,
|
|
11066
|
+
validUntil: parseOptionalInteger(options.validUntil, "valid-until"),
|
|
11067
|
+
workchain: parseOptionalInteger(options.workchain, "workchain")
|
|
11068
|
+
});
|
|
11069
|
+
const result = {
|
|
11070
|
+
signingHashHex: built.signingHashHex,
|
|
11071
|
+
unsignedBocHex: built.unsignedBocHex,
|
|
11072
|
+
fromAddress: built.fromAddress
|
|
11073
|
+
};
|
|
11074
|
+
emitPrepResult("jetton-transfer", result);
|
|
11075
|
+
}
|
|
11076
|
+
async function executePrepSuiTokenTransfer(vault, coinType, from, to, amount, options) {
|
|
11077
|
+
const result = await prepareSuiTokenTransferFromKeys(resolveIdentity(vault, options.identity), {
|
|
11078
|
+
coinType,
|
|
11079
|
+
from,
|
|
11080
|
+
to,
|
|
11081
|
+
amount: parseDecimalBigInt(amount, "amount"),
|
|
11082
|
+
decimals: parseOptionalInteger(options.decimals, "decimals"),
|
|
11083
|
+
ticker: options.ticker
|
|
11084
|
+
});
|
|
11085
|
+
emitPrepResult("sui-token-transfer", result);
|
|
11086
|
+
}
|
|
11087
|
+
function executePrepPolkadotAssetSend(assetId, from, to, amount, options) {
|
|
11088
|
+
const result = preparePolkadotAssetSend({
|
|
11089
|
+
assetId: parseInteger(assetId, "asset-id"),
|
|
11090
|
+
from,
|
|
11091
|
+
to,
|
|
11092
|
+
amount: parseDecimalBigInt(amount, "amount"),
|
|
11093
|
+
decimals: parseOptionalInteger(options.decimals, "decimals"),
|
|
11094
|
+
ticker: options.ticker
|
|
11095
|
+
});
|
|
11096
|
+
emitPrepResult("polkadot-asset-send", result);
|
|
11097
|
+
}
|
|
11098
|
+
function executePrepCosmosStaking(action, delegatorAddress, validatorAddress, amount, denom, options) {
|
|
11099
|
+
const prefixes = {
|
|
11100
|
+
accountPrefix: options.accountPrefix,
|
|
11101
|
+
validatorPrefix: options.validatorPrefix
|
|
11102
|
+
};
|
|
11103
|
+
let result;
|
|
11104
|
+
switch (action) {
|
|
11105
|
+
case "delegate":
|
|
11106
|
+
if (amount === void 0 || denom === void 0) {
|
|
11107
|
+
throw new InvalidInputError("delegate requires amount and denom");
|
|
11108
|
+
}
|
|
11109
|
+
result = buildDelegateMsg({
|
|
11110
|
+
delegatorAddress,
|
|
11111
|
+
validatorAddress,
|
|
11112
|
+
amount,
|
|
11113
|
+
denom,
|
|
11114
|
+
...prefixes
|
|
11115
|
+
});
|
|
11116
|
+
break;
|
|
11117
|
+
case "undelegate":
|
|
11118
|
+
if (amount === void 0 || denom === void 0) {
|
|
11119
|
+
throw new InvalidInputError("undelegate requires amount and denom");
|
|
11120
|
+
}
|
|
11121
|
+
result = buildUndelegateMsg({
|
|
11122
|
+
delegatorAddress,
|
|
11123
|
+
validatorAddress,
|
|
11124
|
+
amount,
|
|
11125
|
+
denom,
|
|
11126
|
+
...prefixes
|
|
11127
|
+
});
|
|
11128
|
+
break;
|
|
11129
|
+
case "redelegate":
|
|
11130
|
+
if (amount === void 0 || denom === void 0 || options.validatorDst === void 0) {
|
|
11131
|
+
throw new InvalidInputError("redelegate requires amount, denom, and --validator-dst");
|
|
11132
|
+
}
|
|
11133
|
+
result = buildRedelegateMsg({
|
|
11134
|
+
delegatorAddress,
|
|
11135
|
+
validatorSrcAddress: validatorAddress,
|
|
11136
|
+
validatorDstAddress: options.validatorDst,
|
|
11137
|
+
amount,
|
|
11138
|
+
denom,
|
|
11139
|
+
...prefixes
|
|
11140
|
+
});
|
|
11141
|
+
break;
|
|
11142
|
+
case "withdraw":
|
|
11143
|
+
if (amount !== void 0 || denom !== void 0) {
|
|
11144
|
+
throw new InvalidInputError("withdraw does not accept amount or denom");
|
|
11145
|
+
}
|
|
11146
|
+
result = buildWithdrawRewardsMsg({
|
|
11147
|
+
delegatorAddress,
|
|
11148
|
+
validatorAddress,
|
|
11149
|
+
...prefixes
|
|
11150
|
+
});
|
|
11151
|
+
break;
|
|
11152
|
+
default:
|
|
11153
|
+
throw new InvalidInputError("staking action must be delegate, undelegate, redelegate, or withdraw");
|
|
11154
|
+
}
|
|
11155
|
+
emitPrepResult("cosmos-staking", result);
|
|
11156
|
+
}
|
|
11157
|
+
function executePrepCw20Transfer(bech32Prefix, contract, recipient, amount, sender, options) {
|
|
11158
|
+
const nativeDenoms = options.nativeDenoms?.split(",").map((value) => value.trim()).filter(Boolean);
|
|
11159
|
+
const result = buildCw20TransferMsg({
|
|
11160
|
+
bech32Prefix,
|
|
11161
|
+
contract,
|
|
11162
|
+
recipient,
|
|
11163
|
+
amount,
|
|
11164
|
+
sender,
|
|
11165
|
+
nativeDenoms
|
|
11166
|
+
});
|
|
11167
|
+
emitPrepResult("cw20-transfer", result);
|
|
11168
|
+
}
|
|
11169
|
+
|
|
10839
11170
|
// src/commands/execute.ts
|
|
10840
11171
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
10841
11172
|
import {
|
|
@@ -11165,7 +11496,7 @@ async function executeBroadcast(ctx2, params) {
|
|
|
11165
11496
|
}
|
|
11166
11497
|
|
|
11167
11498
|
// src/commands/tx-status.ts
|
|
11168
|
-
import { Chain as Chain7, isValidTxHash, Vultisig as Vultisig5 } from "@vultisig/sdk";
|
|
11499
|
+
import { Chain as Chain7, isValidTxHash, pollTxStatusUntilFinal, Vultisig as Vultisig5 } from "@vultisig/sdk";
|
|
11169
11500
|
function resolveTxStatusParams(params) {
|
|
11170
11501
|
if (!Object.values(Chain7).includes(params.chain)) {
|
|
11171
11502
|
throw new InvalidInputError(`Invalid chain: ${params.chain}`);
|
|
@@ -11198,19 +11529,26 @@ async function executeTxStatus(ctx2, params, opts = {}) {
|
|
|
11198
11529
|
try {
|
|
11199
11530
|
let result = await vault.getTxStatus({ chain: params.chain, txHash: params.txHash });
|
|
11200
11531
|
if (!params.noWait && !isTerminal(result.status)) {
|
|
11201
|
-
const
|
|
11532
|
+
const timeoutMs = resolveTimeoutMs(params.timeoutSec);
|
|
11202
11533
|
let waited = 0;
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11534
|
+
const outcome = await pollTxStatusUntilFinal({
|
|
11535
|
+
chain: params.chain,
|
|
11536
|
+
txHash: params.txHash,
|
|
11537
|
+
initialResult: result,
|
|
11538
|
+
timeoutMs,
|
|
11539
|
+
intervalMs: pollIntervalMs,
|
|
11540
|
+
getTxStatus: (pollParams) => vault.getTxStatus(pollParams),
|
|
11541
|
+
isTerminal: (candidate) => isTerminal(candidate.status),
|
|
11542
|
+
sleep: async (ms) => {
|
|
11543
|
+
waited += ms;
|
|
11544
|
+
spinner.text = `Transaction ${result.status}... (${Math.round(waited / 1e3)}s)`;
|
|
11545
|
+
await sleep(ms);
|
|
11208
11546
|
}
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11547
|
+
});
|
|
11548
|
+
if (outcome.result) result = outcome.result;
|
|
11549
|
+
if (outcome.timedOut) {
|
|
11550
|
+
spinner.fail(`Gave up waiting after ${Math.round(outcome.elapsedMs / 1e3)}s (status: ${result.status})`);
|
|
11551
|
+
throw giveUpError(params, result, outcome.elapsedMs);
|
|
11214
11552
|
}
|
|
11215
11553
|
}
|
|
11216
11554
|
if (result.status === "success") {
|
|
@@ -12293,7 +12631,7 @@ init_stringify();
|
|
|
12293
12631
|
init_base();
|
|
12294
12632
|
var InvalidDomainError = class extends BaseError2 {
|
|
12295
12633
|
constructor({ domain }) {
|
|
12296
|
-
super(`Invalid domain "${
|
|
12634
|
+
super(`Invalid domain "${stringify2(domain)}".`, {
|
|
12297
12635
|
metaMessages: ["Must be a valid EIP-712 domain."]
|
|
12298
12636
|
});
|
|
12299
12637
|
}
|
|
@@ -13737,14 +14075,15 @@ import { getChainKind as getChainKind5 } from "@vultisig/sdk";
|
|
|
13737
14075
|
// src/agent/executor.ts
|
|
13738
14076
|
import {
|
|
13739
14077
|
Chain as Chain11,
|
|
13740
|
-
chainFeeCoin as chainFeeCoin2,
|
|
13741
14078
|
computeEip712Hash,
|
|
13742
14079
|
getChainKind as getChainKind4,
|
|
13743
14080
|
getEvmRpcUrl,
|
|
13744
14081
|
knownTokensIndex,
|
|
13745
|
-
|
|
14082
|
+
parseTxReadyEnvelope,
|
|
14083
|
+
pollTxStatusUntilFinal as pollTxStatusUntilFinal2,
|
|
13746
14084
|
resolveChainReference,
|
|
13747
14085
|
toCanonicalEvmSignature,
|
|
14086
|
+
TxReadyParseError,
|
|
13748
14087
|
VaultError as VaultError3,
|
|
13749
14088
|
VaultErrorCode as VaultErrorCode3,
|
|
13750
14089
|
Vultisig as VultisigSdk
|
|
@@ -14162,6 +14501,18 @@ function decodeErc20Transfer(calldata) {
|
|
|
14162
14501
|
}
|
|
14163
14502
|
}
|
|
14164
14503
|
var isEvmChain = (chain) => EVM_CHAINS.has(chain);
|
|
14504
|
+
function stripEmbeddedPayloadContract(value, disclosedContract) {
|
|
14505
|
+
if (!disclosedContract) return value;
|
|
14506
|
+
const escapedContract = disclosedContract.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14507
|
+
const normalizedContract = disclosedContract.toLowerCase();
|
|
14508
|
+
return value.replace(new RegExp(escapedContract, "gi"), "").replace(/0x([0-9a-fA-F]{2,8})(?:…|\.{3})([0-9a-fA-F]{2,8})/g, (match, prefix, suffix) => {
|
|
14509
|
+
const normalizedPrefix = `0x${prefix}`.toLowerCase();
|
|
14510
|
+
return normalizedContract.startsWith(normalizedPrefix) && normalizedContract.endsWith(suffix.toLowerCase()) ? "" : match;
|
|
14511
|
+
}).replace(/\(\s*\)/g, "").replace(/\s{2,}/g, " ").trim();
|
|
14512
|
+
}
|
|
14513
|
+
function formatTokenContractDisclosure(disclosedContract) {
|
|
14514
|
+
return disclosedContract ? ` (token contract ${disclosedContract})` : "";
|
|
14515
|
+
}
|
|
14165
14516
|
var AgentExecutor = class {
|
|
14166
14517
|
vault;
|
|
14167
14518
|
/** Owning SDK (optional); used for address book backed by app storage */
|
|
@@ -14551,11 +14902,35 @@ var AgentExecutor = class {
|
|
|
14551
14902
|
if (transfer) {
|
|
14552
14903
|
return this.renderErc20TransferSummary(transfer.amount, contractTo, stored.chain, to);
|
|
14553
14904
|
}
|
|
14554
|
-
const
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14905
|
+
const disclosedContract = isContractSend && contractTo.toLowerCase() !== to.toLowerCase() ? contractTo : "";
|
|
14906
|
+
return this.renderLabelSendSummary(p, labels, stored.chain, to, disclosedContract);
|
|
14907
|
+
}
|
|
14908
|
+
/**
|
|
14909
|
+
* Render the send summary from producer labels — the fallback for native,
|
|
14910
|
+
* non-EVM, and non-transfer envelopes only (decoded ERC-20 transfers are
|
|
14911
|
+
* rendered from calldata by renderErc20TransferSummary above). De-duplicates
|
|
14912
|
+
* token/chain/contract details the label may repeat, anchored to the routed
|
|
14913
|
+
* chain and the payload-derived contract disclosure.
|
|
14914
|
+
*/
|
|
14915
|
+
renderLabelSendSummary(p, labels, chain, to, disclosedContract) {
|
|
14916
|
+
const amount = stripEmbeddedPayloadContract(labels.resolved_amount ?? p?.txArgs?.amount ?? "?", disclosedContract);
|
|
14917
|
+
const tokenLabel = stripEmbeddedPayloadContract(
|
|
14918
|
+
(labels.token_resolved || labels.token_symbol || "").trim(),
|
|
14919
|
+
disclosedContract
|
|
14920
|
+
);
|
|
14921
|
+
const symbol = tokenLabel.split(/\s+/, 1)[0];
|
|
14922
|
+
const escapedChain = String(chain).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14923
|
+
const routedChainPattern = new RegExp(`(?:^|\\s)(?:not\\s+)?on ${escapedChain}(?=\\s|$)`);
|
|
14924
|
+
const positiveRoutedChainPattern = new RegExp(`(?:^|\\s)(?<!\\bnot\\s+)on ${escapedChain}(?=\\s|$)`);
|
|
14925
|
+
const tokenContext = tokenLabel.slice(symbol.length);
|
|
14926
|
+
const labelCarriesRoutedChain = positiveRoutedChainPattern.test(tokenContext);
|
|
14927
|
+
const tokenDetail = tokenContext.replace(routedChainPattern, "").trim();
|
|
14928
|
+
const amountEmbedsTokenLabel = tokenLabel.length > 0 && amount.endsWith(` ${tokenLabel}`);
|
|
14929
|
+
const amountWithSymbol = symbol && !amount.endsWith(` ${symbol}`) && !amountEmbedsTokenLabel ? `${amount} ${symbol}` : amount;
|
|
14930
|
+
const tokenDetailSuffix = amountEmbedsTokenLabel || !tokenDetail ? "" : ` ${tokenDetail}`;
|
|
14931
|
+
const location = amountEmbedsTokenLabel && labelCarriesRoutedChain ? "" : `on ${chain}${tokenDetailSuffix}`;
|
|
14932
|
+
const contractPart = formatTokenContractDisclosure(disclosedContract);
|
|
14933
|
+
return `send ${amountWithSymbol}${location ? ` ${location}` : ""} to ${to}${contractPart}`;
|
|
14559
14934
|
}
|
|
14560
14935
|
/**
|
|
14561
14936
|
* Render the consent amount for an ERC-20 transfer from the SIGNED calldata
|
|
@@ -14849,8 +15224,8 @@ var AgentExecutor = class {
|
|
|
14849
15224
|
return this.signNonEvmServerTx(serverTxData, chain);
|
|
14850
15225
|
}
|
|
14851
15226
|
/**
|
|
14852
|
-
* Non-EVM signing path: parse the agent's tx_ready envelope
|
|
14853
|
-
*
|
|
15227
|
+
* Non-EVM signing path: parse the agent's tx_ready envelope through the
|
|
15228
|
+
* SDK's canonical discriminated contract and call through. The SDK already
|
|
14854
15229
|
* handles per-chain prepare/sign/broadcast internally via
|
|
14855
15230
|
* `VaultBase.prepareSendTx` virtuals — sdk-cli only owns envelope
|
|
14856
15231
|
* parsing here, not chain-specific signing logic.
|
|
@@ -14877,20 +15252,20 @@ var AgentExecutor = class {
|
|
|
14877
15252
|
`signNonEvmServerTx: dispatcher chain '${chain}' disagrees with envelope chain '${txArgs.chain}'`
|
|
14878
15253
|
);
|
|
14879
15254
|
}
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
15255
|
+
const parsed = parseTxReadyForCli(serverTxData, chain, this.vault.getTokens?.(chain) ?? []);
|
|
15256
|
+
if (parsed.kind === "thor-swap-deposit") {
|
|
15257
|
+
return this.signThorMsgDepositSwap(parsed);
|
|
15258
|
+
}
|
|
15259
|
+
if (parsed.kind === "thor-lp-deposit") {
|
|
15260
|
+
return this.signThorMsgDepositLp(parsed);
|
|
15261
|
+
}
|
|
15262
|
+
if (parsed.kind !== "send") {
|
|
14888
15263
|
throw new VaultError3(
|
|
14889
|
-
VaultErrorCode3.
|
|
14890
|
-
`signNonEvmServerTx:
|
|
15264
|
+
VaultErrorCode3.InvalidConfig,
|
|
15265
|
+
`signNonEvmServerTx: expected a non-EVM send/deposit envelope, got ${parsed.kind}`
|
|
14891
15266
|
);
|
|
14892
15267
|
}
|
|
14893
|
-
const args =
|
|
15268
|
+
const args = parsed;
|
|
14894
15269
|
if (this.verbose)
|
|
14895
15270
|
process.stderr.write(
|
|
14896
15271
|
`[sign_non_evm_server_tx] chain=${chain}, to=${args.to}, amount=${args.amount}${args.symbol ? ` ${args.symbol}` : ""}, memo=${args.memo ? `"${args.memo}"` : "(none)"}
|
|
@@ -14939,38 +15314,20 @@ var AgentExecutor = class {
|
|
|
14939
15314
|
* cross-account route cannot be silently replaced with the vault's address.
|
|
14940
15315
|
* An omitted destination keeps the existing self-swap default.
|
|
14941
15316
|
*/
|
|
14942
|
-
async signThorMsgDepositSwap(
|
|
14943
|
-
const
|
|
14944
|
-
const memo = typeof txArgs.memo === "string" ? txArgs.memo : "";
|
|
14945
|
-
const parsed = parseThorSwapMemo(memo);
|
|
14946
|
-
if (/\s/.test(parsed.destAddress)) {
|
|
14947
|
-
throw new VaultError3(
|
|
14948
|
-
VaultErrorCode3.InvalidConfig,
|
|
14949
|
-
`signThorMsgDepositSwap: destination address in memo '${memo}' must not contain whitespace.`
|
|
14950
|
-
);
|
|
14951
|
-
}
|
|
14952
|
-
const toChain = parsed.toChain;
|
|
14953
|
-
const fromSymbol = chain === Chain11.THORChain ? "RUNE" : "CACAO";
|
|
14954
|
-
const amountRaw = typeof txArgs.amount === "string" ? txArgs.amount : void 0;
|
|
14955
|
-
if (!amountRaw) {
|
|
14956
|
-
throw new VaultError3(
|
|
14957
|
-
VaultErrorCode3.InvalidConfig,
|
|
14958
|
-
`signThorMsgDepositSwap: missing or non-string 'amount' field on ${chain} envelope`
|
|
14959
|
-
);
|
|
14960
|
-
}
|
|
14961
|
-
const amountDecimal = convertBaseUnitsToDecimal(chain, amountRaw, "signThorMsgDepositSwap");
|
|
15317
|
+
async signThorMsgDepositSwap(parsed) {
|
|
15318
|
+
const { amount, chain, fromSymbol, memo, recipient, toChain, toSymbol } = parsed;
|
|
14962
15319
|
if (this.verbose)
|
|
14963
15320
|
process.stderr.write(
|
|
14964
|
-
`[sign_thor_msg_deposit_swap] ${fromSymbol}@${chain} \u2192 ${
|
|
15321
|
+
`[sign_thor_msg_deposit_swap] ${fromSymbol}@${chain} \u2192 ${toSymbol}@${toChain}, amount=${amount}, memo='${memo}'
|
|
14965
15322
|
`
|
|
14966
15323
|
);
|
|
14967
15324
|
const result = await this.vault.swap({
|
|
14968
15325
|
fromChain: chain,
|
|
14969
15326
|
fromSymbol,
|
|
14970
15327
|
toChain,
|
|
14971
|
-
toSymbol
|
|
14972
|
-
amount
|
|
14973
|
-
...
|
|
15328
|
+
toSymbol,
|
|
15329
|
+
amount,
|
|
15330
|
+
...recipient && { recipient }
|
|
14974
15331
|
});
|
|
14975
15332
|
if (result.dryRun) {
|
|
14976
15333
|
throw new VaultError3(
|
|
@@ -15002,28 +15359,16 @@ var AgentExecutor = class {
|
|
|
15002
15359
|
* as base units directly (no decimal conversion) since the agent
|
|
15003
15360
|
* already emits RUNE / CACAO in base units.
|
|
15004
15361
|
*/
|
|
15005
|
-
async signThorMsgDepositLp(
|
|
15006
|
-
const
|
|
15007
|
-
const memo = typeof txArgs.memo === "string" ? txArgs.memo : "";
|
|
15008
|
-
const amountRaw = typeof txArgs.amount === "string" ? txArgs.amount : void 0;
|
|
15009
|
-
if (!amountRaw) {
|
|
15010
|
-
throw new VaultError3(
|
|
15011
|
-
VaultErrorCode3.InvalidConfig,
|
|
15012
|
-
`signThorMsgDepositLp: missing or non-string 'amount' field on ${chain} envelope`
|
|
15013
|
-
);
|
|
15014
|
-
}
|
|
15015
|
-
if (amountRaw.length > MAX_AMOUNT_DIGITS) {
|
|
15016
|
-
throw new VaultError3(
|
|
15017
|
-
VaultErrorCode3.InvalidAmount,
|
|
15018
|
-
`signThorMsgDepositLp: amount '${amountRaw}' for ${chain} exceeds ${MAX_AMOUNT_DIGITS}-digit safety bound. Likely a quote-side bug. Refusing to sign.`
|
|
15019
|
-
);
|
|
15020
|
-
}
|
|
15362
|
+
async signThorMsgDepositLp(parsed) {
|
|
15363
|
+
const { amountBaseUnits, chain, memo } = parsed;
|
|
15021
15364
|
if (this.verbose)
|
|
15022
|
-
process.stderr.write(
|
|
15023
|
-
`
|
|
15365
|
+
process.stderr.write(
|
|
15366
|
+
`[sign_thor_msg_deposit_lp] chain=${chain}, memo='${memo}', amountBaseUnits=${amountBaseUnits}
|
|
15367
|
+
`
|
|
15368
|
+
);
|
|
15024
15369
|
const result = await this.vault.signMsgDeposit({
|
|
15025
15370
|
chain,
|
|
15026
|
-
amountBaseUnits
|
|
15371
|
+
amountBaseUnits,
|
|
15027
15372
|
memo
|
|
15028
15373
|
});
|
|
15029
15374
|
this.pendingPayloads.clear();
|
|
@@ -15211,20 +15556,20 @@ var AgentExecutor = class {
|
|
|
15211
15556
|
* success.
|
|
15212
15557
|
*/
|
|
15213
15558
|
async waitForEvmReceipt(chain, txHash, opts) {
|
|
15214
|
-
const
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
|
|
15223
|
-
} catch (e) {
|
|
15224
|
-
if (e instanceof VaultError3 && e.code === VaultErrorCode3.BroadcastFailed) throw e;
|
|
15225
|
-
if (e?.message?.includes("reverted")) throw e;
|
|
15559
|
+
const outcome = await pollTxStatusUntilFinal2({
|
|
15560
|
+
chain,
|
|
15561
|
+
txHash,
|
|
15562
|
+
timeoutMs: opts.timeoutSec * 1e3,
|
|
15563
|
+
intervalMs: 3e3,
|
|
15564
|
+
getTxStatus: (params) => this.vault.getTxStatus(params),
|
|
15565
|
+
shouldRetryError: (error2) => {
|
|
15566
|
+
if (error2 instanceof VaultError3 && error2.code === VaultErrorCode3.BroadcastFailed) return false;
|
|
15567
|
+
return !error2?.message?.includes("reverted");
|
|
15226
15568
|
}
|
|
15227
|
-
|
|
15569
|
+
});
|
|
15570
|
+
if (outcome.result?.status === "success") return;
|
|
15571
|
+
if (outcome.result?.status === "error") {
|
|
15572
|
+
throw new VaultError3(VaultErrorCode3.BroadcastFailed, `approve tx reverted (${txHash})`);
|
|
15228
15573
|
}
|
|
15229
15574
|
throw new VaultError3(VaultErrorCode3.Timeout, `approve tx ${txHash} not confirmed within ${opts.timeoutSec}s`);
|
|
15230
15575
|
}
|
|
@@ -15719,49 +16064,14 @@ function resolveChainFromTxReady(txReadyData) {
|
|
|
15719
16064
|
function extractNestedTx(txReadyData) {
|
|
15720
16065
|
return txReadyData?.swap_tx || txReadyData?.send_tx || txReadyData?.tx || txReadyData?.txArgs?.tx;
|
|
15721
16066
|
}
|
|
15722
|
-
|
|
15723
|
-
function convertBaseUnitsToDecimal(chain, amountRaw, context) {
|
|
15724
|
-
if (amountRaw.length > MAX_AMOUNT_DIGITS) {
|
|
15725
|
-
throw new VaultError3(
|
|
15726
|
-
VaultErrorCode3.InvalidAmount,
|
|
15727
|
-
`${context}: amount '${amountRaw}' for ${chain} exceeds ${MAX_AMOUNT_DIGITS}-digit safety bound. Likely a quote-side bug. Refusing to sign.`
|
|
15728
|
-
);
|
|
15729
|
-
}
|
|
15730
|
-
const decimals = chainFeeCoin2[chain]?.decimals;
|
|
15731
|
-
if (decimals === void 0) {
|
|
15732
|
-
throw new VaultError3(VaultErrorCode3.UnsupportedChain, `${context}: no native decimals registered for ${chain}`);
|
|
15733
|
-
}
|
|
16067
|
+
function parseTxReadyForCli(serverTxData, defaultChain, tokens = []) {
|
|
15734
16068
|
try {
|
|
15735
|
-
return
|
|
15736
|
-
} catch (
|
|
15737
|
-
throw
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
);
|
|
15741
|
-
}
|
|
15742
|
-
}
|
|
15743
|
-
function parseNonEvmEnvelope(serverTxData, chain) {
|
|
15744
|
-
const txArgs = serverTxData?.txArgs ?? serverTxData;
|
|
15745
|
-
if (!txArgs || typeof txArgs !== "object") {
|
|
15746
|
-
throw new VaultError3(VaultErrorCode3.InvalidConfig, "parseNonEvmEnvelope: envelope missing txArgs");
|
|
15747
|
-
}
|
|
15748
|
-
const to = typeof txArgs.to === "string" ? txArgs.to : void 0;
|
|
15749
|
-
if (!to) {
|
|
15750
|
-
throw new VaultError3(VaultErrorCode3.InvalidConfig, `parseNonEvmEnvelope: missing 'to' field for ${chain}`);
|
|
15751
|
-
}
|
|
15752
|
-
const amountRaw = typeof txArgs.amount === "string" ? txArgs.amount : void 0;
|
|
15753
|
-
if (!amountRaw) {
|
|
15754
|
-
throw new VaultError3(VaultErrorCode3.InvalidConfig, `parseNonEvmEnvelope: missing 'amount' field for ${chain}`);
|
|
15755
|
-
}
|
|
15756
|
-
const amountDecimal = convertBaseUnitsToDecimal(chain, amountRaw, "parseNonEvmEnvelope");
|
|
15757
|
-
let symbol;
|
|
15758
|
-
const tokenResolved = serverTxData?.resolved?.labels?.token_resolved;
|
|
15759
|
-
const nativeTicker = chainFeeCoin2[chain]?.ticker;
|
|
15760
|
-
if (typeof tokenResolved === "string" && tokenResolved !== nativeTicker) {
|
|
15761
|
-
symbol = tokenResolved;
|
|
16069
|
+
return parseTxReadyEnvelope(serverTxData, { defaultChain, tokens });
|
|
16070
|
+
} catch (error2) {
|
|
16071
|
+
if (!(error2 instanceof TxReadyParseError)) throw error2;
|
|
16072
|
+
const code = error2.code === "INVALID_AMOUNT" ? VaultErrorCode3.InvalidAmount : error2.code === "UNKNOWN_CHAIN" ? VaultErrorCode3.UnsupportedChain : error2.code === "UNSUPPORTED_DEPOSIT" || error2.code === "UNSUPPORTED_ENVELOPE" ? VaultErrorCode3.NotImplemented : VaultErrorCode3.InvalidConfig;
|
|
16073
|
+
throw new VaultError3(code, error2.message);
|
|
15762
16074
|
}
|
|
15763
|
-
const memo = typeof txArgs.memo === "string" && txArgs.memo.length > 0 ? txArgs.memo : void 0;
|
|
15764
|
-
return { chain, to, amount: amountDecimal, symbol, memo };
|
|
15765
16075
|
}
|
|
15766
16076
|
function resolveChainId(chainId) {
|
|
15767
16077
|
return resolveChainReference(chainId) ?? null;
|
|
@@ -16822,7 +17132,7 @@ var AgentClient = class {
|
|
|
16822
17132
|
};
|
|
16823
17133
|
|
|
16824
17134
|
// src/agent/context.ts
|
|
16825
|
-
import { chainFeeCoin as
|
|
17135
|
+
import { chainFeeCoin as chainFeeCoin2 } from "@vultisig/sdk";
|
|
16826
17136
|
function applyChainPublicKeys(vault, context) {
|
|
16827
17137
|
const raw = vault.data.chainPublicKeys;
|
|
16828
17138
|
if (!raw) return;
|
|
@@ -16883,7 +17193,7 @@ async function buildMessageContext(vault) {
|
|
|
16883
17193
|
const coins = [];
|
|
16884
17194
|
const chains = vault.chains;
|
|
16885
17195
|
for (const chain of chains) {
|
|
16886
|
-
const nativeCoin =
|
|
17196
|
+
const nativeCoin = chainFeeCoin2[chain];
|
|
16887
17197
|
coins.push({
|
|
16888
17198
|
chain: chain.toString(),
|
|
16889
17199
|
ticker: nativeCoin?.ticker ?? chain.toString(),
|
|
@@ -19190,7 +19500,7 @@ var cachedVersion = null;
|
|
|
19190
19500
|
function getVersion() {
|
|
19191
19501
|
if (cachedVersion) return cachedVersion;
|
|
19192
19502
|
if (true) {
|
|
19193
|
-
cachedVersion = "
|
|
19503
|
+
cachedVersion = "6.0.0";
|
|
19194
19504
|
return cachedVersion;
|
|
19195
19505
|
}
|
|
19196
19506
|
try {
|
|
@@ -19347,6 +19657,35 @@ var COMMAND_EXAMPLES = {
|
|
|
19347
19657
|
execute: {
|
|
19348
19658
|
examples: [`vultisig execute THORChain <contract> '{"swap":{}}'`]
|
|
19349
19659
|
},
|
|
19660
|
+
"prep.contract-call": {
|
|
19661
|
+
examples: [
|
|
19662
|
+
`vultisig prep contract-call Ethereum <contractAddress> approve --sender <senderAddress> --abi '[{"type":"function","name":"approve","inputs":[{"type":"address","name":"spender"},{"type":"uint256","name":"amount"}]}]' --args '["<spenderAddress>","1000000"]'`
|
|
19663
|
+
]
|
|
19664
|
+
},
|
|
19665
|
+
"prep.ibc-transfer": {
|
|
19666
|
+
examples: ["vultisig prep ibc-transfer Osmosis osmo1... cosmos1... uosmo 1000000 --to-chain Cosmos"]
|
|
19667
|
+
},
|
|
19668
|
+
"prep.spl-transfer": {
|
|
19669
|
+
examples: ["vultisig prep spl-transfer <mint> <from> <to> 1000000 6"]
|
|
19670
|
+
},
|
|
19671
|
+
"prep.trc20-transfer": {
|
|
19672
|
+
examples: ["vultisig prep trc20-transfer <contract> <from> <to> 1000000"]
|
|
19673
|
+
},
|
|
19674
|
+
"prep.jetton-transfer": {
|
|
19675
|
+
examples: ["vultisig prep jetton-transfer <recipient> <senderJettonWallet> 1000000 5"]
|
|
19676
|
+
},
|
|
19677
|
+
"prep.sui-token-transfer": {
|
|
19678
|
+
examples: ["vultisig prep sui-token-transfer <coinType> <from> <to> 1000000 --decimals 6"]
|
|
19679
|
+
},
|
|
19680
|
+
"prep.polkadot-asset-send": {
|
|
19681
|
+
examples: ["vultisig prep polkadot-asset-send 1984 <from> <to> 1000000"]
|
|
19682
|
+
},
|
|
19683
|
+
"prep.cosmos-staking": {
|
|
19684
|
+
examples: ["vultisig prep cosmos-staking delegate <delegator> <validator> 5000000 uosmo"]
|
|
19685
|
+
},
|
|
19686
|
+
"prep.cw20-transfer": {
|
|
19687
|
+
examples: ["vultisig prep cw20-transfer osmo <contract> <recipient> 1000000 <sender>"]
|
|
19688
|
+
},
|
|
19350
19689
|
"swap-quote": {
|
|
19351
19690
|
examples: ["vultisig swap-quote Ethereum Bitcoin 0.1 --output json"]
|
|
19352
19691
|
},
|
|
@@ -19426,8 +19765,16 @@ function executeSchema(prog) {
|
|
|
19426
19765
|
};
|
|
19427
19766
|
})
|
|
19428
19767
|
};
|
|
19429
|
-
|
|
19430
|
-
|
|
19768
|
+
return new Promise((resolve, reject) => {
|
|
19769
|
+
process.stdout.write(`${JSON.stringify(schema, null, 2)}
|
|
19770
|
+
`, (error2) => {
|
|
19771
|
+
if (error2) {
|
|
19772
|
+
reject(error2);
|
|
19773
|
+
return;
|
|
19774
|
+
}
|
|
19775
|
+
resolve();
|
|
19776
|
+
});
|
|
19777
|
+
});
|
|
19431
19778
|
}
|
|
19432
19779
|
|
|
19433
19780
|
// src/core/server-endpoints.ts
|
|
@@ -20730,7 +21077,7 @@ Error: ${error2.message}`));
|
|
|
20730
21077
|
|
|
20731
21078
|
// src/lib/completion.ts
|
|
20732
21079
|
import { getVultisigConfigDir as getVultisigConfigDir5 } from "@vultisig/client-shared";
|
|
20733
|
-
import { SUPPORTED_CHAINS as
|
|
21080
|
+
import { SUPPORTED_CHAINS as SUPPORTED_CHAINS3 } from "@vultisig/sdk";
|
|
20734
21081
|
import { program } from "commander";
|
|
20735
21082
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync5 } from "fs";
|
|
20736
21083
|
import { join as join5 } from "path";
|
|
@@ -20752,7 +21099,7 @@ function getCommands() {
|
|
|
20752
21099
|
return program.commands.map((cmd) => cmd.name()).sort();
|
|
20753
21100
|
}
|
|
20754
21101
|
function getChains() {
|
|
20755
|
-
return [...
|
|
21102
|
+
return [...SUPPORTED_CHAINS3];
|
|
20756
21103
|
}
|
|
20757
21104
|
function getVaultNames() {
|
|
20758
21105
|
try {
|
|
@@ -21372,6 +21719,66 @@ See also: balance, tx-status`
|
|
|
21372
21719
|
}
|
|
21373
21720
|
)
|
|
21374
21721
|
);
|
|
21722
|
+
var prepCmd = program2.command("prep").description("Build unsigned transaction payloads with SDK preparation helpers (never signs or broadcasts)");
|
|
21723
|
+
var loadPrepVault = async (identity) => {
|
|
21724
|
+
if (identity !== void 0) return void 0;
|
|
21725
|
+
const context = await init(program2.opts().vault);
|
|
21726
|
+
return context.ensureActiveVault();
|
|
21727
|
+
};
|
|
21728
|
+
prepCmd.command("contract-call <chain> <contractAddress> <functionName>").description("Build an unsigned EVM contract-call KeysignPayload").requiredOption("--abi <json>", "Solidity ABI JSON array").requiredOption("--sender <address>", "Sender EVM address").option("--args <json>", "Function arguments as a JSON array").option("--value <baseUnits>", "Native value in base units", "0").option("--gas-limit <baseUnits>", "Custom EVM gas limit (requires --max-priority-fee-per-gas)").option("--max-priority-fee-per-gas <baseUnits>", "Custom EVM priority fee (requires --gas-limit)").option("--identity <json>", "Public VaultIdentity JSON; otherwise use the active vault").action(
|
|
21729
|
+
withExit(async (chain, contractAddress, functionName, options) => {
|
|
21730
|
+
const vault = await loadPrepVault(options.identity);
|
|
21731
|
+
await executePrepContractCall(vault, resolveChainOrThrow(chain), contractAddress, functionName, options);
|
|
21732
|
+
})
|
|
21733
|
+
);
|
|
21734
|
+
prepCmd.command("ibc-transfer <fromChain> <fromAddress> <toAddress> <denom> <amount>").description("Build an unsigned ICS-20 IBC MsgTransfer envelope").option("--to-chain <chainId>", "Destination chain ID or Vultisig chain name").option("--source-channel <channel>", "IBC source channel (channel-N)").option("--timeout-height <revision/height>", "IBC timeout height (default: 0/0)").option("--timeout-timestamp <nanoseconds>", "Future Unix timeout in nanoseconds").option("--account-number <number>", "Source-chain account number").option("--sequence <number>", "Source-chain account sequence").option("--memo <memo>", "IBC packet memo").option("--now-ms <milliseconds>", "Override current time for deterministic default timeout").action(
|
|
21735
|
+
withExit(
|
|
21736
|
+
async (fromChain, fromAddress, toAddress, denom, amount, options) => {
|
|
21737
|
+
executePrepIbcTransfer(fromChain, fromAddress, toAddress, denom, amount, options);
|
|
21738
|
+
}
|
|
21739
|
+
)
|
|
21740
|
+
);
|
|
21741
|
+
prepCmd.command("spl-transfer <mint> <from> <to> <amount> <decimals>").description("Build an unsigned SPL transferChecked instruction with derived ATAs").option("--token-2022", "Use the Token-2022 program instead of the legacy SPL Token program").action(
|
|
21742
|
+
withExit(async (mint, from, to, amount, decimals, options) => {
|
|
21743
|
+
executePrepSplTransfer(mint, from, to, amount, decimals, options);
|
|
21744
|
+
})
|
|
21745
|
+
);
|
|
21746
|
+
prepCmd.command("trc20-transfer <contractAddress> <from> <to> <amount>").description("Build an unsigned TRC-20 transfer descriptor").option("--memo <memo>", "Optional TRON transaction memo").option("--fee-limit-sun <amount>", "Energy/bandwidth ceiling in SUN").action(
|
|
21747
|
+
withExit(async (contractAddress, from, to, amount, options) => {
|
|
21748
|
+
executePrepTrc20Transfer(contractAddress, from, to, amount, options);
|
|
21749
|
+
})
|
|
21750
|
+
);
|
|
21751
|
+
prepCmd.command("jetton-transfer <receiver> <jettonWalletAddress> <amount> <seqno>").description("Build an unsigned TON Jetton transfer signing payload").option("--memo <memo>", "Forward comment (up to 123 UTF-8 bytes)").option("--valid-until <seconds>", "Unix-seconds expiry").option("--workchain <number>", "Sender wallet workchain (default: 0)").option("--identity <json>", "Public VaultIdentity JSON; otherwise use the active vault").action(
|
|
21752
|
+
withExit(async (receiver, jettonWalletAddress, amount, seqno, options) => {
|
|
21753
|
+
const vault = await loadPrepVault(options.identity);
|
|
21754
|
+
executePrepJettonTransfer(vault, receiver, jettonWalletAddress, amount, seqno, options);
|
|
21755
|
+
})
|
|
21756
|
+
);
|
|
21757
|
+
prepCmd.command("sui-token-transfer <coinType> <from> <to> <amount>").description("Build an unsigned Sui coin-object token-transfer KeysignPayload").option("--decimals <number>", "Token decimals metadata").option("--ticker <symbol>", "Token ticker metadata").option("--identity <json>", "Public VaultIdentity JSON; otherwise use the active vault").action(
|
|
21758
|
+
withExit(async (coinType, from, to, amount, options) => {
|
|
21759
|
+
const vault = await loadPrepVault(options.identity);
|
|
21760
|
+
await executePrepSuiTokenTransfer(vault, coinType, from, to, amount, options);
|
|
21761
|
+
})
|
|
21762
|
+
);
|
|
21763
|
+
prepCmd.command("polkadot-asset-send <assetId> <from> <to> <amount>").description("Build an unsigned Polkadot Asset Hub transferKeepAlive call").option("--decimals <number>", "Asset decimals override").option("--ticker <symbol>", "Asset ticker override").action(
|
|
21764
|
+
withExit(async (assetId, from, to, amount, options) => {
|
|
21765
|
+
executePrepPolkadotAssetSend(assetId, from, to, amount, options);
|
|
21766
|
+
})
|
|
21767
|
+
);
|
|
21768
|
+
prepCmd.command("cosmos-staking <action> <delegatorAddress> <validatorAddress> [amount] [denom]").description("Build an unsigned Cosmos delegate, undelegate, redelegate, or withdraw message").option("--validator-dst <address>", "Destination validator for redelegate").option("--account-prefix <prefix>", "Expected delegator bech32 prefix").option("--validator-prefix <prefix>", "Expected validator bech32 prefix").action(
|
|
21769
|
+
withExit(
|
|
21770
|
+
async (action, delegatorAddress, validatorAddress, amount, denom, options) => {
|
|
21771
|
+
executePrepCosmosStaking(action, delegatorAddress, validatorAddress, amount, denom, options);
|
|
21772
|
+
}
|
|
21773
|
+
)
|
|
21774
|
+
);
|
|
21775
|
+
prepCmd.command("cw20-transfer <bech32Prefix> <contract> <recipient> <amount> <sender>").description("Build an unsigned CosmWasm CW-20 transfer message").option("--native-denoms <csv>", "Comma-separated native denoms to reject on this route").action(
|
|
21776
|
+
withExit(
|
|
21777
|
+
async (bech32Prefix, contract, recipient, amount, sender, options) => {
|
|
21778
|
+
executePrepCw20Transfer(bech32Prefix, contract, recipient, amount, sender, options);
|
|
21779
|
+
}
|
|
21780
|
+
)
|
|
21781
|
+
);
|
|
21375
21782
|
program2.command("execute <chain> <contract> <msg>").description("Execute a CosmWasm smart contract (THORChain, MayaChain)").option("--funds <funds>", 'Funds to send with execution (format: "denom:amount" or "denom:amount,denom2:amount2")').option("--memo <memo>", "Transaction memo").option("--dry-run", "Preview execution without signing or broadcasting").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").addHelpText(
|
|
21376
21783
|
"after",
|
|
21377
21784
|
`
|
|
@@ -21922,7 +22329,12 @@ authCmd.command("status").description("List configured vaults and their keyring
|
|
|
21922
22329
|
const vaults = await executeAuthStatus();
|
|
21923
22330
|
if (isJsonOutput()) {
|
|
21924
22331
|
outputJson({
|
|
21925
|
-
vaults: vaults.map((v) => ({
|
|
22332
|
+
vaults: vaults.map((v) => ({
|
|
22333
|
+
id: v.id,
|
|
22334
|
+
name: v.name,
|
|
22335
|
+
filePath: v.filePath,
|
|
22336
|
+
hasCredentials: v.hasCredentials
|
|
22337
|
+
}))
|
|
21926
22338
|
});
|
|
21927
22339
|
return;
|
|
21928
22340
|
}
|
|
@@ -21941,7 +22353,11 @@ authCmd.command("logout").description("Clear keyring credentials for a vault").o
|
|
|
21941
22353
|
withExit(async (options) => {
|
|
21942
22354
|
await executeAuthLogout({ vaultId: options.vaultId, all: options.all });
|
|
21943
22355
|
if (isJsonOutput()) {
|
|
21944
|
-
outputJson({
|
|
22356
|
+
outputJson({
|
|
22357
|
+
cleared: true,
|
|
22358
|
+
vaultId: options.vaultId ?? null,
|
|
22359
|
+
all: !!options.all
|
|
22360
|
+
});
|
|
21945
22361
|
} else {
|
|
21946
22362
|
printResult(chalk16.green("Credentials cleared."));
|
|
21947
22363
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.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": {
|
|
@@ -67,17 +67,16 @@
|
|
|
67
67
|
},
|
|
68
68
|
"homepage": "https://vultisig.com",
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@cosmjs/cosmwasm-stargate": "^0.39.0",
|
|
71
70
|
"@cosmjs/encoding": "^0.39.0",
|
|
72
71
|
"@cosmjs/proto-signing": "^0.39.0",
|
|
73
72
|
"@cosmjs/stargate": "^0.39.0",
|
|
74
73
|
"@msgpack/msgpack": "^3.1.2",
|
|
75
74
|
"@napi-rs/keyring": "^1.3.0",
|
|
76
75
|
"@noble/hashes": "^2.2.0",
|
|
77
|
-
"@vultisig/client-shared": "^0.3.
|
|
78
|
-
"@vultisig/core-chain": "^
|
|
79
|
-
"@vultisig/rujira": "^
|
|
80
|
-
"@vultisig/sdk": "^
|
|
76
|
+
"@vultisig/client-shared": "^0.3.5",
|
|
77
|
+
"@vultisig/core-chain": "^4.0.0",
|
|
78
|
+
"@vultisig/rujira": "^70.0.0",
|
|
79
|
+
"@vultisig/sdk": "^6.0.0",
|
|
81
80
|
"chalk": "^5.6.2",
|
|
82
81
|
"cli-table3": "^0.6.5",
|
|
83
82
|
"commander": "^15.0.0",
|
|
@@ -95,7 +94,7 @@
|
|
|
95
94
|
"@types/node": "^26.1.1",
|
|
96
95
|
"@types/tabtab": "^3.0.4",
|
|
97
96
|
"@types/ws": "^8.18.1",
|
|
98
|
-
"@vultisig/core-mpc": "^
|
|
97
|
+
"@vultisig/core-mpc": "^2.0.0",
|
|
99
98
|
"esbuild": "^0.28.1",
|
|
100
99
|
"ethers": "^6.17.0",
|
|
101
100
|
"node-pty": "^1.1.0",
|
|
@@ -104,7 +103,7 @@
|
|
|
104
103
|
"vitest": "^4.1.8"
|
|
105
104
|
},
|
|
106
105
|
"engines": {
|
|
107
|
-
"node": ">=20.
|
|
106
|
+
"node": ">=20.19.0"
|
|
108
107
|
},
|
|
109
108
|
"publishConfig": {
|
|
110
109
|
"access": "public",
|