@vultisig/cli 2.19.18 → 2.20.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/dist/index.js CHANGED
@@ -4872,7 +4872,7 @@ var init_secp256k1 = __esm({
4872
4872
  import "dotenv/config";
4873
4873
  import { promises as fs4 } from "node:fs";
4874
4874
  import { descriptions } from "@vultisig/client-shared";
4875
- import { parseKeygenQR, Vultisig as Vultisig6 } from "@vultisig/sdk";
4875
+ import { Chain as Chain14, parseKeygenQR, Vultisig as Vultisig6 } from "@vultisig/sdk";
4876
4876
  import chalk16 from "chalk";
4877
4877
  import { InvalidArgumentError, program } from "commander";
4878
4878
 
@@ -4966,7 +4966,8 @@ var EXIT_CODE_DESCRIPTIONS = {
4966
4966
  [9 /* DUPLICATE_BROADCAST */]: "Duplicate broadcast refused (nothing sent) \u2014 retry with --force to override",
4967
4967
  [10 /* AGENT_TURN_BLOCKED */]: "agent ask: a fund-safety guardrail blocked the requested action",
4968
4968
  [11 /* AGENT_TURN_REFUSAL */]: "agent ask: the model refused or asked a clarifying question (no action taken)",
4969
- [12 /* CONFIRMATION_REQUIRED */]: "Interactive confirmation/input required but the session is non-interactive \u2014 pass --yes/--confirm or the required flag"
4969
+ [12 /* CONFIRMATION_REQUIRED */]: "Interactive confirmation/input required but the session is non-interactive \u2014 pass --yes/--confirm or the required flag",
4970
+ [13 /* BROADCAST_COMMITTED */]: "agent ask: transaction broadcast but the overall request may be incomplete \u2014 inspect the hash, do NOT blindly retry"
4970
4971
  };
4971
4972
  var VsigError = class extends Error {
4972
4973
  hint;
@@ -5027,6 +5028,13 @@ var InvalidInputError = class extends VsigError {
5027
5028
  super(message, hint, suggestions, context);
5028
5029
  }
5029
5030
  };
5031
+ var InvalidTxHashError = class extends VsigError {
5032
+ exitCode = 4 /* INVALID_INPUT */;
5033
+ code = "INVALID_HASH";
5034
+ constructor(message, hint, suggestions, context) {
5035
+ super(message, hint, suggestions, context);
5036
+ }
5037
+ };
5030
5038
  var InsufficientBalanceError = class extends VsigError {
5031
5039
  exitCode = 4 /* INVALID_INPUT */;
5032
5040
  code = "INSUFFICIENT_BALANCE";
@@ -5055,6 +5063,13 @@ var TxNotFoundError = class extends VsigError {
5055
5063
  super(message, hint, suggestions, context);
5056
5064
  }
5057
5065
  };
5066
+ var VaultNotFoundError = class extends VsigError {
5067
+ exitCode = 5 /* RESOURCE_NOT_FOUND */;
5068
+ code = "VAULT_NOT_FOUND";
5069
+ constructor(message, hint, suggestions, context) {
5070
+ super(message, hint, suggestions, context);
5071
+ }
5072
+ };
5058
5073
  var TxStatusTimeoutError = class extends VsigError {
5059
5074
  exitCode = 3 /* NETWORK */;
5060
5075
  code = "TX_STATUS_TIMEOUT";
@@ -5103,53 +5118,78 @@ var DuplicateBroadcastRefusedError = class extends VsigError {
5103
5118
  ]);
5104
5119
  }
5105
5120
  };
