@vultisig/cli 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 5.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#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.
8
+
9
+ ### Patch Changes
10
+
11
+ - 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)]:
12
+ - @vultisig/sdk@5.2.0
13
+ - @vultisig/core-chain@3.0.0
14
+ - @vultisig/rujira@69.0.0
15
+
3
16
  ## 5.1.0
4
17
 
5
18
  ### 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
@@ -3852,10 +3852,10 @@ var init_decodeAbiParameters = __esm({
3852
3852
  });
3853
3853
 
3854
3854
  // ../../node_modules/viem/_esm/utils/stringify.js
3855
- var stringify;
3855
+ var stringify2;
3856
3856
  var init_stringify = __esm({
3857
3857
  "../../node_modules/viem/_esm/utils/stringify.js"() {
3858
- stringify = (value, replacer, space) => JSON.stringify(value, (key, value_) => {
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);
@@ -10836,6 +10836,307 @@ async function sendTransaction(vault, params) {
10836
10836
  }
10837
10837
  }
10838
10838
 
10839
+ // src/commands/prep.ts
10840
+ import {
10841
+ assertSafeDestination,
10842
+ buildCw20TransferMsg,
10843
+ buildDelegateMsg,
10844
+ buildRedelegateMsg,
10845
+ buildSplTransfer,
10846
+ buildUndelegateMsg,
10847
+ buildWithdrawRewardsMsg,
10848
+ prepareContractCallTxFromKeys,
10849
+ prepareIbcTransfer,
10850
+ prepareJettonTransferTxFromKeys,
10851
+ preparePolkadotAssetSend,
10852
+ prepareSuiTokenTransferFromKeys,
10853
+ prepareTrc20TransferFromKeys
10854
+ } from "@vultisig/sdk";
10855
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
10856
+ var parseJson = (raw, label) => {
10857
+ try {
10858
+ return JSON.parse(raw);
10859
+ } catch (error2) {
10860
+ const message = error2 instanceof Error ? error2.message : String(error2);
10861
+ throw new InvalidInputError(`Invalid ${label} JSON: ${message}`);
10862
+ }
10863
+ };
10864
+ var parseJsonArray = (raw, label) => {
10865
+ const value = parseJson(raw, label);
10866
+ if (!Array.isArray(value)) {
10867
+ throw new InvalidInputError(`${label} must be a JSON array`);
10868
+ }
10869
+ return value;
10870
+ };
10871
+ var MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
10872
+ var assertLosslessJsonNumberLexemes = (raw, label) => {
10873
+ let inString = false;
10874
+ let escaped = false;
10875
+ for (let index = 0; index < raw.length; index += 1) {
10876
+ const character = raw[index];
10877
+ if (inString) {
10878
+ if (escaped) {
10879
+ escaped = false;
10880
+ } else if (character === "\\") {
10881
+ escaped = true;
10882
+ } else if (character === '"') {
10883
+ inString = false;
10884
+ }
10885
+ continue;
10886
+ }
10887
+ if (character === '"') {
10888
+ inString = true;
10889
+ continue;
10890
+ }
10891
+ if (character !== "-" && (character < "0" || character > "9")) continue;
10892
+ const match = raw.slice(index).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/);
10893
+ if (match === null) continue;
10894
+ const lexeme = match[0];
10895
+ if (/[.eE]/.test(lexeme) || BigInt(lexeme) > MAX_SAFE_INTEGER || BigInt(lexeme) < -MAX_SAFE_INTEGER) {
10896
+ throw new InvalidInputError(
10897
+ `${label} numeric values must be safe base-10 integer literals; pass ABI integers as decimal strings`
10898
+ );
10899
+ }
10900
+ index += lexeme.length - 1;
10901
+ }
10902
+ };
10903
+ var parseLosslessJsonArray = (raw, label) => {
10904
+ assertLosslessJsonNumberLexemes(raw, label);
10905
+ const value = parseJsonArray(raw, label);
10906
+ return value;
10907
+ };
10908
+ var parseDecimalBigInt = (raw, label) => {
10909
+ if (!/^-?\d+$/.test(raw)) {
10910
+ throw new InvalidInputError(`${label} must be a base-10 integer string`);
10911
+ }
10912
+ return BigInt(raw);
10913
+ };
10914
+ var parseInteger = (raw, label) => {
10915
+ if (!/^-?\d+$/.test(raw)) {
10916
+ throw new InvalidInputError(`${label} must be an integer`);
10917
+ }
10918
+ const value = Number(raw);
10919
+ if (!Number.isSafeInteger(value)) {
10920
+ throw new InvalidInputError(`${label} must be a safe integer`);
10921
+ }
10922
+ return value;
10923
+ };
10924
+ var parseOptionalInteger = (raw, label) => raw === void 0 ? void 0 : parseInteger(raw, label);
10925
+ var parseIdentity = (raw) => {
10926
+ const value = parseJson(raw, "identity");
10927
+ if (!isRecord(value)) {
10928
+ throw new InvalidInputError("identity must be a JSON object");
10929
+ }
10930
+ const requiredStrings = ["ecdsaPublicKey", "eddsaPublicKey", "hexChainCode", "localPartyId", "libType"];
10931
+ for (const field of requiredStrings) {
10932
+ if (typeof value[field] !== "string" || value[field].length === 0) {
10933
+ throw new InvalidInputError(`identity.${field} must be a non-empty string`);
10934
+ }
10935
+ }
10936
+ if (!["GG20", "DKLS", "KeyImport"].includes(value.libType)) {
10937
+ throw new InvalidInputError("identity.libType must be GG20, DKLS, or KeyImport");
10938
+ }
10939
+ if (value.chainPublicKeys !== void 0 && !isRecord(value.chainPublicKeys)) {
10940
+ throw new InvalidInputError("identity.chainPublicKeys must be a JSON object when provided");
10941
+ }
10942
+ return value;
10943
+ };
10944
+ var identityFromVault = (vault) => ({
10945
+ ecdsaPublicKey: vault.publicKeys.ecdsa,
10946
+ eddsaPublicKey: vault.publicKeys.eddsa,
10947
+ hexChainCode: vault.hexChainCode,
10948
+ localPartyId: vault.localPartyId,
10949
+ libType: vault.libType,
10950
+ publicKeyMldsa: vault.publicKeyMldsa,
10951
+ chainPublicKeys: vault.data.chainPublicKeys
10952
+ });
10953
+ var resolveIdentity = (vault, rawIdentity) => {
10954
+ if (rawIdentity !== void 0) return parseIdentity(rawIdentity);
10955
+ if (vault !== void 0) return identityFromVault(vault);
10956
+ throw new InvalidInputError("An active vault or --identity JSON is required");
10957
+ };
10958
+ var stringify = (value) => JSON.stringify(value, (_key, item) => typeof item === "bigint" ? item.toString() : item, 2);
10959
+ var emitPrepResult = (helper, result) => {
10960
+ const output = { helper, unsigned: true, result };
10961
+ if (isJsonOutput()) {
10962
+ outputJson(output);
10963
+ } else {
10964
+ printResult(stringify(output));
10965
+ }
10966
+ };
10967
+ async function executePrepContractCall(vault, chain, contractAddress, functionName, options) {
10968
+ const value = options.value === void 0 ? void 0 : parseDecimalBigInt(options.value, "value");
10969
+ if (value !== void 0 && value > 0n) {
10970
+ assertSafeDestination(chain, contractAddress);
10971
+ }
10972
+ const feeSettings = options.gasLimit !== void 0 || options.maxPriorityFeePerGas !== void 0 ? {
10973
+ gasLimit: parseDecimalBigInt(options.gasLimit ?? "", "gas-limit"),
10974
+ maxPriorityFeePerGas: parseDecimalBigInt(options.maxPriorityFeePerGas ?? "", "max-priority-fee-per-gas")
10975
+ } : void 0;
10976
+ const result = await prepareContractCallTxFromKeys(resolveIdentity(vault, options.identity), {
10977
+ chain,
10978
+ contractAddress,
10979
+ abi: parseJsonArray(options.abi, "abi"),
10980
+ functionName,
10981
+ args: options.args === void 0 ? void 0 : parseLosslessJsonArray(options.args, "args"),
10982
+ value,
10983
+ senderAddress: options.sender,
10984
+ feeSettings
10985
+ });
10986
+ emitPrepResult("contract-call", result);
10987
+ }
10988
+ function executePrepIbcTransfer(fromChain, fromAddress, toAddress, denom, amount, options) {
10989
+ const result = prepareIbcTransfer({
10990
+ fromChain,
10991
+ fromAddress,
10992
+ toAddress,
10993
+ denom,
10994
+ amount,
10995
+ toChainId: options.toChain,
10996
+ sourceChannel: options.sourceChannel,
10997
+ timeoutHeight: options.timeoutHeight,
10998
+ timeoutTimestamp: options.timeoutTimestamp,
10999
+ accountNumber: options.accountNumber,
11000
+ sequence: options.sequence,
11001
+ memo: options.memo,
11002
+ nowMs: parseOptionalInteger(options.nowMs, "now-ms")
11003
+ });
11004
+ emitPrepResult("ibc-transfer", result);
11005
+ }
11006
+ function executePrepSplTransfer(mint, from, to, amount, decimals, options) {
11007
+ assertSafeDestination("Solana", to);
11008
+ const result = buildSplTransfer({
11009
+ mint,
11010
+ from,
11011
+ to,
11012
+ amount: parseDecimalBigInt(amount, "amount"),
11013
+ decimals: parseInteger(decimals, "decimals"),
11014
+ isToken2022: options.token2022
11015
+ });
11016
+ emitPrepResult("spl-transfer", result);
11017
+ }
11018
+ function executePrepTrc20Transfer(contractAddress, from, to, amount, options) {
11019
+ const result = prepareTrc20TransferFromKeys({
11020
+ contractAddress,
11021
+ from,
11022
+ to,
11023
+ amount,
11024
+ memo: options.memo,
11025
+ feeLimitSun: options.feeLimitSun
11026
+ });
11027
+ emitPrepResult("trc20-transfer", result);
11028
+ }
11029
+ function executePrepJettonTransfer(vault, receiver, jettonWalletAddress, amount, seqno, options) {
11030
+ const built = prepareJettonTransferTxFromKeys(resolveIdentity(vault, options.identity), {
11031
+ receiver,
11032
+ jettonWalletAddress,
11033
+ amount: parseDecimalBigInt(amount, "amount"),
11034
+ seqno: parseInteger(seqno, "seqno"),
11035
+ memo: options.memo,
11036
+ validUntil: parseOptionalInteger(options.validUntil, "valid-until"),
11037
+ workchain: parseOptionalInteger(options.workchain, "workchain")
11038
+ });
11039
+ const result = {
11040
+ signingHashHex: built.signingHashHex,
11041
+ unsignedBocHex: built.unsignedBocHex,
11042
+ fromAddress: built.fromAddress
11043
+ };
11044
+ emitPrepResult("jetton-transfer", result);
11045
+ }
11046
+ async function executePrepSuiTokenTransfer(vault, coinType, from, to, amount, options) {
11047
+ const result = await prepareSuiTokenTransferFromKeys(resolveIdentity(vault, options.identity), {
11048
+ coinType,
11049
+ from,
11050
+ to,
11051
+ amount: parseDecimalBigInt(amount, "amount"),
11052
+ decimals: parseOptionalInteger(options.decimals, "decimals"),
11053
+ ticker: options.ticker
11054
+ });
11055
+ emitPrepResult("sui-token-transfer", result);
11056
+ }
11057
+ function executePrepPolkadotAssetSend(assetId, from, to, amount, options) {
11058
+ const result = preparePolkadotAssetSend({
11059
+ assetId: parseInteger(assetId, "asset-id"),
11060
+ from,
11061
+ to,
11062
+ amount: parseDecimalBigInt(amount, "amount"),
11063
+ decimals: parseOptionalInteger(options.decimals, "decimals"),
11064
+ ticker: options.ticker
11065
+ });
11066
+ emitPrepResult("polkadot-asset-send", result);
11067
+ }
11068
+ function executePrepCosmosStaking(action, delegatorAddress, validatorAddress, amount, denom, options) {
11069
+ const prefixes = {
11070
+ accountPrefix: options.accountPrefix,
11071
+ validatorPrefix: options.validatorPrefix
11072
+ };
11073
+ let result;
11074
+ switch (action) {
11075
+ case "delegate":
11076
+ if (amount === void 0 || denom === void 0) {
11077
+ throw new InvalidInputError("delegate requires amount and denom");
11078
+ }
11079
+ result = buildDelegateMsg({
11080
+ delegatorAddress,
11081
+ validatorAddress,
11082
+ amount,
11083
+ denom,
11084
+ ...prefixes
11085
+ });
11086
+ break;
11087
+ case "undelegate":
11088
+ if (amount === void 0 || denom === void 0) {
11089
+ throw new InvalidInputError("undelegate requires amount and denom");
11090
+ }
11091
+ result = buildUndelegateMsg({
11092
+ delegatorAddress,
11093
+ validatorAddress,
11094
+ amount,
11095
+ denom,
11096
+ ...prefixes
11097
+ });
11098
+ break;
11099
+ case "redelegate":
11100
+ if (amount === void 0 || denom === void 0 || options.validatorDst === void 0) {
11101
+ throw new InvalidInputError("redelegate requires amount, denom, and --validator-dst");
11102
+ }
11103
+ result = buildRedelegateMsg({
11104
+ delegatorAddress,
11105
+ validatorSrcAddress: validatorAddress,
11106
+ validatorDstAddress: options.validatorDst,
11107
+ amount,
11108
+ denom,
11109
+ ...prefixes
11110
+ });
11111
+ break;
11112
+ case "withdraw":
11113
+ if (amount !== void 0 || denom !== void 0) {
11114
+ throw new InvalidInputError("withdraw does not accept amount or denom");
11115
+ }
11116
+ result = buildWithdrawRewardsMsg({
11117
+ delegatorAddress,
11118
+ validatorAddress,
11119
+ ...prefixes
11120
+ });
11121
+ break;
11122
+ default:
11123
+ throw new InvalidInputError("staking action must be delegate, undelegate, redelegate, or withdraw");
11124
+ }
11125
+ emitPrepResult("cosmos-staking", result);
11126
+ }
11127
+ function executePrepCw20Transfer(bech32Prefix, contract, recipient, amount, sender, options) {
11128
+ const nativeDenoms = options.nativeDenoms?.split(",").map((value) => value.trim()).filter(Boolean);
11129
+ const result = buildCw20TransferMsg({
11130
+ bech32Prefix,
11131
+ contract,
11132
+ recipient,
11133
+ amount,
11134
+ sender,
11135
+ nativeDenoms
11136
+ });
11137
+ emitPrepResult("cw20-transfer", result);
11138
+ }
11139
+
10839
11140
  // src/commands/execute.ts
10840
11141
  var import_qrcode_terminal = __toESM(require_main(), 1);
10841
11142
  import {
@@ -12293,7 +12594,7 @@ init_stringify();
12293
12594
  init_base();
12294
12595
  var InvalidDomainError = class extends BaseError2 {
12295
12596
  constructor({ domain }) {
12296
- super(`Invalid domain "${stringify(domain)}".`, {
12597
+ super(`Invalid domain "${stringify2(domain)}".`, {
12297
12598
  metaMessages: ["Must be a valid EIP-712 domain."]
12298
12599
  });
12299
12600
  }
@@ -19190,7 +19491,7 @@ var cachedVersion = null;
19190
19491
  function getVersion() {
19191
19492
  if (cachedVersion) return cachedVersion;
19192
19493
  if (true) {
19193
- cachedVersion = "5.1.0";
19494
+ cachedVersion = "5.2.0";
19194
19495
  return cachedVersion;
19195
19496
  }
19196
19497
  try {
@@ -19347,6 +19648,35 @@ var COMMAND_EXAMPLES = {
19347
19648
  execute: {
19348
19649
  examples: [`vultisig execute THORChain <contract> '{"swap":{}}'`]
19349
19650
  },
19651
+ "prep.contract-call": {
19652
+ examples: [
19653
+ `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"]'`
19654
+ ]
19655
+ },
19656
+ "prep.ibc-transfer": {
19657
+ examples: ["vultisig prep ibc-transfer Osmosis osmo1... cosmos1... uosmo 1000000 --to-chain Cosmos"]
19658
+ },
19659
+ "prep.spl-transfer": {
19660
+ examples: ["vultisig prep spl-transfer <mint> <from> <to> 1000000 6"]
19661
+ },
19662
+ "prep.trc20-transfer": {
19663
+ examples: ["vultisig prep trc20-transfer <contract> <from> <to> 1000000"]
19664
+ },
19665
+ "prep.jetton-transfer": {
19666
+ examples: ["vultisig prep jetton-transfer <recipient> <senderJettonWallet> 1000000 5"]
19667
+ },
19668
+ "prep.sui-token-transfer": {
19669
+ examples: ["vultisig prep sui-token-transfer <coinType> <from> <to> 1000000 --decimals 6"]
19670
+ },
19671
+ "prep.polkadot-asset-send": {
19672
+ examples: ["vultisig prep polkadot-asset-send 1984 <from> <to> 1000000"]
19673
+ },
19674
+ "prep.cosmos-staking": {
19675
+ examples: ["vultisig prep cosmos-staking delegate <delegator> <validator> 5000000 uosmo"]
19676
+ },
19677
+ "prep.cw20-transfer": {
19678
+ examples: ["vultisig prep cw20-transfer osmo <contract> <recipient> 1000000 <sender>"]
19679
+ },
19350
19680
  "swap-quote": {
19351
19681
  examples: ["vultisig swap-quote Ethereum Bitcoin 0.1 --output json"]
19352
19682
  },
@@ -21372,6 +21702,66 @@ See also: balance, tx-status`
21372
21702
  }
21373
21703
  )
21374
21704
  );
21705
+ var prepCmd = program2.command("prep").description("Build unsigned transaction payloads with SDK preparation helpers (never signs or broadcasts)");
21706
+ var loadPrepVault = async (identity) => {
21707
+ if (identity !== void 0) return void 0;
21708
+ const context = await init(program2.opts().vault);
21709
+ return context.ensureActiveVault();
21710
+ };
21711
+ 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(
21712
+ withExit(async (chain, contractAddress, functionName, options) => {
21713
+ const vault = await loadPrepVault(options.identity);
21714
+ await executePrepContractCall(vault, resolveChainOrThrow(chain), contractAddress, functionName, options);
21715
+ })
21716
+ );
21717
+ 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(
21718
+ withExit(
21719
+ async (fromChain, fromAddress, toAddress, denom, amount, options) => {
21720
+ executePrepIbcTransfer(fromChain, fromAddress, toAddress, denom, amount, options);
21721
+ }
21722
+ )
21723
+ );
21724
+ 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(
21725
+ withExit(async (mint, from, to, amount, decimals, options) => {
21726
+ executePrepSplTransfer(mint, from, to, amount, decimals, options);
21727
+ })
21728
+ );
21729
+ 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(
21730
+ withExit(async (contractAddress, from, to, amount, options) => {
21731
+ executePrepTrc20Transfer(contractAddress, from, to, amount, options);
21732
+ })
21733
+ );
21734
+ 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(
21735
+ withExit(async (receiver, jettonWalletAddress, amount, seqno, options) => {
21736
+ const vault = await loadPrepVault(options.identity);
21737
+ executePrepJettonTransfer(vault, receiver, jettonWalletAddress, amount, seqno, options);
21738
+ })
21739
+ );
21740
+ 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(
21741
+ withExit(async (coinType, from, to, amount, options) => {
21742
+ const vault = await loadPrepVault(options.identity);
21743
+ await executePrepSuiTokenTransfer(vault, coinType, from, to, amount, options);
21744
+ })
21745
+ );
21746
+ 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(
21747
+ withExit(async (assetId, from, to, amount, options) => {
21748
+ executePrepPolkadotAssetSend(assetId, from, to, amount, options);
21749
+ })
21750
+ );
21751
+ 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(
21752
+ withExit(
21753
+ async (action, delegatorAddress, validatorAddress, amount, denom, options) => {
21754
+ executePrepCosmosStaking(action, delegatorAddress, validatorAddress, amount, denom, options);
21755
+ }
21756
+ )
21757
+ );
21758
+ 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(
21759
+ withExit(
21760
+ async (bech32Prefix, contract, recipient, amount, sender, options) => {
21761
+ executePrepCw20Transfer(bech32Prefix, contract, recipient, amount, sender, options);
21762
+ }
21763
+ )
21764
+ );
21375
21765
  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
21766
  "after",
21377
21767
  `
@@ -21922,7 +22312,12 @@ authCmd.command("status").description("List configured vaults and their keyring
21922
22312
  const vaults = await executeAuthStatus();
21923
22313
  if (isJsonOutput()) {
21924
22314
  outputJson({
21925
- vaults: vaults.map((v) => ({ id: v.id, name: v.name, filePath: v.filePath, hasCredentials: v.hasCredentials }))
22315
+ vaults: vaults.map((v) => ({
22316
+ id: v.id,
22317
+ name: v.name,
22318
+ filePath: v.filePath,
22319
+ hasCredentials: v.hasCredentials
22320
+ }))
21926
22321
  });
21927
22322
  return;
21928
22323
  }
@@ -21941,7 +22336,11 @@ authCmd.command("logout").description("Clear keyring credentials for a vault").o
21941
22336
  withExit(async (options) => {
21942
22337
  await executeAuthLogout({ vaultId: options.vaultId, all: options.all });
21943
22338
  if (isJsonOutput()) {
21944
- outputJson({ cleared: true, vaultId: options.vaultId ?? null, all: !!options.all });
22339
+ outputJson({
22340
+ cleared: true,
22341
+ vaultId: options.vaultId ?? null,
22342
+ all: !!options.all
22343
+ });
21945
22344
  } else {
21946
22345
  printResult(chalk16.green("Credentials cleared."));
21947
22346
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "5.1.0",
3
+ "version": "5.2.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": {
@@ -75,9 +75,9 @@
75
75
  "@napi-rs/keyring": "^1.3.0",
76
76
  "@noble/hashes": "^2.2.0",
77
77
  "@vultisig/client-shared": "^0.3.4",
78
- "@vultisig/core-chain": "^2.39.0",
79
- "@vultisig/rujira": "^68.0.0",
80
- "@vultisig/sdk": "^5.1.0",
78
+ "@vultisig/core-chain": "^3.0.0",
79
+ "@vultisig/rujira": "^69.0.0",
80
+ "@vultisig/sdk": "^5.2.0",
81
81
  "chalk": "^5.6.2",
82
82
  "cli-table3": "^0.6.5",
83
83
  "commander": "^15.0.0",
@@ -95,7 +95,7 @@
95
95
  "@types/node": "^26.1.1",
96
96
  "@types/tabtab": "^3.0.4",
97
97
  "@types/ws": "^8.18.1",
98
- "@vultisig/core-mpc": "^1.20.3",
98
+ "@vultisig/core-mpc": "^1.20.5",
99
99
  "esbuild": "^0.28.1",
100
100
  "ethers": "^6.17.0",
101
101
  "node-pty": "^1.1.0",