@vultisig/cli 0.15.4 → 0.17.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/index.js +2678 -683
  3. package/package.json +9 -4
package/dist/index.js CHANGED
@@ -1049,14 +1049,14 @@ var require_main = __commonJS({
1049
1049
  cb = opts;
1050
1050
  opts = {};
1051
1051
  }
1052
- var qrcode5 = new QRCode(-1, this.error);
1053
- qrcode5.addData(input);
1054
- qrcode5.make();
1052
+ var qrcode4 = new QRCode(-1, this.error);
1053
+ qrcode4.addData(input);
1054
+ qrcode4.make();
1055
1055
  var output = "";
1056
1056
  if (opts && opts.small) {
1057
1057
  var BLACK = true, WHITE = false;
1058
- var moduleCount = qrcode5.getModuleCount();
1059
- var moduleData = qrcode5.modules.slice();
1058
+ var moduleCount = qrcode4.getModuleCount();
1059
+ var moduleData = qrcode4.modules.slice();
1060
1060
  var oddRow = moduleCount % 2 === 1;
1061
1061
  if (oddRow) {
1062
1062
  moduleData.push(fill(moduleCount, WHITE));
@@ -1089,9 +1089,9 @@ var require_main = __commonJS({
1089
1089
  output += borderBottom;
1090
1090
  }
1091
1091
  } else {
1092
- var border = repeat(white).times(qrcode5.getModuleCount() + 3);
1092
+ var border = repeat(white).times(qrcode4.getModuleCount() + 3);
1093
1093
  output += border + "\n";
1094
- qrcode5.modules.forEach(function(row2) {
1094
+ qrcode4.modules.forEach(function(row2) {
1095
1095
  output += white;
1096
1096
  output += row2.map(toCell).join("");
1097
1097
  output += white + "\n";
@@ -1430,7 +1430,7 @@ var init_sha3 = __esm({
1430
1430
  }
1431
1431
  });
1432
1432
 
1433
- // node_modules/viem/_esm/utils/unit/formatUnits.js
1433
+ // ../../node_modules/viem/_esm/utils/unit/formatUnits.js
1434
1434
  function formatUnits(value, decimals) {
1435
1435
  let display = value.toString();
1436
1436
  const negative = display.startsWith("-");
@@ -1445,16 +1445,991 @@ function formatUnits(value, decimals) {
1445
1445
  return `${negative ? "-" : ""}${integer || "0"}${fraction ? `.${fraction}` : ""}`;
1446
1446
  }
1447
1447
  var init_formatUnits = __esm({
1448
- "node_modules/viem/_esm/utils/unit/formatUnits.js"() {
1448
+ "../../node_modules/viem/_esm/utils/unit/formatUnits.js"() {
1449
+ }
1450
+ });
1451
+
1452
+ // ../../packages/lib/utils/dist/promise/isPromise.js
1453
+ function isPromise(value) {
1454
+ return !!value && typeof value.then === "function";
1455
+ }
1456
+ var init_isPromise = __esm({
1457
+ "../../packages/lib/utils/dist/promise/isPromise.js"() {
1458
+ }
1459
+ });
1460
+
1461
+ // ../../packages/lib/utils/dist/attempt.js
1462
+ function attempt(input) {
1463
+ if (typeof input === "function") {
1464
+ try {
1465
+ const result = input();
1466
+ if (isPromise(result)) {
1467
+ return attempt(result);
1468
+ }
1469
+ return { data: result };
1470
+ } catch (error2) {
1471
+ return { error: error2 };
1472
+ }
1473
+ } else {
1474
+ return input.then((data) => ({ data }), (error2) => ({ error: error2 }));
1475
+ }
1476
+ }
1477
+ function withFallback(result, fallback) {
1478
+ if (isPromise(result)) {
1479
+ return result.then((res) => {
1480
+ if ("error" in res) {
1481
+ return fallback;
1482
+ }
1483
+ return res.data;
1484
+ });
1485
+ }
1486
+ if ("error" in result) {
1487
+ return fallback;
1488
+ }
1489
+ return result.data;
1490
+ }
1491
+ var init_attempt = __esm({
1492
+ "../../packages/lib/utils/dist/attempt.js"() {
1493
+ init_isPromise();
1494
+ }
1495
+ });
1496
+
1497
+ // ../../packages/lib/utils/dist/error/extractErrorMsg/index.js
1498
+ var extractErrorMsg;
1499
+ var init_extractErrorMsg = __esm({
1500
+ "../../packages/lib/utils/dist/error/extractErrorMsg/index.js"() {
1501
+ init_attempt();
1502
+ extractErrorMsg = (err) => {
1503
+ if (typeof err === "string") {
1504
+ return err;
1505
+ }
1506
+ if (typeof err === "number" || typeof err === "boolean") {
1507
+ return String(err);
1508
+ }
1509
+ if (typeof err === "object" && err && "message" in err) {
1510
+ return extractErrorMsg(err.message);
1511
+ }
1512
+ return withFallback(attempt(() => JSON.stringify(err)), "Unknown Error");
1513
+ };
1514
+ }
1515
+ });
1516
+
1517
+ // ../../packages/lib/utils/dist/array/isEmpty/index.js
1518
+ var isEmpty;
1519
+ var init_isEmpty = __esm({
1520
+ "../../packages/lib/utils/dist/array/isEmpty/index.js"() {
1521
+ isEmpty = (items) => items.length === 0;
1522
+ }
1523
+ });
1524
+
1525
+ // ../../packages/lib/utils/dist/promise/asyncFallbackChain/index.js
1526
+ var asyncFallbackChain;
1527
+ var init_asyncFallbackChain = __esm({
1528
+ "../../packages/lib/utils/dist/promise/asyncFallbackChain/index.js"() {
1529
+ init_isEmpty();
1530
+ asyncFallbackChain = async (...functions) => {
1531
+ if (isEmpty(functions)) {
1532
+ throw new Error("No functions provided");
1533
+ }
1534
+ try {
1535
+ const result = await functions[0]();
1536
+ return result;
1537
+ } catch (error2) {
1538
+ if (functions.length <= 1) {
1539
+ throw error2;
1540
+ }
1541
+ return asyncFallbackChain(...functions.slice(1));
1542
+ }
1543
+ };
1544
+ }
1545
+ });
1546
+
1547
+ // ../../packages/lib/utils/dist/fetch/HttpResponseError.js
1548
+ var HttpResponseError;
1549
+ var init_HttpResponseError = __esm({
1550
+ "../../packages/lib/utils/dist/fetch/HttpResponseError.js"() {
1551
+ HttpResponseError = class extends Error {
1552
+ status;
1553
+ statusText;
1554
+ url;
1555
+ body;
1556
+ constructor(opts) {
1557
+ super(opts.message);
1558
+ this.name = "HttpResponseError";
1559
+ this.status = opts.status;
1560
+ this.statusText = opts.statusText;
1561
+ this.url = opts.url;
1562
+ this.body = opts.body;
1563
+ }
1564
+ };
1565
+ }
1566
+ });
1567
+
1568
+ // ../../packages/lib/utils/dist/fetch/assertFetchResponse.js
1569
+ var assertFetchResponse;
1570
+ var init_assertFetchResponse = __esm({
1571
+ "../../packages/lib/utils/dist/fetch/assertFetchResponse.js"() {
1572
+ init_extractErrorMsg();
1573
+ init_asyncFallbackChain();
1574
+ init_HttpResponseError();
1575
+ assertFetchResponse = async (response) => {
1576
+ if (!response.ok) {
1577
+ const body = await asyncFallbackChain(async () => response.json(), async () => response.text(), async () => `HTTP ${response.status} ${response.statusText || "Error"}: Request failed for ${response.url}`);
1578
+ const msg = extractErrorMsg(body);
1579
+ throw new HttpResponseError({
1580
+ message: msg,
1581
+ status: response.status,
1582
+ statusText: response.statusText,
1583
+ url: response.url,
1584
+ body
1585
+ });
1586
+ }
1587
+ };
1588
+ }
1589
+ });
1590
+
1591
+ // ../../packages/lib/utils/dist/record/getRecordKeys/index.js
1592
+ var getRecordKeys;
1593
+ var init_getRecordKeys = __esm({
1594
+ "../../packages/lib/utils/dist/record/getRecordKeys/index.js"() {
1595
+ getRecordKeys = (record) => {
1596
+ return Object.keys(record);
1597
+ };
1598
+ }
1599
+ });
1600
+
1601
+ // ../../packages/lib/utils/dist/record/withoutUndefinedFields.js
1602
+ function withoutUndefinedFields(record) {
1603
+ const result = {};
1604
+ getRecordKeys(record).forEach((key) => {
1605
+ const typedKey = key;
1606
+ const value = record[typedKey];
1607
+ if (value !== void 0) {
1608
+ result[typedKey] = value;
1609
+ }
1610
+ });
1611
+ return result;
1612
+ }
1613
+ var init_withoutUndefinedFields = __esm({
1614
+ "../../packages/lib/utils/dist/record/withoutUndefinedFields.js"() {
1615
+ init_getRecordKeys();
1616
+ }
1617
+ });
1618
+
1619
+ // ../../packages/lib/utils/dist/query/queryUrl.js
1620
+ async function queryUrl(url, options = {}) {
1621
+ const { responseType = "json", body, headers, method } = options;
1622
+ const response = await fetch(url, withoutUndefinedFields({
1623
+ method: method ?? (body ? "POST" : "GET"),
1624
+ headers: withoutUndefinedFields({
1625
+ ...headers,
1626
+ "Content-Type": body ? "application/json" : void 0
1627
+ }),
1628
+ body: processBody(body)
1629
+ }));
1630
+ await assertFetchResponse(response);
1631
+ if (responseType !== "none") {
1632
+ return response[responseType]();
1633
+ }
1634
+ }
1635
+ var processBody;
1636
+ var init_queryUrl = __esm({
1637
+ "../../packages/lib/utils/dist/query/queryUrl.js"() {
1638
+ init_assertFetchResponse();
1639
+ init_withoutUndefinedFields();
1640
+ processBody = (body) => {
1641
+ if (body === void 0) {
1642
+ return void 0;
1643
+ }
1644
+ if (typeof body === "string") {
1645
+ return body;
1646
+ }
1647
+ return JSON.stringify(body);
1648
+ };
1649
+ }
1650
+ });
1651
+
1652
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/pools.js
1653
+ var thorchainMidgardBaseUrl, POOL_ID_RE, assertValidPoolId, isValidPoolId, normalizePool, getThorchainPools;
1654
+ var init_pools = __esm({
1655
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/pools.js"() {
1656
+ init_queryUrl();
1657
+ thorchainMidgardBaseUrl = "https://midgard.ninerealms.com";
1658
+ POOL_ID_RE = /^[A-Z0-9]+\.[A-Z0-9]+(-[A-Z0-9]+)?$/;
1659
+ assertValidPoolId = (pool) => {
1660
+ if (typeof pool !== "string" || pool.length === 0) {
1661
+ throw new Error(`assertValidPoolId: pool id must be a non-empty string, got ${typeof pool} ${pool === "" ? '""' : ""}`);
1662
+ }
1663
+ if (!POOL_ID_RE.test(pool)) {
1664
+ throw new Error(`assertValidPoolId: ${JSON.stringify(pool)} is not a valid THORChain pool id. Expected uppercase CHAIN.ASSET (e.g. "BTC.BTC") or CHAIN.ASSET-CONTRACT (e.g. "ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48").`);
1665
+ }
1666
+ };
1667
+ isValidPoolId = (pool) => {
1668
+ if (typeof pool !== "string" || pool.length === 0)
1669
+ return false;
1670
+ return POOL_ID_RE.test(pool);
1671
+ };
1672
+ normalizePool = (raw) => ({
1673
+ asset: raw.asset ?? "",
1674
+ status: raw.status ?? "",
1675
+ assetDepth: raw.assetDepth ?? "0",
1676
+ runeDepth: raw.runeDepth ?? "0",
1677
+ liquidityUnits: raw.liquidityUnits ?? "0",
1678
+ volume24h: raw.volume24h ?? "0",
1679
+ annualPercentageRate: raw.annualPercentageRate ?? "0"
1680
+ });
1681
+ getThorchainPools = async (options = {}) => {
1682
+ const status = options.status === void 0 ? "available" : options.status;
1683
+ const url = status === null ? `${thorchainMidgardBaseUrl}/v2/pools` : `${thorchainMidgardBaseUrl}/v2/pools?status=${encodeURIComponent(status)}`;
1684
+ const raw = await queryUrl(url);
1685
+ if (!Array.isArray(raw)) {
1686
+ throw new Error(`getThorchainPools: expected an array from ${url}, got ${typeof raw}`);
1687
+ }
1688
+ return raw.map(normalizePool);
1689
+ };
1690
+ }
1691
+ });
1692
+
1693
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/memo.js
1694
+ var assertMemoSegmentSafe, addLpMemo, removeLpMemo;
1695
+ var init_memo = __esm({
1696
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/memo.js"() {
1697
+ init_pools();
1698
+ assertMemoSegmentSafe = (value, fieldName) => {
1699
+ if (typeof value !== "string") {
1700
+ throw new Error(`${fieldName} must be a string, got ${typeof value}`);
1701
+ }
1702
+ if (value.includes(":")) {
1703
+ throw new Error(`${fieldName} must not contain \`:\` (would inject extra memo segments), got ${JSON.stringify(value)}`);
1704
+ }
1705
+ if (/\s/.test(value)) {
1706
+ throw new Error(`${fieldName} must not contain whitespace, got ${JSON.stringify(value)}`);
1707
+ }
1708
+ };
1709
+ addLpMemo = ({ pool, pairedAddress }) => {
1710
+ assertValidPoolId(pool);
1711
+ if (pairedAddress && pairedAddress.length > 0) {
1712
+ assertMemoSegmentSafe(pairedAddress, "pairedAddress");
1713
+ return `+:${pool}:${pairedAddress}`;
1714
+ }
1715
+ return `+:${pool}`;
1716
+ };
1717
+ removeLpMemo = ({ pool, basisPoints, withdrawToAsset }) => {
1718
+ assertValidPoolId(pool);
1719
+ if (!Number.isInteger(basisPoints) || basisPoints < 1 || basisPoints > 1e4) {
1720
+ throw new Error(`removeLpMemo: basisPoints must be an integer in [1, 10000], got ${basisPoints}`);
1721
+ }
1722
+ if (withdrawToAsset && withdrawToAsset.length > 0) {
1723
+ assertMemoSegmentSafe(withdrawToAsset, "withdrawToAsset");
1724
+ return `-:${pool}:${basisPoints}:${withdrawToAsset}`;
1725
+ }
1726
+ return `-:${pool}:${basisPoints}`;
1727
+ };
1728
+ }
1729
+ });
1730
+
1731
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/payload.js
1732
+ var LP_REMOVE_DUST_RUNE_BASE_UNITS, isPositiveBaseUnitString, buildThorchainLpAddPayload, buildThorchainLpRemovePayload;
1733
+ var init_payload = __esm({
1734
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/payload.js"() {
1735
+ init_memo();
1736
+ LP_REMOVE_DUST_RUNE_BASE_UNITS = "2000000";
1737
+ isPositiveBaseUnitString = (value) => /^\d+$/.test(value) && BigInt(value) > 0n;
1738
+ buildThorchainLpAddPayload = ({ pool, amountRuneBaseUnits, pairedAddress }) => {
1739
+ if (!isPositiveBaseUnitString(amountRuneBaseUnits)) {
1740
+ throw new Error(`buildThorchainLpAddPayload: amountRuneBaseUnits must be a positive integer string, got ${amountRuneBaseUnits}`);
1741
+ }
1742
+ const memo = addLpMemo({ pool, pairedAddress });
1743
+ return {
1744
+ kind: "thorchain_lp_add",
1745
+ chain: "THORChain",
1746
+ denom: "rune",
1747
+ amount: amountRuneBaseUnits,
1748
+ memo,
1749
+ pool,
1750
+ ...pairedAddress ? { pairedAddress } : {}
1751
+ };
1752
+ };
1753
+ buildThorchainLpRemovePayload = ({ pool, basisPoints, withdrawToAsset }) => {
1754
+ if (!Number.isInteger(basisPoints) || basisPoints < 1 || basisPoints > 1e4) {
1755
+ throw new Error(`buildThorchainLpRemovePayload: basisPoints must be an integer in [1, 10000], got ${basisPoints}`);
1756
+ }
1757
+ const memo = removeLpMemo({ pool, basisPoints, withdrawToAsset });
1758
+ return {
1759
+ kind: "thorchain_lp_remove",
1760
+ chain: "THORChain",
1761
+ denom: "rune",
1762
+ amount: LP_REMOVE_DUST_RUNE_BASE_UNITS,
1763
+ memo,
1764
+ pool,
1765
+ basisPoints,
1766
+ ...withdrawToAsset ? { withdrawToAsset } : {}
1767
+ };
1768
+ };
1769
+ }
1770
+ });
1771
+
1772
+ // ../../packages/core/chain/dist/Chain.js
1773
+ var EthereumL2Chain, EvmChain, UtxoChain, cosmosChainsByKind, IbcEnabledCosmosChain, VaultBasedCosmosChain, CosmosChain, OtherChain, Chain9, UtxoBasedChain, defaultChains;
1774
+ var init_Chain = __esm({
1775
+ "../../packages/core/chain/dist/Chain.js"() {
1776
+ EthereumL2Chain = {
1777
+ Arbitrum: "Arbitrum",
1778
+ Base: "Base",
1779
+ Blast: "Blast",
1780
+ Optimism: "Optimism",
1781
+ Zksync: "Zksync",
1782
+ Mantle: "Mantle"
1783
+ };
1784
+ EvmChain = {
1785
+ ...EthereumL2Chain,
1786
+ Avalanche: "Avalanche",
1787
+ CronosChain: "CronosChain",
1788
+ BSC: "BSC",
1789
+ Ethereum: "Ethereum",
1790
+ Polygon: "Polygon",
1791
+ Hyperliquid: "Hyperliquid",
1792
+ Sei: "Sei"
1793
+ };
1794
+ (function(UtxoChain2) {
1795
+ UtxoChain2["Bitcoin"] = "Bitcoin";
1796
+ UtxoChain2["BitcoinCash"] = "Bitcoin-Cash";
1797
+ UtxoChain2["Litecoin"] = "Litecoin";
1798
+ UtxoChain2["Dogecoin"] = "Dogecoin";
1799
+ UtxoChain2["Dash"] = "Dash";
1800
+ UtxoChain2["Zcash"] = "Zcash";
1801
+ })(UtxoChain || (UtxoChain = {}));
1802
+ cosmosChainsByKind = {
1803
+ ibcEnabled: {
1804
+ Cosmos: "Cosmos",
1805
+ Osmosis: "Osmosis",
1806
+ Dydx: "Dydx",
1807
+ Kujira: "Kujira",
1808
+ Terra: "Terra",
1809
+ TerraClassic: "TerraClassic",
1810
+ Noble: "Noble",
1811
+ Akash: "Akash"
1812
+ },
1813
+ vaultBased: {
1814
+ THORChain: "THORChain",
1815
+ MayaChain: "MayaChain"
1816
+ }
1817
+ };
1818
+ IbcEnabledCosmosChain = cosmosChainsByKind.ibcEnabled;
1819
+ VaultBasedCosmosChain = cosmosChainsByKind.vaultBased;
1820
+ CosmosChain = {
1821
+ ...IbcEnabledCosmosChain,
1822
+ ...VaultBasedCosmosChain
1823
+ };
1824
+ (function(OtherChain2) {
1825
+ OtherChain2["Sui"] = "Sui";
1826
+ OtherChain2["Solana"] = "Solana";
1827
+ OtherChain2["Polkadot"] = "Polkadot";
1828
+ OtherChain2["Bittensor"] = "Bittensor";
1829
+ OtherChain2["Ton"] = "Ton";
1830
+ OtherChain2["Ripple"] = "Ripple";
1831
+ OtherChain2["Tron"] = "Tron";
1832
+ OtherChain2["Cardano"] = "Cardano";
1833
+ OtherChain2["QBTC"] = "QBTC";
1834
+ })(OtherChain || (OtherChain = {}));
1835
+ Chain9 = {
1836
+ ...EvmChain,
1837
+ ...UtxoChain,
1838
+ ...CosmosChain,
1839
+ ...OtherChain
1840
+ };
1841
+ UtxoBasedChain = [
1842
+ ...Object.values(UtxoChain),
1843
+ OtherChain.Cardano
1844
+ ];
1845
+ defaultChains = [
1846
+ Chain9.Bitcoin,
1847
+ Chain9.Ethereum,
1848
+ Chain9.THORChain,
1849
+ Chain9.Solana,
1850
+ Chain9.BSC
1851
+ ];
1852
+ }
1853
+ });
1854
+
1855
+ // ../../packages/core/chain/dist/chains/cosmos/cosmosRpcUrl.js
1856
+ var cosmosRpcUrl;
1857
+ var init_cosmosRpcUrl = __esm({
1858
+ "../../packages/core/chain/dist/chains/cosmos/cosmosRpcUrl.js"() {
1859
+ cosmosRpcUrl = {
1860
+ Cosmos: "https://cosmos-rest.publicnode.com",
1861
+ Osmosis: "https://osmosis-rest.publicnode.com",
1862
+ Dydx: "https://dydx-rest.publicnode.com",
1863
+ Kujira: "https://kujira-rest.publicnode.com",
1864
+ Terra: "https://terra-lcd.publicnode.com",
1865
+ TerraClassic: "https://terra-classic-lcd.publicnode.com",
1866
+ Noble: "https://noble-api.polkachu.com",
1867
+ THORChain: "https://thornode.thorchain.network",
1868
+ MayaChain: "https://mayanode.mayachain.info",
1869
+ Akash: "https://akash-rest.publicnode.com"
1870
+ };
1871
+ }
1872
+ });
1873
+
1874
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/memberPool.js
1875
+ var isNonZeroBaseUnit, normalizeMemberPool;
1876
+ var init_memberPool = __esm({
1877
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/memberPool.js"() {
1878
+ isNonZeroBaseUnit = (value) => {
1879
+ if (!value)
1880
+ return false;
1881
+ try {
1882
+ return BigInt(value) > 0n;
1883
+ } catch {
1884
+ return false;
1885
+ }
1886
+ };
1887
+ normalizeMemberPool = (raw) => ({
1888
+ pool: raw.pool ?? "",
1889
+ liquidityUnits: raw.liquidityUnits ?? "0",
1890
+ runeAdded: raw.runeAdded ?? "0",
1891
+ assetAdded: raw.assetAdded ?? "0",
1892
+ runePending: raw.runePending ?? "0",
1893
+ assetPending: raw.assetPending ?? "0",
1894
+ runeAddress: raw.runeAddress ?? "",
1895
+ assetAddress: raw.assetAddress ?? "",
1896
+ dateLastAdded: raw.dateLastAdded ?? "0",
1897
+ lastAddHeight: "",
1898
+ isPending: isNonZeroBaseUnit(raw.runePending) || isNonZeroBaseUnit(raw.assetPending)
1899
+ });
1900
+ }
1901
+ });
1902
+
1903
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/position.js
1904
+ var isMidgardNotFoundError, getThorchainLpPosition, getThorchainLpPositionFromThornode;
1905
+ var init_position = __esm({
1906
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/position.js"() {
1907
+ init_Chain();
1908
+ init_cosmosRpcUrl();
1909
+ init_HttpResponseError();
1910
+ init_queryUrl();
1911
+ init_memberPool();
1912
+ init_pools();
1913
+ isMidgardNotFoundError = (err) => err instanceof HttpResponseError && err.status === 404;
1914
+ getThorchainLpPosition = async ({ thorAddress, pool }) => {
1915
+ assertValidPoolId(pool);
1916
+ const url = `${thorchainMidgardBaseUrl}/v2/member/${encodeURIComponent(thorAddress)}`;
1917
+ let midgardNotFound = false;
1918
+ let raw = {};
1919
+ try {
1920
+ raw = await queryUrl(url);
1921
+ } catch (err) {
1922
+ if (isMidgardNotFoundError(err)) {
1923
+ midgardNotFound = true;
1924
+ } else {
1925
+ throw err;
1926
+ }
1927
+ }
1928
+ if (!midgardNotFound) {
1929
+ const pools = Array.isArray(raw.pools) ? raw.pools : [];
1930
+ const found = pools.find((p) => p.pool === pool);
1931
+ if (found)
1932
+ return normalizeMemberPool(found);
1933
+ }
1934
+ return getThorchainLpPositionFromThornode({ thorAddress, pool });
1935
+ };
1936
+ getThorchainLpPositionFromThornode = async ({ thorAddress, pool }) => {
1937
+ assertValidPoolId(pool);
1938
+ const url = `${cosmosRpcUrl[Chain9.THORChain]}/thorchain/pool/${encodeURIComponent(pool)}/liquidity_provider/${encodeURIComponent(thorAddress)}`;
1939
+ let raw;
1940
+ try {
1941
+ raw = await queryUrl(url);
1942
+ } catch (err) {
1943
+ if (err instanceof HttpResponseError && err.status === 404)
1944
+ return null;
1945
+ throw err;
1946
+ }
1947
+ const units = raw.units ?? "0";
1948
+ const pendingRune = raw.pending_rune ?? "0";
1949
+ const pendingAsset = raw.pending_asset ?? "0";
1950
+ if (!isNonZeroBaseUnit(units) && !isNonZeroBaseUnit(pendingRune) && !isNonZeroBaseUnit(pendingAsset)) {
1951
+ return null;
1952
+ }
1953
+ return {
1954
+ pool: raw.asset ?? pool,
1955
+ liquidityUnits: units,
1956
+ // Thornode doesn't track historical added amounts — those are a
1957
+ // Midgard-only enrichment. Surface them as 0; the caller can still
1958
+ // act on units/pending.
1959
+ runeAdded: "0",
1960
+ assetAdded: "0",
1961
+ runePending: pendingRune,
1962
+ assetPending: pendingAsset,
1963
+ runeAddress: raw.rune_address ?? thorAddress,
1964
+ assetAddress: raw.asset_address ?? "",
1965
+ // Thornode exposes the last-add block height, not a Unix timestamp.
1966
+ // Keep `dateLastAdded` semantically Unix-seconds-or-0 and expose the
1967
+ // block height via the dedicated `lastAddHeight` field so lockup
1968
+ // checks can use either source.
1969
+ dateLastAdded: "0",
1970
+ lastAddHeight: typeof raw.last_add_height === "number" ? String(raw.last_add_height) : "",
1971
+ isPending: isNonZeroBaseUnit(pendingRune) || isNonZeroBaseUnit(pendingAsset)
1972
+ };
1973
+ };
1974
+ }
1975
+ });
1976
+
1977
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/validation.js
1978
+ var extractPoolStatus, poolPauseMimirKey, getThorchainMimir, assertPoolDepositable;
1979
+ var init_validation = __esm({
1980
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/validation.js"() {
1981
+ init_Chain();
1982
+ init_cosmosRpcUrl();
1983
+ init_queryUrl();
1984
+ init_pools();
1985
+ extractPoolStatus = (raw) => {
1986
+ if (raw && typeof raw === "object" && "status" in raw) {
1987
+ const status = raw.status;
1988
+ return typeof status === "string" ? status : void 0;
1989
+ }
1990
+ return void 0;
1991
+ };
1992
+ poolPauseMimirKey = (pool) => {
1993
+ const dotIdx = pool.indexOf(".");
1994
+ if (dotIdx <= 0 || dotIdx >= pool.length - 1) {
1995
+ throw new Error(`poolPauseMimirKey: invalid pool id ${pool}`);
1996
+ }
1997
+ const chain = pool.slice(0, dotIdx);
1998
+ const asset = pool.slice(dotIdx + 1);
1999
+ return `PAUSELPDEPOSIT-${chain}-${asset}`;
2000
+ };
2001
+ getThorchainMimir = async () => {
2002
+ const url = `${cosmosRpcUrl[Chain9.THORChain]}/thorchain/mimir`;
2003
+ const raw = await queryUrl(url);
2004
+ if (!raw || typeof raw !== "object") {
2005
+ throw new Error(`getThorchainMimir: unexpected response shape from ${url}`);
2006
+ }
2007
+ const out = {};
2008
+ for (const [k, v] of Object.entries(raw)) {
2009
+ if (typeof v === "number" && Number.isFinite(v)) {
2010
+ out[k] = v;
2011
+ } else if (typeof v === "string" && /^-?\d+$/.test(v)) {
2012
+ out[k] = Number(v);
2013
+ }
2014
+ }
2015
+ return out;
2016
+ };
2017
+ assertPoolDepositable = async (pool) => {
2018
+ assertValidPoolId(pool);
2019
+ const [poolRaw, mimir] = await Promise.all([
2020
+ queryUrl(`${cosmosRpcUrl[Chain9.THORChain]}/thorchain/pool/${encodeURIComponent(pool)}`),
2021
+ getThorchainMimir()
2022
+ ]);
2023
+ const status = extractPoolStatus(poolRaw);
2024
+ if (status === void 0) {
2025
+ throw new Error(`assertPoolDepositable: pool ${pool} response from thornode did not include a string \`status\` field`);
2026
+ }
2027
+ if (status !== "Available") {
2028
+ throw new Error(`assertPoolDepositable: pool ${pool} status is ${status}, must be Available for LP add`);
2029
+ }
2030
+ const pauseKey = poolPauseMimirKey(pool);
2031
+ const pauseValue = mimir[pauseKey];
2032
+ if (typeof pauseValue === "number" && pauseValue > 0) {
2033
+ throw new Error(`assertPoolDepositable: pool ${pool} has LP deposits paused on-chain via mimir ${pauseKey}=${pauseValue}. THORChain validators have disabled new adds for this pool; any tx would be rejected at handler execution time.`);
2034
+ }
2035
+ };
2036
+ }
2037
+ });
2038
+
2039
+ // ../../packages/core/chain/dist/chains/cosmos/thor/thorchainLp.js
2040
+ var thorchainLpChainCode;
2041
+ var init_thorchainLp = __esm({
2042
+ "../../packages/core/chain/dist/chains/cosmos/thor/thorchainLp.js"() {
2043
+ init_Chain();
2044
+ thorchainLpChainCode = {
2045
+ [Chain9.Avalanche]: "AVAX",
2046
+ [Chain9.Base]: "BASE",
2047
+ [Chain9.BitcoinCash]: "BCH",
2048
+ [Chain9.BSC]: "BSC",
2049
+ [Chain9.Bitcoin]: "BTC",
2050
+ [Chain9.Dash]: "DASH",
2051
+ [Chain9.Dogecoin]: "DOGE",
2052
+ [Chain9.Ethereum]: "ETH",
2053
+ [Chain9.Cosmos]: "GAIA",
2054
+ [Chain9.Kujira]: "KUJI",
2055
+ [Chain9.Litecoin]: "LTC",
2056
+ [Chain9.THORChain]: "THOR",
2057
+ [Chain9.Tron]: "TRON",
2058
+ [Chain9.Ripple]: "XRP",
2059
+ [Chain9.Arbitrum]: "ARB",
2060
+ [Chain9.Zcash]: "ZEC"
2061
+ };
2062
+ }
2063
+ });
2064
+
2065
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/lpChainMap.js
2066
+ var lpChainMap, chainPrefixToChain, chainToLpPrefix;
2067
+ var init_lpChainMap = __esm({
2068
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/lpChainMap.js"() {
2069
+ init_thorchainLp();
2070
+ lpChainMap = Object.freeze(Object.entries(thorchainLpChainCode).reduce((acc, [chainKey, prefix]) => {
2071
+ if (prefix) {
2072
+ acc[prefix] = chainKey;
2073
+ }
2074
+ return acc;
2075
+ }, {}));
2076
+ chainPrefixToChain = (prefix) => lpChainMap[prefix.toUpperCase()];
2077
+ chainToLpPrefix = (chain) => thorchainLpChainCode[chain];
2078
+ }
2079
+ });
2080
+
2081
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/pairing.js
2082
+ var resolvePairedAddressForLpAdd;
2083
+ var init_pairing = __esm({
2084
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/pairing.js"() {
2085
+ init_Chain();
2086
+ init_lpChainMap();
2087
+ init_pools();
2088
+ resolvePairedAddressForLpAdd = ({ pool, side, vaultAddresses }) => {
2089
+ assertValidPoolId(pool);
2090
+ const [chainPrefix] = pool.split(".");
2091
+ if (!chainPrefix)
2092
+ return void 0;
2093
+ const assetChain = chainPrefixToChain(chainPrefix);
2094
+ if (!assetChain)
2095
+ return void 0;
2096
+ if (side === "asset") {
2097
+ return vaultAddresses[Chain9.THORChain];
2098
+ }
2099
+ return vaultAddresses[assetChain];
2100
+ };
2101
+ }
2102
+ });
2103
+
2104
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/math.js
2105
+ var assertBaseUnitString, getLiquidityUnits, getPoolShare, getLpAddSlippage, estimateLpAdd;
2106
+ var init_math = __esm({
2107
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/math.js"() {
2108
+ init_Chain();
2109
+ init_cosmosRpcUrl();
2110
+ init_queryUrl();
2111
+ init_pools();
2112
+ assertBaseUnitString = (value, fieldName) => {
2113
+ if (typeof value !== "string" || value.length === 0) {
2114
+ throw new Error(`${fieldName} must be a non-empty base-unit string, got ${typeof value === "string" ? JSON.stringify(value) : typeof value}`);
2115
+ }
2116
+ if (!/^\d+$/.test(value)) {
2117
+ throw new Error(`${fieldName} must be a non-negative integer base-unit string, got ${JSON.stringify(value)}`);
2118
+ }
2119
+ return BigInt(value);
2120
+ };
2121
+ getLiquidityUnits = ({ pool, assetAmountBaseUnit, runeAmountBaseUnit }) => {
2122
+ const P = assertBaseUnitString(pool.poolUnits, "pool.poolUnits");
2123
+ const R = assertBaseUnitString(pool.runeDepth, "pool.runeDepth");
2124
+ const A = assertBaseUnitString(pool.assetDepth, "pool.assetDepth");
2125
+ const r = assertBaseUnitString(runeAmountBaseUnit, "runeAmountBaseUnit");
2126
+ const a = assertBaseUnitString(assetAmountBaseUnit, "assetAmountBaseUnit");
2127
+ if (R === 0n || A === 0n || P === 0n) {
2128
+ return "0";
2129
+ }
2130
+ const numerator = P * (R * a + r * A);
2131
+ const denominator = 2n * R * A;
2132
+ return (numerator / denominator).toString();
2133
+ };
2134
+ getPoolShare = ({ pool, liquidityUnits }) => {
2135
+ const P = assertBaseUnitString(pool.poolUnits, "pool.poolUnits");
2136
+ const L = assertBaseUnitString(liquidityUnits, "liquidityUnits");
2137
+ if (P === 0n || L === 0n) {
2138
+ return { poolShareDecimal: "0" };
2139
+ }
2140
+ const totalAfter = P + L;
2141
+ const SCALE = 10n ** 18n;
2142
+ const scaled = L * SCALE / totalAfter;
2143
+ const decimal = scaled.toString().padStart(19, "0");
2144
+ const intPart = decimal.slice(0, -18) || "0";
2145
+ const fracPart = decimal.slice(-18).replace(/0+$/, "");
2146
+ return {
2147
+ poolShareDecimal: fracPart.length > 0 ? `${intPart}.${fracPart}` : intPart
2148
+ };
2149
+ };
2150
+ getLpAddSlippage = ({ pool, assetAmountBaseUnit, runeAmountBaseUnit }) => {
2151
+ const R = assertBaseUnitString(pool.runeDepth, "pool.runeDepth");
2152
+ const A = assertBaseUnitString(pool.assetDepth, "pool.assetDepth");
2153
+ const r = assertBaseUnitString(runeAmountBaseUnit, "runeAmountBaseUnit");
2154
+ const a = assertBaseUnitString(assetAmountBaseUnit, "assetAmountBaseUnit");
2155
+ if (R === 0n || A === 0n) {
2156
+ return { decimalPercent: "0", slippageInRuneBaseUnit: "0" };
2157
+ }
2158
+ const ra = R * a;
2159
+ const ar = A * r;
2160
+ const numerator = ra > ar ? ra - ar : ar - ra;
2161
+ const denominator = A * r + R * A;
2162
+ if (denominator === 0n) {
2163
+ return { decimalPercent: "0", slippageInRuneBaseUnit: "0" };
2164
+ }
2165
+ const SCALE = 10n ** 18n;
2166
+ const scaled = numerator * SCALE / denominator;
2167
+ const decimal = scaled.toString().padStart(19, "0");
2168
+ const intPart = decimal.slice(0, -18) || "0";
2169
+ const fracPart = decimal.slice(-18).replace(/0+$/, "");
2170
+ const decimalPercent = fracPart.length > 0 ? `${intPart}.${fracPart}` : intPart;
2171
+ const imbalanceNumerator = ra > ar ? ra - ar : ar - ra;
2172
+ const imbalanceInRune = A === 0n ? 0n : imbalanceNumerator / (2n * A);
2173
+ const slippageInRune = imbalanceInRune * scaled / SCALE;
2174
+ return {
2175
+ decimalPercent,
2176
+ slippageInRuneBaseUnit: slippageInRune.toString()
2177
+ };
2178
+ };
2179
+ estimateLpAdd = async ({ pool, assetAmountBaseUnit, runeAmountBaseUnit, thornodeBaseUrl }) => {
2180
+ assertValidPoolId(pool);
2181
+ const base = thornodeBaseUrl ?? cosmosRpcUrl[Chain9.THORChain];
2182
+ const url = `${base}/thorchain/pool/${encodeURIComponent(pool)}`;
2183
+ const raw = await queryUrl(url);
2184
+ if (!raw || typeof raw !== "object" || typeof raw.balance_asset !== "string" || typeof raw.balance_rune !== "string") {
2185
+ throw new Error(`estimateLpAdd: pool ${pool} response from ${url} missing balance fields`);
2186
+ }
2187
+ const poolUnitsRaw = raw.pool_units ?? raw.LP_units;
2188
+ if (typeof poolUnitsRaw !== "string" || poolUnitsRaw.length === 0) {
2189
+ throw new Error(`estimateLpAdd: pool ${pool} response from ${url} missing pool_units / LP_units`);
2190
+ }
2191
+ const poolState = {
2192
+ assetDepth: raw.balance_asset,
2193
+ runeDepth: raw.balance_rune,
2194
+ poolUnits: poolUnitsRaw
2195
+ };
2196
+ const liquidityUnits = getLiquidityUnits({
2197
+ pool: poolState,
2198
+ assetAmountBaseUnit,
2199
+ runeAmountBaseUnit
2200
+ });
2201
+ const share = getPoolShare({
2202
+ pool: poolState,
2203
+ liquidityUnits
2204
+ });
2205
+ const slip = getLpAddSlippage({
2206
+ pool: poolState,
2207
+ assetAmountBaseUnit,
2208
+ runeAmountBaseUnit
2209
+ });
2210
+ const R = BigInt(poolState.runeDepth);
2211
+ const A = BigInt(poolState.assetDepth);
2212
+ const P = BigInt(poolState.poolUnits);
2213
+ const r = BigInt(runeAmountBaseUnit);
2214
+ const a = BigInt(assetAmountBaseUnit);
2215
+ const L = BigInt(liquidityUnits);
2216
+ const totalAfter = P + L;
2217
+ const runeDepthAfter = R + r;
2218
+ const assetDepthAfter = A + a;
2219
+ const runeShareBaseUnit = totalAfter === 0n ? "0" : (runeDepthAfter * L / totalAfter).toString();
2220
+ const assetShareBaseUnit = totalAfter === 0n ? "0" : (assetDepthAfter * L / totalAfter).toString();
2221
+ return {
2222
+ liquidityUnits,
2223
+ poolShareDecimal: share.poolShareDecimal,
2224
+ runeShareBaseUnit,
2225
+ assetShareBaseUnit,
2226
+ slippageDecimal: slip.decimalPercent,
2227
+ slippageRuneBaseUnit: slip.slippageInRuneBaseUnit
2228
+ };
2229
+ };
2230
+ }
2231
+ });
2232
+
2233
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/positions.js
2234
+ var getThorchainLpPositions;
2235
+ var init_positions = __esm({
2236
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/positions.js"() {
2237
+ init_HttpResponseError();
2238
+ init_queryUrl();
2239
+ init_memberPool();
2240
+ init_pools();
2241
+ getThorchainLpPositions = async ({ thorAddress }) => {
2242
+ const url = `${thorchainMidgardBaseUrl}/v2/member/${encodeURIComponent(thorAddress)}`;
2243
+ let raw;
2244
+ try {
2245
+ raw = await queryUrl(url);
2246
+ } catch (err) {
2247
+ if (err instanceof HttpResponseError && err.status === 404)
2248
+ return [];
2249
+ throw err;
2250
+ }
2251
+ if (!raw || typeof raw !== "object") {
2252
+ throw new Error(`getThorchainLpPositions: unexpected Midgard response shape from ${url}`);
2253
+ }
2254
+ if (raw.pools === void 0) {
2255
+ return [];
2256
+ }
2257
+ if (!Array.isArray(raw.pools)) {
2258
+ throw new Error(`getThorchainLpPositions: Midgard response ${url} has non-array \`pools\` field`);
2259
+ }
2260
+ return raw.pools.map(normalizeMemberPool);
2261
+ };
2262
+ }
2263
+ });
2264
+
2265
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/lockup.js
2266
+ var THORCHAIN_BLOCK_TIME_SECONDS, getThorchainLpLockupSeconds, getLpWithdrawReadiness;
2267
+ var init_lockup = __esm({
2268
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/lockup.js"() {
2269
+ init_validation();
2270
+ THORCHAIN_BLOCK_TIME_SECONDS = 6;
2271
+ getThorchainLpLockupSeconds = async () => {
2272
+ const mimir = await getThorchainMimir();
2273
+ const blocks = mimir["LIQUIDITYLOCKUPBLOCKS"];
2274
+ if (typeof blocks !== "number" || !Number.isFinite(blocks) || blocks < 0) {
2275
+ throw new Error(`getThorchainLpLockupSeconds: mimir did not include a valid LIQUIDITYLOCKUPBLOCKS value`);
2276
+ }
2277
+ return blocks * THORCHAIN_BLOCK_TIME_SECONDS;
2278
+ };
2279
+ getLpWithdrawReadiness = async ({ position, lockupSeconds: providedLockupSeconds, nowUnix = Math.floor(Date.now() / 1e3) }) => {
2280
+ const lockupSeconds = providedLockupSeconds ?? await getThorchainLpLockupSeconds();
2281
+ const lastAdded = Number(position.dateLastAdded);
2282
+ if (!Number.isFinite(lastAdded) || lastAdded <= 0) {
2283
+ return {
2284
+ isWithdrawable: true,
2285
+ unlockAtUnix: 0,
2286
+ remainingSeconds: 0
2287
+ };
2288
+ }
2289
+ const unlockAtUnix = lastAdded + lockupSeconds;
2290
+ const remainingSeconds = Math.max(unlockAtUnix - nowUnix, 0);
2291
+ return {
2292
+ isWithdrawable: remainingSeconds === 0,
2293
+ unlockAtUnix,
2294
+ remainingSeconds
2295
+ };
2296
+ };
2297
+ }
2298
+ });
2299
+
2300
+ // ../../packages/core/chain/dist/chains/cosmos/thor/getThorchainInboundAddress.js
2301
+ var getThorchainInboundAddress_exports = {};
2302
+ __export(getThorchainInboundAddress_exports, {
2303
+ getThorchainInboundAddress: () => getThorchainInboundAddress
2304
+ });
2305
+ var thorchainInboundAddressApi, getThorchainInboundAddress;
2306
+ var init_getThorchainInboundAddress = __esm({
2307
+ "../../packages/core/chain/dist/chains/cosmos/thor/getThorchainInboundAddress.js"() {
2308
+ init_queryUrl();
2309
+ init_Chain();
2310
+ init_cosmosRpcUrl();
2311
+ thorchainInboundAddressApi = `${cosmosRpcUrl[Chain9.THORChain]}/thorchain/inbound_addresses`;
2312
+ getThorchainInboundAddress = () => queryUrl(thorchainInboundAddressApi);
2313
+ }
2314
+ });
2315
+
2316
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/halts.js
2317
+ var buildStatus, getThorchainLpHaltStatusAll, getThorchainLpHaltStatus, getThorchainLpPoolPauseStatus;
2318
+ var init_halts = __esm({
2319
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/halts.js"() {
2320
+ init_getThorchainInboundAddress();
2321
+ init_validation();
2322
+ buildStatus = (raw) => {
2323
+ const reasons = [];
2324
+ if (raw.halted)
2325
+ reasons.push(`${raw.chain} chain is halted`);
2326
+ if (raw.global_trading_paused)
2327
+ reasons.push("global trading paused");
2328
+ if (raw.chain_trading_paused)
2329
+ reasons.push(`${raw.chain} chain trading paused`);
2330
+ if (raw.chain_lp_actions_paused)
2331
+ reasons.push(`${raw.chain} LP actions paused`);
2332
+ const depositable = !raw.halted && !raw.chain_lp_actions_paused && !raw.chain_trading_paused && !raw.global_trading_paused;
2333
+ const withdrawable = !raw.halted && !raw.chain_lp_actions_paused;
2334
+ return {
2335
+ chain: raw.chain,
2336
+ depositable,
2337
+ withdrawable,
2338
+ reasons,
2339
+ raw: {
2340
+ halted: raw.halted,
2341
+ chain_trading_paused: raw.chain_trading_paused,
2342
+ chain_lp_actions_paused: raw.chain_lp_actions_paused,
2343
+ global_trading_paused: raw.global_trading_paused
2344
+ }
2345
+ };
2346
+ };
2347
+ getThorchainLpHaltStatusAll = async () => {
2348
+ const addresses = await getThorchainInboundAddress();
2349
+ return addresses.map((a) => buildStatus({
2350
+ chain: a.chain,
2351
+ halted: a.halted,
2352
+ chain_trading_paused: a.chain_trading_paused,
2353
+ chain_lp_actions_paused: a.chain_lp_actions_paused,
2354
+ global_trading_paused: a.global_trading_paused
2355
+ }));
2356
+ };
2357
+ getThorchainLpHaltStatus = async (chain) => {
2358
+ const all = await getThorchainLpHaltStatusAll();
2359
+ const upper = chain.toUpperCase();
2360
+ const match = all.find((s) => s.chain.toUpperCase() === upper);
2361
+ if (!match) {
2362
+ throw new Error(`getThorchainLpHaltStatus: chain ${chain} not found in inbound_addresses`);
2363
+ }
2364
+ return match;
2365
+ };
2366
+ getThorchainLpPoolPauseStatus = async (pool) => {
2367
+ const mimir = await getThorchainMimir();
2368
+ const mimirKey = poolPauseMimirKey(pool);
2369
+ const mimirValue = mimir[mimirKey];
2370
+ if (typeof mimirValue === "number" && mimirValue > 0) {
2371
+ return { paused: true, mimirKey, mimirValue };
2372
+ }
2373
+ return { paused: false };
2374
+ };
2375
+ }
2376
+ });
2377
+
2378
+ // ../../packages/core/chain/dist/chains/cosmos/thor/lp/index.js
2379
+ var lp_exports = {};
2380
+ __export(lp_exports, {
2381
+ THORCHAIN_BLOCK_TIME_SECONDS: () => THORCHAIN_BLOCK_TIME_SECONDS,
2382
+ addLpMemo: () => addLpMemo,
2383
+ assertPoolDepositable: () => assertPoolDepositable,
2384
+ assertValidPoolId: () => assertValidPoolId,
2385
+ buildThorchainLpAddPayload: () => buildThorchainLpAddPayload,
2386
+ buildThorchainLpRemovePayload: () => buildThorchainLpRemovePayload,
2387
+ chainPrefixToChain: () => chainPrefixToChain,
2388
+ chainToLpPrefix: () => chainToLpPrefix,
2389
+ estimateLpAdd: () => estimateLpAdd,
2390
+ getLiquidityUnits: () => getLiquidityUnits,
2391
+ getLpAddSlippage: () => getLpAddSlippage,
2392
+ getLpWithdrawReadiness: () => getLpWithdrawReadiness,
2393
+ getPoolShare: () => getPoolShare,
2394
+ getThorchainLpHaltStatus: () => getThorchainLpHaltStatus,
2395
+ getThorchainLpHaltStatusAll: () => getThorchainLpHaltStatusAll,
2396
+ getThorchainLpLockupSeconds: () => getThorchainLpLockupSeconds,
2397
+ getThorchainLpPoolPauseStatus: () => getThorchainLpPoolPauseStatus,
2398
+ getThorchainLpPosition: () => getThorchainLpPosition,
2399
+ getThorchainLpPositionFromThornode: () => getThorchainLpPositionFromThornode,
2400
+ getThorchainLpPositions: () => getThorchainLpPositions,
2401
+ getThorchainMimir: () => getThorchainMimir,
2402
+ getThorchainPools: () => getThorchainPools,
2403
+ isValidPoolId: () => isValidPoolId,
2404
+ lpChainMap: () => lpChainMap,
2405
+ poolPauseMimirKey: () => poolPauseMimirKey,
2406
+ removeLpMemo: () => removeLpMemo,
2407
+ resolvePairedAddressForLpAdd: () => resolvePairedAddressForLpAdd,
2408
+ thorchainMidgardBaseUrl: () => thorchainMidgardBaseUrl
2409
+ });
2410
+ var init_lp = __esm({
2411
+ "../../packages/core/chain/dist/chains/cosmos/thor/lp/index.js"() {
2412
+ init_memo();
2413
+ init_payload();
2414
+ init_pools();
2415
+ init_position();
2416
+ init_validation();
2417
+ init_pairing();
2418
+ init_lpChainMap();
2419
+ init_math();
2420
+ init_positions();
2421
+ init_lockup();
2422
+ init_halts();
1449
2423
  }
1450
2424
  });