5106
- function classifyError(err) {
5107
- if (err instanceof VsigError) return err;
5108
- if (err.code === "DUPLICATE_BROADCAST") {
5109
- return new DuplicateBroadcastRefusedError(err.message);
5121
+ function isPermanentBroadcastInputError(err) {
5122
+ const details = `${err.message}
5123
+ ${err.originalError?.message ?? ""}`;
5124
+ return /failed to decode signed transaction|could not decode (?:signed )?transaction|invalid raw transaction|invalid transaction encoding|invalid (?:transaction )?signature|invalid sender|invalid rlp|rlp:|unsupported transaction type/i.test(
5125
+ details
5126
+ );
5127
+ }
5128
+ var INVALID_ADDRESS_RE = /invalid (?:receiver |recipient |destination )?address|bad address|malformed address/i;
5129
+ function invalidAddressError(message) {
5130
+ const addrMatch = message.match(/(0x[a-fA-F0-9]+|bc1[a-z0-9]+|[13][a-km-zA-HJ-NP-Z1-9]+)/i);
5131
+ return new InvalidAddressError(message, void 0, void 0, addrMatch ? { address: addrMatch[1] } : void 0);
5132
+ }
5133
+ function classifyVaultError(err) {
5134
+ if (err.code === VaultErrorCode.BalanceFetchFailed && err.originalError) {
5135
+ const inner = classifyError(err.originalError);
5136
+ if (!(inner instanceof UnknownError)) return inner;
5110
5137
  }
5111
- if (err instanceof VaultError) {
5112
- if (err.code === VaultErrorCode.BalanceFetchFailed && err.originalError) {
5113
- const inner = classifyError(err.originalError);
5114
- if (!(inner instanceof UnknownError)) return inner;
5138
+ switch (err.code) {
5139
+ case VaultErrorCode.UnsupportedChain:
5140
+ case VaultErrorCode.ChainNotSupported:
5141
+ return new InvalidChainError(err.message);
5142
+ case VaultErrorCode.NetworkError:
5143
+ case VaultErrorCode.BalanceFetchFailed:
5144
+ case VaultErrorCode.Timeout:
5145
+ return new NetworkError(err.message);
5146
+ case VaultErrorCode.InvalidAmount:
5147
+ return new InvalidInputError(err.message);
5148
+ case VaultErrorCode.InvalidConfig: {
5149
+ const lowerMsg = err.message.toLowerCase();
5150
+ if (lowerMsg.includes("unknown chain") || lowerMsg.includes("unsupported chain") || lowerMsg.includes("chain not supported")) {
5151
+ const chainMatch = err.message.match(/chain[:\s]*"([^"]+)"/i);
5152
+ return new InvalidChainError(
5153
+ err.message,
5154
+ void 0,
5155
+ void 0,
5156
+ chainMatch ? { chain: chainMatch[1] } : void 0
5157
+ );
5158
+ }
5159
+ if (INVALID_ADDRESS_RE.test(lowerMsg)) return invalidAddressError(err.message);
5160
+ if (lowerMsg.includes("failed to unlock vault") || lowerMsg.includes("invalid password")) {
5161
+ return new AuthRequiredError(err.message);
5162
+ }
5163
+ return new UsageError(err.message);
5115
5164
  }
5116
- switch (err.code) {
5117
- case VaultErrorCode.UnsupportedChain:
5118
- case VaultErrorCode.ChainNotSupported:
5119
- return new InvalidChainError(err.message);
5120
- case VaultErrorCode.NetworkError:
5121
- case VaultErrorCode.BalanceFetchFailed:
5122
- case VaultErrorCode.Timeout:
5123
- return new NetworkError(err.message);
5124
- case VaultErrorCode.InvalidAmount:
5165
+ case VaultErrorCode.VaultNotFound:
5166
+ return new VaultNotFoundError(err.message);
5167
+ case VaultErrorCode.UnsupportedToken:
5168
+ return new TokenNotFoundError(err.message);
5169
+ case VaultErrorCode.BroadcastFailed:
5170
+ if (isPermanentBroadcastInputError(err)) {
5171
+ return new InvalidInputError(err.message, "Check the signed transaction encoding and signature");
5172
+ }
5173
+ return new ExternalServiceError(err.message, "Broadcast failed \u2014 the node may be temporarily unavailable", [
5174
+ "Retry the transaction"
5175
+ ]);
5176
+ case VaultErrorCode.GasEstimationFailed:
5177
+ return new InvalidInputError(err.message, "Gas estimation failed \u2014 check balance and transaction params");
5178
+ case VaultErrorCode.SigningFailed:
5179
+ if (/must be 32 bytes|expected 32 bytes|non-32-byte/i.test(err.message)) {
5125
5180
  return new InvalidInputError(err.message);
5126
- case VaultErrorCode.InvalidConfig: {
5127
- const lowerMsg = err.message.toLowerCase();
5128
- if (lowerMsg.includes("unknown chain") || lowerMsg.includes("unsupported chain") || lowerMsg.includes("chain not supported")) {
5129
- const chainMatch = err.message.match(/chain[:\s]*"([^"]+)"/i);
5130
- return new InvalidChainError(
5131
- err.message,
5132
- void 0,
5133
- void 0,
5134
- chainMatch ? { chain: chainMatch[1] } : void 0
5135
- );
5136
- }
5137
- return new UsageError(err.message);
5138
5181
  }
5139
- case VaultErrorCode.UnsupportedToken:
5140
- return new TokenNotFoundError(err.message);
5141
- case VaultErrorCode.BroadcastFailed:
5142
- return new ExternalServiceError(err.message, "Broadcast failed \u2014 the node may be temporarily unavailable", [
5143
- "Retry the transaction"
5144
- ]);
5145
- case VaultErrorCode.GasEstimationFailed:
5146
- return new InvalidInputError(err.message, "Gas estimation failed \u2014 check balance and transaction params");
5147
- case VaultErrorCode.SigningFailed:
5148
- return new UnknownError(err.message);
5149
- default:
5150
- return new UnknownError(err.message);
5151
- }
5182
+ return new UnknownError(err.message);
5183
+ default:
5184
+ return new UnknownError(err.message);
5185
+ }
5186
+ }
5187
+ function classifyError(err) {
5188
+ if (err instanceof VsigError) return err;
5189
+ if (err.code === "DUPLICATE_BROADCAST") {
5190
+ return new DuplicateBroadcastRefusedError(err.message);
5152
5191
  }
5192
+ if (err instanceof VaultError) return classifyVaultError(err);
5153
5193
  if (err instanceof VaultImportError) {
5154
5194
  switch (err.code) {
5155
5195
  case VaultImportErrorCode.PASSWORD_REQUIRED:
@@ -5159,18 +5199,24 @@ function classifyError(err) {
5159
5199
  return new UsageError(err.message);
5160
5200
  }
5161
5201
  }
5202
+ if (err.code === "ENOENT") {
5203
+ return new InvalidInputError(err.message, "Check that the file or directory exists");
5204
+ }
5162
5205
  const msg = err.message.toLowerCase();
5206
+ if (msg.includes("no vault found matching") || msg.includes("vault not found")) {
5207
+ return new VaultNotFoundError(err.message);
5208
+ }
5163
5209
  if (msg.includes("unsupported chain") || msg.includes("invalid chain") || msg.includes("unknown chain")) {
5164
5210
  const chainMatch = err.message.match(/chain[:\s]*"([^"]+)"/i) || err.message.match(/chain[:\s]+(\S+)/i);
5165
5211
  return new InvalidChainError(err.message, void 0, void 0, chainMatch ? { chain: chainMatch[1] } : void 0);
5166
5212
  }
5167
- if (msg.includes("invalid address") || msg.includes("bad address") || msg.includes("malformed address")) {
5168
- const addrMatch = err.message.match(/(0x[a-fA-F0-9]+|bc1[a-z0-9]+|[13][a-km-zA-HJ-NP-Z1-9]+)/i);
5169
- return new InvalidAddressError(err.message, void 0, void 0, addrMatch ? { address: addrMatch[1] } : void 0);
5170
- }
5213
+ if (INVALID_ADDRESS_RE.test(msg)) return invalidAddressError(err.message);
5171
5214
  if (msg.includes("insufficient") && msg.includes("balance")) {
5172
5215
  return new InsufficientBalanceError(err.message);
5173
5216
  }
5217
+ if (msg.includes("invalid currency") || msg.includes("invalid amount") || msg.includes("invalid mnemonic") || msg.includes("invalid seedphrase") || msg.includes("must be 32 bytes") || msg.includes("expected 32 bytes") || msg.includes("non-32-byte")) {
5218
+ return new InvalidInputError(err.message);
5219
+ }
5174
5220
  if (msg.includes("no route") || msg.includes("no swap") || msg.includes("no provider")) {
5175
5221
  return new NoRouteError(err.message);
5176
5222
  }
@@ -5482,16 +5528,30 @@ function clearCachedPassword(vaultIdOrName) {
5482
5528
  }
5483
5529
  function parseVaultPasswords() {
5484
5530
  const passwordMap = /* @__PURE__ */ new Map();
5485
- const passwordsEnv = process.env.VAULT_PASSWORDS;
5486
- if (passwordsEnv) {
5487
- const pairs = passwordsEnv.trim().split(/\s+/);
5488
- for (const pair of pairs) {
5489
- const colonIndex = pair.indexOf(":");
5490
- if (colonIndex > 0) {
5491
- const vaultKey = pair.substring(0, colonIndex);
5492
- const password = pair.substring(colonIndex + 1);
5493
- passwordMap.set(vaultKey, password);
5531
+ const passwordsEnv = process.env.VAULT_PASSWORDS?.trim();
5532
+ if (!passwordsEnv) return passwordMap;
5533
+ if (passwordsEnv.startsWith("{")) {
5534
+ try {
5535
+ const parsed = JSON.parse(passwordsEnv);
5536
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
5537
+ const entries = Object.entries(parsed);
5538
+ if (entries.every(([vaultKey, password]) => vaultKey.length > 0 && typeof password === "string")) {
5539
+ return new Map(entries);
5540
+ }
5494
5541
  }
5542
+ throw new Error("expected an object with string values");
5543
+ } catch {
5544
+ process.stderr.write(
5545
+ "Warning: VAULT_PASSWORDS is not a valid JSON object with string values; falling back to legacy key:password parsing.\n"
5546
+ );
5547
+ }
5548
+ }
5549
+ for (const pair of passwordsEnv.split(/\s+/)) {
5550
+ const colonIndex = pair.indexOf(":");
5551
+ if (colonIndex > 0) {
5552
+ const vaultKey = pair.substring(0, colonIndex);
5553
+ const password = pair.substring(colonIndex + 1);
5554
+ passwordMap.set(vaultKey, password);
5495
5555
  }
5496
5556
  }
5497
5557
  return passwordMap;
@@ -5511,7 +5571,7 @@ function getPasswordFromEnv(vaultId, vaultName) {
5511
5571
  }
5512
5572
  async function promptForPassword(vaultName, vaultId) {
5513
5573
  requireInteractive(
5514
- 'Use --password flag, VAULT_PASSWORD env var, or "vsig auth setup" to store credentials in keyring.'
5574
+ 'Use --password, a vault password environment variable, or "vsig auth setup" to store credentials.'
5515
5575
  );
5516
5576
  const displayName = vaultName || vaultId || "vault";
5517
5577
  const { password } = await prompt([
@@ -5530,11 +5590,11 @@ async function resolvePasswordNonInteractive(vaultId, vaultName) {
5530
5590
  return cachedPassword;
5531
5591
  }
5532
5592
  try {
5533
- const keyringPassword = await getServerPassword(vaultId);
5534
- if (keyringPassword) {
5535
- cachePassword(vaultId, keyringPassword);
5536
- if (vaultName) cachePassword(vaultName, keyringPassword);
5537
- return keyringPassword;
5593
+ const storedPassword = await getStoredServerPassword(vaultId);
5594
+ if (storedPassword) {
5595
+ cachePassword(vaultId, storedPassword);
5596
+ if (vaultName) cachePassword(vaultName, storedPassword);
5597
+ return storedPassword;
5538
5598
  }
5539
5599
  } catch {
5540
5600
  }
@@ -5703,7 +5763,7 @@ function displayVaultInfo(vault) {
5703
5763
  printResult(` Chain Code: ${vault.hexChainCode.substring(0, 20)}...
5704
5764
  `);
5705
5765
  }
5706
- function displayTransactionPreview(fromAddress, toAddress, amount, symbol, chain, memo, gas) {
5766
+ function displayTransactionPreview(fromAddress, toAddress, amount, symbol, chain, memo, destinationTag, gas) {
5707
5767
  if (gas) {
5708
5768
  const bigIntReplacer2 = (_k, v) => typeof v === "bigint" ? v.toString() : v;
5709
5769
  info(chalk2.blue(`
@@ -5717,6 +5777,9 @@ Estimated gas: ${JSON.stringify(gas, bigIntReplacer2, 2)}`));
5717
5777
  if (memo) {
5718
5778
  printResult(` Memo: ${memo}`);
5719
5779
  }
5780
+ if (destinationTag !== void 0) {
5781
+ printResult(` Destination tag: ${destinationTag}`);
5782
+ }
5720
5783
  }
5721
5784
  function displayTransactionResult(chain, txHash) {
5722
5785
  const explorerUrl = Vultisig.getTxExplorerUrl(chain, txHash);
@@ -5985,6 +6048,122 @@ function shouldAutoSelectActiveVault(hasActiveVault, corruptPointer, vaultCount)
5985
6048
  return !hasActiveVault && !corruptPointer && vaultCount > 0;
5986
6049
  }
5987
6050
 
6051
+ // ../../packages/core/chain/dist/Chain.js
6052
+ var EthereumL2Chain = {
6053
+ Arbitrum: "Arbitrum",
6054
+ Base: "Base",
6055
+ Blast: "Blast",
6056
+ Optimism: "Optimism",
6057
+ Zksync: "Zksync",
6058
+ Mantle: "Mantle"
6059
+ };
6060
+ var EvmChain = {
6061
+ ...EthereumL2Chain,
6062
+ Avalanche: "Avalanche",
6063
+ CronosChain: "CronosChain",
6064
+ BSC: "BSC",
6065
+ Ethereum: "Ethereum",
6066
+ Polygon: "Polygon",
6067
+ Hyperliquid: "Hyperliquid",
6068
+ Sei: "Sei"
6069
+ };
6070
+ var UtxoChain;
6071
+ (function(UtxoChain2) {
6072
+ UtxoChain2["Bitcoin"] = "Bitcoin";
6073
+ UtxoChain2["BitcoinCash"] = "Bitcoin-Cash";
6074
+ UtxoChain2["Litecoin"] = "Litecoin";
6075
+ UtxoChain2["Dogecoin"] = "Dogecoin";
6076
+ UtxoChain2["Dash"] = "Dash";
6077
+ UtxoChain2["Zcash"] = "Zcash";
6078
+ })(UtxoChain || (UtxoChain = {}));
6079
+ var cosmosChainsByKind = {
6080
+ ibcEnabled: {
6081
+ Cosmos: "Cosmos",
6082
+ Osmosis: "Osmosis",
6083
+ Dydx: "Dydx",
6084
+ Kujira: "Kujira",
6085
+ Terra: "Terra",
6086
+ TerraClassic: "TerraClassic",
6087
+ Noble: "Noble",
6088
+ Akash: "Akash"
6089
+ },
6090
+ vaultBased: {
6091
+ THORChain: "THORChain",
6092
+ MayaChain: "MayaChain"
6093
+ }
6094
+ };
6095
+ var IbcEnabledCosmosChain = cosmosChainsByKind.ibcEnabled;
6096
+ var VaultBasedCosmosChain = cosmosChainsByKind.vaultBased;
6097
+ var CosmosChain = {
6098
+ ...IbcEnabledCosmosChain,
6099
+ ...VaultBasedCosmosChain
6100
+ };
6101
+ var OtherChain;
6102
+ (function(OtherChain2) {
6103
+ OtherChain2["Sui"] = "Sui";
6104
+ OtherChain2["Solana"] = "Solana";
6105
+ OtherChain2["Polkadot"] = "Polkadot";
6106
+ OtherChain2["Bittensor"] = "Bittensor";
6107
+ OtherChain2["Ton"] = "Ton";
6108
+ OtherChain2["Ripple"] = "Ripple";
6109
+ OtherChain2["Tron"] = "Tron";
6110
+ OtherChain2["Cardano"] = "Cardano";
6111
+ OtherChain2["QBTC"] = "QBTC";
6112
+ })(OtherChain || (OtherChain = {}));
6113
+ var Chain = {
6114
+ ...EvmChain,
6115
+ ...UtxoChain,
6116
+ ...CosmosChain,
6117
+ ...OtherChain
6118
+ };
6119
+ var UtxoBasedChain = [...Object.values(UtxoChain), OtherChain.Cardano];
6120
+ var defaultChains = [Chain.Bitcoin, Chain.Ethereum, Chain.THORChain, Chain.Solana, Chain.BSC];
6121
+
6122
+ // ../../packages/core/chain/dist/ChainKind.js
6123
+ var chainKindRecord = {
6124
+ [EvmChain.Arbitrum]: "evm",
6125
+ [EvmChain.Avalanche]: "evm",
6126
+ [EvmChain.Base]: "evm",
6127
+ [EvmChain.CronosChain]: "evm",
6128
+ [EvmChain.BSC]: "evm",
6129
+ [EvmChain.Blast]: "evm",
6130
+ [EvmChain.Ethereum]: "evm",
6131
+ [EvmChain.Optimism]: "evm",
6132
+ [EvmChain.Polygon]: "evm",
6133
+ [EvmChain.Zksync]: "evm",
6134
+ [EvmChain.Mantle]: "evm",
6135
+ [EvmChain.Hyperliquid]: "evm",
6136
+ [EvmChain.Sei]: "evm",
6137
+ [UtxoChain.Bitcoin]: "utxo",
6138
+ [UtxoChain.BitcoinCash]: "utxo",
6139
+ [UtxoChain.Litecoin]: "utxo",
6140
+ [UtxoChain.Dogecoin]: "utxo",
6141
+ [UtxoChain.Dash]: "utxo",
6142
+ [UtxoChain.Zcash]: "utxo",
6143
+ [CosmosChain.THORChain]: "cosmos",
6144
+ [CosmosChain.Cosmos]: "cosmos",
6145
+ [CosmosChain.Osmosis]: "cosmos",
6146
+ [CosmosChain.MayaChain]: "cosmos",
6147
+ [CosmosChain.Dydx]: "cosmos",
6148
+ [CosmosChain.Kujira]: "cosmos",
6149
+ [CosmosChain.Terra]: "cosmos",
6150
+ [CosmosChain.TerraClassic]: "cosmos",
6151
+ [CosmosChain.Noble]: "cosmos",
6152
+ [CosmosChain.Akash]: "cosmos",
6153
+ [OtherChain.Sui]: "sui",
6154
+ [OtherChain.Solana]: "solana",
6155
+ [OtherChain.Polkadot]: "polkadot",
6156
+ [OtherChain.Bittensor]: "bittensor",
6157
+ [OtherChain.Ton]: "ton",
6158
+ [OtherChain.Ripple]: "ripple",
6159
+ [OtherChain.Tron]: "tron",
6160
+ [OtherChain.Cardano]: "cardano",
6161
+ [OtherChain.QBTC]: "qbtc"
6162
+ };
6163
+ function getChainKind(chain) {
6164
+ return chainKindRecord[chain];
6165
+ }
6166
+
5988
6167
  // src/agent/broadcastJournal.ts
5989
6168
  import { createHash } from "node:crypto";
5990
6169
  import {
@@ -6019,6 +6198,10 @@ var AgentErrorCode = /* @__PURE__ */ ((AgentErrorCode3) => {
6019
6198
  AgentErrorCode3["TRANSACTION_FAILED"] = "TRANSACTION_FAILED";
6020
6199
  AgentErrorCode3["SIGNING_FAILED"] = "SIGNING_FAILED";
6021
6200
  AgentErrorCode3["ACK_FAILED"] = "ACK_FAILED";
6201
+ AgentErrorCode3["BROADCAST_COMMITTED"] = "BROADCAST_COMMITTED";
6202
+ AgentErrorCode3["AGENT_TURN_BLOCKED"] = "AGENT_TURN_BLOCKED";
6203
+ AgentErrorCode3["AGENT_TURN_REFUSAL"] = "AGENT_TURN_REFUSAL";
6204
+ AgentErrorCode3["AGENT_TURN_ERROR"] = "AGENT_TURN_ERROR";
6022
6205
  AgentErrorCode3["DUPLICATE_BROADCAST"] = "DUPLICATE_BROADCAST";
6023
6206
  AgentErrorCode3["SESSION_NOT_INITIALIZED"] = "SESSION_NOT_INITIALIZED";
6024
6207
  AgentErrorCode3["LOOP_DEPTH_EXCEEDED"] = "LOOP_DEPTH_EXCEEDED";
@@ -6138,6 +6321,14 @@ function agentErrorCodeToExitCode(code) {
6138
6321
  switch (code) {
6139
6322
  case "ACK_FAILED" /* ACK_FAILED */:
6140
6323
  return 8 /* ACK_FAILED */;
6324
+ case "BROADCAST_COMMITTED" /* BROADCAST_COMMITTED */:
6325
+ return 13 /* BROADCAST_COMMITTED */;
6326
+ case "AGENT_TURN_BLOCKED" /* AGENT_TURN_BLOCKED */:
6327
+ return 10 /* AGENT_TURN_BLOCKED */;
6328
+ case "AGENT_TURN_REFUSAL" /* AGENT_TURN_REFUSAL */:
6329
+ return 11 /* AGENT_TURN_REFUSAL */;
6330
+ case "AGENT_TURN_ERROR" /* AGENT_TURN_ERROR */:
6331
+ return 1 /* USAGE */;
6141
6332
  case "AUTH_FAILED" /* AUTH_FAILED */:
6142
6333
  case "VAULT_LOCKED" /* VAULT_LOCKED */:
6143
6334
  case "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */:
@@ -6157,8 +6348,9 @@ function agentErrorCodeToExitCode(code) {
6157
6348
  case "ACTION_NOT_IMPLEMENTED" /* ACTION_NOT_IMPLEMENTED */:
6158
6349
  case "TOOL_UNSUPPORTED" /* TOOL_UNSUPPORTED */:
6159
6350
  case "SESSION_NOT_INITIALIZED" /* SESSION_NOT_INITIALIZED */:
6160
- case "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */:
6161
6351
  return 1 /* USAGE */;
6352
+ case "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */:
6353
+ return 12 /* CONFIRMATION_REQUIRED */;
6162
6354
  case "SIGNING_FAILED" /* SIGNING_FAILED */:
6163
6355
  case "LOOP_DEPTH_EXCEEDED" /* LOOP_DEPTH_EXCEEDED */:
6164
6356
  case "UNKNOWN_ERROR" /* UNKNOWN_ERROR */:
@@ -6214,8 +6406,9 @@ function journalPath() {
6214
6406
  const dir = process.env.VULTISIG_CONFIG_DIR && process.env.VULTISIG_CONFIG_DIR.trim() ? process.env.VULTISIG_CONFIG_DIR : join(homedir(), ".vultisig");
6215
6407
  return join(dir, "broadcasts.jsonl");
6216
6408
  }
6217
- function normalize(v) {
6218
- return (v ?? "").trim().toLowerCase();
6409
+ function normalize(v, canonicalizeEmptyCalldata = false) {
6410
+ const normalized = (v ?? "").trim().toLowerCase();
6411
+ return canonicalizeEmptyCalldata && normalized === "0x" ? "" : normalized;
6219
6412
  }
6220
6413
  function computeFingerprint(intent) {
6221
6414
  const canonical = [
@@ -6223,7 +6416,10 @@ function computeFingerprint(intent) {
6223
6416
  normalize(intent.chain),
6224
6417
  normalize(intent.to),
6225
6418
  normalize(intent.value),
6226
- normalize(intent.data),
6419
+ // Fold empty `"0x"` calldata to `""` for EVM only. For a memo (the default)
6420
+ // `"0x"` is a real, distinct value and must survive — collapsing it would
6421
+ // falsely dedupe two different memo-chain sends (PR #1259).
6422
+ normalize(intent.data, intent.dataIsEvmCalldata === true),
6227
6423
  normalize(intent.asset)
6228
6424
  ].join("|");
6229
6425
  return createHash("sha256").update(canonical).digest("hex").slice(0, 32);
@@ -6528,7 +6724,17 @@ function buildSendBroadcastIntent(vault, chain, keysignPayload, opts = {}) {
6528
6724
  chain: chain.toString(),
6529
6725
  to: keysignPayload.toAddress || void 0,
6530
6726
  value: opts.isMax ? MAX_AMOUNT_SENTINEL : keysignPayload.toAmount || void 0,
6727
+ // `data` is the user-supplied memo. On an EVM chain the signer encodes a
6728
+ // `0x`-prefixed memo AS calldata (memoToTxData), so a memo of `"0x"` is empty
6729
+ // calldata — functionally identical to a no-memo native transfer, and it must
6730
+ // fold to `""` to cross-path dedupe with the agent path (which fingerprints the
6731
+ // same send as empty `"0x"` calldata). On a memo-routed chain (THORChain,
6732
+ // Cosmos, UTXO) the memo is a real distinct value and must NOT fold (PR #1259).
6733
+ // So the fold is gated on chain kind — the single "is this data EVM calldata?"
6734
+ // authority — not hardcoded, which keeps a new chain family from silently
6735
+ // reintroducing the memo collision.
6531
6736
  data: keysignPayload.memo || void 0,
6737
+ dataIsEvmCalldata: getChainKind(chain) === "evm",
6532
6738
  asset: isNative ? void 0 : coin?.contractAddress || coin?.ticker || void 0
6533
6739
  };
6534
6740
  }
@@ -6794,11 +7000,37 @@ Use --add <contractAddress> to add or --remove <tokenId> to remove`));
6794
7000
  }
6795
7001
  }
6796
7002
 
7003
+ // ../../packages/core/chain/dist/chains/ripple/address.js
7004
+ import { classicAddressToXAddress, isValidXAddress, xAddressToClassicAddress } from "ripple-address-codec";
7005
+ var assertSupportedTag = (tag) => {
7006
+ if (tag === false)
7007
+ return void 0;
7008
+ return tag;
7009
+ };
7010
+ var decodeRippleXAddress = (address) => {
7011
+ const value = address.trim();
7012
+ if (!isValidXAddress(value))
7013
+ throw new Error("Invalid XRP X-address");
7014
+ const decoded = xAddressToClassicAddress(value);
7015
+ if (decoded.test)
7016
+ throw new Error("XRP testnet X-addresses are not supported");
7017
+ return {
7018
+ address: decoded.classicAddress,
7019
+ destinationTag: assertSupportedTag(decoded.tag)
7020
+ };
7021
+ };
7022
+ var normalizeRippleDestination = (address) => {
7023
+ const value = address.trim();
7024
+ if (value.startsWith("X") || value.startsWith("T"))
7025
+ return decodeRippleXAddress(value);
7026
+ return { address: value };
7027
+ };
7028
+
6797
7029
  // src/commands/transaction.ts
6798
- import { Chain, Vultisig as Vultisig2 } from "@vultisig/sdk";
7030
+ import { Chain as Chain2, Vultisig as Vultisig2 } from "@vultisig/sdk";
6799
7031
  async function executeSend(ctx2, params) {
6800
7032
  const vault = await ctx2.ensureActiveVault();
6801
- if (!Object.values(Chain).includes(params.chain)) {
7033
+ if (!Object.values(Chain2).includes(params.chain)) {
6802
7034
  throw new Error(`Invalid chain: ${params.chain}`);
6803
7035
  }
6804
7036
  const isMax = params.amount === "max";
@@ -6814,6 +7046,14 @@ async function sendTransaction(vault, params) {
6814
7046
  "Pass --yes to confirm, or --dry-run to preview without signing."
6815
7047
  );
6816
7048
  }
7049
+ const rippleDestination = params.chain === Chain2.Ripple ? normalizeRippleDestination(params.to) : { address: params.to };
7050
+ const to = rippleDestination.address;
7051
+ if (params.destinationTag !== void 0 && rippleDestination.destinationTag !== void 0 && params.destinationTag !== rippleDestination.destinationTag) {
7052
+ throw new Error(
7053
+ `Conflicting XRP destination tags: --destination-tag=${params.destinationTag} does not match the tag embedded in the X-address (${rippleDestination.destinationTag})`
7054
+ );
7055
+ }
7056
+ const destinationTag = params.destinationTag ?? rippleDestination.destinationTag;
6817
7057
  const prepareSpinner = createSpinner("Preparing transaction...");
6818
7058
  const dryResult = await vault.send({
6819
7059
  chain: params.chain,
@@ -6821,6 +7061,7 @@ async function sendTransaction(vault, params) {
6821
7061
  amount: params.amount,
6822
7062
  symbol: params.tokenId,
6823
7063
  memo: params.memo,
7064
+ destinationTag,
6824
7065
  dryRun: true
6825
7066
  });
6826
7067
  prepareSpinner.succeed("Transaction prepared");
@@ -6831,10 +7072,11 @@ async function sendTransaction(vault, params) {
6831
7072
  const result = {
6832
7073
  dryRun: true,
6833
7074
  chain: params.chain,
6834
- to: params.to,
7075
+ to,
6835
7076
  amount: params.amount,
6836
7077
  symbol: balance2.symbol,
6837
- balance: balance2.formattedAmount
7078
+ balance: balance2.formattedAmount,
7079
+ destinationTag
6838
7080
  };
6839
7081
  if (hasInsufficientBalance) {
6840
7082
  result.warning = `Insufficient balance: you have ${balance2.formattedAmount} ${balance2.symbol}`;
@@ -6847,6 +7089,7 @@ Dry-run preview:`);
6847
7089
  info(` Chain: ${result.chain}`);
6848
7090
  info(` To: ${result.to}`);
6849
7091
  info(` Amount: ${result.amount} ${result.symbol}`);
7092
+ if (result.destinationTag !== void 0) info(` Destination tag: ${result.destinationTag}`);
6850
7093
  info(` Fee: ${dryResult.fee} ${result.symbol}`);
6851
7094
  info(` Balance: ${result.balance} ${result.symbol}`);
6852
7095
  if (result.warning) warn(` Warning: ${result.warning}`);
@@ -6862,7 +7105,16 @@ Dry-run preview:`);
6862
7105
  const balance = await vault.balance(params.chain, params.tokenId);
6863
7106
  if (!isJsonOutput()) {
6864
7107
  const address = await vault.address(params.chain);
6865
- displayTransactionPreview(address, params.to, dryResult.total, balance.symbol, params.chain, params.memo, gas);
7108
+ displayTransactionPreview(
7109
+ address,
7110
+ to,
7111
+ dryResult.total,
7112
+ balance.symbol,
7113
+ params.chain,
7114
+ params.memo,
7115
+ destinationTag,
7116
+ gas
7117
+ );
6866
7118
  }
6867
7119
  if (!params.yes) {
6868
7120
  const confirmed = await confirmTransaction();
@@ -6889,7 +7141,8 @@ Dry-run preview:`);
6889
7141
  to: params.to,
6890
7142
  amount: params.amount,
6891
7143
  symbol: params.tokenId,
6892
- memo: params.memo
7144
+ memo: params.memo,
7145
+ destinationTag
6893
7146
  });
6894
7147
  if (result.dryRun) throw new Error("unreachable");
6895
7148
  return result;
@@ -6916,7 +7169,7 @@ Dry-run preview:`);
6916
7169
 
6917
7170
  // src/commands/execute.ts
6918
7171
  var import_qrcode_terminal = __toESM(require_main(), 1);
6919
- import { Vultisig as Vultisig3 } from "@vultisig/sdk";
7172
+ import { buildCosmosWasmExecuteMsg, Vultisig as Vultisig3 } from "@vultisig/sdk";
6920
7173
  var COSMOS_CHAIN_CONFIG = {
6921
7174
  THORChain: {
6922
7175
  chainId: "thorchain-1",
@@ -6948,7 +7201,9 @@ async function executeExecute(ctx2, params) {
6948
7201
  const chainConfig = COSMOS_CHAIN_CONFIG[params.chain];
6949
7202
  if (!chainConfig) {
6950
7203
  throw new Error(
6951
- `Chain ${params.chain} does not support CosmWasm execute. Supported chains: ${Object.keys(COSMOS_CHAIN_CONFIG).join(", ")}`
7204
+ `Chain ${params.chain} does not support CosmWasm execute. Supported chains: ${Object.keys(
7205
+ COSMOS_CHAIN_CONFIG
7206
+ ).join(", ")}`
6952
7207
  );
6953
7208
  }
6954
7209
  let msg;
@@ -7069,15 +7324,12 @@ Or use this URL: ${qrPayload}
7069
7324
  decimals: chainConfig.decimals,
7070
7325
  ticker: chainConfig.denom.toUpperCase()
7071
7326
  };
7072
- const executeContractMsg = {
7073
- type: "wasm/MsgExecuteContract",
7074
- value: JSON.stringify({
7075
- sender: address,
7076
- contract: params.contract,
7077
- msg,
7078
- funds: funds.map((f) => ({ denom: f.denom, amount: f.amount }))
7079
- })
7080
- };
7327
+ const executeContractMsg = buildCosmosWasmExecuteMsg({
7328
+ sender: address,
7329
+ contract: params.contract,
7330
+ msg,
7331
+ funds
7332
+ });
7081
7333
  const fee = {
7082
7334
  amount: [{ denom: chainConfig.denom, amount: "0" }],
7083
7335
  gas: chainConfig.gasLimit
@@ -7128,10 +7380,10 @@ Or use this URL: ${qrPayload}
7128
7380
 
7129
7381
  // src/commands/sign.ts
7130
7382
  var import_qrcode_terminal2 = __toESM(require_main(), 1);
7131
- import { Chain as Chain3 } from "@vultisig/sdk";
7383
+ import { Chain as Chain4 } from "@vultisig/sdk";
7132
7384
  async function executeSignBytes(ctx2, params) {
7133
7385
  const vault = await ctx2.ensureActiveVault();
7134
- if (!Object.values(Chain3).includes(params.chain)) {
7386
+ if (!Object.values(Chain4).includes(params.chain)) {
7135
7387
  throw new Error(`Invalid chain: ${params.chain}`);
7136
7388
  }
7137
7389
  return signBytes(vault, params);
@@ -7211,10 +7463,10 @@ Or use this URL: ${qrPayload}
7211
7463
  }
7212
7464
 
7213
7465
  // src/commands/broadcast.ts
7214
- import { Chain as Chain4, Vultisig as Vultisig4 } from "@vultisig/sdk";
7466
+ import { Chain as Chain5, Vultisig as Vultisig4 } from "@vultisig/sdk";
7215
7467
  async function executeBroadcast(ctx2, params) {
7216
7468
  const vault = await ctx2.ensureActiveVault();
7217
- if (!Object.values(Chain4).includes(params.chain)) {
7469
+ if (!Object.values(Chain5).includes(params.chain)) {
7218
7470
  throw new Error(`Invalid chain: ${params.chain}`);
7219
7471
  }
7220
7472
  const broadcastSpinner = createSpinner("Broadcasting transaction...");
@@ -7243,7 +7495,21 @@ async function executeBroadcast(ctx2, params) {
7243
7495
  }
7244
7496
 
7245
7497
  // src/commands/tx-status.ts
7246
- import { Chain as Chain5, isValidTxHash, Vultisig as Vultisig5 } from "@vultisig/sdk";
7498
+ import { Chain as Chain6, isValidTxHash, Vultisig as Vultisig5 } from "@vultisig/sdk";
7499
+ function resolveTxStatusParams(params) {
7500
+ if (!Object.values(Chain6).includes(params.chain)) {
7501
+ throw new InvalidInputError(`Invalid chain: ${params.chain}`);
7502
+ }
7503
+ if (!isValidTxHash(params.chain, params.txHash)) {
7504
+ throw new InvalidTxHashError(
7505
+ `Invalid transaction hash for ${params.chain}: "${params.txHash}"`,
7506
+ "Check the hash \u2014 it must match the expected format for the chain.",
7507
+ void 0,
7508
+ { chain: params.chain, txHash: params.txHash, status: "invalid_hash" }
7509
+ );
7510
+ }
7511
+ return params;
7512
+ }
7247
7513
  var POLL_INTERVAL_MS = 5e3;
7248
7514
  var DEFAULT_TIMEOUT_SEC = 120;
7249
7515
  var isTerminal = (status) => status === "success" || status === "error";
@@ -7251,21 +7517,12 @@ function resolveTimeoutMs(timeoutSec) {
7251
7517
  if (typeof timeoutSec !== "number" || !Number.isFinite(timeoutSec)) {
7252
7518
  return DEFAULT_TIMEOUT_SEC * 1e3;
7253
7519
  }
7254
- return Math.max(0, timeoutSec) * 1e3;
7520
+ const ms = Math.max(0, timeoutSec) * 1e3;
7521
+ return Number.isFinite(ms) ? ms : Number.MAX_SAFE_INTEGER;
7255
7522
  }
7256
7523
  async function executeTxStatus(ctx2, params, opts = {}) {
7524
+ resolveTxStatusParams(params);
7257
7525
  const vault = await ctx2.ensureActiveVault();
7258
- if (!Object.values(Chain5).includes(params.chain)) {
7259
- throw new InvalidInputError(`Invalid chain: ${params.chain}`);
7260
- }
7261
- if (!isValidTxHash(params.chain, params.txHash)) {
7262
- throw new InvalidInputError(
7263
- `Invalid transaction hash for ${params.chain}: "${params.txHash}"`,
7264
- "Check the hash \u2014 it must match the expected format for the chain.",
7265
- void 0,
7266
- { chain: params.chain, txHash: params.txHash }
7267
- );
7268
- }
7269
7526
  const pollIntervalMs = opts.pollIntervalMs ?? POLL_INTERVAL_MS;
7270
7527
  const spinner = createSpinner("Checking transaction status...");
7271
7528
  try {
@@ -7286,7 +7543,12 @@ async function executeTxStatus(ctx2, params, opts = {}) {
7286
7543
  result = await vault.getTxStatus({ chain: params.chain, txHash: params.txHash });
7287
7544
  }
7288
7545
  }
7289
- spinner.succeed(`Transaction status: ${result.status}`);
7546
+ if (result.status === "success") {
7547
+ recordResolution(params.txHash, "confirmed");
7548
+ } else if (result.status === "error") {
7549
+ recordResolution(params.txHash, "failed");
7550
+ }
7551
+ spinner.succeed(`Transaction status: ${toCliStatus(result.status)}`);
7290
7552
  displayResult(params.chain, params.txHash, result);
7291
7553
  return result;
7292
7554
  } catch (error2) {
@@ -7316,11 +7578,12 @@ function giveUpError(params, result, waitedMs) {
7316
7578
  );
7317
7579
  }
7318
7580
  function displayResult(chain, txHash, result) {
7581
+ const status = toCliStatus(result.status);
7319
7582
  if (isJsonOutput()) {
7320
7583
  outputJson({
7321
7584
  chain,
7322
7585
  txHash,
7323
- status: result.status,
7586
+ status,
7324
7587
  receipt: result.receipt ? {
7325
7588
  feeAmount: result.receipt.feeAmount.toString(),
7326
7589
  feeDecimals: result.receipt.feeDecimals,
@@ -7329,7 +7592,7 @@ function displayResult(chain, txHash, result) {
7329
7592
  explorerUrl: Vultisig5.getTxExplorerUrl(chain, txHash)
7330
7593
  });
7331
7594
  } else {
7332
- printResult(`Status: ${result.status}`);
7595
+ printResult(`Status: ${status}`);
7333
7596
  if (result.receipt) {
7334
7597
  const fee = formatFee(result.receipt.feeAmount, result.receipt.feeDecimals);
7335
7598
  printResult(`Fee: ${fee} ${result.receipt.feeTicker}`);
@@ -7337,6 +7600,11 @@ function displayResult(chain, txHash, result) {
7337
7600
  printResult(`Explorer: ${Vultisig5.getTxExplorerUrl(chain, txHash)}`);
7338
7601
  }
7339
7602
  }
7603
+ function toCliStatus(status) {
7604
+ if (status === "success") return "confirmed";
7605
+ if (status === "error") return "failed";
7606
+ return status;
7607
+ }
7340
7608
  function formatFee(amount, decimals) {
7341
7609
  const str2 = amount.toString().padStart(decimals + 1, "0");
7342
7610
  const whole = str2.slice(0, -decimals) || "0";
@@ -8394,7 +8662,7 @@ async function executeSwap(ctx2, options) {
8394
8662
  }
8395
8663
 
8396
8664
  // src/commands/settings.ts
8397
- import { Chain as Chain6, fiatCurrencies as fiatCurrencies2, fiatCurrencyNameRecord as fiatCurrencyNameRecord3 } from "@vultisig/sdk";
8665
+ import { Chain as Chain7, fiatCurrencies as fiatCurrencies2, fiatCurrencyNameRecord as fiatCurrencyNameRecord3 } from "@vultisig/sdk";
8398
8666
  import chalk6 from "chalk";
8399
8667
  async function executeCurrency(ctx2, newCurrency) {
8400
8668
  const vault = await ctx2.ensureActiveVault();
@@ -8461,7 +8729,7 @@ async function executeAddressBook(ctx2, options = {}) {
8461
8729
  type: "select",
8462
8730
  name: "chain",
8463
8731
  message: "Select chain:",
8464
- choices: Object.values(Chain6)
8732
+ choices: Object.values(Chain7)
8465
8733
  });
8466
8734
  }
8467
8735
  if (!address) {
@@ -9340,11 +9608,11 @@ var genKeccak = (suffix, blockLen, outputLen, info2 = {}) => createHasher(() =>
9340
9608
  var keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
9341
9609
 
9342
9610
  // src/agent/auth.ts
9343
- import { Chain as Chain7 } from "@vultisig/sdk";
9611
+ import { Chain as Chain8 } from "@vultisig/sdk";
9344
9612
  async function authenticateVault(client, vault, password, maxAttempts = 3) {
9345
9613
  const publicKey = vault.publicKeys.ecdsa;
9346
9614
  const chainCode = vault.hexChainCode;
9347
- const ethAddress = await vault.address(Chain7.Ethereum);
9615
+ const ethAddress = await vault.address(Chain8.Ethereum);
9348
9616
  const nonce = "0x" + randomBytes(16).toString("hex");
9349
9617
  const expiresAt = new Date(Date.now() + 15 * 60 * 1e3).toISOString();
9350
9618
  const authMessage = JSON.stringify({
@@ -9361,7 +9629,7 @@ async function authenticateVault(client, vault, password, maxAttempts = 3) {
9361
9629
  process.stderr.write(` Retry ${attempt}/${maxAttempts}...
9362
9630
  `);
9363
9631
  }
9364
- const signature = await vault.signBytes({ data: Buffer.from(messageHash), chain: Chain7.Ethereum }, {});
9632
+ const signature = await vault.signBytes({ data: Buffer.from(messageHash), chain: Chain8.Ethereum }, {});
9365
9633
  const sigHex = formatSignature65(signature.signature, signature.recovery ?? 0);
9366
9634
  const authResponse = await client.authenticate({
9367
9635
  public_key: publicKey,
@@ -9592,380 +9860,19 @@ function renderBalanceSummaryCard(card) {
9592
9860
  return lines.join("\n");
9593
9861
  }
9594
9862
 
9595
- // ../../packages/core/chain/dist/Chain.js
9596
- var EthereumL2Chain = {
9597
- Arbitrum: "Arbitrum",
9598
- Base: "Base",
9599
- Blast: "Blast",
9600
- Optimism: "Optimism",
9601
- Zksync: "Zksync",
9602
- Mantle: "Mantle"
9603
- };
9604
- var EvmChain = {
9605
- ...EthereumL2Chain,
9606
- Avalanche: "Avalanche",
9607
- CronosChain: "CronosChain",
9608
- BSC: "BSC",
9609
- Ethereum: "Ethereum",
9610
- Polygon: "Polygon",
9611
- Hyperliquid: "Hyperliquid",
9612
- Sei: "Sei"
9613
- };
9614
- var UtxoChain;
9615
- (function(UtxoChain2) {
9616
- UtxoChain2["Bitcoin"] = "Bitcoin";
9617
- UtxoChain2["BitcoinCash"] = "Bitcoin-Cash";
9618
- UtxoChain2["Litecoin"] = "Litecoin";
9619
- UtxoChain2["Dogecoin"] = "Dogecoin";
9620
- UtxoChain2["Dash"] = "Dash";
9621
- UtxoChain2["Zcash"] = "Zcash";
9622
- })(UtxoChain || (UtxoChain = {}));
9623
- var cosmosChainsByKind = {
9624
- ibcEnabled: {
9625
- Cosmos: "Cosmos",
9626
- Osmosis: "Osmosis",
9627
- Dydx: "Dydx",
9628
- Kujira: "Kujira",
9629
- Terra: "Terra",
9630
- TerraClassic: "TerraClassic",
9631
- Noble: "Noble",
9632
- Akash: "Akash"
9633
- },
9634
- vaultBased: {
9635
- THORChain: "THORChain",
9636
- MayaChain: "MayaChain"
9637
- }
9638
- };
9639
- var IbcEnabledCosmosChain = cosmosChainsByKind.ibcEnabled;
9640
- var VaultBasedCosmosChain = cosmosChainsByKind.vaultBased;
9641
- var CosmosChain = {
9642
- ...IbcEnabledCosmosChain,
9643
- ...VaultBasedCosmosChain
9644
- };
9645
- var OtherChain;
9646
- (function(OtherChain2) {
9647
- OtherChain2["Sui"] = "Sui";
9648
- OtherChain2["Solana"] = "Solana";
9649
- OtherChain2["Polkadot"] = "Polkadot";
9650
- OtherChain2["Bittensor"] = "Bittensor";
9651
- OtherChain2["Ton"] = "Ton";
9652
- OtherChain2["Ripple"] = "Ripple";
9653
- OtherChain2["Tron"] = "Tron";
9654
- OtherChain2["Cardano"] = "Cardano";
9655
- OtherChain2["QBTC"] = "QBTC";
9656
- })(OtherChain || (OtherChain = {}));
9657
- var Chain8 = {
9658
- ...EvmChain,
9659
- ...UtxoChain,
9660
- ...CosmosChain,
9661
- ...OtherChain
9662
- };
9663
- var UtxoBasedChain = [...Object.values(UtxoChain), OtherChain.Cardano];
9664
- var defaultChains = [Chain8.Bitcoin, Chain8.Ethereum, Chain8.THORChain, Chain8.Solana, Chain8.BSC];
9665
-
9666
- // ../../packages/core/chain/dist/ChainKind.js
9667
- var chainKindRecord = {
9668
- [EvmChain.Arbitrum]: "evm",
9669
- [EvmChain.Avalanche]: "evm",
9670
- [EvmChain.Base]: "evm",
9671
- [EvmChain.CronosChain]: "evm",
9672
- [EvmChain.BSC]: "evm",
9673
- [EvmChain.Blast]: "evm",
9674
- [EvmChain.Ethereum]: "evm",
9675
- [EvmChain.Optimism]: "evm",
9676
- [EvmChain.Polygon]: "evm",
9677
- [EvmChain.Zksync]: "evm",
9678
- [EvmChain.Mantle]: "evm",
9679
- [EvmChain.Hyperliquid]: "evm",
9680
- [EvmChain.Sei]: "evm",
9681
- [UtxoChain.Bitcoin]: "utxo",
9682
- [UtxoChain.BitcoinCash]: "utxo",
9683
- [UtxoChain.Litecoin]: "utxo",
9684
- [UtxoChain.Dogecoin]: "utxo",
9685
- [UtxoChain.Dash]: "utxo",
9686
- [UtxoChain.Zcash]: "utxo",
9687
- [CosmosChain.THORChain]: "cosmos",
9688
- [CosmosChain.Cosmos]: "cosmos",
9689
- [CosmosChain.Osmosis]: "cosmos",
9690
- [CosmosChain.MayaChain]: "cosmos",
9691
- [CosmosChain.Dydx]: "cosmos",
9692
- [CosmosChain.Kujira]: "cosmos",
9693
- [CosmosChain.Terra]: "cosmos",
9694
- [CosmosChain.TerraClassic]: "cosmos",
9695
- [CosmosChain.Noble]: "cosmos",
9696
- [CosmosChain.Akash]: "cosmos",
9697
- [OtherChain.Sui]: "sui",
9698
- [OtherChain.Solana]: "solana",
9699
- [OtherChain.Polkadot]: "polkadot",
9700
- [OtherChain.Bittensor]: "bittensor",
9701
- [OtherChain.Ton]: "ton",
9702
- [OtherChain.Ripple]: "ripple",
9703
- [OtherChain.Tron]: "tron",
9704
- [OtherChain.Cardano]: "cardano",
9705
- [OtherChain.QBTC]: "qbtc"
9706
- };
9707
- function getChainKind(chain) {
9708
- return chainKindRecord[chain];
9709
- }
9710
-
9711
- // ../../packages/lib/utils/dist/record/recordMap.js
9712
- function recordMap(record, fn) {
9713
- return Object.fromEntries(Object.entries(record).map(([key, value]) => [key, fn(value, key)]));
9714
- }
9715
-
9716
- // ../../packages/lib/utils/dist/record/makeRecord/index.js
9717
- var makeRecord = (keys, getValue) => {
9718
- const record = {};
9719
- keys.forEach((key, index) => {
9720
- record[key] = getValue(key, index);
9721
- });
9722
- return record;
9723
- };
9724
-
9725
- // ../../packages/core/chain/dist/chains/cosmos/thor/kujira-merge/index.js
9726
- var kujiraCoinsMigratedToThorChain = ["kuji", "rkuji", "fuzn", "nstk", "wink", "lvn"];
9727
- var kujiraCoinsMigratedToThorChainMetadata = {
9728
- kuji: {
9729
- ticker: "KUJI",
9730
- logo: "kuji",
9731
- priceProviderId: "kujira"
9732
- },
9733
- rkuji: {
9734
- ticker: "rKUJI",
9735
- logo: "rkuji.png",
9736
- priceProviderId: "kujira"
9737
- },
9738
- fuzn: {
9739
- ticker: "FUZN",
9740
- logo: "fuzn.png",
9741
- priceProviderId: "fuzion"
9742
- },
9743
- lvn: {
9744
- ticker: "LVN",
9745
- logo: "levana",
9746
- priceProviderId: "levana-protocol"
9747
- },
9748
- nstk: {
9749
- ticker: "NSTK",
9750
- logo: "nstk.png",
9751
- priceProviderId: "unstake-fi"
9752
- },
9753
- wink: {
9754
- ticker: "WINK",
9755
- logo: "wink.png",
9756
- priceProviderId: "winkhub"
9757
- }
9758
- };
9759
- var kujiraCoinMigratedToThorChainDestinationId = makeRecord(kujiraCoinsMigratedToThorChain, (id) => `thor.${id}`);
9760
-
9761
- // ../../packages/core/chain/dist/coin/chainFeeCoin.js
9762
- var ether = {
9763
- ticker: "ETH",
9764
- logo: "eth",
9765
- decimals: 18,
9766
- priceProviderId: "ethereum"
9767
- };
9768
- var leanChainFeeCoin = {
9769
- [Chain8.Bitcoin]: {
9770
- ticker: "BTC",
9771
- logo: "btc",
9772
- decimals: 8,
9773
- priceProviderId: "bitcoin"
9774
- },
9775
- [Chain8.BitcoinCash]: {
9776
- ticker: "BCH",
9777
- logo: "bch",
9778
- decimals: 8,
9779
- priceProviderId: "bitcoin-cash"
9780
- },
9781
- [Chain8.Litecoin]: {
9782
- ticker: "LTC",
9783
- logo: "ltc",
9784
- decimals: 8,
9785
- priceProviderId: "litecoin"
9786
- },
9787
- [Chain8.Dogecoin]: {
9788
- ticker: "DOGE",
9789
- logo: "doge",
9790
- decimals: 8,
9791
- priceProviderId: "dogecoin"
9792
- },
9793
- [Chain8.Dash]: {
9794
- ticker: "DASH",
9795
- logo: "dash",
9796
- decimals: 8,
9797
- priceProviderId: "dash"
9798
- },
9799
- [Chain8.Ripple]: {
9800
- ticker: "XRP",
9801
- logo: "xrp",
9802
- decimals: 6,
9803
- priceProviderId: "ripple"
9804
- },
9805
- [Chain8.THORChain]: {
9806
- ticker: "RUNE",
9807
- logo: "rune",
9808
- decimals: 8,
9809
- priceProviderId: "thorchain"
9810
- },
9811
- [Chain8.MayaChain]: {
9812
- ticker: "CACAO",
9813
- logo: "cacao",
9814
- decimals: 10,
9815
- priceProviderId: "cacao"
9816
- },
9817
- [Chain8.Solana]: {
9818
- ticker: "SOL",
9819
- logo: "solana",
9820
- decimals: 9,
9821
- priceProviderId: "solana"
9822
- },
9823
- [Chain8.Ton]: {
9824
- ticker: "GRAM",
9825
- logo: "gram",
9826
- decimals: 9,
9827
- priceProviderId: "the-open-network"
9828
- },
9829
- [Chain8.Ethereum]: ether,
9830
- [Chain8.Avalanche]: {
9831
- ticker: "AVAX",
9832
- logo: "avax",
9833
- decimals: 18,
9834
- priceProviderId: "avalanche-2"
9835
- },
9836
- [Chain8.BSC]: {
9837
- ticker: "BNB",
9838
- logo: "bsc",
9839
- decimals: 18,
9840
- priceProviderId: "binancecoin"
9841
- },
9842
- [Chain8.Polygon]: {
9843
- ticker: "POL",
9844
- logo: "polygon",
9845
- decimals: 18,
9846
- priceProviderId: "polygon-ecosystem-token"
9847
- },
9848
- [Chain8.CronosChain]: {
9849
- ticker: "CRO",
9850
- logo: "cro",
9851
- decimals: 18,
9852
- priceProviderId: "crypto-com-chain"
9853
- },
9854
- [Chain8.Dydx]: {
9855
- ticker: "DYDX",
9856
- logo: "dydx",
9857
- decimals: 18,
9858
- priceProviderId: "dydx-chain"
9859
- },
9860
- [Chain8.Kujira]: {
9861
- ...kujiraCoinsMigratedToThorChainMetadata.kuji,
9862
- decimals: 6
9863
- },
9864
- [Chain8.Terra]: {
9865
- ticker: "LUNA",
9866
- logo: "luna",
9867
- decimals: 6,
9868
- priceProviderId: "terra-luna-2"
9869
- },
9870
- [Chain8.TerraClassic]: {
9871
- ticker: "LUNC",
9872
- logo: "lunc",
9873
- decimals: 6,
9874
- priceProviderId: "terra-luna"
9875
- },
9876
- [Chain8.Sui]: {
9877
- ticker: "SUI",
9878
- logo: "sui",
9879
- decimals: 9,
9880
- priceProviderId: "sui"
9881
- },
9882
- [Chain8.Polkadot]: {
9883
- ticker: "DOT",
9884
- logo: "dot",
9885
- decimals: 10,
9886
- priceProviderId: "polkadot"
9887
- },
9888
- [Chain8.Bittensor]: {
9889
- ticker: "TAO",
9890
- logo: "bittensor",
9891
- decimals: 9,
9892
- priceProviderId: "bittensor"
9893
- },
9894
- [Chain8.Noble]: {
9895
- ticker: "USDC",
9896
- logo: "noble",
9897
- decimals: 6,
9898
- priceProviderId: "usd-coin"
9899
- },
9900
- [Chain8.Akash]: {
9901
- ticker: "AKT",
9902
- logo: "akash",
9903
- decimals: 6,
9904
- priceProviderId: "akash-network"
9905
- },
9906
- [Chain8.Cosmos]: {
9907
- ticker: "ATOM",
9908
- logo: "atom",
9909
- decimals: 6,
9910
- priceProviderId: "cosmos"
9911
- },
9912
- [Chain8.Osmosis]: {
9913
- ticker: "OSMO",
9914
- logo: "osmo",
9915
- decimals: 6,
9916
- priceProviderId: "osmosis"
9917
- },
9918
- [Chain8.Tron]: {
9919
- ticker: "TRX",
9920
- logo: "tron",
9921
- decimals: 6,
9922
- priceProviderId: "tron"
9923
- },
9924
- ...recordMap(EthereumL2Chain, () => ether),
9925
- [Chain8.Zcash]: {
9926
- ticker: "ZEC",
9927
- logo: "zec",
9928
- decimals: 8,
9929
- priceProviderId: "zcash"
9930
- },
9931
- [Chain8.Cardano]: {
9932
- ticker: "ADA",
9933
- logo: "ada",
9934
- decimals: 6,
9935
- priceProviderId: "cardano"
9936
- },
9937
- [Chain8.Mantle]: {
9938
- ticker: "MNT",
9939
- logo: "mantle",
9940
- decimals: 18,
9941
- priceProviderId: "mantle"
9942
- },
9943
- [Chain8.Hyperliquid]: {
9944
- ticker: "HYPE",
9945
- logo: "hyperliquid",
9946
- decimals: 18,
9947
- priceProviderId: "hyperliquid"
9948
- },
9949
- [Chain8.Sei]: {
9950
- ticker: "SEI",
9951
- logo: "sei",
9952
- decimals: 18,
9953
- priceProviderId: "sei-network"
9954
- },
9955
- [Chain8.QBTC]: {
9956
- ticker: "QBTC",
9957
- logo: "qbtc",
9958
- decimals: 8,
9959
- priceProviderId: "qbtc-testnet"
9960
- }
9961
- };
9962
- var chainFeeCoin = recordMap(leanChainFeeCoin, (coin, chain) => ({
9963
- ...coin,
9964
- chain
9965
- }));
9863
+ // src/agent/toolOutputSigning.ts
9864
+ import { getChainKind as getChainKind3 } from "@vultisig/sdk";
9966
9865
 
9967
9866
  // src/agent/executor.ts
9968
- import { Chain as Chain9, VaultError as VaultError3, VaultErrorCode as VaultErrorCode3, Vultisig as VultisigSdk } from "@vultisig/sdk";
9867
+ import {
9868
+ Chain as Chain9,
9869
+ chainFeeCoin,
9870
+ getChainKind as getChainKind2,
9871
+ resolveChainReference,
9872
+ VaultError as VaultError3,
9873
+ VaultErrorCode as VaultErrorCode3,
9874
+ Vultisig as VultisigSdk
9875
+ } from "@vultisig/sdk";
9969
9876
 
9970
9877
  // ../../node_modules/viem/_esm/accounts/utils/publicKeyToAddress.js
9971
9878
  init_getAddress();
@@ -10518,6 +10425,7 @@ var AgentExecutor = class {
10518
10425
  */
10519
10426
  buildBroadcastIntent(payload, chain, overrideTx) {
10520
10427
  const source = overrideTx ?? payload;
10428
+ const dataIsEvmCalldata = getChainKind2(chain) === "evm";
10521
10429
  const nested = extractNestedTx(source);
10522
10430
  if (nested && (nested.to || nested.value || nested.data)) {
10523
10431
  return {
@@ -10525,7 +10433,8 @@ var AgentExecutor = class {
10525
10433
  chain: chain.toString(),
10526
10434
  to: nested.to != null ? String(nested.to) : void 0,
10527
10435
  value: nested.value != null ? String(nested.value) : void 0,
10528
- data: nested.data != null ? String(nested.data) : void 0
10436
+ data: nested.data != null ? String(nested.data) : void 0,
10437
+ dataIsEvmCalldata
10529
10438
  };
10530
10439
  }
10531
10440
  const txArgs = source?.txArgs ?? source;
@@ -10536,6 +10445,7 @@ var AgentExecutor = class {
10536
10445
  to: txArgs?.to != null ? String(txArgs.to) : void 0,
10537
10446
  value: txArgs?.amount != null ? String(txArgs.amount) : void 0,
10538
10447
  data: txArgs?.memo != null ? String(txArgs.memo) : void 0,
10448
+ dataIsEvmCalldata,
10539
10449
  asset: asset != null ? String(asset) : void 0
10540
10450
  };
10541
10451
  }
@@ -10621,7 +10531,7 @@ var AgentExecutor = class {
10621
10531
  const txArgs = txReadyData.txArgs;
10622
10532
  if (txArgs && typeof txArgs === "object" && typeof txArgs.to === "string" && typeof txArgs.amount === "string") {
10623
10533
  const chain2 = resolveChainFromTxReady(txReadyData) || Chain9.Ethereum;
10624
- if (getChainKind(chain2) !== "evm") {
10534
+ if (getChainKind2(chain2) !== "evm") {
10625
10535
  this.pendingPayloads.clear();
10626
10536
  this.pendingLegs = [];
10627
10537
  this.pendingPayloads.set("latest", {
@@ -10632,7 +10542,7 @@ var AgentExecutor = class {
10632
10542
  });
10633
10543
  if (this.verbose)
10634
10544
  process.stderr.write(
10635
- `[executor] Stored non-EVM server tx for chain ${chain2} (kind=${getChainKind(chain2)})
10545
+ `[executor] Stored non-EVM server tx for chain ${chain2} (kind=${getChainKind2(chain2)})
10636
10546
  `
10637
10547
  );
10638
10548
  return true;
@@ -10981,7 +10891,7 @@ var AgentExecutor = class {
10981
10891
  */
10982
10892
  async signServerTx(serverTxData, defaultChain, params) {
10983
10893
  const chain = resolveChainFromTxReady(serverTxData) || defaultChain;
10984
- const chainKind = getChainKind(chain);
10894
+ const chainKind = getChainKind2(chain);
10985
10895
  if (chainKind === "evm") {
10986
10896
  return this.signEvmServerTx(serverTxData, defaultChain, params);
10987
10897
  }
@@ -11824,41 +11734,7 @@ var AgentExecutor = class {
11824
11734
  }
11825
11735
  };
11826
11736
  function resolveChain(name) {
11827
- if (!name) return null;
11828
- if (Object.values(Chain9).includes(name)) {
11829
- return name;
11830
- }
11831
- const lower = name.toLowerCase();
11832
- for (const [, value] of Object.entries(Chain9)) {
11833
- if (typeof value === "string" && value.toLowerCase() === lower) {
11834
- return value;
11835
- }
11836
- }
11837
- const aliases = {
11838
- eth: "Ethereum",
11839
- btc: "Bitcoin",
11840
- sol: "Solana",
11841
- bnb: "BSC",
11842
- avax: "Avalanche",
11843
- matic: "Polygon",
11844
- arb: "Arbitrum",
11845
- op: "Optimism",
11846
- ltc: "Litecoin",
11847
- doge: "Dogecoin",
11848
- dot: "Polkadot",
11849
- atom: "Cosmos",
11850
- rune: "THORChain",
11851
- thor: "THORChain",
11852
- sui: "Sui",
11853
- ton: "Ton",
11854
- trx: "Tron",
11855
- xrp: "Ripple"
11856
- };
11857
- const aliased = aliases[lower];
11858
- if (aliased && Object.values(Chain9).includes(aliased)) {
11859
- return aliased;
11860
- }
11861
- return null;
11737
+ return resolveChainReference(name) ?? null;
11862
11738
  }
11863
11739
  function resolveChainFromTxReady(txReadyData) {
11864
11740
  if (txReadyData.chain) {
@@ -11961,21 +11837,7 @@ function parseThorSwapMemo(memo) {
11961
11837
  return { destChainCode, destAsset, destAddress };
11962
11838
  }
11963
11839
  function resolveChainId(chainId) {
11964
- const id = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
11965
- if (isNaN(id)) return null;
11966
- const chainIdMap = {
11967
- 1: Chain9.Ethereum,
11968
- 56: Chain9.BSC,
11969
- 137: Chain9.Polygon,
11970
- 43114: Chain9.Avalanche,
11971
- 42161: Chain9.Arbitrum,
11972
- 10: Chain9.Optimism,
11973
- 8453: Chain9.Base,
11974
- 81457: Chain9.Blast,
11975
- 324: Chain9.Zksync,
11976
- 25: Chain9.CronosChain
11977
- };
11978
- return chainIdMap[id] || null;
11840
+ return resolveChainReference(chainId) ?? null;
11979
11841
  }
11980
11842
  function computeEIP712Hash(domain, types, primaryType, message) {
11981
11843
  const messageTypes = { ...types };
@@ -12107,7 +11969,7 @@ function resolveStrictEvmChain(chain, chainId) {
12107
11969
  const byName = resolveChain(chain);
12108
11970
  const byId = resolveChainId(chainId);
12109
11971
  if (!byName || !byId || byName !== byId) return null;
12110
- if (getChainKind(byName) !== "evm") return null;
11972
+ if (getChainKind3(byName) !== "evm") return null;
12111
11973
  return byName;
12112
11974
  }
12113
11975
  function asChainString(value) {
@@ -12760,7 +12622,7 @@ var AgentClient = class {
12760
12622
  };
12761
12623
 
12762
12624
  // src/agent/context.ts
12763
- import { Chain as Chain10 } from "@vultisig/sdk";
12625
+ import { Chain as Chain11 } from "@vultisig/sdk";
12764
12626
  function applyChainPublicKeys(vault, context) {
12765
12627
  const raw = vault.data.chainPublicKeys;
12766
12628
  if (!raw) return;
@@ -12873,57 +12735,57 @@ async function buildMinimalContext(vault) {
12873
12735
  }
12874
12736
  function getNativeTokenTicker(chain) {
12875
12737
  const tickers = {
12876
- [Chain10.Ethereum]: "ETH",
12877
- [Chain10.Bitcoin]: "BTC",
12878
- [Chain10.Solana]: "SOL",
12879
- [Chain10.THORChain]: "RUNE",
12880
- [Chain10.Cosmos]: "ATOM",
12881
- [Chain10.Avalanche]: "AVAX",
12882
- [Chain10.BSC]: "BNB",
12883
- [Chain10.Polygon]: "MATIC",
12884
- [Chain10.Arbitrum]: "ETH",
12885
- [Chain10.Optimism]: "ETH",
12886
- [Chain10.Base]: "ETH",
12887
- [Chain10.Blast]: "ETH",
12888
- [Chain10.Litecoin]: "LTC",
12889
- [Chain10.Dogecoin]: "DOGE",
12890
- [Chain10.Dash]: "DASH",
12891
- [Chain10.MayaChain]: "CACAO",
12892
- [Chain10.Polkadot]: "DOT",
12893
- [Chain10.Sui]: "SUI",
12894
- [Chain10.Ton]: "TON",
12895
- [Chain10.Tron]: "TRX",
12896
- [Chain10.Ripple]: "XRP",
12897
- [Chain10.Dydx]: "DYDX",
12898
- [Chain10.Osmosis]: "OSMO",
12899
- [Chain10.Terra]: "LUNA",
12900
- [Chain10.Noble]: "USDC",
12901
- [Chain10.Kujira]: "KUJI",
12902
- [Chain10.Zksync]: "ETH",
12903
- [Chain10.CronosChain]: "CRO"
12738
+ [Chain11.Ethereum]: "ETH",
12739
+ [Chain11.Bitcoin]: "BTC",
12740
+ [Chain11.Solana]: "SOL",
12741
+ [Chain11.THORChain]: "RUNE",
12742
+ [Chain11.Cosmos]: "ATOM",
12743
+ [Chain11.Avalanche]: "AVAX",
12744
+ [Chain11.BSC]: "BNB",
12745
+ [Chain11.Polygon]: "MATIC",
12746
+ [Chain11.Arbitrum]: "ETH",
12747
+ [Chain11.Optimism]: "ETH",
12748
+ [Chain11.Base]: "ETH",
12749
+ [Chain11.Blast]: "ETH",
12750
+ [Chain11.Litecoin]: "LTC",
12751
+ [Chain11.Dogecoin]: "DOGE",
12752
+ [Chain11.Dash]: "DASH",
12753
+ [Chain11.MayaChain]: "CACAO",
12754
+ [Chain11.Polkadot]: "DOT",
12755
+ [Chain11.Sui]: "SUI",
12756
+ [Chain11.Ton]: "TON",
12757
+ [Chain11.Tron]: "TRX",
12758
+ [Chain11.Ripple]: "XRP",
12759
+ [Chain11.Dydx]: "DYDX",
12760
+ [Chain11.Osmosis]: "OSMO",
12761
+ [Chain11.Terra]: "LUNA",
12762
+ [Chain11.Noble]: "USDC",
12763
+ [Chain11.Kujira]: "KUJI",
12764
+ [Chain11.Zksync]: "ETH",
12765
+ [Chain11.CronosChain]: "CRO"
12904
12766
  };
12905
12767
  return tickers[chain] || chain.toString();
12906
12768
  }
12907
12769
  function getNativeTokenDecimals(chain) {
12908
12770
  const decimals = {
12909
- [Chain10.Bitcoin]: 8,
12910
- [Chain10.Litecoin]: 8,
12911
- [Chain10.Dogecoin]: 8,
12912
- [Chain10.Dash]: 8,
12913
- [Chain10.Solana]: 9,
12914
- [Chain10.Sui]: 9,
12915
- [Chain10.Ton]: 9,
12916
- [Chain10.Polkadot]: 10,
12917
- [Chain10.Cosmos]: 6,
12918
- [Chain10.THORChain]: 8,
12919
- [Chain10.MayaChain]: 10,
12920
- [Chain10.Osmosis]: 6,
12921
- [Chain10.Dydx]: 18,
12922
- [Chain10.Tron]: 6,
12923
- [Chain10.Ripple]: 6,
12924
- [Chain10.Noble]: 6,
12925
- [Chain10.Kujira]: 6,
12926
- [Chain10.Terra]: 6
12771
+ [Chain11.Bitcoin]: 8,
12772
+ [Chain11.Litecoin]: 8,
12773
+ [Chain11.Dogecoin]: 8,
12774
+ [Chain11.Dash]: 8,
12775
+ [Chain11.Solana]: 9,
12776
+ [Chain11.Sui]: 9,
12777
+ [Chain11.Ton]: 9,
12778
+ [Chain11.Polkadot]: 10,
12779
+ [Chain11.Cosmos]: 6,
12780
+ [Chain11.THORChain]: 8,
12781
+ [Chain11.MayaChain]: 10,
12782
+ [Chain11.Osmosis]: 6,
12783
+ [Chain11.Dydx]: 18,
12784
+ [Chain11.Tron]: 6,
12785
+ [Chain11.Ripple]: 6,
12786
+ [Chain11.Noble]: 6,
12787
+ [Chain11.Kujira]: 6,
12788
+ [Chain11.Terra]: 6
12927
12789
  };
12928
12790
  return decimals[chain] || 18;
12929
12791
  }
@@ -13298,6 +13160,16 @@ var AgentSession = class {
13298
13160
  const conv = await this.withAuthRetry(() => this.client.getConversation(this.conversationId, this.publicKey));
13299
13161
  this.historyMessages = conv.messages || [];
13300
13162
  } catch (err) {
13163
+ if (this.config.askMode) {
13164
+ this.conversationId = null;
13165
+ this.historyMessages = [];
13166
+ throw Object.assign(
13167
+ new Error(
13168
+ `Session ${this.config.sessionId} could not be resumed (${err?.message ?? "unknown error"}); refusing to execute the request without its conversation context`
13169
+ ),
13170
+ { code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
13171
+ );
13172
+ }
13301
13173
  this.conversationId = null;
13302
13174
  this.historyMessages = [];
13303
13175
  const conv = await this.withAuthRetry(() => this.client.createConversation(this.publicKey));
@@ -14454,10 +14326,79 @@ function outputAskError(wantsJson, message, code, conversationId, result) {
14454
14326
  ...Object.keys(data).length > 0 ? { data } : {}
14455
14327
  });
14456
14328
  } else {
14329
+ if (result) {
14330
+ process.stderr.write(`session:${result.sessionId}
14331
+ `);
14332
+ if (result.outcome) {
14333
+ const { kind, code: outcomeCode } = result.outcome;
14334
+ process.stderr.write(`outcome:${kind}${outcomeCode ? `:${outcomeCode}` : ""}
14335
+ `);
14336
+ }
14337
+ if (result.response) process.stderr.write(`${result.response}
14338
+ `);
14339
+ }
14457
14340
  process.stderr.write(`Error: ${message} [${code}]
14458
14341
  `);
14459
14342
  }
14460
14343
  }
14344
+ var BROADCAST_COMMITTED_MESSAGE = "A transaction was broadcast, but the overall agent request may be incomplete. Inspect the transaction status before continuing.";
14345
+ var ACK_FAILED_MESSAGE = "A transaction was broadcast, but its post-broadcast report failed. Inspect the transaction status before continuing.";
14346
+ function hasCommittedBroadcast(result) {
14347
+ return !!result?.transactions.some((tx) => tx.hash.trim().length > 0 && tx.status !== "failed");
14348
+ }
14349
+ var SIGNING_TOOLS = /* @__PURE__ */ new Set(["sign_tx", "sign_typed_data"]);
14350
+ function failedSigningError(result) {
14351
+ const failed = [...result.toolCalls].reverse().find((call) => SIGNING_TOOLS.has(call.action));
14352
+ if (!failed || failed.success) return void 0;
14353
+ const message = failed.error ?? (typeof failed.data?.error === "string" ? failed.data.error : void 0) ?? `${failed.action} failed`;
14354
+ const dataCode = failed.data?.code;
14355
+ const code = failed.code ?? (typeof dataCode === "string" && isAgentErrorCode(dataCode) ? dataCode : inferAgentErrorCodeFromMessage(message));
14356
+ return { message, code };
14357
+ }
14358
+ function outputPostBroadcastFailure(wantsJson, result, conversationId, classification, originalError) {
14359
+ const message = classification === "ACK_FAILED" /* ACK_FAILED */ ? ACK_FAILED_MESSAGE : BROADCAST_COMMITTED_MESSAGE;
14360
+ if (wantsJson) {
14361
+ const data = {
14362
+ transactions: result.transactions,
14363
+ tool_calls: result.toolCalls,
14364
+ response: result.response,
14365
+ ...result.outcome ? { outcome: result.outcome } : {},
14366
+ ...originalError ? { original_error: originalError } : {}
14367
+ };
14368
+ outputErrorJson({
14369
+ success: false,
14370
+ v: 1,
14371
+ error: { message, code: classification, conversation_id: conversationId },
14372
+ data
14373
+ });
14374
+ return;
14375
+ }
14376
+ const label = classification === "ACK_FAILED" /* ACK_FAILED */ ? "Broadcast acknowledgement failed" : "Broadcast committed";
14377
+ process.stderr.write(`session:${result.sessionId}
14378
+ `);
14379
+ process.stderr.write(`${label}: ${message}
14380
+ `);
14381
+ if (result.outcome) {
14382
+ const { kind, code } = result.outcome;
14383
+ process.stderr.write(`outcome:${kind}${code ? `:${code}` : ""}
14384
+ `);
14385
+ }
14386
+ if (originalError) {
14387
+ process.stderr.write(`backend-error:${originalError.message} [${originalError.code}]
14388
+ `);
14389
+ }
14390
+ for (const tx of result.transactions) {
14391
+ process.stderr.write(`tx:${tx.chain}:${tx.hash}
14392
+ `);
14393
+ process.stderr.write(`status:${tx.status ?? "unknown"}
14394
+ `);
14395
+ if (tx.explorerUrl) process.stderr.write(`explorer:${tx.explorerUrl}
14396
+ `);
14397
+ }
14398
+ process.stderr.write(
14399
+ "WARNING: DO NOT blindly retry. Verify each transaction hash and continue only the incomplete step.\n"
14400
+ );
14401
+ }
14461
14402
  function outputAskHuman(result, confirmationRequired, proposed) {
14462
14403
  process.stdout.write(`session:${result.sessionId}
14463
14404
  `);
@@ -14511,8 +14452,7 @@ function outputAskSuccess(wantsJson, result, conversationId) {
14511
14452
  // a2a-02: the typed turn ending (success | blocked | refusal | error) at
14512
14453
  // `data.outcome` — the same relative slot as on the error envelope. Present
14513
14454
  // only against a backend that honored the advertised turn_outcome surface;
14514
- // headless callers should branch on this (and the exit code), not `success`
14515
- // (which stays true for a completed-but-blocked/refused turn).
14455
+ // headless callers can inspect it without parsing response prose.
14516
14456
  ...result.outcome ? { outcome: result.outcome } : {},
14517
14457
  ...confirmationRequired ? { confirmation_required: true } : {},
14518
14458
  ...proposed ? { proposed } : {}
@@ -14521,17 +14461,23 @@ function outputAskSuccess(wantsJson, result, conversationId) {
14521
14461
  }
14522
14462
  outputAskHuman(result, confirmationRequired, proposed);
14523
14463
  }
14524
- function outcomeToExitCode(outcome) {
14464
+ function outcomeError(outcome) {
14525
14465
  switch (outcome?.kind) {
14526
14466
  case "blocked":
14527
- return 10 /* AGENT_TURN_BLOCKED */;
14467
+ return {
14468
+ message: "The agent request was blocked by a safety guardrail.",
14469
+ code: "AGENT_TURN_BLOCKED" /* AGENT_TURN_BLOCKED */
14470
+ };
14528
14471
  case "refusal":
14529
- return 11 /* AGENT_TURN_REFUSAL */;
14472
+ return {
14473
+ message: "The agent did not complete the requested action. Refine or clarify the request.",
14474
+ code: "AGENT_TURN_REFUSAL" /* AGENT_TURN_REFUSAL */
14475
+ };
14530
14476
  case "error":
14531
- return 1 /* USAGE */;
14532
- // 1 generic failure; a stream error-frame path sets a more specific code first
14533
- case "success":
14534
- return 0 /* SUCCESS */;
14477
+ return {
14478
+ message: "The agent could not complete the requested action.",
14479
+ code: "AGENT_TURN_ERROR" /* AGENT_TURN_ERROR */
14480
+ };
14535
14481
  default:
14536
14482
  return void 0;
14537
14483
  }
@@ -14566,24 +14512,40 @@ async function executeAgentAsk(ctx2, message, options) {
14566
14512
  const result = await ask.ask(message);
14567
14513
  conversationId = result.sessionId;
14568
14514
  if (result.error) {
14569
- exitCode = agentErrorCodeToExitCode(result.error.code);
14570
- outputAskError(wantsJson, result.error.message, result.error.code, conversationId, result);
14515
+ if (hasCommittedBroadcast(result)) {
14516
+ exitCode = 13 /* BROADCAST_COMMITTED */;
14517
+ outputPostBroadcastFailure(wantsJson, result, conversationId, "BROADCAST_COMMITTED" /* BROADCAST_COMMITTED */, result.error);
14518
+ } else {
14519
+ exitCode = agentErrorCodeToExitCode(result.error.code);
14520
+ outputAskError(wantsJson, result.error.message, result.error.code, conversationId, result);
14521
+ }
14571
14522
  } else {
14572
- exitCode = outcomeToExitCode(result.outcome) ?? 0;
14573
- outputAskSuccess(wantsJson, result, conversationId);
14523
+ const failure = failedSigningError(result) ?? outcomeError(result.outcome);
14524
+ if (failure && hasCommittedBroadcast(result)) {
14525
+ exitCode = 13 /* BROADCAST_COMMITTED */;
14526
+ outputPostBroadcastFailure(wantsJson, result, conversationId, "BROADCAST_COMMITTED" /* BROADCAST_COMMITTED */, failure);
14527
+ } else if (failure) {
14528
+ exitCode = agentErrorCodeToExitCode(failure.code);
14529
+ outputAskError(wantsJson, failure.message, failure.code, conversationId, result);
14530
+ } else {
14531
+ exitCode = 0 /* SUCCESS */;
14532
+ outputAskSuccess(wantsJson, result, conversationId);
14533
+ }
14574
14534
  }
14575
14535
  } catch (err) {
14576
14536
  const normalized = normalizeAgentError(err);
14577
- let code = normalized.code;
14537
+ const code = normalized.code;
14578
14538
  const message2 = normalized.message;
14579
14539
  const partial = ask?.partialResult();
14580
14540
  if (partial && !conversationId) conversationId = partial.sessionId;
14581
- const liveBroadcast = !!partial && partial.transactions.some((t) => t.hash && t.status !== "failed");
14582
- if (liveBroadcast && ask?.hasUnacknowledgedBroadcast()) {
14583
- code = "ACK_FAILED" /* ACK_FAILED */;
14541
+ if (partial && hasCommittedBroadcast(partial)) {
14542
+ const classification = ask?.hasUnacknowledgedBroadcast() ? "ACK_FAILED" /* ACK_FAILED */ : "BROADCAST_COMMITTED" /* BROADCAST_COMMITTED */;
14543
+ exitCode = agentErrorCodeToExitCode(classification);
14544
+ outputPostBroadcastFailure(wantsJson, partial, conversationId, classification, { message: message2, code });
14545
+ } else {
14546
+ exitCode = agentErrorCodeToExitCode(code);
14547
+ outputAskError(wantsJson, message2, code, conversationId, partial);
14584
14548
  }
14585
- exitCode = agentErrorCodeToExitCode(code);
14586
- outputAskError(wantsJson, message2, code, conversationId, partial);
14587
14549
  } finally {
14588
14550
  console.log = originalConsoleLog;
14589
14551
  setSilentMode(false);
@@ -14688,7 +14650,7 @@ var cachedVersion = null;
14688
14650
  function getVersion() {
14689
14651
  if (cachedVersion) return cachedVersion;
14690
14652
  if (true) {
14691
- cachedVersion = "2.19.18";
14653
+ cachedVersion = "2.20.0";
14692
14654
  return cachedVersion;
14693
14655
  }
14694
14656
  try {
@@ -14971,7 +14933,7 @@ function readArgValue(args, optionName) {
14971
14933
  }
14972
14934
 
14973
14935
  // src/interactive/completer.ts
14974
- import { Chain as Chain11 } from "@vultisig/sdk";
14936
+ import { Chain as Chain12 } from "@vultisig/sdk";
14975
14937
  import fs3 from "fs";
14976
14938
  import path3 from "path";
14977
14939
  var COMMANDS = [
@@ -15115,7 +15077,7 @@ function completeVaultName(ctx2, partial) {
15115
15077
  return [show, partial];
15116
15078
  }
15117
15079
  function completeChainName(partial) {
15118
- const allChains = Object.values(Chain11);
15080
+ const allChains = Object.values(Chain12);
15119
15081
  const partialLower = partial.toLowerCase();
15120
15082
  const matches = allChains.filter((chain) => chain.toLowerCase().startsWith(partialLower));
15121
15083
  matches.sort();
@@ -15123,7 +15085,7 @@ function completeChainName(partial) {
15123
15085
  return [show, partial];
15124
15086
  }
15125
15087
  function findChainByName(name) {
15126
- const allChains = Object.values(Chain11);
15088
+ const allChains = Object.values(Chain12);
15127
15089
  const nameLower = name.toLowerCase();
15128
15090
  const found = allChains.find((chain) => chain.toLowerCase() === nameLower);
15129
15091
  return found ? found : null;
@@ -15306,7 +15268,7 @@ var EventBuffer = class {
15306
15268
  };
15307
15269
 
15308
15270
  // src/interactive/session.ts
15309
- import { fiatCurrencies as fiatCurrencies3 } from "@vultisig/sdk";
15271
+ import { Chain as Chain13, fiatCurrencies as fiatCurrencies3 } from "@vultisig/sdk";
15310
15272
  import chalk14 from "chalk";
15311
15273
  import ora3 from "ora";
15312
15274
  import * as readline3 from "readline";
@@ -16132,24 +16094,40 @@ Error: ${error2.message}`));
16132
16094
  }
16133
16095
  async runSend(args) {
16134
16096
  if (args.length < 3) {
16135
- console.log(chalk14.yellow("Usage: send <chain> <to> <amount> [--token <tokenId>] [--memo <memo>]"));
16097
+ console.log(
16098
+ chalk14.yellow("Usage: send <chain> <to> <amount> [--token <tokenId>] [--memo <memo>] [--destination-tag <tag>]")
16099
+ );
16136
16100
  return;
16137
16101
  }
16138
16102
  const [chainStr, to, amount, ...rest] = args;
16139
16103
  const chain = findChainByName(chainStr) || chainStr;
16140
16104
  let tokenId;
16141
16105
  let memo;
16106
+ let destinationTag;
16142
16107
  for (let i = 0; i < rest.length; i++) {
16143
16108
  if (rest[i] === "--token" && i + 1 < rest.length) {
16144
16109
  tokenId = rest[i + 1];
16145
16110
  i++;
16146
16111
  } else if (rest[i] === "--memo" && i + 1 < rest.length) {
16147
- memo = rest.slice(i + 1).join(" ");
16148
- break;
16112
+ const nextOption = rest.findIndex(
16113
+ (arg, index) => index > i && ["--token", "--memo", "--destination-tag"].includes(arg)
16114
+ );
16115
+ memo = rest.slice(i + 1, nextOption === -1 ? void 0 : nextOption).join(" ");
16116
+ i = nextOption === -1 ? rest.length : nextOption - 1;
16117
+ } else if (rest[i] === "--destination-tag") {
16118
+ const tag = rest[i + 1];
16119
+ const parsedTag = Number(tag);
16120
+ if (chain !== Chain13.Ripple || !/^(0|[1-9]\d*)$/.test(tag ?? "") || !Number.isSafeInteger(parsedTag) || parsedTag > 4294967295) {
16121
+ throw new Error("Invalid XRP DestinationTag: expected an integer from 0 to 4294967295");
16122
+ }
16123
+ destinationTag = parsedTag;
16124
+ i++;
16149
16125
  }
16150
16126
  }
16151
16127
  try {
16152
- await this.withAbortHandler((signal) => executeSend(this.ctx, { chain, to, amount, tokenId, memo, signal }));
16128
+ await this.withAbortHandler(
16129
+ (signal) => executeSend(this.ctx, { chain, to, amount, tokenId, memo, destinationTag, signal })
16130
+ );
16153
16131
  } catch (err) {
16154
16132
  if (err.message === "Transaction cancelled by user" || err.message === "Operation cancelled" || err.message === "Operation aborted") {
16155
16133
  console.log(chalk14.yellow("\nTransaction cancelled"));
@@ -16735,7 +16713,7 @@ program.name("vultisig").description("Vultisig CLI - Secure multi-party crypto w
16735
16713
  process.stdout.isTTY ? "table" : "json"
16736
16714
  ).option("-q, --quiet", "Strip empty/zero fields from output").option("--fields <fields>", "Comma-separated list of fields to include in output").option("--non-interactive", "Disable interactive prompts (fail instead of asking)").option("--ci", "CI/automation mode (equivalent to --output json --non-interactive --quiet)").option("-i, --interactive", "Start interactive shell mode").option("--vault <nameOrId>", "Specify vault by name or ID").option("--server-url <url>", "Base Vultisig API URL for FastVault and relay endpoints").addHelpText(
16737
16715
  "after",
16738
- "\nExit codes:\n" + Object.entries(EXIT_CODE_DESCRIPTIONS).map(([k, v]) => ` ${k} ${v}`).join("\n") + "\n\nEnvironment variables:\n VAULT_PASSWORD Vault password \u2014 unlocks the vault for reads and signing (no prompt)\n VULTISIG_PASSWORD Alias for VAULT_PASSWORD\n VAULT_PASSWORDS Space-separated VaultName:password pairs\n VULTISIG_VAULT Default vault name or ID\n VULTISIG_CONFIG_DIR Override config directory (~/.vultisig)\n VULTISIG_SILENT Set to 1 for silent mode\n VULTISIG_HTTP_TIMEOUT_MS Agent-backend request timeout in ms (default 30000)\n NO_COLOR Disable colored output"
16716
+ "\nExit codes:\n" + Object.entries(EXIT_CODE_DESCRIPTIONS).map(([k, v]) => ` ${k} ${v}`).join("\n") + "\n\nEnvironment variables:\n VAULT_PASSWORD Single fallback; unlocks the vault for reads and signing\n VULTISIG_PASSWORD Alias during normal unlock/signing (not auth setup)\n VAULT_PASSWORDS JSON object or space-separated key:password pairs\n VAULT_DECRYPT_PASSWORD Decrypt an encrypted .vult file during auth setup\n VULTISIG_CREDENTIALS_PASSPHRASE Encrypt credentials on disk without a keyring\n VULTISIG_VAULT Default vault name or ID\n VULTISIG_CONFIG_DIR Override config directory (~/.vultisig)\n VULTISIG_SILENT Set to 1 for silent mode\n VULTISIG_HTTP_TIMEOUT_MS Agent-backend request timeout in ms (default 30000)\n NO_COLOR Disable colored output"
16739
16717
  ).hook("preAction", (thisCommand) => {
16740
16718
  const opts = thisCommand.opts();
16741
16719
  if (opts.ci) {
@@ -17013,7 +16991,7 @@ Examples:
17013
16991
  });
17014
16992
  })
17015
16993
  );
17016
- program.command("send <chain> <to> [amount]").description(descriptions.send.description).option("--max", "Send maximum amount (balance minus fees)").option("--token <tokenId>", "Token to send (default: native)").option("--memo <memo>", "Transaction memo").option("--dry-run", "Preview transaction without signing or broadcasting").option("--confirm", "Confirm and broadcast (without this flag, runs as a preview)").option("-y, --yes", "Alias for --confirm").option("--force", "Bypass the duplicate-broadcast guard (re-send an identical, recently-broadcast tx)").option("--password <password>", "Vault password for signing").addHelpText(
16994
+ program.command("send <chain> <to> [amount]").description(descriptions.send.description).option("--max", "Send maximum amount (balance minus fees)").option("--token <tokenId>", "Token to send (default: native)").option("--memo <memo>", "Transaction memo").option("--destination-tag <tag>", "XRP DestinationTag (0 to 4294967295)").option("--dry-run", "Preview transaction without signing or broadcasting").option("--confirm", "Confirm and broadcast (without this flag, runs as a preview)").option("-y, --yes", "Alias for --confirm").option("--force", "Bypass the duplicate-broadcast guard (re-send an identical, recently-broadcast tx)").option("--password <password>", "Vault password for signing").addHelpText(
17017
16995
  "after",
17018
16996
  `
17019
16997
  Examples:
@@ -17023,7 +17001,7 @@ Examples:
17023
17001
 
17024
17002
  Environment variables:
17025
17003
  VAULT_PASSWORD Vault password (bypasses prompt)
17026
- VAULT_PASSWORDS Space-separated VaultName:password pairs
17004
+ VAULT_PASSWORDS JSON object or space-separated key:password pairs
17027
17005
 
17028
17006
  See also: balance, tx-status`
17029
17007
  ).action(
@@ -17031,14 +17009,23 @@ See also: balance, tx-status`
17031
17009
  async (chainStr, to, amount, options) => {
17032
17010
  if (!amount && !options.max) throw new Error("Provide an amount or use --max");
17033
17011
  if (amount && options.max) throw new Error("Cannot specify both amount and --max");
17012
+ const chain = findChainByName(chainStr) || chainStr;
17013
+ if (options.destinationTag !== void 0 && chain !== Chain14.Ripple) {
17014
+ throw new Error("--destination-tag is only supported for XRP");
17015
+ }
17016
+ const destinationTag = options.destinationTag === void 0 ? void 0 : Number(options.destinationTag);
17017
+ if (options.destinationTag !== void 0 && (!/^(0|[1-9]\d*)$/.test(options.destinationTag) || !Number.isSafeInteger(destinationTag) || destinationTag > 4294967295)) {
17018
+ throw new Error("Invalid XRP DestinationTag: expected an integer from 0 to 4294967295");
17019
+ }
17034
17020
  const context = await init(program.opts().vault);
17035
17021
  try {
17036
17022
  await executeSend(context, {
17037
- chain: findChainByName(chainStr) || chainStr,
17023
+ chain,
17038
17024
  to,
17039
17025
  amount: amount ?? "max",
17040
17026
  tokenId: options.token,
17041
17027
  memo: options.memo,
17028
+ destinationTag,
17042
17029
  dryRun: options.dryRun,
17043
17030
  yes: options.yes || options.confirm,
17044
17031
  force: options.force,
@@ -17104,28 +17091,32 @@ program.command("broadcast").description("Broadcast a pre-signed raw transaction
17104
17091
  });
17105
17092
  })
17106
17093
  );
17107
- program.command("tx-status").description("Check the status of a transaction (polls until confirmed)").requiredOption("--chain <chain>", "Target blockchain").requiredOption("--tx-hash <hash>", "Transaction hash to check").option("--no-wait", "Return immediately without waiting for confirmation").option("--timeout <seconds>", "Max seconds to poll before giving up (default 120)").addHelpText(
17094
+ program.command("tx-status").description("Check transaction status (polls until terminal or timeout)").requiredOption("--chain <chain>", "Target blockchain").requiredOption("--tx-hash <hash>", "Transaction hash to check").option("--no-wait", "Return immediately without waiting for confirmation").option("--timeout <seconds>", "Max seconds to poll before giving up (default 120)").addHelpText(
17108
17095
  "after",
17109
17096
  `
17097
+ Statuses: pending, not_found, confirmed, failed
17098
+ Malformed hashes fail with INVALID_HASH (exit 4).
17099
+
17110
17100
  Examples:
17111
17101
  vultisig tx-status --chain Ethereum --tx-hash 0xabc...
17112
17102
  vultisig tx-status --chain Ethereum --tx-hash 0xabc... --timeout 300
17113
17103
  vultisig tx-status --chain Bitcoin --tx-hash abc... --no-wait --output json`
17114
17104
  ).action(
17115
17105
  withExit(async (options) => {
17116
- const context = await init(program.opts().vault);
17117
17106
  const timeoutSec = options.timeout !== void 0 ? Number(options.timeout) : void 0;
17118
17107
  if (timeoutSec !== void 0 && (!Number.isFinite(timeoutSec) || timeoutSec < 0)) {
17119
17108
  throw new InvalidInputError(
17120
17109
  `Invalid --timeout: "${options.timeout}" (expected a non-negative number of seconds)`
17121
17110
  );
17122
17111
  }
17123
- await executeTxStatus(context, {
17112
+ const params = resolveTxStatusParams({
17124
17113
  chain: findChainByName(options.chain) || options.chain,
17125
17114
  txHash: options.txHash,
17126
17115
  noWait: !options.wait,
17127
17116
  timeoutSec
17128
17117
  });
17118
+ const context = await init(program.opts().vault);
17119
+ await executeTxStatus(context, params);
17129
17120
  })
17130
17121
  );
17131
17122
  program.command("portfolio").description(descriptions.portfolio.description).option("-c, --currency <currency>", "Fiat currency (usd, eur, gbp, etc.)", "usd").option("--raw", "Show raw values (wei/satoshis) for programmatic use").addHelpText(
@@ -17482,7 +17473,12 @@ Exit codes:
17482
17473
  7 unknown/unexpected error
17483
17474
  8 ACK_FAILED \u2014 broadcast succeeded but the post-broadcast report failed; the
17484
17475
  emitted tx hash IS VALID, do NOT blindly retry (that risks a double-spend)
17485
- 9 duplicate-broadcast refused \u2014 nothing was sent; retry with --force`
17476
+ 9 duplicate-broadcast refused \u2014 nothing was sent; retry with --force
17477
+ 10 agent turn blocked by a fund-safety guardrail
17478
+ 11 model refusal or clarifying question; no action taken
17479
+ 12 non-interactive confirmation/input required
17480
+ 13 BROADCAST_COMMITTED \u2014 a transaction was submitted but the overall request may
17481
+ be incomplete; inspect every emitted hash and DO NOT blindly retry`
17486
17482
  ).action(
17487
17483
  async (message, options) => {
17488
17484
  const parentOpts = agentCmd.opts();
@@ -17554,14 +17550,20 @@ program.command("update").description("Check for updates and show update command
17554
17550
  }
17555
17551
  })
17556
17552
  );
17557
- var authCmd = program.command("auth").description("Manage keyring-stored vault credentials");
17558
- authCmd.command("setup").description("Discover .vult files, prompt for passwords, and store credentials in the OS keyring").option("--vault-file <path>", "Path to a specific .vult file").option("--non-interactive", "Fail instead of prompting (use env vars)").addHelpText(
17553
+ var authCmd = program.command("auth").description("Manage stored vault credentials");
17554
+ authCmd.command("setup").description("Import a .vult file and store credentials in the OS keyring or encrypted file").option("--vault-file <path>", "Path to a specific .vult file").option("--non-interactive", "Fail instead of prompting (use env vars)").addHelpText(
17559
17555
  "after",
17560
17556
  `
17561
17557
  Examples:
17562
17558
  vultisig auth setup
17563
17559
  vultisig auth setup --vault-file ~/vault.vult
17564
- VAULT_PASSWORD=secret VAULT_DECRYPT_PASSWORD=pass vultisig auth setup --non-interactive`
17560
+
17561
+ Keychain-less Docker/CI:
17562
+ VULTISIG_CONFIG_DIR=/data/vultisig \\
17563
+ VAULT_DECRYPT_PASSWORD=backup-password \\
17564
+ VAULT_PASSWORD=server-password \\
17565
+ VULTISIG_CREDENTIALS_PASSPHRASE=file-passphrase \\
17566
+ vultisig auth setup --non-interactive --vault-file /vaults/vault.vult`
17565
17567
  ).action(
17566
17568
  withExit(async (options) => {
17567
17569
  const result = await executeAuthSetup({