1451
2425
 
1452
2426
  // src/index.ts
1453
2427
  import "dotenv/config";
1454
2428
  import { promises as fs4 } from "node:fs";
2429
+ import { descriptions } from "@vultisig/client-shared";
1455
2430
  import { parseKeygenQR, Vultisig as Vultisig6 } from "@vultisig/sdk";
1456
2431
  import chalk15 from "chalk";
1457
- import { program } from "commander";
2432
+ import { InvalidArgumentError, program } from "commander";
1458
2433
  import inquirer8 from "inquirer";
1459
2434
 
1460
2435
  // src/core/command-context.ts
@@ -1536,12 +2511,32 @@ import chalk from "chalk";
1536
2511
  import ora from "ora";
1537
2512
  var silentMode = false;
1538
2513
  var outputFormat = "table";
2514
+ var nonInteractive = false;
2515
+ var quietMode = false;
2516
+ var fieldFilter;
1539
2517
  function setSilentMode(silent) {
1540
2518
  silentMode = silent;
1541
2519
  }
1542
2520
  function isSilent() {
1543
2521
  return silentMode;
1544
2522
  }
2523
+ function setNonInteractive(value) {
2524
+ nonInteractive = value;
2525
+ }
2526
+ function isNonInteractive() {
2527
+ return nonInteractive;
2528
+ }
2529
+ function requireInteractive(hint) {
2530
+ if (nonInteractive) {
2531
+ throw new Error(`Interactive prompt required but --non-interactive is set. ${hint}`);
2532
+ }
2533
+ }
2534
+ function setQuiet(value) {
2535
+ quietMode = value;
2536
+ }
2537
+ function setFields(fields) {
2538
+ fieldFilter = fields;
2539
+ }
1545
2540
  function initOutputMode(options) {
1546
2541
  outputFormat = options.output ?? "table";
1547
2542
  silentMode = options.silent ?? process.env.VULTISIG_SILENT === "1";
@@ -1552,14 +2547,72 @@ function initOutputMode(options) {
1552
2547
  function isJsonOutput() {
1553
2548
  return outputFormat === "json";
1554
2549
  }
2550
+ function stripEmpty(data) {
2551
+ if (Array.isArray(data)) return data.map(stripEmpty);
2552
+ if (data !== null && typeof data === "object") {
2553
+ return Object.fromEntries(
2554
+ Object.entries(data).filter(([, v]) => v != null && v !== "").map(([k, v]) => [k, stripEmpty(v)])
2555
+ );
2556
+ }
2557
+ return data;
2558
+ }
2559
+ function filterFields(data, fields) {
2560
+ if (!fields.length) return data;
2561
+ if (Array.isArray(data)) return data.map((item) => filterFields(item, fields));
2562
+ if (data !== null && typeof data === "object") {
2563
+ const entries = Object.entries(data);
2564
+ const matched = entries.filter(([k]) => fields.includes(k));
2565
+ if (matched.length > 0) return Object.fromEntries(matched);
2566
+ const recursed = entries.map(([k, v]) => [k, filterFields(v, fields)]);
2567
+ return Object.fromEntries(recursed);
2568
+ }
2569
+ return data;
2570
+ }
2571
+ function collectKeys(data) {
2572
+ const keys = /* @__PURE__ */ new Set();
2573
+ if (Array.isArray(data)) {
2574
+ for (const item of data) {
2575
+ if (item !== null && typeof item === "object") {
2576
+ for (const k of Object.keys(item)) keys.add(k);
2577
+ }
2578
+ }
2579
+ } else if (data !== null && typeof data === "object") {
2580
+ for (const [k, v] of Object.entries(data)) {
2581
+ keys.add(k);
2582
+ if (v !== null && typeof v === "object") {
2583
+ for (const nested of collectKeys(v)) keys.add(nested);
2584
+ }
2585
+ }
2586
+ }
2587
+ return keys;
2588
+ }
2589
+ function warnInvalidFields(data, fields) {
2590
+ const available = collectKeys(data);
2591
+ if (available.size === 0) return;
2592
+ const invalid = fields.filter((f) => !available.has(f));
2593
+ if (invalid.length > 0) {
2594
+ process.stderr.write(`Warning: unknown field(s): ${invalid.join(", ")}. Available: ${[...available].join(", ")}
2595
+ `);
2596
+ }
2597
+ }
2598
+ function applyOutputTransforms(data) {
2599
+ let out = quietMode ? stripEmpty(data) : data;
2600
+ if (fieldFilter?.length) {
2601
+ warnInvalidFields(out, fieldFilter);
2602
+ out = filterFields(out, fieldFilter);
2603
+ }
2604
+ return out;
2605
+ }
1555
2606
  function bigIntReplacer(_key, value) {
1556
2607
  return typeof value === "bigint" ? value.toString() : value;
1557
2608
  }
1558
2609
  function outputJson(data) {
1559
- console.log(JSON.stringify({ success: true, data }, bigIntReplacer, 2));
2610
+ const transformed = applyOutputTransforms(data);
2611
+ console.log(JSON.stringify({ success: true, v: 1, data: transformed }, bigIntReplacer, 2));
1560
2612
  }
1561
- function outputJsonError(message, code) {
1562
- console.log(JSON.stringify({ success: false, error: { message, code } }, bigIntReplacer, 2));
2613
+ function outputErrorJson(errJson) {
2614
+ const transformed = applyOutputTransforms(errJson);
2615
+ console.log(JSON.stringify(transformed, bigIntReplacer, 2));
1563
2616
  }
1564
2617
  function info(message) {
1565
2618
  if (!silentMode) {
@@ -1661,11 +2714,24 @@ function createSpinner(text) {
1661
2714
  activeSpinners.add(spinner2);
1662
2715
  return spinner2;
1663
2716
  }
1664
- const spinner = wrapOraSpinner(ora(text).start());
2717
+ const spinner = wrapOraSpinner(ora({ text, stream: process.stderr }).start());
1665
2718
  activeSpinners.add(spinner);
1666
2719
  return spinner;
1667
2720
  }
1668
2721
 
2722
+ // src/core/credential-store.ts
2723
+ import {
2724
+ _resetAll,
2725
+ clearCredentials,
2726
+ getDecryptionPassword,
2727
+ getServerPassword,
2728
+ getStoredServerPassword,
2729
+ isUsingFileFallback,
2730
+ setDecryptionPassword,
2731
+ setFilePassphrase,
2732
+ setServerPassword
2733
+ } from "@vultisig/client-shared";
2734
+
1669
2735
  // src/core/password-manager.ts
1670
2736
  var passwordCache = /* @__PURE__ */ new Map();
1671
2737
  function cachePassword(vaultIdOrName, password) {
@@ -1700,12 +2766,15 @@ function getPasswordFromEnv(vaultId, vaultName) {
1700
2766
  if (vaultPasswords.has(vaultId)) {
1701
2767
  return vaultPasswords.get(vaultId);
1702
2768
  }
1703
- if (process.env.VAULT_PASSWORD) {
1704
- return process.env.VAULT_PASSWORD;
2769
+ if (process.env.VAULT_PASSWORD || process.env.VULTISIG_PASSWORD) {
2770
+ return process.env.VAULT_PASSWORD || process.env.VULTISIG_PASSWORD;
1705
2771
  }
1706
2772
  return null;
1707
2773
  }
1708
2774
  async function promptForPassword(vaultName, vaultId) {
2775
+ requireInteractive(
2776
+ 'Use --password flag, VAULT_PASSWORD env var, or "vsig auth setup" to store credentials in keyring.'
2777
+ );
1709
2778
  const displayName = vaultName || vaultId || "vault";
1710
2779
  const { password } = await inquirer.prompt([
1711
2780
  {
@@ -1722,51 +2791,281 @@ async function getPassword(vaultId, vaultName) {
1722
2791
  if (cachedPassword) {
1723
2792
  return cachedPassword;
1724
2793
  }
1725
- const envPassword = getPasswordFromEnv(vaultId, vaultName);
1726
- if (envPassword) {
1727
- cachePassword(vaultId, envPassword);
1728
- if (vaultName) cachePassword(vaultName, envPassword);
1729
- return envPassword;
2794
+ try {
2795
+ const keyringPassword = await getServerPassword(vaultId);
2796
+ if (keyringPassword) {
2797
+ cachePassword(vaultId, keyringPassword);
2798
+ if (vaultName) cachePassword(vaultName, keyringPassword);
2799
+ return keyringPassword;
2800
+ }
2801
+ } catch {
2802
+ }
2803
+ const envPassword = getPasswordFromEnv(vaultId, vaultName);
2804
+ if (envPassword) {
2805
+ cachePassword(vaultId, envPassword);
2806
+ if (vaultName) cachePassword(vaultName, envPassword);
2807
+ return envPassword;
2808
+ }
2809
+ if (isSilent() || isJsonOutput() || isNonInteractive()) {
2810
+ throw new Error(
2811
+ "Password required but not provided. Set VAULT_PASSWORD or VAULT_PASSWORDS environment variable, or use --password flag."
2812
+ );
2813
+ }
2814
+ const password = await promptForPassword(vaultName, vaultId);
2815
+ cachePassword(vaultId, password);
2816
+ if (vaultName) cachePassword(vaultName, password);
2817
+ return password;
2818
+ }
2819
+ function createPasswordCallback() {
2820
+ return async (vaultId, vaultName) => {
2821
+ return getPassword(vaultId, vaultName);
2822
+ };
2823
+ }
2824
+ async function ensureVaultUnlocked(vault, password) {
2825
+ if (!vault.isEncrypted || vault.isUnlocked()) {
2826
+ return;
2827
+ }
2828
+ const resolvedPassword = password || await getPassword(vault.id, vault.name);
2829
+ await vault.unlock(resolvedPassword);
2830
+ }
2831
+
2832
+ // src/adapters/cli-context.ts
2833
+ var CLIContext = class extends BaseCommandContext {
2834
+ get isInteractive() {
2835
+ return false;
2836
+ }
2837
+ /**
2838
+ * Get password for a vault
2839
+ * In CLI mode, we check env vars first, then prompt
2840
+ * No caching since each command runs independently
2841
+ */
2842
+ async getPassword(vaultId, vaultName) {
2843
+ return getPassword(vaultId, vaultName);
2844
+ }
2845
+ };
2846
+
2847
+ // src/core/errors.ts
2848
+ import { VaultError, VaultErrorCode, VaultImportError, VaultImportErrorCode } from "@vultisig/sdk";
2849
+ var EXIT_CODE_DESCRIPTIONS = {
2850
+ [0 /* SUCCESS */]: "Success",
2851
+ [1 /* USAGE */]: "Usage error (bad arguments, unknown command)",
2852
+ [2 /* AUTH_REQUIRED */]: "Authentication required",
2853
+ [3 /* NETWORK */]: "Network error (retryable)",
2854
+ [4 /* INVALID_INPUT */]: "Invalid input (bad chain, address, amount)",
2855
+ [5 /* RESOURCE_NOT_FOUND */]: "Resource not found (token, route)",
2856
+ [6 /* EXTERNAL_SERVICE */]: "External service error (retryable)",
2857
+ [7 /* UNKNOWN */]: "Unknown/unexpected error"
2858
+ };
2859
+ var VsigError = class extends Error {
2860
+ hint;
2861
+ suggestions;
2862
+ context;
2863
+ retryable = false;
2864
+ constructor(message, hint, suggestions, context) {
2865
+ super(message);
2866
+ this.name = this.constructor.name;
2867
+ this.hint = hint;
2868
+ this.suggestions = suggestions;
2869
+ this.context = context;
2870
+ }
2871
+ };
2872
+ var UsageError = class extends VsigError {
2873
+ exitCode = 1 /* USAGE */;
2874
+ code = "USAGE_ERROR";
2875
+ constructor(message, hint, suggestions) {
2876
+ super(message, hint, suggestions);
2877
+ }
2878
+ };
2879
+ var AuthRequiredError = class extends VsigError {
2880
+ exitCode = 2 /* AUTH_REQUIRED */;
2881
+ code = "AUTH_REQUIRED";
2882
+ constructor(message) {
2883
+ super(message ?? "Authentication required. Set up vault credentials.", "Ensure your vault is unlocked", [
2884
+ "vsig vaults",
2885
+ "vsig create"
2886
+ ]);
2887
+ }
2888
+ };
2889
+ var NetworkError = class extends VsigError {
2890
+ exitCode = 3 /* NETWORK */;
2891
+ code = "NETWORK_ERROR";
2892
+ retryable = true;
2893
+ constructor(message, hint, suggestions) {
2894
+ super(message, hint, suggestions);
2895
+ }
2896
+ };
2897
+ var InvalidChainError = class extends VsigError {
2898
+ exitCode = 4 /* INVALID_INPUT */;
2899
+ code = "INVALID_CHAIN";
2900
+ constructor(message, hint, suggestions, context) {
2901
+ super(message, hint, suggestions, context);
2902
+ }
2903
+ };
2904
+ var InvalidAddressError = class extends VsigError {
2905
+ exitCode = 4 /* INVALID_INPUT */;
2906
+ code = "INVALID_ADDRESS";
2907
+ constructor(message, hint, suggestions, context) {
2908
+ super(message, hint, suggestions, context);
2909
+ }
2910
+ };
2911
+ var InvalidInputError = class extends VsigError {
2912
+ exitCode = 4 /* INVALID_INPUT */;
2913
+ code = "INVALID_INPUT";
2914
+ constructor(message, hint, suggestions, context) {
2915
+ super(message, hint, suggestions, context);
2916
+ }
2917
+ };
2918
+ var InsufficientBalanceError = class extends VsigError {
2919
+ exitCode = 4 /* INVALID_INPUT */;
2920
+ code = "INSUFFICIENT_BALANCE";
2921
+ constructor(message, hint, suggestions, context) {
2922
+ super(message, hint, suggestions, context);
2923
+ }
2924
+ };
2925
+ var NoRouteError = class extends VsigError {
2926
+ exitCode = 5 /* RESOURCE_NOT_FOUND */;
2927
+ code = "NO_ROUTE";
2928
+ constructor(message, hint, suggestions, context) {
2929
+ super(message, hint, suggestions, context);
2930
+ }
2931
+ };
2932
+ var TokenNotFoundError = class extends VsigError {
2933
+ exitCode = 5 /* RESOURCE_NOT_FOUND */;
2934
+ code = "TOKEN_NOT_FOUND";
2935
+ constructor(message, hint, suggestions, context) {
2936
+ super(message, hint, suggestions, context);
2937
+ }
2938
+ };
2939
+ var ExternalServiceError = class extends VsigError {
2940
+ exitCode = 6 /* EXTERNAL_SERVICE */;
2941
+ code = "EXTERNAL_SERVICE";
2942
+ retryable = true;
2943
+ constructor(message, hint, suggestions) {
2944
+ super(message, hint, suggestions);
2945
+ }
2946
+ };
2947
+ var PricingUnavailableError = class extends VsigError {
2948
+ exitCode = 6 /* EXTERNAL_SERVICE */;
2949
+ code = "PRICING_UNAVAILABLE";
2950
+ retryable = true;
2951
+ constructor(message, hint, suggestions) {
2952
+ super(message, hint, suggestions);
2953
+ }
2954
+ };
2955
+ var UnknownError = class extends VsigError {
2956
+ exitCode = 7 /* UNKNOWN */;
2957
+ code = "UNKNOWN_ERROR";
2958
+ constructor(message) {
2959
+ super(message);
2960
+ }
2961
+ };
2962
+ function classifyError(err) {
2963
+ if (err instanceof VsigError) return err;
2964
+ if (err instanceof VaultError) {
2965
+ if (err.code === VaultErrorCode.BalanceFetchFailed && err.originalError) {
2966
+ const inner = classifyError(err.originalError);
2967
+ if (!(inner instanceof UnknownError)) return inner;
2968
+ }
2969
+ switch (err.code) {
2970
+ case VaultErrorCode.UnsupportedChain:
2971
+ case VaultErrorCode.ChainNotSupported:
2972
+ return new InvalidChainError(err.message);
2973
+ case VaultErrorCode.NetworkError:
2974
+ case VaultErrorCode.BalanceFetchFailed:
2975
+ case VaultErrorCode.Timeout:
2976
+ return new NetworkError(err.message);
2977
+ case VaultErrorCode.InvalidAmount:
2978
+ return new InvalidInputError(err.message);
2979
+ case VaultErrorCode.InvalidConfig: {
2980
+ const lowerMsg = err.message.toLowerCase();
2981
+ if (lowerMsg.includes("unknown chain") || lowerMsg.includes("unsupported chain") || lowerMsg.includes("chain not supported")) {
2982
+ const chainMatch = err.message.match(/chain[:\s]*"([^"]+)"/i);
2983
+ return new InvalidChainError(
2984
+ err.message,
2985
+ void 0,
2986
+ void 0,
2987
+ chainMatch ? { chain: chainMatch[1] } : void 0
2988
+ );
2989
+ }
2990
+ return new UsageError(err.message);
2991
+ }
2992
+ case VaultErrorCode.UnsupportedToken:
2993
+ return new TokenNotFoundError(err.message);
2994
+ case VaultErrorCode.BroadcastFailed:
2995
+ return new ExternalServiceError(err.message, "Broadcast failed \u2014 the node may be temporarily unavailable", [
2996
+ "Retry the transaction"
2997
+ ]);
2998
+ case VaultErrorCode.GasEstimationFailed:
2999
+ return new InvalidInputError(err.message, "Gas estimation failed \u2014 check balance and transaction params");
3000
+ case VaultErrorCode.SigningFailed:
3001
+ return new UnknownError(err.message);
3002
+ default:
3003
+ return new UnknownError(err.message);
3004
+ }
3005
+ }
3006
+ if (err instanceof VaultImportError) {
3007
+ switch (err.code) {
3008
+ case VaultImportErrorCode.PASSWORD_REQUIRED:
3009
+ case VaultImportErrorCode.INVALID_PASSWORD:
3010
+ return new AuthRequiredError(err.message);
3011
+ default:
3012
+ return new UsageError(err.message);
3013
+ }
3014
+ }
3015
+ const msg = err.message.toLowerCase();
3016
+ if (msg.includes("unsupported chain") || msg.includes("invalid chain") || msg.includes("unknown chain")) {
3017
+ const chainMatch = err.message.match(/chain[:\s]*"([^"]+)"/i) || err.message.match(/chain[:\s]+(\S+)/i);
3018
+ return new InvalidChainError(err.message, void 0, void 0, chainMatch ? { chain: chainMatch[1] } : void 0);
1730
3019
  }
1731
- if (isSilent() || isJsonOutput()) {
1732
- throw new Error("Password required but not provided. Set VAULT_PASSWORD or VAULT_PASSWORDS environment variable.");
3020
+ if (msg.includes("invalid address") || msg.includes("bad address") || msg.includes("malformed address")) {
3021
+ const addrMatch = err.message.match(/(0x[a-fA-F0-9]+|bc1[a-z0-9]+|[13][a-km-zA-HJ-NP-Z1-9]+)/i);
3022
+ return new InvalidAddressError(err.message, void 0, void 0, addrMatch ? { address: addrMatch[1] } : void 0);
1733
3023
  }
1734
- const password = await promptForPassword(vaultName, vaultId);
1735
- cachePassword(vaultId, password);
1736
- if (vaultName) cachePassword(vaultName, password);
1737
- return password;
1738
- }
1739
- function createPasswordCallback() {
1740
- return async (vaultId, vaultName) => {
1741
- return getPassword(vaultId, vaultName);
1742
- };
1743
- }
1744
- async function ensureVaultUnlocked(vault, password) {
1745
- if (!vault.isEncrypted || vault.isUnlocked()) {
1746
- return;
3024
+ if (msg.includes("insufficient") && msg.includes("balance")) {
3025
+ return new InsufficientBalanceError(err.message);
1747
3026
  }
1748
- if (password) {
1749
- await vault.unlock(password);
1750
- return;
3027
+ if (msg.includes("no route") || msg.includes("no swap") || msg.includes("no provider")) {
3028
+ return new NoRouteError(err.message);
1751
3029
  }
1752
- const inputPassword = await promptForPassword(vault.name, vault.id);
1753
- await vault.unlock(inputPassword);
1754
- }
1755
-
1756
- // src/adapters/cli-context.ts
1757
- var CLIContext = class extends BaseCommandContext {
1758
- get isInteractive() {
1759
- return false;
3030
+ if (msg.includes("token not found") || msg.includes("unknown token")) {
3031
+ return new TokenNotFoundError(err.message);
1760
3032
  }
1761
- /**
1762
- * Get password for a vault
1763
- * In CLI mode, we check env vars first, then prompt
1764
- * No caching since each command runs independently
1765
- */
1766
- async getPassword(vaultId, vaultName) {
1767
- return getPassword(vaultId, vaultName);
3033
+ if (msg.includes("pricing") || msg.includes("price unavailable") || msg.includes("price service")) {
3034
+ return new PricingUnavailableError(err.message);
1768
3035
  }
1769
- };
3036
+ if (msg.includes("econnrefused") || msg.includes("etimedout") || msg.includes("enotfound") || msg.includes("econnreset") || msg.includes("fetch failed") || msg.includes("network") || msg.includes("socket hang up") || msg.includes("dns")) {
3037
+ return new NetworkError(err.message);
3038
+ }
3039
+ return new UnknownError(err.message);
3040
+ }
3041
+ function toErrorJson(err) {
3042
+ if (err instanceof VsigError) {
3043
+ const json = {
3044
+ success: false,
3045
+ v: 1,
3046
+ error: {
3047
+ code: err.code,
3048
+ exitCode: err.exitCode,
3049
+ message: err.message,
3050
+ hint: err.hint,
3051
+ retryable: err.retryable
3052
+ }
3053
+ };
3054
+ if (err.suggestions?.length) json.error.suggestions = err.suggestions;
3055
+ if (err.context) json.error.context = err.context;
3056
+ return json;
3057
+ }
3058
+ return {
3059
+ success: false,
3060
+ v: 1,
3061
+ error: {
3062
+ code: "UNKNOWN_ERROR",
3063
+ exitCode: 7 /* UNKNOWN */,
3064
+ message: err.message,
3065
+ retryable: false
3066
+ }
3067
+ };
3068
+ }
1770
3069
 
1771
3070
  // src/adapters/cli-runner.ts
1772
3071
  function withExit(handler) {
@@ -1775,17 +3074,18 @@ function withExit(handler) {
1775
3074
  await handler(...args);
1776
3075
  process.exit(0);
1777
3076
  } catch (err) {
1778
- const exitCode = err.exitCode ?? 1;
3077
+ const classified = err instanceof VsigError ? err : err instanceof Error ? classifyError(err) : classifyError(new Error(String(err)));
1779
3078
  if (isJsonOutput()) {
1780
- outputJsonError(err.message, err.code ?? "GENERAL_ERROR");
1781
- process.exit(exitCode);
1782
- }
1783
- if (err.exitCode !== void 0) {
1784
- process.exit(err.exitCode);
3079
+ outputErrorJson(toErrorJson(classified));
3080
+ process.exit(classified.exitCode);
1785
3081
  }
1786
3082
  printError(`
1787
- x ${err.message}`);
1788
- process.exit(1);
3083
+ x ${classified.message}`);
3084
+ if (classified.hint) printError(` hint: ${classified.hint}`);
3085
+ if (classified.suggestions?.length) {
3086
+ for (const s of classified.suggestions) printError(` - ${s}`);
3087
+ }
3088
+ process.exit(classified.exitCode);
1789
3089
  }
1790
3090
  };
1791
3091
  }
@@ -1914,6 +3214,7 @@ function displayVaultsList(vaults, activeVault) {
1914
3214
  printTable(table);
1915
3215
  }
1916
3216
  async function confirmTransaction() {
3217
+ requireInteractive("Use --yes to skip confirmation, or --password to provide password non-interactively.");
1917
3218
  const { confirmed } = await inquirer2.prompt([
1918
3219
  {
1919
3220
  type: "confirm",
@@ -2033,6 +3334,7 @@ function displaySwapChains(chains) {
2033
3334
  Total: ${chains.length} chains`);
2034
3335
  }
2035
3336
  async function confirmSwap() {
3337
+ requireInteractive("Use --yes to skip confirmation, or --password to provide password non-interactively.");
2036
3338
  const { confirmed } = await inquirer2.prompt([
2037
3339
  {
2038
3340
  type: "confirm",
@@ -2121,13 +3423,25 @@ async function executeChains(ctx2, options = {}) {
2121
3423
  return;
2122
3424
  }
2123
3425
  if (options.add) {
2124
- await vault.addChain(options.add);
2125
- success(`
2126
- + Added chain: ${options.add}`);
3426
+ const alreadyActive = vault.chains.includes(options.add);
3427
+ if (!alreadyActive) {
3428
+ await vault.addChain(options.add);
3429
+ }
2127
3430
  const address = await vault.address(options.add);
3431
+ if (isJsonOutput()) {
3432
+ outputJson({ chain: options.add, alreadyActive, address, chains: [...vault.chains] });
3433
+ return;
3434
+ }
3435
+ success(alreadyActive ? `
3436
+ Chain already active: ${options.add}` : `
3437
+ + Added chain: ${options.add}`);
2128
3438
  info(`Address: ${address}`);
2129
3439
  } else if (options.remove) {
2130
3440
  await vault.removeChain(options.remove);
3441
+ if (isJsonOutput()) {
3442
+ outputJson({ chain: options.remove, removed: true, chains: [...vault.chains] });
3443
+ return;
3444
+ }
2131
3445
  success(`
2132
3446
  + Removed chain: ${options.remove}`);
2133
3447
  } else {
@@ -2162,6 +3476,10 @@ import chalk4 from "chalk";
2162
3476
  import inquirer3 from "inquirer";
2163
3477
  async function executeTokens(ctx2, options) {
2164
3478
  await ctx2.ensureActiveVault();
3479
+ if (options.discover) {
3480
+ await discoverTokens(ctx2, options.chain);
3481
+ return;
3482
+ }
2165
3483
  if (options.add) {
2166
3484
  let symbol = options.symbol;
2167
3485
  let name = options.name;
@@ -2193,6 +3511,7 @@ async function executeTokens(ctx2, options) {
2193
3511
  });
2194
3512
  }
2195
3513
  if (prompts.length > 0) {
3514
+ requireInteractive("Provide --symbol, --name, and --decimals flags for non-interactive token addition.");
2196
3515
  const answers = await inquirer3.prompt(prompts);
2197
3516
  symbol = symbol || answers.symbol?.trim();
2198
3517
  name = name || answers.name?.trim();
@@ -2231,6 +3550,57 @@ async function removeToken(ctx2, chain, tokenId) {
2231
3550
  success(`
2232
3551
  + Removed token ${tokenId} from ${chain}`);
2233
3552
  }
3553
+ async function discoverTokens(ctx2, chain) {
3554
+ const vault = await ctx2.ensureActiveVault();
3555
+ const spinner = createSpinner(`Discovering tokens on ${chain}...`);
3556
+ let discovered;
3557
+ try {
3558
+ discovered = await vault.discoverTokens(chain);
3559
+ } catch (err) {
3560
+ spinner.fail(`Token discovery failed for ${chain}`);
3561
+ throw err;
3562
+ }
3563
+ if (discovered.length === 0) {
3564
+ spinner.succeed(`No new tokens found on ${chain}`);
3565
+ if (isJsonOutput()) {
3566
+ outputJson({ chain, discovered: [], count: 0 });
3567
+ }
3568
+ return;
3569
+ }
3570
+ const existingTokens = vault.getTokens(chain);
3571
+ const existingAddresses = new Set(existingTokens.map((t) => t.contractAddress ?? t.id));
3572
+ const newTokens = discovered.filter((d) => d.contractAddress && !existingAddresses.has(d.contractAddress));
3573
+ for (const d of newTokens) {
3574
+ await vault.addToken(chain, {
3575
+ id: d.contractAddress,
3576
+ symbol: d.ticker,
3577
+ name: d.ticker,
3578
+ decimals: d.decimals,
3579
+ contractAddress: d.contractAddress,
3580
+ chainId: chain,
3581
+ isNative: false
3582
+ });
3583
+ }
3584
+ const allTokens = vault.getTokens(chain);
3585
+ spinner.succeed(`Discovered ${newTokens.length} new token(s) on ${chain}`);
3586
+ if (isJsonOutput()) {
3587
+ outputJson({
3588
+ chain,
3589
+ discovered: newTokens.map((d) => ({
3590
+ symbol: d.ticker,
3591
+ contractAddress: d.contractAddress,
3592
+ decimals: d.decimals
3593
+ })),
3594
+ count: newTokens.length
3595
+ });
3596
+ return;
3597
+ }
3598
+ for (const d of newTokens) {
3599
+ printResult(` ${d.ticker} (${d.contractAddress})`);
3600
+ }
3601
+ info(chalk4.gray(`
3602
+ ${allTokens.length} total token(s) tracked on ${chain}`));
3603
+ }
2234
3604
  async function listTokens(ctx2, chain) {
2235
3605
  const vault = await ctx2.ensureActiveVault();
2236
3606
  const spinner = createSpinner(`Loading tokens for ${chain}...`);
@@ -2263,8 +3633,15 @@ Use --add <contractAddress> to add or --remove <tokenId> to remove`));
2263
3633
  }
2264
3634
 
2265
3635
  // src/commands/transaction.ts
2266
- var import_qrcode_terminal = __toESM(require_main(), 1);
2267
3636
  import { Chain, Vultisig as Vultisig2 } from "@vultisig/sdk";
3637
+
3638
+ // src/core/config-store.ts
3639
+ import { getConfigPath, loadConfig, saveConfig } from "@vultisig/client-shared";
3640
+
3641
+ // src/core/vault-discovery.ts
3642
+ import { discoverVaultFiles, SEARCH_DIRS } from "@vultisig/client-shared";
3643
+
3644
+ // src/commands/transaction.ts
2268
3645
  async function executeSend(ctx2, params) {
2269
3646
  const vault = await ctx2.ensureActiveVault();
2270
3647
  if (!Object.values(Chain).includes(params.chain)) {
@@ -2278,59 +3655,59 @@ async function executeSend(ctx2, params) {
2278
3655
  }
2279
3656
  async function sendTransaction(vault, params) {
2280
3657
  const prepareSpinner = createSpinner("Preparing transaction...");
2281
- const address = await vault.address(params.chain);
2282
- const balance = await vault.balance(params.chain, params.tokenId);
2283
- const coin = {
3658
+ const dryResult = await vault.send({
2284
3659
  chain: params.chain,
2285
- address,
2286
- decimals: balance.decimals,
2287
- ticker: balance.symbol,
2288
- id: params.tokenId
2289
- };
2290
- const isMax = params.amount === "max";
2291
- let amount;
2292
- let displayAmount;
2293
- if (isMax) {
2294
- const maxInfo = await vault.getMaxSendAmount({ coin, receiver: params.to, memo: params.memo });
2295
- amount = maxInfo.maxSendable;
2296
- if (amount === 0n) {
2297
- throw new Error("Insufficient balance to cover network fees");
2298
- }
2299
- displayAmount = formatBigintAmount(amount, balance.decimals);
2300
- } else {
2301
- const [whole, frac = ""] = params.amount.split(".");
2302
- if (frac.length > balance.decimals) {
2303
- throw new Error(`Amount has more than ${balance.decimals} decimal places`);
2304
- }
2305
- const paddedFrac = frac.padEnd(balance.decimals, "0");
2306
- amount = BigInt(whole || "0") * 10n ** BigInt(balance.decimals) + BigInt(paddedFrac || "0");
2307
- displayAmount = params.amount;
2308
- }
2309
- const payload = await vault.prepareSendTx({
2310
- coin,
2311
- receiver: params.to,
2312
- amount,
2313
- memo: params.memo
3660
+ to: params.to,
3661
+ amount: params.amount,
3662
+ symbol: params.tokenId,
3663
+ memo: params.memo,
3664
+ dryRun: true
2314
3665
  });
2315
3666
  prepareSpinner.succeed("Transaction prepared");
3667
+ if (!dryResult.dryRun) throw new Error("unreachable");
3668
+ if (params.dryRun) {
3669
+ const balance2 = await vault.balance(params.chain, params.tokenId);
3670
+ const hasInsufficientBalance = parseFloat(dryResult.total) > parseFloat(balance2.formattedAmount);
3671
+ const result = {
3672
+ dryRun: true,
3673
+ chain: params.chain,
3674
+ to: params.to,
3675
+ amount: params.amount,
3676
+ symbol: balance2.symbol,
3677
+ balance: balance2.formattedAmount
3678
+ };
3679
+ if (hasInsufficientBalance) {
3680
+ result.warning = `Insufficient balance: you have ${balance2.formattedAmount} ${balance2.symbol}`;
3681
+ }
3682
+ if (isJsonOutput()) {
3683
+ outputJson(result);
3684
+ } else {
3685
+ info(`
3686
+ Dry-run preview:`);
3687
+ info(` Chain: ${result.chain}`);
3688
+ info(` To: ${result.to}`);
3689
+ info(` Amount: ${result.amount} ${result.symbol}`);
3690
+ info(` Fee: ${dryResult.fee} ${result.symbol}`);
3691
+ info(` Balance: ${result.balance} ${result.symbol}`);
3692
+ if (result.warning) warn(` Warning: ${result.warning}`);
3693
+ }
3694
+ return result;
3695
+ }
2316
3696
  let gas;
2317
3697
  try {
2318
3698
  gas = await vault.gas(params.chain);
2319
3699
  } catch {
2320
3700
  warn("\nGas estimation unavailable");
2321
3701
  }
3702
+ const balance = await vault.balance(params.chain, params.tokenId);
2322
3703
  if (!isJsonOutput()) {
2323
- displayTransactionPreview(
2324
- payload.coin.address,
2325
- params.to,
2326
- displayAmount,
2327
- payload.coin.ticker,
2328
- params.chain,
2329
- params.memo,
2330
- gas
2331
- );
3704
+ const address = await vault.address(params.chain);
3705
+ displayTransactionPreview(address, params.to, dryResult.total, balance.symbol, params.chain, params.memo, gas);
2332
3706
  }
2333
- if (!params.yes && !isJsonOutput()) {
3707
+ if (!params.yes) {
3708
+ if (isNonInteractive()) {
3709
+ throw new Error("Transaction requires confirmation. Use --yes to skip, or --dry-run to preview.");
3710
+ }
2334
3711
  const confirmed = await confirmTransaction();
2335
3712
  if (!confirmed) {
2336
3713
  warn("Transaction cancelled");
@@ -2338,90 +3715,55 @@ async function sendTransaction(vault, params) {
2338
3715
  }
2339
3716
  }
2340
3717
  await ensureVaultUnlocked(vault, params.password);
2341
- const isSecureVault = vault.type === "secure";
2342
- const signSpinner = createSpinner(isSecureVault ? "Preparing secure signing session..." : "Signing transaction...");
3718
+ const signSpinner = createSpinner(
3719
+ vault.type === "secure" ? "Preparing secure signing session..." : "Signing transaction..."
3720
+ );
2343
3721
  vault.on("signingProgress", ({ step }) => {
2344
3722
  signSpinner.text = `${step.message} (${step.progress}%)`;
2345
3723
  });
2346
- if (isSecureVault) {
2347
- vault.on("qrCodeReady", ({ qrPayload }) => {
2348
- if (isJsonOutput()) {
2349
- printResult(qrPayload);
2350
- } else if (isSilent()) {
2351
- printResult(`QR Payload: ${qrPayload}`);
2352
- } else {
2353
- signSpinner.stop();
2354
- info("\nScan this QR code with your Vultisig mobile app to sign:");
2355
- import_qrcode_terminal.default.generate(qrPayload, { small: true });
2356
- info(`
2357
- Or use this URL: ${qrPayload}
2358
- `);
2359
- signSpinner.start("Waiting for devices to join signing session...");
2360
- }
2361
- });
2362
- vault.on(
2363
- "deviceJoined",
2364
- ({ deviceId, totalJoined, required }) => {
2365
- if (!isSilent()) {
2366
- signSpinner.text = `Device joined: ${totalJoined}/${required} (${deviceId})`;
2367
- } else if (!isJsonOutput()) {
2368
- printResult(`Device joined: ${totalJoined}/${required}`);
2369
- }
2370
- }
2371
- );
2372
- }
2373
3724
  try {
2374
- const messageHashes = await vault.extractMessageHashes(payload);
2375
- const signature = await vault.sign(
2376
- {
2377
- transaction: payload,
2378
- chain: payload.coin.chain,
2379
- messageHashes
2380
- },
2381
- { signal: params.signal }
2382
- );
2383
- signSpinner.succeed("Transaction signed");
2384
- const broadcastSpinner = createSpinner("Broadcasting transaction...");
2385
- const txHash = await vault.broadcastTx({
3725
+ const result = await vault.send({
2386
3726
  chain: params.chain,
2387
- keysignPayload: payload,
2388
- signature
3727
+ to: params.to,
3728
+ amount: params.amount,
3729
+ symbol: params.tokenId,
3730
+ memo: params.memo
2389
3731
  });
2390
- broadcastSpinner.succeed(`Transaction broadcast: ${txHash}`);
2391
- const result = {
2392
- txHash,
3732
+ if (result.dryRun) throw new Error("unreachable");
3733
+ const broadcast = result;
3734
+ signSpinner.succeed(`Transaction broadcast: ${broadcast.txHash}`);
3735
+ const txResult = {
3736
+ txHash: broadcast.txHash,
2393
3737
  chain: params.chain,
2394
- explorerUrl: Vultisig2.getTxExplorerUrl(params.chain, txHash)
3738
+ explorerUrl: Vultisig2.getTxExplorerUrl(params.chain, broadcast.txHash)
2395
3739
  };
2396
3740
  if (isJsonOutput()) {
2397
- outputJson(result);
3741
+ outputJson(txResult);
2398
3742
  } else {
2399
- displayTransactionResult(params.chain, txHash);
3743
+ displayTransactionResult(params.chain, broadcast.txHash);
2400
3744
  }
2401
- return result;
3745
+ return txResult;
2402
3746
  } finally {
2403
3747
  vault.removeAllListeners("signingProgress");
2404
- if (isSecureVault) {
2405
- vault.removeAllListeners("qrCodeReady");
2406
- vault.removeAllListeners("deviceJoined");
2407
- }
2408
3748
  }
2409
3749
  }
2410
3750
 
2411
3751
  // src/commands/execute.ts
2412
- var import_qrcode_terminal2 = __toESM(require_main(), 1);
3752
+ var import_qrcode_terminal = __toESM(require_main(), 1);
2413
3753
  import { Vultisig as Vultisig3 } from "@vultisig/sdk";
2414
3754
  var COSMOS_CHAIN_CONFIG = {
2415
3755
  THORChain: {
2416
3756
  chainId: "thorchain-1",
2417
3757
  prefix: "thor",
2418
3758
  denom: "rune",
3759
+ decimals: 8,
2419
3760
  gasLimit: "500000"
2420
3761
  },
2421
3762
  MayaChain: {
2422
3763
  chainId: "mayachain-mainnet-v1",
2423
3764
  prefix: "maya",
2424
3765
  denom: "cacao",
3766
+ decimals: 10,
2425
3767
  gasLimit: "500000"
2426
3768
  }
2427
3769
  };
@@ -2456,8 +3798,42 @@ async function executeContractTransaction(vault, params, chainConfig, msg, funds
2456
3798
  const prepareSpinner = createSpinner("Preparing contract execution...");
2457
3799
  const address = await vault.address(params.chain);
2458
3800
  prepareSpinner.succeed("Transaction prepared");
3801
+ if (params.dryRun) {
3802
+ if (isJsonOutput()) {
3803
+ outputJson({
3804
+ dryRun: true,
3805
+ chain: params.chain,
3806
+ contract: params.contract,
3807
+ msg,
3808
+ funds,
3809
+ address,
3810
+ memo: params.memo
3811
+ });
3812
+ } else {
3813
+ info("\nContract Execution Preview (dry-run)");
3814
+ info("\u2501".repeat(50));
3815
+ info(`Chain: ${params.chain}`);
3816
+ info(`From: ${address}`);
3817
+ info(`Contract: ${params.contract}`);
3818
+ info(
3819
+ `Message: ${JSON.stringify(msg, null, 2).substring(0, 200)}${JSON.stringify(msg).length > 200 ? "..." : ""}`
3820
+ );
3821
+ if (funds.length > 0) {
3822
+ info(`Funds: ${funds.map((f) => `${f.amount} ${f.denom}`).join(", ")}`);
3823
+ }
3824
+ if (params.memo) {
3825
+ info(`Memo: ${params.memo}`);
3826
+ }
3827
+ info("\u2501".repeat(50));
3828
+ }
3829
+ return {
3830
+ txHash: "",
3831
+ chain: params.chain,
3832
+ explorerUrl: ""
3833
+ };
3834
+ }
2459
3835
  if (!isJsonOutput()) {
2460
- info("\n\u{1F4DD} Contract Execution Preview");
3836
+ info("\nContract Execution Preview");
2461
3837
  info("\u2501".repeat(50));
2462
3838
  info(`Chain: ${params.chain}`);
2463
3839
  info(`From: ${address}`);
@@ -2473,7 +3849,10 @@ async function executeContractTransaction(vault, params, chainConfig, msg, funds
2473
3849
  }
2474
3850
  info("\u2501".repeat(50));
2475
3851
  }
2476
- if (!params.yes && !isJsonOutput()) {
3852
+ if (!params.yes) {
3853
+ if (isNonInteractive()) {
3854
+ throw new Error("Transaction requires confirmation. Use --yes to skip, or --dry-run to preview.");
3855
+ }
2477
3856
  const confirmed = await confirmTransaction();
2478
3857
  if (!confirmed) {
2479
3858
  warn("Transaction cancelled");
@@ -2495,7 +3874,7 @@ async function executeContractTransaction(vault, params, chainConfig, msg, funds
2495
3874
  } else {
2496
3875
  signSpinner.stop();
2497
3876
  info("\nScan this QR code with your Vultisig mobile app to sign:");
2498
- import_qrcode_terminal2.default.generate(qrPayload, { small: true });
3877
+ import_qrcode_terminal.default.generate(qrPayload, { small: true });
2499
3878
  info(`
2500
3879
  Or use this URL: ${qrPayload}
2501
3880
  `);
@@ -2518,8 +3897,7 @@ Or use this URL: ${qrPayload}
2518
3897
  const coin = {
2519
3898
  chain: cosmosChain,
2520
3899
  address,
2521
- decimals: 8,
2522
- // THORChain uses 8 decimals
3900
+ decimals: chainConfig.decimals,
2523
3901
  ticker: chainConfig.denom.toUpperCase()
2524
3902
  };
2525
3903
  const executeContractMsg = {
@@ -2580,7 +3958,7 @@ Or use this URL: ${qrPayload}
2580
3958
  }
2581
3959
 
2582
3960
  // src/commands/sign.ts
2583
- var import_qrcode_terminal3 = __toESM(require_main(), 1);
3961
+ var import_qrcode_terminal2 = __toESM(require_main(), 1);
2584
3962
  import { Chain as Chain3 } from "@vultisig/sdk";
2585
3963
  async function executeSignBytes(ctx2, params) {
2586
3964
  const vault = await ctx2.ensureActiveVault();
@@ -2606,7 +3984,7 @@ async function signBytes(vault, params) {
2606
3984
  } else {
2607
3985
  signSpinner.stop();
2608
3986
  info("\nScan this QR code with your Vultisig mobile app to sign:");
2609
- import_qrcode_terminal3.default.generate(qrPayload, { small: true });
3987
+ import_qrcode_terminal2.default.generate(qrPayload, { small: true });
2610
3988
  info(`
2611
3989
  Or use this URL: ${qrPayload}
2612
3990
  `);
@@ -2756,7 +4134,7 @@ function sleep(ms) {
2756
4134
  }
2757
4135
 
2758
4136
  // src/commands/vault-management.ts
2759
- var import_qrcode_terminal4 = __toESM(require_main(), 1);
4137
+ var import_qrcode_terminal3 = __toESM(require_main(), 1);
2760
4138
  import { FastVault } from "@vultisig/sdk";
2761
4139
  import chalk5 from "chalk";
2762
4140
  import { promises as fs } from "fs";
@@ -2904,7 +4282,7 @@ async function executeCreateSecure(ctx2, options) {
2904
4282
  } else {
2905
4283
  spinner.stop();
2906
4284
  info("\nScan this QR code with your Vultisig mobile app:");
2907
- import_qrcode_terminal4.default.generate(qrPayload, { small: true });
4285
+ import_qrcode_terminal3.default.generate(qrPayload, { small: true });
2908
4286
  info(`
2909
4287
  Or use this URL: ${qrPayload}
2910
4288
  `);
@@ -3427,7 +4805,7 @@ async function executeCreateFromSeedphraseSecure(ctx2, options) {
3427
4805
  } else {
3428
4806
  importSpinner.stop();
3429
4807
  info("\nScan this QR code with your Vultisig mobile app:");
3430
- import_qrcode_terminal4.default.generate(qrPayload, { small: true });
4808
+ import_qrcode_terminal3.default.generate(qrPayload, { small: true });
3431
4809
  info(`
3432
4810
  Or use this URL: ${qrPayload}
3433
4811
  `);
@@ -3616,35 +4994,24 @@ async function executeSwapQuote(ctx2, options) {
3616
4994
  if (!isMax && (isNaN(options.amount) || options.amount <= 0)) {
3617
4995
  throw new Error("Invalid amount");
3618
4996
  }
3619
- const isSupported = await vault.isSwapSupported(options.fromChain, options.toChain);
3620
- if (!isSupported) {
3621
- throw new Error(`Swaps from ${options.fromChain} to ${options.toChain} are not supported`);
3622
- }
3623
- let resolvedAmount;
3624
- if (isMax) {
3625
- const bal = await vault.balance(options.fromChain, options.fromToken);
3626
- resolvedAmount = parseFloat(bal.formattedAmount);
3627
- if (resolvedAmount <= 0) {
3628
- throw new Error("Zero balance \u2014 nothing to swap");
3629
- }
3630
- } else {
3631
- resolvedAmount = options.amount;
3632
- }
3633
4997
  const spinner = createSpinner("Getting swap quote...");
3634
- const quote = await vault.getSwapQuote({
3635
- fromCoin: { chain: options.fromChain, token: options.fromToken },
3636
- toCoin: { chain: options.toChain, token: options.toToken },
3637
- amount: resolvedAmount,
3638
- fiatCurrency: "usd"
3639
- // Request fiat conversion
4998
+ const result = await vault.swap({
4999
+ fromChain: options.fromChain,
5000
+ fromSymbol: options.fromToken || "",
5001
+ toChain: options.toChain,
5002
+ toSymbol: options.toToken || "",
5003
+ amount: isMax ? "max" : String(options.amount),
5004
+ dryRun: true
3640
5005
  });
5006
+ if (!result.dryRun) throw new Error("unreachable");
3641
5007
  spinner.succeed("Quote received");
3642
- const fromAmountDisplay = isMax ? `${formatBigintAmount(quote.maxSwapable, quote.fromCoin.decimals)} (max)` : String(resolvedAmount);
5008
+ const quote = result.quote;
5009
+ const fromAmountDisplay = isMax ? `${formatBigintAmount(quote.maxSwapable, quote.fromCoin.decimals)} (max)` : String(options.amount);
3643
5010
  if (isJsonOutput()) {
3644
5011
  outputJson({
3645
5012
  fromChain: options.fromChain,
3646
5013
  toChain: options.toChain,
3647
- amount: resolvedAmount,
5014
+ amount: isMax ? "max" : options.amount,
3648
5015
  isMax,
3649
5016
  quote
3650
5017
  });
@@ -3668,30 +5035,57 @@ async function executeSwap(ctx2, options) {
3668
5035
  if (!isMax && (isNaN(options.amount) || options.amount <= 0)) {
3669
5036
  throw new Error("Invalid amount");
3670
5037
  }
3671
- const isSupported = await vault.isSwapSupported(options.fromChain, options.toChain);
3672
- if (!isSupported) {
3673
- throw new Error(`Swaps from ${options.fromChain} to ${options.toChain} are not supported`);
3674
- }
3675
- let resolvedAmount;
3676
- if (isMax) {
3677
- const bal = await vault.balance(options.fromChain, options.fromToken);
3678
- resolvedAmount = parseFloat(bal.formattedAmount);
3679
- if (resolvedAmount <= 0) {
3680
- throw new Error("Zero balance \u2014 nothing to swap");
3681
- }
3682
- } else {
3683
- resolvedAmount = options.amount;
3684
- }
5038
+ const amountStr = isMax ? "max" : String(options.amount);
3685
5039
  const quoteSpinner = createSpinner("Getting swap quote...");
3686
- const quote = await vault.getSwapQuote({
3687
- fromCoin: { chain: options.fromChain, token: options.fromToken },
3688
- toCoin: { chain: options.toChain, token: options.toToken },
3689
- amount: resolvedAmount,
3690
- fiatCurrency: "usd"
3691
- // Request fiat conversion
5040
+ const dryResult = await vault.swap({
5041
+ fromChain: options.fromChain,
5042
+ fromSymbol: options.fromToken || "",
5043
+ toChain: options.toChain,
5044
+ toSymbol: options.toToken || "",
5045
+ amount: amountStr,
5046
+ dryRun: true
3692
5047
  });
5048
+ if (!dryResult.dryRun) throw new Error("unreachable");
3693
5049
  quoteSpinner.succeed("Quote received");
3694
- const fromAmountDisplay = isMax ? `${formatBigintAmount(quote.maxSwapable, quote.fromCoin.decimals)} (max)` : String(resolvedAmount);
5050
+ const quote = dryResult.quote;
5051
+ const fromAmountRaw = isMax ? formatBigintAmount(quote.maxSwapable, quote.fromCoin.decimals) : String(options.amount);
5052
+ const fromAmountDisplay = isMax ? `${fromAmountRaw} (max)` : fromAmountRaw;
5053
+ if (options.dryRun) {
5054
+ const estimatedOutput = formatBigintAmount(quote.estimatedOutput, quote.toCoin.decimals);
5055
+ const result = {
5056
+ dryRun: true,
5057
+ fromChain: String(options.fromChain),
5058
+ fromToken: quote.fromCoin.ticker,
5059
+ toChain: String(options.toChain),
5060
+ toToken: quote.toCoin.ticker,
5061
+ inputAmount: fromAmountRaw,
5062
+ ...isMax && { isMax: true },
5063
+ estimatedOutput,
5064
+ provider: quote.provider
5065
+ };
5066
+ if (quote.estimatedOutputFiat != null) {
5067
+ result.estimatedOutputFiat = parseFloat(quote.estimatedOutputFiat.toFixed(2));
5068
+ }
5069
+ if (quote.requiresApproval) {
5070
+ result.requiresApproval = true;
5071
+ }
5072
+ if (quote.warnings && quote.warnings.length > 0) {
5073
+ result.warnings = [...quote.warnings];
5074
+ }
5075
+ if (isJsonOutput()) {
5076
+ outputJson(result);
5077
+ } else {
5078
+ info(`
5079
+ Dry-run preview:`);
5080
+ info(` From: ${result.inputAmount} ${result.fromToken} (${result.fromChain})`);
5081
+ info(` To: ${result.estimatedOutput} ${result.toToken} (${result.toChain})`);
5082
+ info(` Provider: ${result.provider}`);
5083
+ if (result.estimatedOutputFiat != null) info(` Est. value (USD): $${result.estimatedOutputFiat}`);
5084
+ if (result.requiresApproval) info(` Requires approval: yes`);
5085
+ if (result.warnings?.length) result.warnings.forEach((w) => warn(` Warning: ${w}`));
5086
+ }
5087
+ return result;
5088
+ }
3695
5089
  const feeBalance = await vault.balance(options.fromChain);
3696
5090
  const discountTier = await vault.getDiscountTier();
3697
5091
  if (!isJsonOutput()) {
@@ -3703,86 +5097,43 @@ async function executeSwap(ctx2, options) {
3703
5097
  discountTier
3704
5098
  });
3705
5099
  }
3706
- if (!options.yes && !isJsonOutput()) {
5100
+ if (!options.yes) {
5101
+ if (isNonInteractive()) {
5102
+ throw new Error("Swap requires confirmation. Use --yes to skip, or --dry-run to preview.");
5103
+ }
3707
5104
  const confirmed = await confirmSwap();
3708
5105
  if (!confirmed) {
3709
5106
  warn("Swap cancelled");
3710
5107
  throw new Error("Swap cancelled by user");
3711
5108
  }
3712
5109
  }
3713
- const prepSpinner = createSpinner("Preparing swap transaction...");
3714
- const { keysignPayload, approvalPayload } = await vault.prepareSwapTx({
3715
- fromCoin: { chain: options.fromChain, token: options.fromToken },
3716
- toCoin: { chain: options.toChain, token: options.toToken },
3717
- amount: resolvedAmount,
3718
- swapQuote: quote,
3719
- autoApprove: false
3720
- });
3721
- prepSpinner.succeed("Swap prepared");
3722
5110
  await ensureVaultUnlocked(vault, options.password);
3723
- if (approvalPayload) {
3724
- info("\nToken approval required before swap...");
3725
- const approvalSpinner = createSpinner("Signing approval transaction...");
3726
- vault.on("signingProgress", ({ step }) => {
3727
- approvalSpinner.text = `Approval: ${step.message} (${step.progress}%)`;
3728
- });
3729
- try {
3730
- const approvalHashes = await vault.extractMessageHashes(approvalPayload);
3731
- const approvalSig = await vault.sign(
3732
- {
3733
- transaction: approvalPayload,
3734
- chain: options.fromChain,
3735
- messageHashes: approvalHashes
3736
- },
3737
- { signal: options.signal }
3738
- );
3739
- approvalSpinner.succeed("Approval signed");
3740
- const broadcastApprovalSpinner = createSpinner("Broadcasting approval...");
3741
- const approvalTxHash = await vault.broadcastTx({
3742
- chain: options.fromChain,
3743
- keysignPayload: approvalPayload,
3744
- signature: approvalSig
3745
- });
3746
- broadcastApprovalSpinner.succeed(`Approval broadcast: ${approvalTxHash}`);
3747
- info("Waiting for approval to confirm...");
3748
- await new Promise((resolve) => setTimeout(resolve, 5e3));
3749
- } finally {
3750
- vault.removeAllListeners("signingProgress");
3751
- }
3752
- }
3753
5111
  const signSpinner = createSpinner("Signing swap transaction...");
3754
5112
  vault.on("signingProgress", ({ step }) => {
3755
5113
  signSpinner.text = `${step.message} (${step.progress}%)`;
3756
5114
  });
3757
5115
  try {
3758
- const messageHashes = await vault.extractMessageHashes(keysignPayload);
3759
- const signature = await vault.sign(
3760
- {
3761
- transaction: keysignPayload,
3762
- chain: options.fromChain,
3763
- messageHashes
3764
- },
3765
- { signal: options.signal }
3766
- );
3767
- signSpinner.succeed("Swap transaction signed");
3768
- const broadcastSpinner = createSpinner("Broadcasting swap transaction...");
3769
- const txHash = await vault.broadcastTx({
3770
- chain: options.fromChain,
3771
- keysignPayload,
3772
- signature
5116
+ const result = await vault.swap({
5117
+ fromChain: options.fromChain,
5118
+ fromSymbol: options.fromToken || "",
5119
+ toChain: options.toChain,
5120
+ toSymbol: options.toToken || "",
5121
+ amount: amountStr
3773
5122
  });
3774
- broadcastSpinner.succeed(`Swap broadcast: ${txHash}`);
5123
+ if (result.dryRun) throw new Error("unreachable");
5124
+ const broadcast = result;
5125
+ signSpinner.succeed(`Swap broadcast: ${broadcast.txHash}`);
3775
5126
  if (isJsonOutput()) {
3776
5127
  outputJson({
3777
- txHash,
5128
+ txHash: broadcast.txHash,
3778
5129
  fromChain: options.fromChain,
3779
5130
  toChain: options.toChain,
3780
5131
  quote
3781
5132
  });
3782
5133
  } else {
3783
- displaySwapResult(options.fromChain, options.toChain, txHash, quote, quote.toCoin.decimals);
5134
+ displaySwapResult(options.fromChain, options.toChain, broadcast.txHash, quote, quote.toCoin.decimals);
3784
5135
  }
3785
- return { txHash, quote };
5136
+ return { txHash: broadcast.txHash, quote };
3786
5137
  } finally {
3787
5138
  vault.removeAllListeners("signingProgress");
3788
5139
  }
@@ -4067,20 +5418,31 @@ async function executeRujiraSwap(ctx2, options) {
4067
5418
  slippageBps: options.slippageBps
4068
5419
  });
4069
5420
  quoteSpinner.succeed("Quote received");
4070
- if (isJsonOutput()) {
4071
- const result2 = await client.swap.execute(quote, { slippageBps: options.slippageBps });
4072
- outputJson({ quote, result: result2 });
5421
+ if (options.dryRun) {
5422
+ if (isJsonOutput()) {
5423
+ outputJson({ dryRun: true, quote });
5424
+ } else {
5425
+ printResult("FIN Swap Preview (dry-run)");
5426
+ printResult(` From: ${options.fromAsset}`);
5427
+ printResult(` To: ${options.toAsset}`);
5428
+ printResult(` Amount (in): ${options.amount}`);
5429
+ printResult(` Expected out:${quote.expectedOutput}`);
5430
+ printResult(` Min out: ${quote.minimumOutput}`);
5431
+ printResult(` Contract: ${quote.contractAddress}`);
5432
+ }
4073
5433
  return;
4074
5434
  }
4075
- printResult("FIN Swap Preview");
4076
- printResult(` From: ${options.fromAsset}`);
4077
- printResult(` To: ${options.toAsset}`);
4078
- printResult(` Amount (in): ${options.amount}`);
4079
- printResult(` Expected out:${quote.expectedOutput}`);
4080
- printResult(` Min out: ${quote.minimumOutput}`);
4081
- printResult(` Contract: ${quote.contractAddress}`);
4082
- if (quote.warning) {
4083
- warn(quote.warning);
5435
+ if (!isJsonOutput()) {
5436
+ printResult("FIN Swap Preview");
5437
+ printResult(` From: ${options.fromAsset}`);
5438
+ printResult(` To: ${options.toAsset}`);
5439
+ printResult(` Amount (in): ${options.amount}`);
5440
+ printResult(` Expected out:${quote.expectedOutput}`);
5441
+ printResult(` Min out: ${quote.minimumOutput}`);
5442
+ printResult(` Contract: ${quote.contractAddress}`);
5443
+ if (quote.warning) {
5444
+ warn(quote.warning);
5445
+ }
4084
5446
  }
4085
5447
  if (!options.yes) {
4086
5448
  warn("This command will execute a swap. Re-run with -y/--yes to skip this warning.");
@@ -4089,7 +5451,11 @@ async function executeRujiraSwap(ctx2, options) {
4089
5451
  const execSpinner = createSpinner("Executing FIN swap...");
4090
5452
  const result = await client.swap.execute(quote, { slippageBps: options.slippageBps });
4091
5453
  execSpinner.succeed("Swap submitted");
4092
- printResult(`Tx Hash: ${result.txHash}`);
5454
+ if (isJsonOutput()) {
5455
+ outputJson({ quote, result });
5456
+ } else {
5457
+ printResult(`Tx Hash: ${result.txHash}`);
5458
+ }
4093
5459
  }
4094
5460
  async function executeRujiraWithdraw(ctx2, options) {
4095
5461
  const vault = await ctx2.ensureActiveVault();
@@ -4103,17 +5469,27 @@ async function executeRujiraWithdraw(ctx2, options) {
4103
5469
  maxFeeBps: options.maxFeeBps
4104
5470
  });
4105
5471
  prepSpinner.succeed("Withdrawal prepared");
4106
- if (isJsonOutput()) {
4107
- const result2 = await client.withdraw.execute(prepared);
4108
- outputJson({ prepared, result: result2 });
5472
+ if (options.dryRun) {
5473
+ if (isJsonOutput()) {
5474
+ outputJson({ dryRun: true, prepared });
5475
+ } else {
5476
+ printResult("Withdraw Preview (dry-run)");
5477
+ printResult(` Asset: ${prepared.asset}`);
5478
+ printResult(` Amount: ${prepared.amount}`);
5479
+ printResult(` Destination: ${prepared.destination}`);
5480
+ printResult(` Memo: ${prepared.memo}`);
5481
+ printResult(` Est. fee: ${prepared.estimatedFee}`);
5482
+ }
4109
5483
  return;
4110
5484
  }
4111
- printResult("Withdraw Preview");
4112
- printResult(` Asset: ${prepared.asset}`);
4113
- printResult(` Amount: ${prepared.amount}`);
4114
- printResult(` Destination: ${prepared.destination}`);
4115
- printResult(` Memo: ${prepared.memo}`);
4116
- printResult(` Est. fee: ${prepared.estimatedFee}`);
5485
+ if (!isJsonOutput()) {
5486
+ printResult("Withdraw Preview");
5487
+ printResult(` Asset: ${prepared.asset}`);
5488
+ printResult(` Amount: ${prepared.amount}`);
5489
+ printResult(` Destination: ${prepared.destination}`);
5490
+ printResult(` Memo: ${prepared.memo}`);
5491
+ printResult(` Est. fee: ${prepared.estimatedFee}`);
5492
+ }
4117
5493
  if (!options.yes) {
4118
5494
  warn("This command will broadcast a THORChain MsgDeposit withdrawal. Re-run with -y/--yes to proceed.");
4119
5495
  throw new Error("Confirmation required (use --yes)");
@@ -4121,7 +5497,11 @@ async function executeRujiraWithdraw(ctx2, options) {
4121
5497
  const execSpinner = createSpinner("Broadcasting withdrawal...");
4122
5498
  const result = await client.withdraw.execute(prepared);
4123
5499
  execSpinner.succeed("Withdrawal submitted");
4124
- printResult(`Tx Hash: ${result.txHash}`);
5500
+ if (isJsonOutput()) {
5501
+ outputJson({ prepared, result });
5502
+ } else {
5503
+ printResult(`Tx Hash: ${result.txHash}`);
5504
+ }
4125
5505
  }
4126
5506
 
4127
5507
  // src/commands/discount.ts
@@ -4222,12 +5602,15 @@ function displayDiscountTier(tierInfo) {
4222
5602
  printResult("");
4223
5603
  }
4224
5604
 
5605
+ // src/commands/auth.ts
5606
+ import { executeAuthLogout, executeAuthSetup, executeAuthStatus } from "@vultisig/client-shared";
5607
+
4225
5608
  // src/commands/agent.ts
4226
5609
  import chalk9 from "chalk";
4227
5610
  import Table from "cli-table3";
4228
5611
 
4229
5612
  // src/agent/agentErrors.ts
4230
- import { VaultError, VaultErrorCode, VaultImportError, VaultImportErrorCode } from "@vultisig/sdk";
5613
+ import { VaultError as VaultError2, VaultErrorCode as VaultErrorCode2, VaultImportError as VaultImportError2, VaultImportErrorCode as VaultImportErrorCode2 } from "@vultisig/sdk";
4231
5614
  var AgentErrorCode = /* @__PURE__ */ ((AgentErrorCode3) => {
4232
5615
  AgentErrorCode3["BACKEND_UNREACHABLE"] = "BACKEND_UNREACHABLE";
4233
5616
  AgentErrorCode3["AUTH_FAILED"] = "AUTH_FAILED";
@@ -4249,32 +5632,32 @@ function isAgentErrorCode(value) {
4249
5632
  return AGENT_ERROR_CODE_VALUES.has(value);
4250
5633
  }
4251
5634
  function mapVaultError(err) {
4252
- if (err.code === VaultErrorCode.InvalidConfig && /failed to unlock vault/i.test(err.message)) {
5635
+ if (err.code === VaultErrorCode2.InvalidConfig && /failed to unlock vault/i.test(err.message)) {
4253
5636
  return "AUTH_FAILED" /* AUTH_FAILED */;
4254
5637
  }
4255
5638
  switch (err.code) {
4256
- case VaultErrorCode.Timeout:
5639
+ case VaultErrorCode2.Timeout:
4257
5640
  return "TIMEOUT" /* TIMEOUT */;
4258
- case VaultErrorCode.NetworkError:
4259
- case VaultErrorCode.BalanceFetchFailed:
5641
+ case VaultErrorCode2.NetworkError:
5642
+ case VaultErrorCode2.BalanceFetchFailed:
4260
5643
  return "NETWORK_ERROR" /* NETWORK_ERROR */;
4261
- case VaultErrorCode.SigningFailed:
5644
+ case VaultErrorCode2.SigningFailed:
4262
5645
  return "SIGNING_FAILED" /* SIGNING_FAILED */;
4263
- case VaultErrorCode.BroadcastFailed:
4264
- case VaultErrorCode.GasEstimationFailed:
5646
+ case VaultErrorCode2.BroadcastFailed:
5647
+ case VaultErrorCode2.GasEstimationFailed:
4265
5648
  return "TRANSACTION_FAILED" /* TRANSACTION_FAILED */;
4266
- case VaultErrorCode.NotImplemented:
5649
+ case VaultErrorCode2.NotImplemented:
4267
5650
  return "ACTION_NOT_IMPLEMENTED" /* ACTION_NOT_IMPLEMENTED */;
4268
- case VaultErrorCode.InvalidAmount:
4269
- case VaultErrorCode.UnsupportedChain:
4270
- case VaultErrorCode.UnsupportedToken:
4271
- case VaultErrorCode.ChainNotSupported:
4272
- case VaultErrorCode.InvalidVault:
4273
- case VaultErrorCode.InvalidPublicKey:
4274
- case VaultErrorCode.InvalidChainCode:
4275
- case VaultErrorCode.AddressDerivationFailed:
5651
+ case VaultErrorCode2.InvalidAmount:
5652
+ case VaultErrorCode2.UnsupportedChain:
5653
+ case VaultErrorCode2.UnsupportedToken:
5654
+ case VaultErrorCode2.ChainNotSupported:
5655
+ case VaultErrorCode2.InvalidVault:
5656
+ case VaultErrorCode2.InvalidPublicKey:
5657
+ case VaultErrorCode2.InvalidChainCode:
5658
+ case VaultErrorCode2.AddressDerivationFailed:
4276
5659
  return "INVALID_INPUT" /* INVALID_INPUT */;
4277
- case VaultErrorCode.InvalidConfig:
5660
+ case VaultErrorCode2.InvalidConfig:
4278
5661
  return "INVALID_INPUT" /* INVALID_INPUT */;
4279
5662
  default:
4280
5663
  return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
@@ -4282,9 +5665,9 @@ function mapVaultError(err) {
4282
5665
  }
4283
5666
  function mapVaultImportError(err) {
4284
5667
  switch (err.code) {
4285
- case VaultImportErrorCode.PASSWORD_REQUIRED:
5668
+ case VaultImportErrorCode2.PASSWORD_REQUIRED:
4286
5669
  return "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */;
4287
- case VaultImportErrorCode.INVALID_PASSWORD:
5670
+ case VaultImportErrorCode2.INVALID_PASSWORD:
4288
5671
  return "AUTH_FAILED" /* AUTH_FAILED */;
4289
5672
  default:
4290
5673
  return "INVALID_INPUT" /* INVALID_INPUT */;
@@ -4322,10 +5705,10 @@ function nodeErrCode(err) {
4322
5705
  return void 0;
4323
5706
  }
4324
5707
  function normalizeAgentError(err) {
4325
- if (err instanceof VaultError) {
5708
+ if (err instanceof VaultError2) {
4326
5709
  return { code: mapVaultError(err), message: err.message };
4327
5710
  }
4328
- if (err instanceof VaultImportError) {
5711
+ if (err instanceof VaultImportError2) {
4329
5712
  return { code: mapVaultImportError(err), message: err.message };
4330
5713
  }
4331
5714
  const name = err instanceof Error ? err.name : "";
@@ -4441,10 +5824,10 @@ async function authenticateVault(client, vault, password, maxAttempts = 3) {
4441
5824
  });
4442
5825
  const messageHash = computePersonalSignHash(authMessage);
4443
5826
  let lastError = null;
4444
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
5827
+ for (let attempt2 = 1; attempt2 <= maxAttempts; attempt2++) {
4445
5828
  try {
4446
- if (attempt > 1) {
4447
- process.stderr.write(` Retry ${attempt}/${maxAttempts}...
5829
+ if (attempt2 > 1) {
5830
+ process.stderr.write(` Retry ${attempt2}/${maxAttempts}...
4448
5831
  `);
4449
5832
  }
4450
5833
  const signature = await vault.signBytes({ data: Buffer.from(messageHash), chain: Chain7.Ethereum }, {});
@@ -4461,7 +5844,7 @@ async function authenticateVault(client, vault, password, maxAttempts = 3) {
4461
5844
  };
4462
5845
  } catch (err) {
4463
5846
  lastError = err;
4464
- if (attempt < maxAttempts && err.message?.includes("timeout")) {
5847
+ if (attempt2 < maxAttempts && err.message?.includes("timeout")) {
4465
5848
  continue;
4466
5849
  }
4467
5850
  throw err;
@@ -4522,6 +5905,18 @@ function padTo32Bytes(buf) {
4522
5905
  }
4523
5906
 
4524
5907
  // src/agent/client.ts
5908
+ function v1StatusFromType(type) {
5909
+ switch (type) {
5910
+ case "tool-input-start":
5911
+ case "tool-input-available":
5912
+ case "tool-input-delta":
5913
+ return "running";
5914
+ case "tool-output-available":
5915
+ return "done";
5916
+ default:
5917
+ return void 0;
5918
+ }
5919
+ }
4525
5920
  function sseErrorToMessage(value) {
4526
5921
  if (value == null) return "";
4527
5922
  if (typeof value === "string") return value;
@@ -4625,6 +6020,7 @@ var AgentClient = class {
4625
6020
  transactions: [],
4626
6021
  message: null
4627
6022
  };
6023
+ const toolNameByCallId = /* @__PURE__ */ new Map();
4628
6024
  const reader = res.body.getReader();
4629
6025
  const decoder = new TextDecoder();
4630
6026
  let buffer = "";
@@ -4639,7 +6035,7 @@ var AgentClient = class {
4639
6035
  currentData += (currentData ? "\n" : "") + stripLeadingSpace(line.slice(5));
4640
6036
  } else if (line === "") {
4641
6037
  if (currentData) {
4642
- this.handleSSEEvent(currentEvent || "message", currentData, result, callbacks);
6038
+ this.handleSSEEvent(currentEvent || "message", currentData, result, callbacks, toolNameByCallId);
4643
6039
  }
4644
6040
  currentEvent = "";
4645
6041
  currentData = "";
@@ -4659,7 +6055,7 @@ var AgentClient = class {
4659
6055
  if (done) {
4660
6056
  if (trailing) processLine(trailing);
4661
6057
  if (currentData) {
4662
- this.handleSSEEvent(currentEvent || "message", currentData, result, callbacks);
6058
+ this.handleSSEEvent(currentEvent || "message", currentData, result, callbacks, toolNameByCallId);
4663
6059
  }
4664
6060
  break;
4665
6061
  }
@@ -4669,49 +6065,75 @@ var AgentClient = class {
4669
6065
  }
4670
6066
  return result;
4671
6067
  }
4672
- handleSSEEvent(event, data, result, callbacks) {
6068
+ handleSSEEvent(event, data, result, callbacks, toolNameByCallId) {
4673
6069
  try {
4674
6070
  const parsed = JSON.parse(data);
4675
- switch (event) {
6071
+ const v1Type = typeof parsed?.type === "string" && parsed.type.length > 0 ? parsed.type : null;
6072
+ const routingEvent = v1Type ? this.mapV1EventType(v1Type) : event;
6073
+ const v1Data = typeof parsed?.type === "string" && parsed.type.startsWith("data-") ? parsed.data : null;
6074
+ switch (routingEvent) {
4676
6075
  case "text_delta":
4677
6076
  if (typeof parsed.delta === "string") {
4678
6077
  result.fullText += parsed.delta;
4679
6078
  callbacks.onTextDelta?.(parsed.delta);
4680
6079
  }
4681
6080
  break;
4682
- case "tool_progress":
6081
+ case "tool_progress": {
4683
6082
  if (this.verbose) process.stderr.write(`[SSE:tool_progress] raw: ${data.slice(0, 1e3)}
4684
6083
  `);
4685
- callbacks.onToolProgress?.(parsed.tool, parsed.status, parsed.label);
6084
+ const v1Status = v1StatusFromType(v1Type);
6085
+ const status = parsed.status ?? v1Status;
6086
+ const callId = typeof parsed.toolCallId === "string" ? parsed.toolCallId : null;
6087
+ const rawInlineName = parsed.tool ?? parsed.toolName;
6088
+ const inlineName = typeof rawInlineName === "string" && rawInlineName.length > 0 ? rawInlineName : void 0;
6089
+ if (callId && inlineName) {
6090
+ toolNameByCallId.set(callId, inlineName);
6091
+ }
6092
+ const toolName = inlineName ?? (callId ? toolNameByCallId.get(callId) : void 0);
6093
+ const label = typeof parsed.label === "string" ? parsed.label : void 0;
6094
+ if (status && toolName) {
6095
+ callbacks.onToolProgress?.(toolName, status, label);
6096
+ }
6097
+ if (status === "done" && callId) toolNameByCallId.delete(callId);
4686
6098
  break;
4687
- case "title":
4688
- callbacks.onTitle?.(parsed.title);
6099
+ }
6100
+ case "title": {
6101
+ const title = v1Data?.title ?? parsed.title;
6102
+ if (typeof title === "string") callbacks.onTitle?.(title);
4689
6103
  break;
4690
- case "actions":
6104
+ }
6105
+ case "actions": {
4691
6106
  if (this.verbose) process.stderr.write(`[SSE:actions] raw: ${data.slice(0, 1e3)}
4692
6107
  `);
4693
- result.actions.push(...parsed.actions || []);
4694
- callbacks.onActions?.(parsed.actions || []);
6108
+ const actions = v1Data?.actions ?? parsed.actions ?? [];
6109
+ result.actions.push(...actions);
6110
+ callbacks.onActions?.(actions);
4695
6111
  break;
4696
- case "suggestions":
4697
- result.suggestions.push(...parsed.suggestions || []);
4698
- callbacks.onSuggestions?.(parsed.suggestions || []);
6112
+ }
6113
+ case "suggestions": {
6114
+ const suggestions = v1Data?.suggestions ?? parsed.suggestions ?? [];
6115
+ result.suggestions.push(...suggestions);
6116
+ callbacks.onSuggestions?.(suggestions);
4699
6117
  break;
6118
+ }
4700
6119
  case "tx_ready":
4701
6120
  if (this.verbose) process.stderr.write(`[SSE:tx_ready] raw: ${data.slice(0, 2e3)}
4702
6121
  `);
4703
6122
  {
4704
- const txReady = parsed;
6123
+ const txReady = v1Data ?? parsed;
4705
6124
  result.transactions.push(txReady);
4706
6125
  callbacks.onTxReady?.(txReady);
4707
6126
  }
4708
6127
  break;
4709
- case "message":
4710
- result.message = parsed.message || parsed;
6128
+ case "message": {
6129
+ const msg = v1Data?.message ?? parsed.message ?? parsed;
6130
+ result.message = msg;
4711
6131
  callbacks.onMessage?.(result.message);
4712
6132
  break;
6133
+ }
4713
6134
  case "error": {
4714
- const msg = sseErrorToMessage(parsed.error);
6135
+ const errorText = typeof parsed.errorText === "string" ? parsed.errorText : parsed.error;
6136
+ const msg = sseErrorToMessage(errorText);
4715
6137
  const codeFromBackend = typeof parsed.code === "string" && isAgentErrorCode(parsed.code) ? parsed.code : inferAgentErrorCodeFromMessage(msg);
4716
6138
  callbacks.onError?.(msg, codeFromBackend);
4717
6139
  break;
@@ -4728,6 +6150,37 @@ var AgentClient = class {
4728
6150
  }
4729
6151
  }
4730
6152
  }
6153
+ // Maps a V1 `type` field to the legacy event bucket used by handleSSEEvent's
6154
+ // switch. Frame-level types (start, text-start, text-end, finish-step) and
6155
+ // non-critical telemetry (data-tokens, data-usage, data-confirmation) route
6156
+ // to 'ignore' which is a no-op.
6157
+ mapV1EventType(type) {
6158
+ switch (type) {
6159
+ case "text-delta":
6160
+ return "text_delta";
6161
+ case "tool-input-start":
6162
+ case "tool-input-available":
6163
+ case "tool-input-delta":
6164
+ case "tool-output-available":
6165
+ return "tool_progress";
6166
+ case "data-title":
6167
+ return "title";
6168
+ case "data-actions":
6169
+ return "actions";
6170
+ case "data-suggestions":
6171
+ return "suggestions";
6172
+ case "data-tx_ready":
6173
+ return "tx_ready";
6174
+ case "data-message":
6175
+ return "message";
6176
+ case "error":
6177
+ return "error";
6178
+ case "finish":
6179
+ return "done";
6180
+ default:
6181
+ return "ignore";
6182
+ }
6183
+ }
4731
6184
  // ============================================================================
4732
6185
  // Calldata
4733
6186
  // ============================================================================
@@ -4922,9 +6375,9 @@ function getNativeTokenDecimals(chain) {
4922
6375
  }
4923
6376
 
4924
6377
  // src/agent/executor.ts
4925
- import { Chain as Chain9, evmCall, fiatCurrencies as fiatCurrencies3, Vultisig as VultisigSdk } from "@vultisig/sdk";
6378
+ import { Chain as Chain10, evmCall, fiatCurrencies as fiatCurrencies3, Vultisig as VultisigSdk } from "@vultisig/sdk";
4926
6379
 
4927
- // node_modules/viem/_esm/index.js
6380
+ // ../../node_modules/viem/_esm/index.js
4928
6381
  init_formatUnits();
4929
6382
 
4930
6383
  // src/core/VaultStateStore.ts
@@ -5102,7 +6555,10 @@ var AUTO_EXECUTE_ACTIONS = /* @__PURE__ */ new Set([
5102
6555
  "sign_tx",
5103
6556
  "sign_typed_data",
5104
6557
  "read_evm_contract",
5105
- "scan_tx"
6558
+ "scan_tx",
6559
+ "thorchain_pool_info",
6560
+ "thorchain_add_liquidity",
6561
+ "thorchain_remove_liquidity"
5106
6562
  ]);
5107
6563
  var PASSWORD_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["sign_tx", "sign_typed_data", "build_custom_tx"]);
5108
6564
 
@@ -5137,7 +6593,7 @@ var EVM_GAS_RPC = {
5137
6593
  Hyperliquid: "https://rpc.hyperliquid.xyz/evm",
5138
6594
  Sei: "https://evm-rpc.sei-apis.com"
5139
6595
  };
5140
- var AgentExecutor = class {
6596
+ var AgentExecutor = class _AgentExecutor {
5141
6597
  vault;
5142
6598
  /** Owning SDK (optional); used for address book backed by app storage */
5143
6599
  vultisig;
@@ -5147,6 +6603,7 @@ var AgentExecutor = class {
5147
6603
  stateStore = null;
5148
6604
  /** Held chain lock release functions, keyed by chain name */
5149
6605
  chainLockReleases = /* @__PURE__ */ new Map();
6606
+ evmLastBroadcast = /* @__PURE__ */ new Map();
5150
6607
  /** Backend client for resolving calldata_id references. */
5151
6608
  backendClient = null;
5152
6609
  constructor(vault, verbose = false, vaultId, vultisig) {
@@ -5187,7 +6644,7 @@ var AgentExecutor = class {
5187
6644
  `);
5188
6645
  return false;
5189
6646
  }
5190
- const chain = resolveChainFromTxReady(txReadyData) || Chain9.Ethereum;
6647
+ const chain = resolveChainFromTxReady(txReadyData) || Chain10.Ethereum;
5191
6648
  this.pendingPayloads.clear();
5192
6649
  this.pendingPayloads.set("latest", {
5193
6650
  payload: { __serverTx: true, ...txReadyData },
@@ -5276,6 +6733,12 @@ var AgentExecutor = class {
5276
6733
  return this.scanTx(params);
5277
6734
  case "read_evm_contract":
5278
6735
  return this.readEvmContract(params);
6736
+ case "thorchain_pool_info":
6737
+ return this.thorchainPoolInfo(params);
6738
+ case "thorchain_add_liquidity":
6739
+ return this.thorchainAddLiquidity(params);
6740
+ case "thorchain_remove_liquidity":
6741
+ return this.thorchainRemoveLiquidity(params);
5279
6742
  default:
5280
6743
  throw new Error(
5281
6744
  `Action type '${action.type}' is not implemented locally. The backend may handle this action server-side.`
@@ -5545,6 +7008,227 @@ var AgentExecutor = class {
5545
7008
  throw err;
5546
7009
  }
5547
7010
  }
7011
+ // ============================================================================
7012
+ // THORChain LP (RUNE-side asym add / remove via prepareSendTx + memo)
7013
+ // ============================================================================
7014
+ /**
7015
+ * Pool stats from Midgard (no signing). Optional `pool` filters to one row.
7016
+ */
7017
+ async thorchainPoolInfo(params) {
7018
+ const { assertValidPoolId: assertValidPoolId2, getThorchainPools: getThorchainPools2, thorchainMidgardBaseUrl: thorchainMidgardBaseUrl2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
7019
+ const statusRaw = params.status;
7020
+ let poolFetchOpts = {};
7021
+ if (statusRaw === null || String(statusRaw).toLowerCase() === "all") {
7022
+ poolFetchOpts = { status: null };
7023
+ } else if (statusRaw !== void 0) {
7024
+ poolFetchOpts = { status: String(statusRaw) };
7025
+ }
7026
+ const pools = await getThorchainPools2(poolFetchOpts);
7027
+ const poolArg = params.pool;
7028
+ if (poolArg) {
7029
+ const normalized = poolArg.trim().toUpperCase();
7030
+ assertValidPoolId2(normalized);
7031
+ const row = pools.find((p) => p.asset.toUpperCase() === normalized);
7032
+ return {
7033
+ found: !!row,
7034
+ pool_id: normalized,
7035
+ summary: row ?? null,
7036
+ midgard: thorchainMidgardBaseUrl2
7037
+ };
7038
+ }
7039
+ const limitRaw = params.limit;
7040
+ const limit = Math.min(500, Math.max(1, typeof limitRaw === "number" ? limitRaw : Number(limitRaw) || 80));
7041
+ return {
7042
+ pools: pools.slice(0, limit),
7043
+ total: pools.length,
7044
+ midgard: thorchainMidgardBaseUrl2
7045
+ };
7046
+ }
7047
+ async thorchainAddLiquidity(params) {
7048
+ const { assertValidPoolId: assertValidPoolId2, buildThorchainLpAddPayload: buildThorchainLpAddPayload2, resolvePairedAddressForLpAdd: resolvePairedAddressForLpAdd2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
7049
+ const { getThorchainInboundAddress: getThorchainInboundAddress2 } = await Promise.resolve().then(() => (init_getThorchainInboundAddress(), getThorchainInboundAddress_exports));
7050
+ const pool = this.normalizeThorchainPoolId(params.pool, assertValidPoolId2);
7051
+ const amountStr = String(params.amount ?? "").trim();
7052
+ if (!amountStr) {
7053
+ throw new Error('amount is required (RUNE amount as a decimal string, e.g. "0.25")');
7054
+ }
7055
+ if (!/^\d+(\.\d+)?$/.test(amountStr)) {
7056
+ throw new Error('amount must be a positive decimal string (no sign or scientific notation), e.g. "0.25"');
7057
+ }
7058
+ const [, frac = ""] = amountStr.split(".");
7059
+ if (frac.length > 8) {
7060
+ throw new Error("RUNE amount supports at most 8 decimal places");
7061
+ }
7062
+ const amountRuneBaseUnits = parseAmount(amountStr, 8);
7063
+ if (amountRuneBaseUnits <= 0n) {
7064
+ throw new Error("amount must be greater than zero");
7065
+ }
7066
+ let pairedAddress = params.paired_address?.trim() || void 0;
7067
+ const autoPairRaw = params.auto_pair ?? params.autoPair;
7068
+ const autoPairDisabled = autoPairRaw === false || autoPairRaw === 0 || typeof autoPairRaw === "string" && ["false", "0"].includes(autoPairRaw.toLowerCase());
7069
+ const autoPair = !pairedAddress && !autoPairDisabled;
7070
+ if (autoPair) {
7071
+ const vaultAddresses = await this.buildVaultAddressMap();
7072
+ pairedAddress = resolvePairedAddressForLpAdd2({
7073
+ pool,
7074
+ side: "rune",
7075
+ vaultAddresses
7076
+ }) || void 0;
7077
+ }
7078
+ const lpPayload = buildThorchainLpAddPayload2({
7079
+ pool,
7080
+ amountRuneBaseUnits: amountRuneBaseUnits.toString(),
7081
+ ...pairedAddress ? { pairedAddress } : {}
7082
+ });
7083
+ const receiver = await this.getThorchainNativeInboundAddress(getThorchainInboundAddress2);
7084
+ const address = await this.vault.address(Chain10.THORChain);
7085
+ const coin = {
7086
+ chain: Chain10.THORChain,
7087
+ address,
7088
+ decimals: 8,
7089
+ ticker: "RUNE"
7090
+ };
7091
+ const payload = await this.vault.prepareSendTx({
7092
+ coin,
7093
+ receiver,
7094
+ amount: BigInt(lpPayload.amount),
7095
+ memo: lpPayload.memo
7096
+ });
7097
+ const messageHashes = await this.vault.extractMessageHashes(payload);
7098
+ this.pendingPayloads.clear();
7099
+ const payloadId = `tc_lp_add_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
7100
+ this.pendingPayloads.set(payloadId, {
7101
+ payload,
7102
+ coin,
7103
+ chain: Chain10.THORChain,
7104
+ timestamp: Date.now()
7105
+ });
7106
+ this.pendingPayloads.set("latest", {
7107
+ payload,
7108
+ coin,
7109
+ chain: Chain10.THORChain,
7110
+ timestamp: Date.now()
7111
+ });
7112
+ return {
7113
+ keysign_payload: payloadId,
7114
+ chain: "THORChain",
7115
+ pool: lpPayload.pool,
7116
+ memo: lpPayload.memo,
7117
+ amount_rune: amountStr,
7118
+ paired_address: pairedAddress,
7119
+ inbound_receiver: receiver,
7120
+ sender: address,
7121
+ message_hashes: messageHashes
7122
+ };
7123
+ }
7124
+ async thorchainRemoveLiquidity(params) {
7125
+ const { assertValidPoolId: assertValidPoolId2, buildThorchainLpRemovePayload: buildThorchainLpRemovePayload2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
7126
+ const { getThorchainInboundAddress: getThorchainInboundAddress2 } = await Promise.resolve().then(() => (init_getThorchainInboundAddress(), getThorchainInboundAddress_exports));
7127
+ const pool = this.normalizeThorchainPoolId(params.pool, assertValidPoolId2);
7128
+ let basisPoints;
7129
+ if (params.basis_points != null) {
7130
+ basisPoints = Number(params.basis_points);
7131
+ } else if (params.basisPoints != null) {
7132
+ basisPoints = Number(params.basisPoints);
7133
+ }
7134
+ if (basisPoints == null && params.withdraw_percent != null) {
7135
+ const pct = Number(params.withdraw_percent);
7136
+ if (Number.isFinite(pct)) {
7137
+ basisPoints = Math.round(pct * 100);
7138
+ }
7139
+ }
7140
+ if (basisPoints == null || !Number.isInteger(basisPoints)) {
7141
+ throw new Error("basis_points (integer 1\u201310000) or withdraw_percent (0.01\u2013100, maps to basis points) is required");
7142
+ }
7143
+ let withdrawToAsset = params.withdraw_to_asset?.trim();
7144
+ if (!withdrawToAsset && params.withdrawToAsset) {
7145
+ withdrawToAsset = String(params.withdrawToAsset).trim();
7146
+ }
7147
+ if (withdrawToAsset) {
7148
+ withdrawToAsset = withdrawToAsset.toUpperCase();
7149
+ }
7150
+ const lpPayload = buildThorchainLpRemovePayload2({
7151
+ pool,
7152
+ basisPoints,
7153
+ ...withdrawToAsset ? { withdrawToAsset } : {}
7154
+ });
7155
+ const receiver = await this.getThorchainNativeInboundAddress(getThorchainInboundAddress2);
7156
+ const address = await this.vault.address(Chain10.THORChain);
7157
+ const coin = {
7158
+ chain: Chain10.THORChain,
7159
+ address,
7160
+ decimals: 8,
7161
+ ticker: "RUNE"
7162
+ };
7163
+ const payload = await this.vault.prepareSendTx({
7164
+ coin,
7165
+ receiver,
7166
+ amount: BigInt(lpPayload.amount),
7167
+ memo: lpPayload.memo
7168
+ });
7169
+ const messageHashes = await this.vault.extractMessageHashes(payload);
7170
+ this.pendingPayloads.clear();
7171
+ const payloadId = `tc_lp_rm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
7172
+ this.pendingPayloads.set(payloadId, {
7173
+ payload,
7174
+ coin,
7175
+ chain: Chain10.THORChain,
7176
+ timestamp: Date.now()
7177
+ });
7178
+ this.pendingPayloads.set("latest", {
7179
+ payload,
7180
+ coin,
7181
+ chain: Chain10.THORChain,
7182
+ timestamp: Date.now()
7183
+ });
7184
+ return {
7185
+ keysign_payload: payloadId,
7186
+ chain: "THORChain",
7187
+ pool: lpPayload.pool,
7188
+ memo: lpPayload.memo,
7189
+ basis_points: basisPoints,
7190
+ withdraw_to_asset: withdrawToAsset || void 0,
7191
+ dust_rune_base_units: lpPayload.amount,
7192
+ inbound_receiver: receiver,
7193
+ sender: address,
7194
+ message_hashes: messageHashes
7195
+ };
7196
+ }
7197
+ normalizeThorchainPoolId(raw, assertValidPoolId2) {
7198
+ const pool = String(raw ?? "").trim();
7199
+ if (!pool) {
7200
+ throw new Error('pool is required (e.g. "BTC.BTC")');
7201
+ }
7202
+ const upper = pool.toUpperCase();
7203
+ assertValidPoolId2(upper);
7204
+ return upper;
7205
+ }
7206
+ async buildVaultAddressMap() {
7207
+ const map = {};
7208
+ for (const c of this.vault.chains) {
7209
+ try {
7210
+ map[c] = await this.vault.address(c);
7211
+ } catch {
7212
+ }
7213
+ }
7214
+ return map;
7215
+ }
7216
+ /** THORChain protocol vault for native RUNE deposits (SWAP/LP memos). Matches SDK e2e fixture. */
7217
+ static THORCHAIN_RUNE_DEPOSIT_ADDRESS = "thor1g98cy3n9mmjrpn0sxmn63lztelera37n8n67c0";
7218
+ async getThorchainNativeInboundAddress(getInbound) {
7219
+ const rows = await getInbound();
7220
+ const thor = rows.find((r) => r.chain.toUpperCase() === "THOR");
7221
+ if (thor?.address) {
7222
+ return thor.address;
7223
+ }
7224
+ if (this.verbose) {
7225
+ process.stderr.write(
7226
+ `[thorchain_lp] THOR inbound row missing; using static RUNE deposit vault ${_AgentExecutor.THORCHAIN_RUNE_DEPOSIT_ADDRESS}
7227
+ `
7228
+ );
7229
+ }
7230
+ return _AgentExecutor.THORCHAIN_RUNE_DEPOSIT_ADDRESS;
7231
+ }
5548
7232
  async buildTx(params) {
5549
7233
  if (params.calldata_id && !params.data && this.backendClient) {
5550
7234
  const id = params.calldata_id;
@@ -5576,7 +7260,7 @@ var AgentExecutor = class {
5576
7260
  if (!stored) {
5577
7261
  throw new Error("Could not stage calldata transaction for signing (invalid or empty tx payload)");
5578
7262
  }
5579
- const chain = resolveChain(params.chain) || Chain9.Ethereum;
7263
+ const chain = resolveChain(params.chain) || Chain10.Ethereum;
5580
7264
  const address = await this.vault.address(chain);
5581
7265
  return {
5582
7266
  status: "ready",
@@ -5693,6 +7377,7 @@ var AgentExecutor = class {
5693
7377
  keysignPayload: payload,
5694
7378
  signature
5695
7379
  });
7380
+ this.evmLastBroadcast.set(chain.toString(), Date.now());
5696
7381
  try {
5697
7382
  this.recordEvmNonceFromPayload(chain, payload, messageHashes.length);
5698
7383
  } catch (nonceErr) {
@@ -5790,6 +7475,7 @@ var AgentExecutor = class {
5790
7475
  keysignPayload,
5791
7476
  signature
5792
7477
  });
7478
+ this.evmLastBroadcast.set(chain.toString(), Date.now());
5793
7479
  try {
5794
7480
  this.recordEvmNonceFromPayload(chain, keysignPayload, messageHashes.length);
5795
7481
  } catch (nonceErr) {
@@ -5948,6 +7634,16 @@ var AgentExecutor = class {
5948
7634
  const rpcNonce = bs.value.nonce;
5949
7635
  const nextNonce = this.stateStore.getNextEvmNonce(chain, rpcNonce);
5950
7636
  if (nextNonce !== rpcNonce) {
7637
+ const lastBroadcast = this.evmLastBroadcast.get(chain.toString()) ?? 0;
7638
+ if (Date.now() - lastBroadcast < 15e3) {
7639
+ if (this.verbose)
7640
+ process.stderr.write(
7641
+ `[nonce] Keeping local nonce ${nextNonce} for ${chain} (broadcast ${Date.now() - lastBroadcast}ms ago)
7642
+ `
7643
+ );
7644
+ bs.value.nonce = nextNonce;
7645
+ return;
7646
+ }
5951
7647
  const pendingNonce = await this.fetchEvmPendingNonce(chain);
5952
7648
  if (pendingNonce !== null && pendingNonce === rpcNonce) {
5953
7649
  if (this.verbose)
@@ -6115,11 +7811,11 @@ var AgentExecutor = class {
6115
7811
  `);
6116
7812
  const chainName = params.chain;
6117
7813
  const chainId = domain.chainId;
6118
- let chain = Chain9.Ethereum;
7814
+ let chain = Chain10.Ethereum;
6119
7815
  if (chainName) {
6120
- chain = resolveChain(chainName) || Chain9.Ethereum;
7816
+ chain = resolveChain(chainName) || Chain10.Ethereum;
6121
7817
  } else if (chainId) {
6122
- chain = resolveChainId(chainId) || Chain9.Ethereum;
7818
+ chain = resolveChainId(chainId) || Chain10.Ethereum;
6123
7819
  }
6124
7820
  const sigResult = await this.vault.signBytes({
6125
7821
  data: eip712Hash,
@@ -6189,7 +7885,7 @@ var AgentExecutor = class {
6189
7885
  return { tokens };
6190
7886
  }
6191
7887
  const out = [];
6192
- for (const c of Object.values(Chain9)) {
7888
+ for (const c of Object.values(Chain10)) {
6193
7889
  for (const t of VultisigSdk.getKnownTokens(c)) {
6194
7890
  if (!tokenMatchesQuery(t)) continue;
6195
7891
  out.push(t);
@@ -6272,11 +7968,11 @@ function abiEncodeParam(type, value) {
6272
7968
  }
6273
7969
  function resolveChain(name) {
6274
7970
  if (!name) return null;
6275
- if (Object.values(Chain9).includes(name)) {
7971
+ if (Object.values(Chain10).includes(name)) {
6276
7972
  return name;
6277
7973
  }
6278
7974
  const lower = name.toLowerCase();
6279
- for (const [, value] of Object.entries(Chain9)) {
7975
+ for (const [, value] of Object.entries(Chain10)) {
6280
7976
  if (typeof value === "string" && value.toLowerCase() === lower) {
6281
7977
  return value;
6282
7978
  }
@@ -6302,7 +7998,7 @@ function resolveChain(name) {
6302
7998
  xrp: "Ripple"
6303
7999
  };
6304
8000
  const aliased = aliases[lower];
6305
- if (aliased && Object.values(Chain9).includes(aliased)) {
8001
+ if (aliased && Object.values(Chain10).includes(aliased)) {
6306
8002
  return aliased;
6307
8003
  }
6308
8004
  return null;
@@ -6336,16 +8032,16 @@ function resolveChainId(chainId) {
6336
8032
  const id = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
6337
8033
  if (isNaN(id)) return null;
6338
8034
  const chainIdMap = {
6339
- 1: Chain9.Ethereum,
6340
- 56: Chain9.BSC,
6341
- 137: Chain9.Polygon,
6342
- 43114: Chain9.Avalanche,
6343
- 42161: Chain9.Arbitrum,
6344
- 10: Chain9.Optimism,
6345
- 8453: Chain9.Base,
6346
- 81457: Chain9.Blast,
6347
- 324: Chain9.Zksync,
6348
- 25: Chain9.CronosChain
8035
+ 1: Chain10.Ethereum,
8036
+ 56: Chain10.BSC,
8037
+ 137: Chain10.Polygon,
8038
+ 43114: Chain10.Avalanche,
8039
+ 42161: Chain10.Arbitrum,
8040
+ 10: Chain10.Optimism,
8041
+ 8453: Chain10.Base,
8042
+ 81457: Chain10.Blast,
8043
+ 324: Chain10.Zksync,
8044
+ 25: Chain10.CronosChain
6349
8045
  };
6350
8046
  return chainIdMap[id] || null;
6351
8047
  }
@@ -7524,15 +9220,13 @@ async function executeAgentAsk(ctx2, message, options) {
7524
9220
  const callbacks = ask.getCallbacks();
7525
9221
  await session.initialize(callbacks);
7526
9222
  const result = await ask.ask(message);
7527
- if (options.json) {
7528
- process.stdout.write(
7529
- JSON.stringify({
7530
- session_id: result.sessionId,
7531
- response: result.response,
7532
- tool_calls: result.toolCalls,
7533
- transactions: result.transactions
7534
- }) + "\n"
7535
- );
9223
+ if (options.json || isJsonOutput()) {
9224
+ outputJson({
9225
+ session_id: result.sessionId,
9226
+ response: result.response,
9227
+ tool_calls: result.toolCalls,
9228
+ transactions: result.transactions
9229
+ });
7536
9230
  } else {
7537
9231
  process.stdout.write(`session:${result.sessionId}
7538
9232
  `);
@@ -7598,46 +9292,294 @@ async function executeAgentSessionsList(ctx2, options) {
7598
9292
  printResult("No sessions found.");
7599
9293
  return;
7600
9294
  }
7601
- const table = new Table({
7602
- head: [chalk9.cyan("ID"), chalk9.cyan("Title"), chalk9.cyan("Created"), chalk9.cyan("Updated")]
7603
- });
7604
- for (const conv of allConversations) {
7605
- table.push([
7606
- conv.id,
7607
- conv.title || chalk9.gray("(untitled)"),
7608
- formatDate(conv.created_at),
7609
- formatDate(conv.updated_at)
7610
- ]);
9295
+ const table = new Table({
9296
+ head: [chalk9.cyan("ID"), chalk9.cyan("Title"), chalk9.cyan("Created"), chalk9.cyan("Updated")]
9297
+ });
9298
+ for (const conv of allConversations) {
9299
+ table.push([
9300
+ conv.id,
9301
+ conv.title || chalk9.gray("(untitled)"),
9302
+ formatDate(conv.created_at),
9303
+ formatDate(conv.updated_at)
9304
+ ]);
9305
+ }
9306
+ printResult(table.toString());
9307
+ printResult(chalk9.gray(`
9308
+ ${totalCount} session(s) total`));
9309
+ }
9310
+ async function executeAgentSessionsDelete(ctx2, sessionId, options) {
9311
+ const vault = await ctx2.ensureActiveVault();
9312
+ const backendUrl = options.backendUrl || process.env.VULTISIG_AGENT_URL || "https://abe.vultisig.com";
9313
+ const client = await createAuthenticatedClient(backendUrl, vault, options.password);
9314
+ const publicKey = vault.publicKeys.ecdsa;
9315
+ await client.deleteConversation(sessionId, publicKey);
9316
+ if (isJsonOutput()) {
9317
+ outputJson({ deleted: sessionId });
9318
+ return;
9319
+ }
9320
+ printResult(chalk9.green(`Session ${sessionId} deleted.`));
9321
+ }
9322
+ async function createAuthenticatedClient(backendUrl, vault, password) {
9323
+ const client = new AgentClient(backendUrl);
9324
+ const auth = await authenticateVault(client, vault, password);
9325
+ client.setAuthToken(auth.token);
9326
+ return client;
9327
+ }
9328
+ function formatDate(iso) {
9329
+ try {
9330
+ const d = new Date(iso);
9331
+ return d.toLocaleDateString() + " " + d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
9332
+ } catch {
9333
+ return iso;
9334
+ }
9335
+ }
9336
+
9337
+ // src/lib/version.ts
9338
+ import chalk10 from "chalk";
9339
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync2 } from "fs";
9340
+ import { homedir as homedir3 } from "os";
9341
+ import { join as join3 } from "path";
9342
+ var cachedVersion = null;
9343
+ function getVersion() {
9344
+ if (cachedVersion) return cachedVersion;
9345
+ if (true) {
9346
+ cachedVersion = "0.17.0";
9347
+ return cachedVersion;
9348
+ }
9349
+ try {
9350
+ const packagePath = new URL("../../package.json", import.meta.url);
9351
+ const pkg = JSON.parse(readFileSync3(packagePath, "utf-8"));
9352
+ cachedVersion = pkg.version;
9353
+ return cachedVersion;
9354
+ } catch {
9355
+ cachedVersion = "0.0.0-unknown";
9356
+ return cachedVersion;
9357
+ }
9358
+ }
9359
+ var CACHE_DIR = join3(homedir3(), ".vultisig", "cache");
9360
+ var VERSION_CACHE_FILE = join3(CACHE_DIR, "version-check.json");
9361
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
9362
+ function readVersionCache() {
9363
+ try {
9364
+ if (!existsSync2(VERSION_CACHE_FILE)) return null;
9365
+ const data = readFileSync3(VERSION_CACHE_FILE, "utf-8");
9366
+ return JSON.parse(data);
9367
+ } catch {
9368
+ return null;
9369
+ }
9370
+ }
9371
+ function writeVersionCache(cache) {
9372
+ try {
9373
+ if (!existsSync2(CACHE_DIR)) {
9374
+ mkdirSync3(CACHE_DIR, { recursive: true });
9375
+ }
9376
+ writeFileSync3(VERSION_CACHE_FILE, JSON.stringify(cache, null, 2));
9377
+ } catch {
9378
+ }
9379
+ }
9380
+ async function fetchLatestVersion() {
9381
+ try {
9382
+ const controller = new AbortController();
9383
+ const timeout = setTimeout(() => controller.abort(), 5e3);
9384
+ const response = await fetch("https://registry.npmjs.org/@vultisig/cli/latest", {
9385
+ signal: controller.signal,
9386
+ headers: {
9387
+ Accept: "application/json"
9388
+ }
9389
+ });
9390
+ clearTimeout(timeout);
9391
+ if (!response.ok) return null;
9392
+ const data = await response.json();
9393
+ return data.version ?? null;
9394
+ } catch {
9395
+ return null;
9396
+ }
9397
+ }
9398
+ function isNewerVersion(v1, v2) {
9399
+ const parse = (v) => {
9400
+ const clean2 = v.replace(/^v/, "").replace(/-.*$/, "");
9401
+ return clean2.split(".").map((n) => parseInt(n, 10) || 0);
9402
+ };
9403
+ const p1 = parse(v1);
9404
+ const p2 = parse(v2);
9405
+ for (let i = 0; i < 3; i++) {
9406
+ const n1 = p1[i] ?? 0;
9407
+ const n2 = p2[i] ?? 0;
9408
+ if (n2 > n1) return true;
9409
+ if (n2 < n1) return false;
9410
+ }
9411
+ if (v1.includes("-") && !v2.includes("-")) return true;
9412
+ return false;
9413
+ }
9414
+ async function checkForUpdates() {
9415
+ if (process.env.VULTISIG_NO_UPDATE_CHECK === "1") {
9416
+ return null;
9417
+ }
9418
+ const currentVersion = getVersion();
9419
+ const cache = readVersionCache();
9420
+ if (cache && Date.now() - cache.lastCheck < CACHE_TTL_MS) {
9421
+ return {
9422
+ currentVersion,
9423
+ latestVersion: cache.latestVersion,
9424
+ updateAvailable: cache.latestVersion ? isNewerVersion(currentVersion, cache.latestVersion) : false
9425
+ };
9426
+ }
9427
+ const latestVersion = await fetchLatestVersion();
9428
+ writeVersionCache({
9429
+ lastCheck: Date.now(),
9430
+ latestVersion
9431
+ });
9432
+ return {
9433
+ currentVersion,
9434
+ latestVersion,
9435
+ updateAvailable: latestVersion ? isNewerVersion(currentVersion, latestVersion) : false
9436
+ };
9437
+ }
9438
+ function formatVersionShort() {
9439
+ return `vultisig/${getVersion()}`;
9440
+ }
9441
+ function formatVersionDetailed() {
9442
+ const lines = [];
9443
+ lines.push(chalk10.bold(`Vultisig CLI v${getVersion()}`));
9444
+ lines.push("");
9445
+ lines.push(` Node.js: ${process.version}`);
9446
+ lines.push(` Platform: ${process.platform}-${process.arch}`);
9447
+ lines.push(` Config: ~/.vultisig/`);
9448
+ return lines.join("\n");
9449
+ }
9450
+ function detectInstallMethod() {
9451
+ const execPath = process.execPath;
9452
+ if (execPath.includes("homebrew") || execPath.includes("Cellar")) {
9453
+ return "homebrew";
9454
+ }
9455
+ if (process.env.npm_execpath?.includes("yarn")) {
9456
+ return "yarn";
9457
+ }
9458
+ if (process.env.npm_config_user_agent?.includes("npm")) {
9459
+ return "npm";
9460
+ }
9461
+ if (execPath.includes("node_modules")) {
9462
+ return "npm";
9463
+ }
9464
+ return "unknown";
9465
+ }
9466
+ function getUpdateCommand() {
9467
+ const method = detectInstallMethod();
9468
+ switch (method) {
9469
+ case "npm":
9470
+ return "npm update -g @vultisig/cli";
9471
+ case "yarn":
9472
+ return "yarn global upgrade @vultisig/cli";
9473
+ case "homebrew":
9474
+ return "brew upgrade vultisig";
9475
+ default:
9476
+ return "npm update -g @vultisig/cli";
7611
9477
  }
7612
- printResult(table.toString());
7613
- printResult(chalk9.gray(`
7614
- ${totalCount} session(s) total`));
7615
9478
  }
7616
- async function executeAgentSessionsDelete(ctx2, sessionId, options) {
7617
- const vault = await ctx2.ensureActiveVault();
7618
- const backendUrl = options.backendUrl || process.env.VULTISIG_AGENT_URL || "https://abe.vultisig.com";
7619
- const client = await createAuthenticatedClient(backendUrl, vault, options.password);
7620
- const publicKey = vault.publicKeys.ecdsa;
7621
- await client.deleteConversation(sessionId, publicKey);
7622
- if (isJsonOutput()) {
7623
- outputJson({ deleted: sessionId });
7624
- return;
9479
+
9480
+ // src/commands/schema.ts
9481
+ var COMMAND_EXAMPLES = {
9482
+ balance: {
9483
+ examples: [
9484
+ "vultisig balance",
9485
+ "vultisig balance Ethereum --tokens",
9486
+ "vultisig balance --output json --fields amount,symbol"
9487
+ ]
9488
+ },
9489
+ addresses: {
9490
+ examples: ["vultisig addresses", "vultisig addresses --output json"]
9491
+ },
9492
+ send: {
9493
+ examples: [
9494
+ "vultisig send Ethereum 0x... 0.1",
9495
+ "vultisig send Bitcoin bc1q... --max --yes",
9496
+ "vultisig send Ethereum 0x... 0.5 --dry-run --output json"
9497
+ ]
9498
+ },
9499
+ execute: {
9500
+ examples: [`vultisig execute THORChain <contract> '{"swap":{}}'`]
9501
+ },
9502
+ "swap-quote": {
9503
+ examples: ["vultisig swap-quote Ethereum Bitcoin 0.1 --output json"]
9504
+ },
9505
+ vaults: {
9506
+ examples: ["vultisig vaults", "vultisig vaults --output json"]
9507
+ },
9508
+ chains: {
9509
+ examples: ["vultisig chains", "vultisig chains --add Solana"]
9510
+ },
9511
+ import: {
9512
+ examples: ["vultisig import ~/vault.vult", "vultisig import ~/vault.vult --password secret"]
9513
+ },
9514
+ export: {
9515
+ examples: ["vultisig export ~/backup.vult"]
9516
+ },
9517
+ "create.fast": {
9518
+ examples: ["vultisig create fast --name mywallet --password secret --email me@example.com"]
9519
+ },
9520
+ "agent.ask": {
9521
+ examples: [
9522
+ 'vultisig agent ask "What is my ETH balance?" --output json',
9523
+ 'vultisig agent ask "Send 0.1 ETH to 0x..." --session abc123'
9524
+ ]
7625
9525
  }
7626
- printResult(chalk9.green(`Session ${sessionId} deleted.`));
9526
+ };
9527
+ var GLOBAL_ENUM_VALUES = {
9528
+ "--output": ["json", "table"]
9529
+ };
9530
+ function mapOption(o, enumValues) {
9531
+ return {
9532
+ flags: o.flags,
9533
+ description: o.description,
9534
+ required: !!o.mandatory,
9535
+ defaultValue: o.defaultValue,
9536
+ ...enumValues?.[o.long] ? { enumValues: enumValues[o.long] } : {}
9537
+ };
7627
9538
  }
7628
- async function createAuthenticatedClient(backendUrl, vault, password) {
7629
- const client = new AgentClient(backendUrl);
7630
- const auth = await authenticateVault(client, vault, password);
7631
- client.setAuthToken(auth.token);
7632
- return client;
9539
+ function mapArguments(cmd) {
9540
+ const args = cmd.registeredArguments;
9541
+ if (!args?.length) return void 0;
9542
+ return args.map((a) => ({
9543
+ name: a._name ?? a.name?.(),
9544
+ required: a.required,
9545
+ description: a.description
9546
+ }));
7633
9547
  }
7634
- function formatDate(iso) {
7635
- try {
7636
- const d = new Date(iso);
7637
- return d.toLocaleDateString() + " " + d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
7638
- } catch {
7639
- return iso;
7640
- }
9548
+ function executeSchema(prog) {
9549
+ const schema = {
9550
+ name: prog.name(),
9551
+ version: getVersion(),
9552
+ exitCodes: Object.fromEntries(Object.entries(EXIT_CODE_DESCRIPTIONS).map(([k, v]) => [String(k), v])),
9553
+ globalOptions: prog.options.filter((o) => !o.hidden).map((o) => mapOption(o, GLOBAL_ENUM_VALUES)),
9554
+ commands: prog.commands.filter((c) => !c._hidden).map((c) => {
9555
+ const meta = COMMAND_EXAMPLES[c.name()];
9556
+ const args = mapArguments(c);
9557
+ return {
9558
+ name: c.name(),
9559
+ description: c.description(),
9560
+ ...args ? { arguments: args } : {},
9561
+ options: c.options.filter((o) => !o.hidden && o.long !== "--help").map((o) => mapOption(o, meta?.enumValues)),
9562
+ ...meta?.examples ? { examples: meta.examples } : {},
9563
+ subcommands: c.commands.length ? c.commands.map((sub) => {
9564
+ const subMeta = COMMAND_EXAMPLES[`${c.name()}.${sub.name()}`];
9565
+ const subArgs = mapArguments(sub);
9566
+ return {
9567
+ name: sub.name(),
9568
+ description: sub.description(),
9569
+ ...subArgs ? { arguments: subArgs } : {},
9570
+ options: sub.options.filter((o) => !o.hidden && o.long !== "--help").map((o) => ({
9571
+ flags: o.flags,
9572
+ description: o.description,
9573
+ required: !!o.mandatory
9574
+ })),
9575
+ ...subMeta?.examples ? { examples: subMeta.examples } : {}
9576
+ };
9577
+ }) : void 0
9578
+ };
9579
+ })
9580
+ };
9581
+ process.stdout.write(`${JSON.stringify(schema, null, 2)}
9582
+ `);
7641
9583
  }
7642
9584
 
7643
9585
  // src/core/server-endpoints.ts
@@ -7684,7 +9626,7 @@ function readArgValue(args, optionName) {
7684
9626
  }
7685
9627
 
7686
9628
  // src/interactive/completer.ts
7687
- import { Chain as Chain10 } from "@vultisig/sdk";
9629
+ import { Chain as Chain11 } from "@vultisig/sdk";
7688
9630
  import fs3 from "fs";
7689
9631
  import path3 from "path";
7690
9632
  var COMMANDS = [
@@ -7828,7 +9770,7 @@ function completeVaultName(ctx2, partial) {
7828
9770
  return [show, partial];
7829
9771
  }
7830
9772
  function completeChainName(partial) {
7831
- const allChains = Object.values(Chain10);
9773
+ const allChains = Object.values(Chain11);
7832
9774
  const partialLower = partial.toLowerCase();
7833
9775
  const matches = allChains.filter((chain) => chain.toLowerCase().startsWith(partialLower));
7834
9776
  matches.sort();
@@ -7836,14 +9778,14 @@ function completeChainName(partial) {
7836
9778
  return [show, partial];
7837
9779
  }
7838
9780
  function findChainByName(name) {
7839
- const allChains = Object.values(Chain10);
9781
+ const allChains = Object.values(Chain11);
7840
9782
  const nameLower = name.toLowerCase();
7841
9783
  const found = allChains.find((chain) => chain.toLowerCase() === nameLower);
7842
9784
  return found ? found : null;
7843
9785
  }
7844
9786
 
7845
9787
  // src/interactive/event-buffer.ts
7846
- import chalk10 from "chalk";
9788
+ import chalk11 from "chalk";
7847
9789
  var EventBuffer = class {
7848
9790
  eventBuffer = [];
7849
9791
  isCommandRunning = false;
@@ -7883,17 +9825,17 @@ var EventBuffer = class {
7883
9825
  displayEvent(message, type) {
7884
9826
  switch (type) {
7885
9827
  case "success":
7886
- console.log(chalk10.green(message));
9828
+ console.log(chalk11.green(message));
7887
9829
  break;
7888
9830
  case "warning":
7889
- console.log(chalk10.yellow(message));
9831
+ console.log(chalk11.yellow(message));
7890
9832
  break;
7891
9833
  case "error":
7892
- console.error(chalk10.red(message));
9834
+ console.error(chalk11.red(message));
7893
9835
  break;
7894
9836
  case "info":
7895
9837
  default:
7896
- console.log(chalk10.blue(message));
9838
+ console.log(chalk11.blue(message));
7897
9839
  break;
7898
9840
  }
7899
9841
  }
@@ -7904,13 +9846,13 @@ var EventBuffer = class {
7904
9846
  if (this.eventBuffer.length === 0) {
7905
9847
  return;
7906
9848
  }
7907
- console.log(chalk10.gray("\n--- Background Events ---"));
9849
+ console.log(chalk11.gray("\n--- Background Events ---"));
7908
9850
  this.eventBuffer.forEach((event) => {
7909
9851
  const timeStr = event.timestamp.toLocaleTimeString();
7910
9852
  const message = `[${timeStr}] ${event.message}`;
7911
9853
  this.displayEvent(message, event.type);
7912
9854
  });
7913
- console.log(chalk10.gray("--- End Events ---\n"));
9855
+ console.log(chalk11.gray("--- End Events ---\n"));
7914
9856
  }
7915
9857
  /**
7916
9858
  * Setup all vault event listeners
@@ -8020,12 +9962,12 @@ var EventBuffer = class {
8020
9962
 
8021
9963
  // src/interactive/session.ts
8022
9964
  import { fiatCurrencies as fiatCurrencies4 } from "@vultisig/sdk";
8023
- import chalk12 from "chalk";
9965
+ import chalk13 from "chalk";
8024
9966
  import ora3 from "ora";
8025
9967
  import * as readline3 from "readline";
8026
9968
 
8027
9969
  // src/interactive/shell-commands.ts
8028
- import chalk11 from "chalk";
9970
+ import chalk12 from "chalk";
8029
9971
  import Table2 from "cli-table3";
8030
9972
  import inquirer6 from "inquirer";
8031
9973
  import ora2 from "ora";
@@ -8042,25 +9984,25 @@ function formatTimeRemaining(ms) {
8042
9984
  async function executeLock(ctx2) {
8043
9985
  const vault = ctx2.getActiveVault();
8044
9986
  if (!vault) {
8045
- console.log(chalk11.red("No active vault."));
8046
- console.log(chalk11.yellow('Use "vault <name>" to switch to a vault first.'));
9987
+ console.log(chalk12.red("No active vault."));
9988
+ console.log(chalk12.yellow('Use "vault <name>" to switch to a vault first.'));
8047
9989
  return;
8048
9990
  }
8049
9991
  ctx2.lockVault(vault.id);
8050
- console.log(chalk11.green("\n+ Vault locked"));
8051
- console.log(chalk11.gray("Password cache cleared. You will need to enter the password again."));
9992
+ console.log(chalk12.green("\n+ Vault locked"));
9993
+ console.log(chalk12.gray("Password cache cleared. You will need to enter the password again."));
8052
9994
  }
8053
9995
  async function executeUnlock(ctx2) {
8054
9996
  const vault = ctx2.getActiveVault();
8055
9997
  if (!vault) {
8056
- console.log(chalk11.red("No active vault."));
8057
- console.log(chalk11.yellow('Use "vault <name>" to switch to a vault first.'));
9998
+ console.log(chalk12.red("No active vault."));
9999
+ console.log(chalk12.yellow('Use "vault <name>" to switch to a vault first.'));
8058
10000
  return;
8059
10001
  }
8060
10002
  if (ctx2.isVaultUnlocked(vault.id)) {
8061
10003
  const timeRemaining = ctx2.getUnlockTimeRemaining(vault.id);
8062
- console.log(chalk11.yellow("\nVault is already unlocked."));
8063
- console.log(chalk11.gray(`Time remaining: ${formatTimeRemaining(timeRemaining)}`));
10004
+ console.log(chalk12.yellow("\nVault is already unlocked."));
10005
+ console.log(chalk12.gray(`Time remaining: ${formatTimeRemaining(timeRemaining)}`));
8064
10006
  return;
8065
10007
  }
8066
10008
  const { password } = await inquirer6.prompt([
@@ -8077,19 +10019,19 @@ async function executeUnlock(ctx2) {
8077
10019
  ctx2.cachePassword(vault.id, password);
8078
10020
  const timeRemaining = ctx2.getUnlockTimeRemaining(vault.id);
8079
10021
  spinner.succeed("Vault unlocked");
8080
- console.log(chalk11.green(`
10022
+ console.log(chalk12.green(`
8081
10023
  + Vault unlocked for ${formatTimeRemaining(timeRemaining)}`));
8082
10024
  } catch (err) {
8083
10025
  spinner.fail("Failed to unlock vault");
8084
- console.error(chalk11.red(`
10026
+ console.error(chalk12.red(`
8085
10027
  x ${err.message}`));
8086
10028
  }
8087
10029
  }
8088
10030
  async function executeStatus(ctx2) {
8089
10031
  const vault = ctx2.getActiveVault();
8090
10032
  if (!vault) {
8091
- console.log(chalk11.red("No active vault."));
8092
- console.log(chalk11.yellow('Use "vault <name>" to switch to a vault first.'));
10033
+ console.log(chalk12.red("No active vault."));
10034
+ console.log(chalk12.yellow('Use "vault <name>" to switch to a vault first.'));
8093
10035
  return;
8094
10036
  }
8095
10037
  const isUnlocked = ctx2.isVaultUnlocked(vault.id);
@@ -8120,30 +10062,30 @@ async function executeStatus(ctx2) {
8120
10062
  displayStatus(status);
8121
10063
  }
8122
10064
  function displayStatus(status) {
8123
- console.log(chalk11.cyan("\n+----------------------------------------+"));
8124
- console.log(chalk11.cyan("| Vault Status |"));
8125
- console.log(chalk11.cyan("+----------------------------------------+\n"));
8126
- console.log(chalk11.bold("Vault:"));
8127
- console.log(` Name: ${chalk11.green(status.name)}`);
10065
+ console.log(chalk12.cyan("\n+----------------------------------------+"));
10066
+ console.log(chalk12.cyan("| Vault Status |"));
10067
+ console.log(chalk12.cyan("+----------------------------------------+\n"));
10068
+ console.log(chalk12.bold("Vault:"));
10069
+ console.log(` Name: ${chalk12.green(status.name)}`);
8128
10070
  console.log(` ID: ${status.id}`);
8129
- console.log(` Type: ${chalk11.yellow(status.type)}`);
8130
- console.log(chalk11.bold("\nSecurity:"));
10071
+ console.log(` Type: ${chalk12.yellow(status.type)}`);
10072
+ console.log(chalk12.bold("\nSecurity:"));
8131
10073
  if (status.isUnlocked) {
8132
- console.log(` Status: ${chalk11.green("Unlocked")} ${chalk11.green("\u{1F513}")}`);
10074
+ console.log(` Status: ${chalk12.green("Unlocked")} ${chalk12.green("\u{1F513}")}`);
8133
10075
  console.log(` Expires: ${status.timeRemainingFormatted}`);
8134
10076
  } else {
8135
- console.log(` Status: ${chalk11.yellow("Locked")} ${chalk11.yellow("\u{1F512}")}`);
10077
+ console.log(` Status: ${chalk12.yellow("Locked")} ${chalk12.yellow("\u{1F512}")}`);
8136
10078
  }
8137
- console.log(` Encrypted: ${status.isEncrypted ? chalk11.green("Yes") : chalk11.gray("No")}`);
8138
- console.log(` Backed Up: ${status.isBackedUp ? chalk11.green("Yes") : chalk11.yellow("No")}`);
8139
- console.log(chalk11.bold("\nMPC Configuration:"));
10079
+ console.log(` Encrypted: ${status.isEncrypted ? chalk12.green("Yes") : chalk12.gray("No")}`);
10080
+ console.log(` Backed Up: ${status.isBackedUp ? chalk12.green("Yes") : chalk12.yellow("No")}`);
10081
+ console.log(chalk12.bold("\nMPC Configuration:"));
8140
10082
  console.log(` Library: ${status.libType}`);
8141
- console.log(` Threshold: ${chalk11.cyan(status.threshold)} of ${chalk11.cyan(status.totalSigners)}`);
8142
- console.log(chalk11.bold("\nSigning Modes:"));
10083
+ console.log(` Threshold: ${chalk12.cyan(status.threshold)} of ${chalk12.cyan(status.totalSigners)}`);
10084
+ console.log(chalk12.bold("\nSigning Modes:"));
8143
10085
  status.availableSigningModes.forEach((mode) => {
8144
10086
  console.log(` - ${mode}`);
8145
10087
  });
8146
- console.log(chalk11.bold("\nDetails:"));
10088
+ console.log(chalk12.bold("\nDetails:"));
8147
10089
  console.log(` Chains: ${status.chains}`);
8148
10090
  console.log(` Currency: ${status.currency.toUpperCase()}`);
8149
10091
  console.log(` Created: ${new Date(status.createdAt).toLocaleString()}`);
@@ -8152,7 +10094,7 @@ function displayStatus(status) {
8152
10094
  }
8153
10095
  function showHelp() {
8154
10096
  const table = new Table2({
8155
- head: [chalk11.bold("Available Commands")],
10097
+ head: [chalk12.bold("Available Commands")],
8156
10098
  colWidths: [50],
8157
10099
  chars: {
8158
10100
  mid: "",
@@ -8166,7 +10108,7 @@ function showHelp() {
8166
10108
  }
8167
10109
  });
8168
10110
  table.push(
8169
- [chalk11.bold("Vault Management:")],
10111
+ [chalk12.bold("Vault Management:")],
8170
10112
  [" vaults - List all vaults"],
8171
10113
  [" vault <name> - Switch to vault"],
8172
10114
  [" import <file> - Import vault from file"],
@@ -8175,7 +10117,7 @@ function showHelp() {
8175
10117
  [" info - Show vault details"],
8176
10118
  [" export [path] - Export vault to file"],
8177
10119
  [""],
8178
- [chalk11.bold("Wallet Operations:")],
10120
+ [chalk12.bold("Wallet Operations:")],
8179
10121
  [" balance [chain] - Show balances"],
8180
10122
  [" send <chain> <to> <amount> - Send transaction"],
8181
10123
  [" tx-status <chain> <txHash> - Check transaction status"],
@@ -8184,22 +10126,22 @@ function showHelp() {
8184
10126
  [" chains [--add/--remove/--add-all] - Manage chains"],
8185
10127
  [" tokens <chain> - Manage tokens"],
8186
10128
  [""],
8187
- [chalk11.bold("Swap Operations:")],
10129
+ [chalk12.bold("Swap Operations:")],
8188
10130
  [" swap-chains - List swap-enabled chains"],
8189
10131
  [" swap-quote <from> <to> <amount> - Get quote"],
8190
10132
  [" swap <from> <to> <amount> - Execute swap"],
8191
10133
  [""],
8192
- [chalk11.bold("Session Commands (shell only):")],
10134
+ [chalk12.bold("Session Commands (shell only):")],
8193
10135
  [" lock - Lock vault"],
8194
10136
  [" unlock - Unlock vault"],
8195
10137
  [" status - Show vault status"],
8196
10138
  [""],
8197
- [chalk11.bold("Settings:")],
10139
+ [chalk12.bold("Settings:")],
8198
10140
  [" currency [code] - View/set currency"],
8199
10141
  [" server - Check server status"],
8200
10142
  [" address-book - Manage saved addresses"],
8201
10143
  [""],
8202
- [chalk11.bold("Help & Navigation:")],
10144
+ [chalk12.bold("Help & Navigation:")],
8203
10145
  [" help, ? - Show this help"],
8204
10146
  [" .clear - Clear screen"],
8205
10147
  [" .exit - Exit shell"]
@@ -8337,12 +10279,12 @@ var ShellSession = class {
8337
10279
  */
8338
10280
  async start() {
8339
10281
  console.clear();
8340
- console.log(chalk12.cyan.bold("\n=============================================="));
8341
- console.log(chalk12.cyan.bold(" Vultisig Interactive Shell"));
8342
- console.log(chalk12.cyan.bold("==============================================\n"));
10282
+ console.log(chalk13.cyan.bold("\n=============================================="));
10283
+ console.log(chalk13.cyan.bold(" Vultisig Interactive Shell"));
10284
+ console.log(chalk13.cyan.bold("==============================================\n"));
8343
10285
  await this.loadAllVaults();
8344
10286
  this.displayVaultList();
8345
- console.log(chalk12.gray('Type "help" for available commands, "exit" to quit\n'));
10287
+ console.log(chalk13.gray('Type "help" for available commands, "exit" to quit\n'));
8346
10288
  this.promptLoop().catch(() => {
8347
10289
  });
8348
10290
  }
@@ -8376,12 +10318,12 @@ var ShellSession = class {
8376
10318
  const now = Date.now();
8377
10319
  if (now - this.lastSigintTime < this.DOUBLE_CTRL_C_TIMEOUT) {
8378
10320
  rl.close();
8379
- console.log(chalk12.yellow("\nGoodbye!"));
10321
+ console.log(chalk13.yellow("\nGoodbye!"));
8380
10322
  this.ctx.dispose();
8381
10323
  process.exit(0);
8382
10324
  }
8383
10325
  this.lastSigintTime = now;
8384
- console.log(chalk12.yellow("\n(Press Ctrl+C again to exit)"));
10326
+ console.log(chalk13.yellow("\n(Press Ctrl+C again to exit)"));
8385
10327
  rl.close();
8386
10328
  resolve("");
8387
10329
  });
@@ -8476,7 +10418,7 @@ var ShellSession = class {
8476
10418
  stopAllSpinners();
8477
10419
  process.stdout.write("\x1B[?25h");
8478
10420
  process.stdout.write("\r\x1B[K");
8479
- console.log(chalk12.yellow("\nCancelling operation..."));
10421
+ console.log(chalk13.yellow("\nCancelling operation..."));
8480
10422
  };
8481
10423
  const cleanup = () => {
8482
10424
  process.removeListener("SIGINT", onSigint);
@@ -8513,10 +10455,10 @@ var ShellSession = class {
8513
10455
  stopAllSpinners();
8514
10456
  process.stdout.write("\x1B[?25h");
8515
10457
  process.stdout.write("\r\x1B[K");
8516
- console.log(chalk12.yellow("Operation cancelled"));
10458
+ console.log(chalk13.yellow("Operation cancelled"));
8517
10459
  return;
8518
10460
  }
8519
- console.error(chalk12.red(`
10461
+ console.error(chalk13.red(`
8520
10462
  Error: ${error2.message}`));
8521
10463
  }
8522
10464
  }
@@ -8549,7 +10491,7 @@ Error: ${error2.message}`));
8549
10491
  break;
8550
10492
  case "rename":
8551
10493
  if (args.length === 0) {
8552
- console.log(chalk12.yellow("Usage: rename <newName>"));
10494
+ console.log(chalk13.yellow("Usage: rename <newName>"));
8553
10495
  return;
8554
10496
  }
8555
10497
  await executeRename(this.ctx, args.join(" "));
@@ -8625,41 +10567,41 @@ Error: ${error2.message}`));
8625
10567
  // Exit
8626
10568
  case "exit":
8627
10569
  case "quit":
8628
- console.log(chalk12.yellow("\nGoodbye!"));
10570
+ console.log(chalk13.yellow("\nGoodbye!"));
8629
10571
  this.ctx.dispose();
8630
10572
  process.exit(0);
8631
10573
  break;
8632
10574
  // eslint requires break even after process.exit
8633
10575
  default:
8634
- console.log(chalk12.yellow(`Unknown command: ${command}`));
8635
- console.log(chalk12.gray('Type "help" for available commands'));
10576
+ console.log(chalk13.yellow(`Unknown command: ${command}`));
10577
+ console.log(chalk13.gray('Type "help" for available commands'));
8636
10578
  break;
8637
10579
  }
8638
10580
  }
8639
10581
  // ===== Command Helpers =====
8640
10582
  async switchVault(args) {
8641
10583
  if (args.length === 0) {
8642
- console.log(chalk12.yellow("Usage: vault <name>"));
8643
- console.log(chalk12.gray('Run "vaults" to see available vaults'));
10584
+ console.log(chalk13.yellow("Usage: vault <name>"));
10585
+ console.log(chalk13.gray('Run "vaults" to see available vaults'));
8644
10586
  return;
8645
10587
  }
8646
10588
  const vaultName = args.join(" ");
8647
10589
  const vault = this.ctx.findVaultByName(vaultName);
8648
10590
  if (!vault) {
8649
- console.log(chalk12.red(`Vault not found: ${vaultName}`));
8650
- console.log(chalk12.gray('Run "vaults" to see available vaults'));
10591
+ console.log(chalk13.red(`Vault not found: ${vaultName}`));
10592
+ console.log(chalk13.gray('Run "vaults" to see available vaults'));
8651
10593
  return;
8652
10594
  }
8653
10595
  await this.ctx.setActiveVault(vault);
8654
- console.log(chalk12.green(`
10596
+ console.log(chalk13.green(`
8655
10597
  + Switched to: ${vault.name}`));
8656
10598
  const isUnlocked = this.ctx.isVaultUnlocked(vault.id);
8657
- const status = isUnlocked ? chalk12.green("Unlocked") : chalk12.yellow("Locked");
10599
+ const status = isUnlocked ? chalk13.green("Unlocked") : chalk13.yellow("Locked");
8658
10600
  console.log(`Status: ${status}`);
8659
10601
  }
8660
10602
  async importVault(args) {
8661
10603
  if (args.length === 0) {
8662
- console.log(chalk12.yellow("Usage: import <file>"));
10604
+ console.log(chalk13.yellow("Usage: import <file>"));
8663
10605
  return;
8664
10606
  }
8665
10607
  const filePath = args.join(" ");
@@ -8674,45 +10616,45 @@ Error: ${error2.message}`));
8674
10616
  async createVault(args) {
8675
10617
  const type = args[0]?.toLowerCase();
8676
10618
  if (!type || type !== "fast" && type !== "secure") {
8677
- console.log(chalk12.yellow("Usage: create <fast|secure>"));
8678
- console.log(chalk12.gray(" create fast - Create a fast vault (server-assisted 2-of-2)"));
8679
- console.log(chalk12.gray(" create secure - Create a secure vault (multi-device MPC)"));
10619
+ console.log(chalk13.yellow("Usage: create <fast|secure>"));
10620
+ console.log(chalk13.gray(" create fast - Create a fast vault (server-assisted 2-of-2)"));
10621
+ console.log(chalk13.gray(" create secure - Create a secure vault (multi-device MPC)"));
8680
10622
  return;
8681
10623
  }
8682
10624
  let vault;
8683
10625
  if (type === "fast") {
8684
10626
  const name = await this.prompt("Vault name");
8685
10627
  if (!name) {
8686
- console.log(chalk12.red("Name is required"));
10628
+ console.log(chalk13.red("Name is required"));
8687
10629
  return;
8688
10630
  }
8689
10631
  const password = await this.promptPassword("Vault password");
8690
10632
  if (!password) {
8691
- console.log(chalk12.red("Password is required"));
10633
+ console.log(chalk13.red("Password is required"));
8692
10634
  return;
8693
10635
  }
8694
10636
  const email = await this.prompt("Email for verification");
8695
10637
  if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
8696
- console.log(chalk12.red("Valid email is required"));
10638
+ console.log(chalk13.red("Valid email is required"));
8697
10639
  return;
8698
10640
  }
8699
10641
  vault = await this.withCancellation((signal) => executeCreateFast(this.ctx, { name, password, email, signal }));
8700
10642
  } else {
8701
10643
  const name = await this.prompt("Vault name");
8702
10644
  if (!name) {
8703
- console.log(chalk12.red("Name is required"));
10645
+ console.log(chalk13.red("Name is required"));
8704
10646
  return;
8705
10647
  }
8706
10648
  const sharesStr = await this.prompt("Total shares (devices)", "3");
8707
10649
  const shares = parseInt(sharesStr, 10);
8708
10650
  if (isNaN(shares) || shares < 2) {
8709
- console.log(chalk12.red("Must have at least 2 shares"));
10651
+ console.log(chalk13.red("Must have at least 2 shares"));
8710
10652
  return;
8711
10653
  }
8712
10654
  const thresholdStr = await this.prompt("Signing threshold", "2");
8713
10655
  const threshold = parseInt(thresholdStr, 10);
8714
10656
  if (isNaN(threshold) || threshold < 1 || threshold > shares) {
8715
- console.log(chalk12.red(`Threshold must be between 1 and ${shares}`));
10657
+ console.log(chalk13.red(`Threshold must be between 1 and ${shares}`));
8716
10658
  return;
8717
10659
  }
8718
10660
  const password = await this.promptPassword("Vault password (optional, press Enter to skip)");
@@ -8734,37 +10676,37 @@ Error: ${error2.message}`));
8734
10676
  async importSeedphrase(args) {
8735
10677
  const type = args[0]?.toLowerCase();
8736
10678
  if (!type || type !== "fast" && type !== "secure") {
8737
- console.log(chalk12.cyan("Usage: create-from-seedphrase <fast|secure>"));
8738
- console.log(chalk12.gray(" fast - Import with VultiServer (2-of-2)"));
8739
- console.log(chalk12.gray(" secure - Import with device coordination (N-of-M)"));
10679
+ console.log(chalk13.cyan("Usage: create-from-seedphrase <fast|secure>"));
10680
+ console.log(chalk13.gray(" fast - Import with VultiServer (2-of-2)"));
10681
+ console.log(chalk13.gray(" secure - Import with device coordination (N-of-M)"));
8740
10682
  return;
8741
10683
  }
8742
- console.log(chalk12.cyan("\nEnter your recovery phrase (words separated by spaces):"));
10684
+ console.log(chalk13.cyan("\nEnter your recovery phrase (words separated by spaces):"));
8743
10685
  const mnemonic = await this.promptPassword("Seedphrase");
8744
10686
  const validation = await this.ctx.sdk.validateSeedphrase(mnemonic);
8745
10687
  if (!validation.valid) {
8746
- console.log(chalk12.red(`Invalid seedphrase: ${validation.error}`));
10688
+ console.log(chalk13.red(`Invalid seedphrase: ${validation.error}`));
8747
10689
  if (validation.invalidWords?.length) {
8748
- console.log(chalk12.yellow(`Invalid words: ${validation.invalidWords.join(", ")}`));
10690
+ console.log(chalk13.yellow(`Invalid words: ${validation.invalidWords.join(", ")}`));
8749
10691
  }
8750
10692
  return;
8751
10693
  }
8752
- console.log(chalk12.green(`\u2713 Valid ${validation.wordCount}-word seedphrase`));
10694
+ console.log(chalk13.green(`\u2713 Valid ${validation.wordCount}-word seedphrase`));
8753
10695
  let vault;
8754
10696
  if (type === "fast") {
8755
10697
  const name = await this.prompt("Vault name");
8756
10698
  if (!name) {
8757
- console.log(chalk12.red("Name is required"));
10699
+ console.log(chalk13.red("Name is required"));
8758
10700
  return;
8759
10701
  }
8760
10702
  const password = await this.promptPassword("Vault password");
8761
10703
  if (!password) {
8762
- console.log(chalk12.red("Password is required"));
10704
+ console.log(chalk13.red("Password is required"));
8763
10705
  return;
8764
10706
  }
8765
10707
  const email = await this.prompt("Email for verification");
8766
10708
  if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
8767
- console.log(chalk12.red("Valid email is required"));
10709
+ console.log(chalk13.red("Valid email is required"));
8768
10710
  return;
8769
10711
  }
8770
10712
  const discoverStr = await this.prompt("Discover chains with balances? (y/n)", "y");
@@ -8782,19 +10724,19 @@ Error: ${error2.message}`));
8782
10724
  } else {
8783
10725
  const name = await this.prompt("Vault name");
8784
10726
  if (!name) {
8785
- console.log(chalk12.red("Name is required"));
10727
+ console.log(chalk13.red("Name is required"));
8786
10728
  return;
8787
10729
  }
8788
10730
  const sharesStr = await this.prompt("Total shares (devices)", "3");
8789
10731
  const shares = parseInt(sharesStr, 10);
8790
10732
  if (isNaN(shares) || shares < 2) {
8791
- console.log(chalk12.red("Must have at least 2 shares"));
10733
+ console.log(chalk13.red("Must have at least 2 shares"));
8792
10734
  return;
8793
10735
  }
8794
10736
  const thresholdStr = await this.prompt("Signing threshold", "2");
8795
10737
  const threshold = parseInt(thresholdStr, 10);
8796
10738
  if (isNaN(threshold) || threshold < 1 || threshold > shares) {
8797
- console.log(chalk12.red(`Threshold must be between 1 and ${shares}`));
10739
+ console.log(chalk13.red(`Threshold must be between 1 and ${shares}`));
8798
10740
  return;
8799
10741
  }
8800
10742
  const password = await this.promptPassword("Vault password (optional, Enter to skip)");
@@ -8838,8 +10780,8 @@ Error: ${error2.message}`));
8838
10780
  }
8839
10781
  }
8840
10782
  if (!fiatCurrencies4.includes(currency)) {
8841
- console.log(chalk12.red(`Invalid currency: ${currency}`));
8842
- console.log(chalk12.yellow(`Supported currencies: ${fiatCurrencies4.join(", ")}`));
10783
+ console.log(chalk13.red(`Invalid currency: ${currency}`));
10784
+ console.log(chalk13.yellow(`Supported currencies: ${fiatCurrencies4.join(", ")}`));
8843
10785
  return;
8844
10786
  }
8845
10787
  const raw = args.includes("--raw");
@@ -8847,7 +10789,7 @@ Error: ${error2.message}`));
8847
10789
  }
8848
10790
  async runSend(args) {
8849
10791
  if (args.length < 3) {
8850
- console.log(chalk12.yellow("Usage: send <chain> <to> <amount> [--token <tokenId>] [--memo <memo>]"));
10792
+ console.log(chalk13.yellow("Usage: send <chain> <to> <amount> [--token <tokenId>] [--memo <memo>]"));
8851
10793
  return;
8852
10794
  }
8853
10795
  const [chainStr, to, amount, ...rest] = args;
@@ -8867,7 +10809,7 @@ Error: ${error2.message}`));
8867
10809
  await this.withAbortHandler((signal) => executeSend(this.ctx, { chain, to, amount, tokenId, memo, signal }));
8868
10810
  } catch (err) {
8869
10811
  if (err.message === "Transaction cancelled by user" || err.message === "Operation cancelled" || err.message === "Operation aborted") {
8870
- console.log(chalk12.yellow("\nTransaction cancelled"));
10812
+ console.log(chalk13.yellow("\nTransaction cancelled"));
8871
10813
  return;
8872
10814
  }
8873
10815
  throw err;
@@ -8875,7 +10817,7 @@ Error: ${error2.message}`));
8875
10817
  }
8876
10818
  async runTxStatus(args) {
8877
10819
  if (args.length < 2) {
8878
- console.log(chalk12.yellow("Usage: tx-status <chain> <txHash> [--no-wait]"));
10820
+ console.log(chalk13.yellow("Usage: tx-status <chain> <txHash> [--no-wait]"));
8879
10821
  return;
8880
10822
  }
8881
10823
  const [chainStr, txHash, ...rest] = args;
@@ -8893,8 +10835,8 @@ Error: ${error2.message}`));
8893
10835
  } else if (args[i] === "--add" && i + 1 < args.length) {
8894
10836
  const chain = findChainByName(args[i + 1]);
8895
10837
  if (!chain) {
8896
- console.log(chalk12.red(`Unknown chain: ${args[i + 1]}`));
8897
- console.log(chalk12.gray("Use tab completion to see available chains"));
10838
+ console.log(chalk13.red(`Unknown chain: ${args[i + 1]}`));
10839
+ console.log(chalk13.gray("Use tab completion to see available chains"));
8898
10840
  return;
8899
10841
  }
8900
10842
  addChain = chain;
@@ -8902,8 +10844,8 @@ Error: ${error2.message}`));
8902
10844
  } else if (args[i] === "--remove" && i + 1 < args.length) {
8903
10845
  const chain = findChainByName(args[i + 1]);
8904
10846
  if (!chain) {
8905
- console.log(chalk12.red(`Unknown chain: ${args[i + 1]}`));
8906
- console.log(chalk12.gray("Use tab completion to see available chains"));
10847
+ console.log(chalk13.red(`Unknown chain: ${args[i + 1]}`));
10848
+ console.log(chalk13.gray("Use tab completion to see available chains"));
8907
10849
  return;
8908
10850
  }
8909
10851
  removeChain = chain;
@@ -8914,7 +10856,7 @@ Error: ${error2.message}`));
8914
10856
  }
8915
10857
  async runTokens(args) {
8916
10858
  if (args.length === 0) {
8917
- console.log(chalk12.yellow("Usage: tokens <chain> [--add <address>] [--remove <tokenId>]"));
10859
+ console.log(chalk13.yellow("Usage: tokens <chain> [--add <address>] [--remove <tokenId>]"));
8918
10860
  return;
8919
10861
  }
8920
10862
  const chainStr = args[0];
@@ -8935,7 +10877,7 @@ Error: ${error2.message}`));
8935
10877
  async runSwapQuote(args) {
8936
10878
  if (args.length < 3) {
8937
10879
  console.log(
8938
- chalk12.yellow("Usage: swap-quote <fromChain> <toChain> <amount> [--from-token <addr>] [--to-token <addr>]")
10880
+ chalk13.yellow("Usage: swap-quote <fromChain> <toChain> <amount> [--from-token <addr>] [--to-token <addr>]")
8939
10881
  );
8940
10882
  return;
8941
10883
  }
@@ -8959,7 +10901,7 @@ Error: ${error2.message}`));
8959
10901
  async runSwap(args) {
8960
10902
  if (args.length < 3) {
8961
10903
  console.log(
8962
- chalk12.yellow(
10904
+ chalk13.yellow(
8963
10905
  "Usage: swap <fromChain> <toChain> <amount> [--from-token <addr>] [--to-token <addr>] [--slippage <pct>]"
8964
10906
  )
8965
10907
  );
@@ -8990,7 +10932,7 @@ Error: ${error2.message}`));
8990
10932
  );
8991
10933
  } catch (err) {
8992
10934
  if (err.message === "Swap cancelled by user" || err.message === "Operation cancelled" || err.message === "Operation aborted") {
8993
- console.log(chalk12.yellow("\nSwap cancelled"));
10935
+ console.log(chalk13.yellow("\nSwap cancelled"));
8994
10936
  return;
8995
10937
  }
8996
10938
  throw err;
@@ -9052,24 +10994,24 @@ Error: ${error2.message}`));
9052
10994
  }
9053
10995
  getPrompt() {
9054
10996
  const vault = this.ctx.getActiveVault();
9055
- if (!vault) return chalk12.cyan("wallet> ");
10997
+ if (!vault) return chalk13.cyan("wallet> ");
9056
10998
  const isUnlocked = this.ctx.isVaultUnlocked(vault.id);
9057
- const status = isUnlocked ? chalk12.green("\u{1F513}") : chalk12.yellow("\u{1F512}");
9058
- return chalk12.cyan(`wallet[${vault.name}]${status}> `);
10999
+ const status = isUnlocked ? chalk13.green("\u{1F513}") : chalk13.yellow("\u{1F512}");
11000
+ return chalk13.cyan(`wallet[${vault.name}]${status}> `);
9059
11001
  }
9060
11002
  displayVaultList() {
9061
11003
  const vaults = Array.from(this.ctx.getVaults().values());
9062
11004
  const activeVault = this.ctx.getActiveVault();
9063
11005
  if (vaults.length === 0) {
9064
- console.log(chalk12.yellow('No vaults found. Use "create" or "import <file>" to add a vault.\n'));
11006
+ console.log(chalk13.yellow('No vaults found. Use "create" or "import <file>" to add a vault.\n'));
9065
11007
  return;
9066
11008
  }
9067
- console.log(chalk12.cyan("Loaded Vaults:\n"));
11009
+ console.log(chalk13.cyan("Loaded Vaults:\n"));
9068
11010
  vaults.forEach((vault) => {
9069
11011
  const isActive = vault.id === activeVault?.id;
9070
11012
  const isUnlocked = this.ctx.isVaultUnlocked(vault.id);
9071
- const activeMarker = isActive ? chalk12.green(" (active)") : "";
9072
- const lockIcon = isUnlocked ? chalk12.green("\u{1F513}") : chalk12.yellow("\u{1F512}");
11013
+ const activeMarker = isActive ? chalk13.green(" (active)") : "";
11014
+ const lockIcon = isUnlocked ? chalk13.green("\u{1F513}") : chalk13.yellow("\u{1F512}");
9073
11015
  console.log(` ${lockIcon} ${vault.name}${activeMarker} - ${vault.type}`);
9074
11016
  });
9075
11017
  console.log();
@@ -9077,150 +11019,7 @@ Error: ${error2.message}`));
9077
11019
  };
9078
11020
 
9079
11021
  // src/lib/errors.ts
9080
- import chalk13 from "chalk";
9081
-
9082
- // src/lib/version.ts
9083
11022
  import chalk14 from "chalk";
9084
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync2 } from "fs";
9085
- import { homedir as homedir3 } from "os";
9086
- import { join as join3 } from "path";
9087
- var cachedVersion = null;
9088
- function getVersion() {
9089
- if (cachedVersion) return cachedVersion;
9090
- if (true) {
9091
- cachedVersion = "0.15.4";
9092
- return cachedVersion;
9093
- }
9094
- try {
9095
- const packagePath = new URL("../../package.json", import.meta.url);
9096
- const pkg = JSON.parse(readFileSync3(packagePath, "utf-8"));
9097
- cachedVersion = pkg.version;
9098
- return cachedVersion;
9099
- } catch {
9100
- cachedVersion = "0.0.0-unknown";
9101
- return cachedVersion;
9102
- }
9103
- }
9104
- var CACHE_DIR = join3(homedir3(), ".vultisig", "cache");
9105
- var VERSION_CACHE_FILE = join3(CACHE_DIR, "version-check.json");
9106
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
9107
- function readVersionCache() {
9108
- try {
9109
- if (!existsSync2(VERSION_CACHE_FILE)) return null;
9110
- const data = readFileSync3(VERSION_CACHE_FILE, "utf-8");
9111
- return JSON.parse(data);
9112
- } catch {
9113
- return null;
9114
- }
9115
- }
9116
- function writeVersionCache(cache) {
9117
- try {
9118
- if (!existsSync2(CACHE_DIR)) {
9119
- mkdirSync3(CACHE_DIR, { recursive: true });
9120
- }
9121
- writeFileSync3(VERSION_CACHE_FILE, JSON.stringify(cache, null, 2));
9122
- } catch {
9123
- }
9124
- }
9125
- async function fetchLatestVersion() {
9126
- try {
9127
- const controller = new AbortController();
9128
- const timeout = setTimeout(() => controller.abort(), 5e3);
9129
- const response = await fetch("https://registry.npmjs.org/@vultisig/cli/latest", {
9130
- signal: controller.signal,
9131
- headers: {
9132
- Accept: "application/json"
9133
- }
9134
- });
9135
- clearTimeout(timeout);
9136
- if (!response.ok) return null;
9137
- const data = await response.json();
9138
- return data.version ?? null;
9139
- } catch {
9140
- return null;
9141
- }
9142
- }
9143
- function isNewerVersion(v1, v2) {
9144
- const parse = (v) => {
9145
- const clean2 = v.replace(/^v/, "").replace(/-.*$/, "");
9146
- return clean2.split(".").map((n) => parseInt(n, 10) || 0);
9147
- };
9148
- const p1 = parse(v1);
9149
- const p2 = parse(v2);
9150
- for (let i = 0; i < 3; i++) {
9151
- const n1 = p1[i] ?? 0;
9152
- const n2 = p2[i] ?? 0;
9153
- if (n2 > n1) return true;
9154
- if (n2 < n1) return false;
9155
- }
9156
- if (v1.includes("-") && !v2.includes("-")) return true;
9157
- return false;
9158
- }
9159
- async function checkForUpdates() {
9160
- if (process.env.VULTISIG_NO_UPDATE_CHECK === "1") {
9161
- return null;
9162
- }
9163
- const currentVersion = getVersion();
9164
- const cache = readVersionCache();
9165
- if (cache && Date.now() - cache.lastCheck < CACHE_TTL_MS) {
9166
- return {
9167
- currentVersion,
9168
- latestVersion: cache.latestVersion,
9169
- updateAvailable: cache.latestVersion ? isNewerVersion(currentVersion, cache.latestVersion) : false
9170
- };
9171
- }
9172
- const latestVersion = await fetchLatestVersion();
9173
- writeVersionCache({
9174
- lastCheck: Date.now(),
9175
- latestVersion
9176
- });
9177
- return {
9178
- currentVersion,
9179
- latestVersion,
9180
- updateAvailable: latestVersion ? isNewerVersion(currentVersion, latestVersion) : false
9181
- };
9182
- }
9183
- function formatVersionShort() {
9184
- return `vultisig/${getVersion()}`;
9185
- }
9186
- function formatVersionDetailed() {
9187
- const lines = [];
9188
- lines.push(chalk14.bold(`Vultisig CLI v${getVersion()}`));
9189
- lines.push("");
9190
- lines.push(` Node.js: ${process.version}`);
9191
- lines.push(` Platform: ${process.platform}-${process.arch}`);
9192
- lines.push(` Config: ~/.vultisig/`);
9193
- return lines.join("\n");
9194
- }
9195
- function detectInstallMethod() {
9196
- const execPath = process.execPath;
9197
- if (execPath.includes("homebrew") || execPath.includes("Cellar")) {
9198
- return "homebrew";
9199
- }
9200
- if (process.env.npm_execpath?.includes("yarn")) {
9201
- return "yarn";
9202
- }
9203
- if (process.env.npm_config_user_agent?.includes("npm")) {
9204
- return "npm";
9205
- }
9206
- if (execPath.includes("node_modules")) {
9207
- return "npm";
9208
- }
9209
- return "unknown";
9210
- }
9211
- function getUpdateCommand() {
9212
- const method = detectInstallMethod();
9213
- switch (method) {
9214
- case "npm":
9215
- return "npm update -g @vultisig/cli";
9216
- case "yarn":
9217
- return "yarn global upgrade @vultisig/cli";
9218
- case "homebrew":
9219
- return "brew upgrade vultisig";
9220
- default:
9221
- return "npm update -g @vultisig/cli";
9222
- }
9223
- }
9224
11023
 
9225
11024
  // src/lib/completion.ts
9226
11025
  import { homedir as homedir4 } from "os";
@@ -9561,9 +11360,32 @@ setupUserAgent();
9561
11360
  if (handled) process.exit(0);
9562
11361
  })();
9563
11362
  var ctx;
9564
- program.name("vultisig").description("Vultisig CLI - Secure multi-party crypto wallet").version(formatVersionShort(), "-v, --version", "Show version").option("--debug", "Enable debug output").option("--silent", "Suppress informational output, show only results").option("-o, --output <format>", "Output format: table, json (default: table)", "table").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").hook("preAction", (thisCommand) => {
11363
+ program.name("vultisig").description("Vultisig CLI - Secure multi-party crypto wallet").version(formatVersionShort(), "-v, --version", "Show version").option("--debug", "Enable debug output").option("--silent", "Suppress informational output, show only results").option(
11364
+ "-o, --output <format>",
11365
+ "Output format: json, table (defaults to json when piped)",
11366
+ (val) => {
11367
+ if (!["json", "table"].includes(val)) throw new InvalidArgumentError('Must be "json" or "table"');
11368
+ return val;
11369
+ },
11370
+ process.stdout.isTTY ? "table" : "json"
11371
+ ).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(
11372
+ "after",
11373
+ "\nExit codes:\n" + Object.entries(EXIT_CODE_DESCRIPTIONS).map(([k, v]) => ` ${k} ${v}`).join("\n") + "\n\nEnvironment variables:\n VAULT_PASSWORD Vault password for signing (bypasses 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 NO_COLOR Disable colored output"
11374
+ ).hook("preAction", (thisCommand) => {
9565
11375
  const opts = thisCommand.opts();
11376
+ if (opts.ci) {
11377
+ const outputExplicit = process.argv.some((a) => a === "--output" || a === "-o" || a.startsWith("--output="));
11378
+ opts.output = opts.output === "table" && !outputExplicit ? "json" : opts.output;
11379
+ opts.quiet = true;
11380
+ opts.nonInteractive = true;
11381
+ }
9566
11382
  initOutputMode({ silent: opts.silent, output: opts.output });
11383
+ setQuiet(!!opts.quiet);
11384
+ setNonInteractive(!!opts.nonInteractive);
11385
+ const fields = opts.fields;
11386
+ setFields(
11387
+ fields ? fields.split(",").map((f) => f.trim()).filter(Boolean) : void 0
11388
+ );
9567
11389
  });
9568
11390
  async function findVaultByNameOrId(sdk, nameOrId) {
9569
11391
  const vaults = await sdk.listVaults();
@@ -9607,7 +11429,15 @@ async function init(vaultOverride, unlockPassword, passwordTTL) {
9607
11429
  return ctx;
9608
11430
  }
9609
11431
  var createCmd = program.command("create").description("Create a vault");
9610
- createCmd.command("fast").description("Create a fast vault (server-assisted 2-of-2)").requiredOption("--name <name>", "Vault name").requiredOption("--password <password>", "Vault password").requiredOption("--email <email>", "Email for verification").option("--two-step", 'Create vault without verifying OTP (verify later with "vultisig verify")').action(
11432
+ createCmd.command("fast").description("Create a fast vault (server-assisted 2-of-2)").requiredOption("--name <name>", "Vault name").requiredOption("--password <password>", "Vault password").requiredOption("--email <email>", "Email for verification").option("--two-step", 'Create vault without verifying OTP (verify later with "vultisig verify")').addHelpText(
11433
+ "after",
11434
+ `
11435
+ Examples:
11436
+ vultisig create fast --name mywallet --password secret --email me@example.com
11437
+ vultisig create fast --name mywallet --password secret --email me@example.com --two-step
11438
+
11439
+ See also: verify, auth setup`
11440
+ ).action(
9611
11441
  withExit(async (options) => {
9612
11442
  const context = await init(program.opts().vault);
9613
11443
  await executeCreateFast(context, { ...options, twoStep: options.twoStep });
@@ -9633,7 +11463,13 @@ program.command("add-mldsa").description("Add ML-DSA (post-quantum) keys to the
9633
11463
  });
9634
11464
  })
9635
11465
  );
9636
- program.command("import <file>").description("Import vault from .vult file").option("--password <password>", "Password to decrypt the vault file").action(
11466
+ program.command("import <file>").description("Import vault from .vult file").option("--password <password>", "Password to decrypt the vault file").addHelpText(
11467
+ "after",
11468
+ `
11469
+ Examples:
11470
+ vultisig import ~/vault-backup.vult
11471
+ vultisig import ~/vault-backup.vult --password mypassword`
11472
+ ).action(
9637
11473
  withExit(async (file, options) => {
9638
11474
  const context = await init(program.opts().vault);
9639
11475
  await executeImport(context, file, options.password);
@@ -9641,6 +11477,7 @@ program.command("import <file>").description("Import vault from .vult file").opt
9641
11477
  );
9642
11478
  var createFromSeedphraseCmd = program.command("create-from-seedphrase").description("Create vault from BIP39 seedphrase");
9643
11479
  async function promptSeedphrase() {
11480
+ requireInteractive("Use --mnemonic flag to provide seedphrase non-interactively.");
9644
11481
  info("\nEnter your 12 or 24-word recovery phrase.");
9645
11482
  info("Words will be hidden as you type.\n");
9646
11483
  const answer = await inquirer8.prompt([
@@ -9661,6 +11498,7 @@ async function promptSeedphrase() {
9661
11498
  return answer.mnemonic.trim().toLowerCase();
9662
11499
  }
9663
11500
  async function promptQrPayload() {
11501
+ requireInteractive("Use --qr or --qr-file flag to provide QR payload non-interactively.");
9664
11502
  info("\nEnter the QR code payload from the initiator device.");
9665
11503
  info('The payload starts with "vultisig://".\n');
9666
11504
  const answer = await inquirer8.prompt([
@@ -9786,7 +11624,15 @@ program.command("verify <vaultId>").description("Verify vault with email verific
9786
11624
  }
9787
11625
  )
9788
11626
  );
9789
- program.command("balance [chain]").description("Show balance for a chain or all chains").option("-t, --tokens", "Include token balances").option("--raw", "Show raw values (wei/satoshis) for programmatic use").action(
11627
+ program.command("balance [chain]").description(descriptions.balance.description).option("-t, --tokens", descriptions.balance.params.includeTokens).option("--raw", "Show raw values (wei/satoshis) for programmatic use").addHelpText(
11628
+ "after",
11629
+ `
11630
+ Examples:
11631
+ vultisig balance
11632
+ vultisig balance Ethereum --tokens
11633
+ vultisig balance --output json --fields chain,amount
11634
+ vultisig balance --output json -q`
11635
+ ).action(
9790
11636
  withExit(async (chainStr, options) => {
9791
11637
  const context = await init(program.opts().vault);
9792
11638
  await executeBalance(context, {
@@ -9796,7 +11642,20 @@ program.command("balance [chain]").description("Show balance for a chain or all
9796
11642
  });
9797
11643
  })
9798
11644
  );
9799
- program.command("send <chain> <to> [amount]").description("Send tokens to an address").option("--max", "Send maximum amount (balance minus fees)").option("--token <tokenId>", "Token to send (default: native)").option("--memo <memo>", "Transaction memo").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").action(
11645
+ 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("--password <password>", "Vault password for signing").addHelpText(
11646
+ "after",
11647
+ `
11648
+ Examples:
11649
+ vultisig send Ethereum 0x1234...abcd 0.1
11650
+ vultisig send Bitcoin bc1q... --max --confirm
11651
+ vultisig send Ethereum 0x... 0.5 --dry-run --output json
11652
+
11653
+ Environment variables:
11654
+ VAULT_PASSWORD Vault password (bypasses prompt)
11655
+ VAULT_PASSWORDS Space-separated VaultName:password pairs
11656
+
11657
+ See also: balance, tx-status`
11658
+ ).action(
9800
11659
  withExit(
9801
11660
  async (chainStr, to, amount, options) => {
9802
11661
  if (!amount && !options.max) throw new Error("Provide an amount or use --max");
@@ -9809,7 +11668,8 @@ program.command("send <chain> <to> [amount]").description("Send tokens to an add
9809
11668
  amount: amount ?? "max",
9810
11669
  tokenId: options.token,
9811
11670
  memo: options.memo,
9812
- yes: options.yes,
11671
+ dryRun: options.dryRun,
11672
+ yes: options.yes || options.confirm,
9813
11673
  password: options.password
9814
11674
  });
9815
11675
  } catch (err) {
@@ -9822,7 +11682,13 @@ program.command("send <chain> <to> [amount]").description("Send tokens to an add
9822
11682
  }
9823
11683
  )
9824
11684
  );
9825
- program.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("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").action(
11685
+ program.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(
11686
+ "after",
11687
+ `
11688
+ Examples:
11689
+ vultisig execute THORChain <contract> '{"swap":{}}' --yes
11690
+ vultisig execute THORChain <contract> '{"deposit":{}}' --funds rune:1000000 --output json`
11691
+ ).action(
9826
11692
  withExit(
9827
11693
  async (chainStr, contract, msg, options) => {
9828
11694
  const context = await init(program.opts().vault, options.password);
@@ -9833,6 +11699,7 @@ program.command("execute <chain> <contract> <msg>").description("Execute a CosmW
9833
11699
  msg,
9834
11700
  funds: options.funds,
9835
11701
  memo: options.memo,
11702
+ dryRun: options.dryRun,
9836
11703
  yes: options.yes,
9837
11704
  password: options.password
9838
11705
  });
@@ -9865,7 +11732,13 @@ program.command("broadcast").description("Broadcast a pre-signed raw transaction
9865
11732
  });
9866
11733
  })
9867
11734
  );
9868
- 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").action(
11735
+ 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").addHelpText(
11736
+ "after",
11737
+ `
11738
+ Examples:
11739
+ vultisig tx-status --chain Ethereum --tx-hash 0xabc...
11740
+ vultisig tx-status --chain Bitcoin --tx-hash abc... --no-wait --output json`
11741
+ ).action(
9869
11742
  withExit(async (options) => {
9870
11743
  const context = await init(program.opts().vault);
9871
11744
  await executeTxStatus(context, {
@@ -9875,7 +11748,13 @@ program.command("tx-status").description("Check the status of a transaction (pol
9875
11748
  });
9876
11749
  })
9877
11750
  );
9878
- program.command("portfolio").description("Show total portfolio value").option("-c, --currency <currency>", "Fiat currency (usd, eur, gbp, etc.)", "usd").option("--raw", "Show raw values (wei/satoshis) for programmatic use").action(
11751
+ 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(
11752
+ "after",
11753
+ `
11754
+ Examples:
11755
+ vultisig portfolio
11756
+ vultisig portfolio --currency eur --output json`
11757
+ ).action(
9879
11758
  withExit(async (options) => {
9880
11759
  const context = await init(program.opts().vault);
9881
11760
  await executePortfolio(context, {
@@ -9902,7 +11781,13 @@ program.command("discount").description("Show your VULT discount tier for swap f
9902
11781
  await executeDiscount(context, { refresh: options.refresh });
9903
11782
  })
9904
11783
  );
9905
- program.command("export [path]").description("Export vault to file").option("--password <password>", "Password to unlock the vault (for encrypted vaults)").option("--exportPassword <password>", "Password to encrypt the exported file (defaults to --password)").action(
11784
+ program.command("export [path]").description("Export vault to file").option("--password <password>", "Password to unlock the vault (for encrypted vaults)").option("--exportPassword <password>", "Password to encrypt the exported file (defaults to --password)").addHelpText(
11785
+ "after",
11786
+ `
11787
+ Examples:
11788
+ vultisig export ~/backup.vult
11789
+ vultisig export ~/backup.vult --password mypass --output json`
11790
+ ).action(
9906
11791
  withExit(async (path4, options) => {
9907
11792
  const context = await init(program.opts().vault, options.password);
9908
11793
  await executeExport(context, {
@@ -9912,7 +11797,13 @@ program.command("export [path]").description("Export vault to file").option("--p
9912
11797
  });
9913
11798
  })
9914
11799
  );
9915
- program.command("addresses").description("Show all vault addresses").action(
11800
+ program.command("addresses").description(descriptions.address.description).addHelpText(
11801
+ "after",
11802
+ `
11803
+ Examples:
11804
+ vultisig addresses
11805
+ vultisig addresses --output json --fields chain,address`
11806
+ ).action(
9916
11807
  withExit(async () => {
9917
11808
  const context = await init(program.opts().vault);
9918
11809
  await executeAddresses(context);
@@ -9930,7 +11821,14 @@ program.command("address-book").description("Manage address book entries").optio
9930
11821
  });
9931
11822
  })
9932
11823
  );
9933
- program.command("chains").description("List and manage chains").option("--add <chain>", "Add a chain").option("--add-all", "Add all supported chains").option("--remove <chain>", "Remove a chain").action(
11824
+ program.command("chains").description("List and manage chains").option("--add <chain>", "Add a chain").option("--add-all", "Add all supported chains").option("--remove <chain>", "Remove a chain").addHelpText(
11825
+ "after",
11826
+ `
11827
+ Examples:
11828
+ vultisig chains
11829
+ vultisig chains --add Solana
11830
+ vultisig chains --add-all --output json`
11831
+ ).action(
9934
11832
  withExit(async (options) => {
9935
11833
  const context = await init(program.opts().vault);
9936
11834
  await executeChains(context, {
@@ -9940,7 +11838,13 @@ program.command("chains").description("List and manage chains").option("--add <c
9940
11838
  });
9941
11839
  })
9942
11840
  );
9943
- program.command("vaults").description("List all stored vaults").action(
11841
+ program.command("vaults").description("List all stored vaults").addHelpText(
11842
+ "after",
11843
+ `
11844
+ Examples:
11845
+ vultisig vaults
11846
+ vultisig vaults --output json`
11847
+ ).action(
9944
11848
  withExit(async () => {
9945
11849
  const context = await init(program.opts().vault);
9946
11850
  await executeVaults(context);
@@ -9958,7 +11862,7 @@ program.command("rename <newName>").description("Rename the active vault").actio
9958
11862
  await executeRename(context, newName);
9959
11863
  })
9960
11864
  );
9961
- program.command("info").description("Show detailed vault information").action(
11865
+ program.command("info").description(descriptions.vaultInfo.description).action(
9962
11866
  withExit(async () => {
9963
11867
  const context = await init(program.opts().vault);
9964
11868
  await executeInfo(context);
@@ -9973,7 +11877,14 @@ program.command("delete [vault]").description("Delete a vault from local storage
9973
11877
  });
9974
11878
  })
9975
11879
  );
9976
- program.command("tokens <chain>").description("List and manage tokens for a chain").option("--add <contractAddress>", "Add a token by contract address").option("--remove <tokenId>", "Remove a token by ID").option("--symbol <symbol>", "Token symbol (for --add)").option("--name <name>", "Token name (for --add)").option("--decimals <decimals>", "Token decimals (for --add)", "18").action(
11880
+ program.command("tokens <chain>").description("List and manage tokens for a chain").option("--add <contractAddress>", "Add a token by contract address").option("--remove <tokenId>", "Remove a token by ID").option("--discover", "Auto-discover tokens with balances on the chain").addHelpText(
11881
+ "after",
11882
+ `
11883
+ Examples:
11884
+ vultisig tokens Ethereum
11885
+ vultisig tokens Ethereum --discover --output json
11886
+ vultisig tokens Ethereum --add 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --symbol USDC --decimals 6`
11887
+ ).option("--symbol <symbol>", "Token symbol (for --add)").option("--name <name>", "Token name (for --add)").option("--decimals <decimals>", "Token decimals (for --add)", "18").action(
9977
11888
  withExit(
9978
11889
  async (chainStr, options) => {
9979
11890
  const context = await init(program.opts().vault);
@@ -9981,6 +11892,7 @@ program.command("tokens <chain>").description("List and manage tokens for a chai
9981
11892
  chain: findChainByName(chainStr) || chainStr,
9982
11893
  add: options.add,
9983
11894
  remove: options.remove,
11895
+ discover: options.discover,
9984
11896
  symbol: options.symbol,
9985
11897
  name: options.name,
9986
11898
  decimals: options.decimals ? parseInt(options.decimals, 10) : void 0
@@ -9988,13 +11900,19 @@ program.command("tokens <chain>").description("List and manage tokens for a chai
9988
11900
  }
9989
11901
  )
9990
11902
  );
9991
- program.command("swap-chains").description("List chains that support swaps").action(
11903
+ program.command("swap-chains").description(descriptions.supportedChains.description).action(
9992
11904
  withExit(async () => {
9993
11905
  const context = await init(program.opts().vault);
9994
11906
  await executeSwapChains(context);
9995
11907
  })
9996
11908
  );
9997
- program.command("swap-quote <fromChain> <toChain> [amount]").description("Get a swap quote without executing").option("--max", "Swap maximum amount (full balance minus fees for native)").option("--from-token <address>", "Token address to swap from (default: native)").option("--to-token <address>", "Token address to swap to (default: native)").action(
11909
+ program.command("swap-quote <fromChain> <toChain> [amount]").description(descriptions.swapQuote.description).option("--max", "Swap maximum amount (full balance minus fees for native)").option("--from-token <address>", "Token address to swap from (default: native)").option("--to-token <address>", "Token address to swap to (default: native)").addHelpText(
11910
+ "after",
11911
+ `
11912
+ Examples:
11913
+ vultisig swap-quote Ethereum Bitcoin 0.1
11914
+ vultisig swap-quote Ethereum Bitcoin --max --output json`
11915
+ ).action(
9998
11916
  withExit(
9999
11917
  async (fromChainStr, toChainStr, amountStr, options) => {
10000
11918
  if (!amountStr && !options.max) throw new Error("Provide an amount or use --max");
@@ -10010,7 +11928,16 @@ program.command("swap-quote <fromChain> <toChain> [amount]").description("Get a
10010
11928
  }
10011
11929
  )
10012
11930
  );
10013
- program.command("swap <fromChain> <toChain> [amount]").description("Swap tokens between chains").option("--max", "Swap maximum amount (full balance minus fees for native)").option("--from-token <address>", "Token address to swap from (default: native)").option("--to-token <address>", "Token address to swap to (default: native)").option("--slippage <percent>", "Slippage tolerance in percent", "1").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").action(
11931
+ program.command("swap <fromChain> <toChain> [amount]").description(descriptions.swap.description).option("--max", "Swap maximum amount (full balance minus fees for native)").option("--from-token <address>", "Token address to swap from (default: native)").option("--to-token <address>", "Token address to swap to (default: native)").option("--slippage <percent>", "Slippage tolerance in percent", "1").option("--dry-run", "Preview swap without signing or broadcasting").option("--confirm", "Confirm and broadcast (without this flag, runs as a preview)").option("-y, --yes", "Alias for --confirm").option("--password <password>", "Vault password for signing").addHelpText(
11932
+ "after",
11933
+ `
11934
+ Examples:
11935
+ vultisig swap Ethereum Bitcoin 0.1
11936
+ vultisig swap Ethereum Bitcoin --max --confirm
11937
+ vultisig swap Ethereum Bitcoin 0.5 --dry-run --output json
11938
+
11939
+ See also: swap-quote, swap-chains, balance`
11940
+ ).action(
10014
11941
  withExit(
10015
11942
  async (fromChainStr, toChainStr, amountStr, options) => {
10016
11943
  if (!amountStr && !options.max) throw new Error("Provide an amount or use --max");
@@ -10024,7 +11951,8 @@ program.command("swap <fromChain> <toChain> [amount]").description("Swap tokens
10024
11951
  fromToken: options.fromToken,
10025
11952
  toToken: options.toToken,
10026
11953
  slippage: options.slippage ? parseFloat(options.slippage) : void 0,
10027
- yes: options.yes,
11954
+ dryRun: options.dryRun,
11955
+ yes: options.yes || options.confirm,
10028
11956
  password: options.password
10029
11957
  });
10030
11958
  } catch (err) {
@@ -10068,7 +11996,7 @@ rujiraCmd.command("deposit").description("Show deposit instructions (inbound add
10068
11996
  }
10069
11997
  )
10070
11998
  );
10071
- rujiraCmd.command("swap <fromAsset> <toAsset> <amount>").description("Execute a FIN swap (amount in base units)").option("--slippage-bps <bps>", "Slippage tolerance in basis points (default: 100 = 1%)", "100").option("--destination <thorAddress>", "Destination THOR address (default: vault THORChain address)").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").option("--rpc <url>", "Override THORChain RPC endpoint").option("--rest <url>", "Override THORNode REST endpoint").action(
11999
+ rujiraCmd.command("swap <fromAsset> <toAsset> <amount>").description("Execute a FIN swap (amount in base units)").option("--slippage-bps <bps>", "Slippage tolerance in basis points (default: 100 = 1%)", "100").option("--destination <thorAddress>", "Destination THOR address (default: vault THORChain address)").option("--dry-run", "Preview swap quote without executing").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").option("--rpc <url>", "Override THORChain RPC endpoint").option("--rest <url>", "Override THORNode REST endpoint").action(
10072
12000
  withExit(
10073
12001
  async (fromAsset, toAsset, amount, options) => {
10074
12002
  const context = await init(program.opts().vault, options.password);
@@ -10078,6 +12006,7 @@ rujiraCmd.command("swap <fromAsset> <toAsset> <amount>").description("Execute a
10078
12006
  amount,
10079
12007
  slippageBps: options.slippageBps ? parseInt(options.slippageBps, 10) : void 0,
10080
12008
  destination: options.destination,
12009
+ dryRun: options.dryRun,
10081
12010
  yes: options.yes,
10082
12011
  password: options.password,
10083
12012
  rpcEndpoint: options.rpc,
@@ -10086,7 +12015,7 @@ rujiraCmd.command("swap <fromAsset> <toAsset> <amount>").description("Execute a
10086
12015
  }
10087
12016
  )
10088
12017
  );
10089
- rujiraCmd.command("withdraw <asset> <amount> <l1Address>").description("Withdraw secured assets to L1 (amount in base units)").option("--max-fee-bps <bps>", "Max outbound fee as bps of amount (optional)").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").option("--rpc <url>", "Override THORChain RPC endpoint").option("--rest <url>", "Override THORNode REST endpoint").action(
12018
+ rujiraCmd.command("withdraw <asset> <amount> <l1Address>").description("Withdraw secured assets to L1 (amount in base units)").option("--max-fee-bps <bps>", "Max outbound fee as bps of amount (optional)").option("--dry-run", "Preview withdrawal without executing").option("-y, --yes", "Skip confirmation prompt").option("--password <password>", "Vault password for signing").option("--rpc <url>", "Override THORChain RPC endpoint").option("--rest <url>", "Override THORNode REST endpoint").action(
10090
12019
  withExit(
10091
12020
  async (asset, amount, l1Address, options) => {
10092
12021
  const context = await init(program.opts().vault, options.password);
@@ -10095,6 +12024,7 @@ rujiraCmd.command("withdraw <asset> <amount> <l1Address>").description("Withdraw
10095
12024
  amount,
10096
12025
  l1Address,
10097
12026
  maxFeeBps: options.maxFeeBps ? parseInt(options.maxFeeBps, 10) : void 0,
12027
+ dryRun: options.dryRun,
10098
12028
  yes: options.yes,
10099
12029
  password: options.password,
10100
12030
  rpcEndpoint: options.rpc,
@@ -10129,7 +12059,13 @@ var agentCmd = program.command("agent").description("AI-powered chat interface f
10129
12059
  });
10130
12060
  }
10131
12061
  );
10132
- agentCmd.command("ask <message>").description("Send a single message and get the response (for AI agent integration)").option("--session <id>", "Continue an existing conversation").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--verbose", "Show tool calls and debug info on stderr").option("--json", "Output structured JSON instead of text").action(
12062
+ agentCmd.command("ask <message>").description("Send a single message and get the response (for AI agent integration)").option("--session <id>", "Continue an existing conversation").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--verbose", "Show tool calls and debug info on stderr").option("--json", "Output structured JSON (deprecated: use --output json)").addHelpText(
12063
+ "after",
12064
+ `
12065
+ Examples:
12066
+ vultisig agent ask "What is my ETH balance?" --output json
12067
+ vultisig agent ask "Send 0.1 ETH to 0x..." --session abc123 --yes`
12068
+ ).action(
10133
12069
  async (message, options) => {
10134
12070
  const parentOpts = agentCmd.opts();
10135
12071
  const context = await init(program.opts().vault, options.password || parentOpts.password);
@@ -10197,7 +12133,66 @@ program.command("update").description("Check for updates and show update command
10197
12133
  }
10198
12134
  })
10199
12135
  );
12136
+ var authCmd = program.command("auth").description("Manage keyring-stored vault credentials");
12137
+ 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(
12138
+ "after",
12139
+ `
12140
+ Examples:
12141
+ vultisig auth setup
12142
+ vultisig auth setup --vault-file ~/vault.vult
12143
+ VAULT_PASSWORD=secret VAULT_DECRYPT_PASSWORD=pass vultisig auth setup --non-interactive`
12144
+ ).action(
12145
+ withExit(async (options) => {
12146
+ const result = await executeAuthSetup({
12147
+ vaultFile: options.vaultFile,
12148
+ nonInteractive: options.nonInteractive || isNonInteractive()
12149
+ });
12150
+ if (isJsonOutput()) {
12151
+ outputJson({
12152
+ stored: true,
12153
+ vaultId: result.vaultId,
12154
+ vaultName: result.vaultName,
12155
+ storageBackend: result.storageBackend
12156
+ });
12157
+ } else {
12158
+ printResult(
12159
+ chalk15.green(`Vault "${result.vaultName}" (${result.vaultId}) credentials stored in ${result.storageBackend}.`)
12160
+ );
12161
+ }
12162
+ })
12163
+ );
12164
+ authCmd.command("status").description("List configured vaults and their keyring credential status").action(
12165
+ withExit(async () => {
12166
+ const vaults = await executeAuthStatus();
12167
+ if (isJsonOutput()) {
12168
+ outputJson({
12169
+ vaults: vaults.map((v) => ({ id: v.id, name: v.name, filePath: v.filePath, hasCredentials: v.hasCredentials }))
12170
+ });
12171
+ return;
12172
+ }
12173
+ if (vaults.length === 0) {
12174
+ printResult("No vaults configured. Run: vsig auth setup");
12175
+ return;
12176
+ }
12177
+ for (const v of vaults) {
12178
+ const status = v.hasCredentials ? chalk15.green("authenticated") : chalk15.red("no credentials");
12179
+ printResult(` ${v.name} (${v.id}) - ${status}`);
12180
+ printResult(` File: ${v.filePath}`);
12181
+ }
12182
+ })
12183
+ );
12184
+ authCmd.command("logout").description("Clear keyring credentials for a vault").option("--vault-id <id>", "Specific vault ID to clear").option("--all", "Clear credentials for all configured vaults").action(
12185
+ withExit(async (options) => {
12186
+ await executeAuthLogout({ vaultId: options.vaultId, all: options.all });
12187
+ if (isJsonOutput()) {
12188
+ outputJson({ cleared: true, vaultId: options.vaultId ?? null, all: !!options.all });
12189
+ } else {
12190
+ printResult(chalk15.green("Credentials cleared."));
12191
+ }
12192
+ })
12193
+ );
10200
12194
  setupCompletionCommand(program);
12195
+ program.command("schema", { hidden: true }).description("Output machine-readable command schema (JSON introspection for agents)").helpOption(false).action(withExit(async () => executeSchema(program)));
10201
12196
  async function startInteractiveMode() {
10202
12197
  const serverEndpoints = resolveServerEndpoints(parseServerEndpointOverridesFromArgv(process.argv.slice(2)));
10203
12198
  const sdk = new Vultisig6({