@vultisig/cli 0.22.4 → 0.22.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/index.js +1065 -1891
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1449,980 +1449,6 @@ var init_formatUnits = __esm({
|
|
|
1449
1449
|
}
|
|
1450
1450
|
});
|
|
1451
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://gateway.liquify.com/chain/thorchain_midgard";
|
|
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://gateway.liquify.com/chain/thorchain_api",
|
|
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();
|
|
2423
|
-
}
|
|
2424
|
-
});
|
|
2425
|
-
|
|
2426
1452
|
// src/index.ts
|
|
2427
1453
|
import "dotenv/config";
|
|
2428
1454
|
import { promises as fs4 } from "node:fs";
|
|
@@ -4514,8 +3540,9 @@ async function executeVaults(ctx2) {
|
|
|
4514
3540
|
spinner.succeed("Vaults loaded");
|
|
4515
3541
|
if (isJsonOutput()) {
|
|
4516
3542
|
const activeVault2 = ctx2.getActiveVault();
|
|
3543
|
+
const sorted = [...vaults].sort((a, b) => a.id === activeVault2?.id ? -1 : b.id === activeVault2?.id ? 1 : 0);
|
|
4517
3544
|
outputJson({
|
|
4518
|
-
vaults:
|
|
3545
|
+
vaults: sorted.map((v) => ({
|
|
4519
3546
|
id: v.id,
|
|
4520
3547
|
name: v.name,
|
|
4521
3548
|
type: v.type,
|
|
@@ -5824,10 +4851,10 @@ async function authenticateVault(client, vault, password, maxAttempts = 3) {
|
|
|
5824
4851
|
});
|
|
5825
4852
|
const messageHash = computePersonalSignHash(authMessage);
|
|
5826
4853
|
let lastError = null;
|
|
5827
|
-
for (let
|
|
4854
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
5828
4855
|
try {
|
|
5829
|
-
if (
|
|
5830
|
-
process.stderr.write(` Retry ${
|
|
4856
|
+
if (attempt > 1) {
|
|
4857
|
+
process.stderr.write(` Retry ${attempt}/${maxAttempts}...
|
|
5831
4858
|
`);
|
|
5832
4859
|
}
|
|
5833
4860
|
const signature = await vault.signBytes({ data: Buffer.from(messageHash), chain: Chain7.Ethereum }, {});
|
|
@@ -5844,7 +4871,7 @@ async function authenticateVault(client, vault, password, maxAttempts = 3) {
|
|
|
5844
4871
|
};
|
|
5845
4872
|
} catch (err) {
|
|
5846
4873
|
lastError = err;
|
|
5847
|
-
if (
|
|
4874
|
+
if (attempt < maxAttempts && err.message?.includes("timeout")) {
|
|
5848
4875
|
continue;
|
|
5849
4876
|
}
|
|
5850
4877
|
throw err;
|
|
@@ -6368,22 +5395,413 @@ function getNativeTokenDecimals(chain) {
|
|
|
6368
5395
|
return decimals[chain] || 18;
|
|
6369
5396
|
}
|
|
6370
5397
|
|
|
6371
|
-
//
|
|
6372
|
-
|
|
5398
|
+
// ../../packages/core/chain/dist/Chain.js
|
|
5399
|
+
var EthereumL2Chain = {
|
|
5400
|
+
Arbitrum: "Arbitrum",
|
|
5401
|
+
Base: "Base",
|
|
5402
|
+
Blast: "Blast",
|
|
5403
|
+
Optimism: "Optimism",
|
|
5404
|
+
Zksync: "Zksync",
|
|
5405
|
+
Mantle: "Mantle"
|
|
5406
|
+
};
|
|
5407
|
+
var EvmChain = {
|
|
5408
|
+
...EthereumL2Chain,
|
|
5409
|
+
Avalanche: "Avalanche",
|
|
5410
|
+
CronosChain: "CronosChain",
|
|
5411
|
+
BSC: "BSC",
|
|
5412
|
+
Ethereum: "Ethereum",
|
|
5413
|
+
Polygon: "Polygon",
|
|
5414
|
+
Hyperliquid: "Hyperliquid",
|
|
5415
|
+
Sei: "Sei"
|
|
5416
|
+
};
|
|
5417
|
+
var UtxoChain;
|
|
5418
|
+
(function(UtxoChain2) {
|
|
5419
|
+
UtxoChain2["Bitcoin"] = "Bitcoin";
|
|
5420
|
+
UtxoChain2["BitcoinCash"] = "Bitcoin-Cash";
|
|
5421
|
+
UtxoChain2["Litecoin"] = "Litecoin";
|
|
5422
|
+
UtxoChain2["Dogecoin"] = "Dogecoin";
|
|
5423
|
+
UtxoChain2["Dash"] = "Dash";
|
|
5424
|
+
UtxoChain2["Zcash"] = "Zcash";
|
|
5425
|
+
})(UtxoChain || (UtxoChain = {}));
|
|
5426
|
+
var cosmosChainsByKind = {
|
|
5427
|
+
ibcEnabled: {
|
|
5428
|
+
Cosmos: "Cosmos",
|
|
5429
|
+
Osmosis: "Osmosis",
|
|
5430
|
+
Dydx: "Dydx",
|
|
5431
|
+
Kujira: "Kujira",
|
|
5432
|
+
Terra: "Terra",
|
|
5433
|
+
TerraClassic: "TerraClassic",
|
|
5434
|
+
Noble: "Noble",
|
|
5435
|
+
Akash: "Akash"
|
|
5436
|
+
},
|
|
5437
|
+
vaultBased: {
|
|
5438
|
+
THORChain: "THORChain",
|
|
5439
|
+
MayaChain: "MayaChain"
|
|
5440
|
+
}
|
|
5441
|
+
};
|
|
5442
|
+
var IbcEnabledCosmosChain = cosmosChainsByKind.ibcEnabled;
|
|
5443
|
+
var VaultBasedCosmosChain = cosmosChainsByKind.vaultBased;
|
|
5444
|
+
var CosmosChain = {
|
|
5445
|
+
...IbcEnabledCosmosChain,
|
|
5446
|
+
...VaultBasedCosmosChain
|
|
5447
|
+
};
|
|
5448
|
+
var OtherChain;
|
|
5449
|
+
(function(OtherChain2) {
|
|
5450
|
+
OtherChain2["Sui"] = "Sui";
|
|
5451
|
+
OtherChain2["Solana"] = "Solana";
|
|
5452
|
+
OtherChain2["Polkadot"] = "Polkadot";
|
|
5453
|
+
OtherChain2["Bittensor"] = "Bittensor";
|
|
5454
|
+
OtherChain2["Ton"] = "Ton";
|
|
5455
|
+
OtherChain2["Ripple"] = "Ripple";
|
|
5456
|
+
OtherChain2["Tron"] = "Tron";
|
|
5457
|
+
OtherChain2["Cardano"] = "Cardano";
|
|
5458
|
+
OtherChain2["QBTC"] = "QBTC";
|
|
5459
|
+
})(OtherChain || (OtherChain = {}));
|
|
5460
|
+
var Chain9 = {
|
|
5461
|
+
...EvmChain,
|
|
5462
|
+
...UtxoChain,
|
|
5463
|
+
...CosmosChain,
|
|
5464
|
+
...OtherChain
|
|
5465
|
+
};
|
|
5466
|
+
var UtxoBasedChain = [
|
|
5467
|
+
...Object.values(UtxoChain),
|
|
5468
|
+
OtherChain.Cardano
|
|
5469
|
+
];
|
|
5470
|
+
var defaultChains = [
|
|
5471
|
+
Chain9.Bitcoin,
|
|
5472
|
+
Chain9.Ethereum,
|
|
5473
|
+
Chain9.THORChain,
|
|
5474
|
+
Chain9.Solana,
|
|
5475
|
+
Chain9.BSC
|
|
5476
|
+
];
|
|
6373
5477
|
|
|
6374
|
-
// ../../
|
|
6375
|
-
|
|
5478
|
+
// ../../packages/core/chain/dist/ChainKind.js
|
|
5479
|
+
var chainKindRecord = {
|
|
5480
|
+
[EvmChain.Arbitrum]: "evm",
|
|
5481
|
+
[EvmChain.Avalanche]: "evm",
|
|
5482
|
+
[EvmChain.Base]: "evm",
|
|
5483
|
+
[EvmChain.CronosChain]: "evm",
|
|
5484
|
+
[EvmChain.BSC]: "evm",
|
|
5485
|
+
[EvmChain.Blast]: "evm",
|
|
5486
|
+
[EvmChain.Ethereum]: "evm",
|
|
5487
|
+
[EvmChain.Optimism]: "evm",
|
|
5488
|
+
[EvmChain.Polygon]: "evm",
|
|
5489
|
+
[EvmChain.Zksync]: "evm",
|
|
5490
|
+
[EvmChain.Mantle]: "evm",
|
|
5491
|
+
[EvmChain.Hyperliquid]: "evm",
|
|
5492
|
+
[EvmChain.Sei]: "evm",
|
|
5493
|
+
[UtxoChain.Bitcoin]: "utxo",
|
|
5494
|
+
[UtxoChain.BitcoinCash]: "utxo",
|
|
5495
|
+
[UtxoChain.Litecoin]: "utxo",
|
|
5496
|
+
[UtxoChain.Dogecoin]: "utxo",
|
|
5497
|
+
[UtxoChain.Dash]: "utxo",
|
|
5498
|
+
[UtxoChain.Zcash]: "utxo",
|
|
5499
|
+
[CosmosChain.THORChain]: "cosmos",
|
|
5500
|
+
[CosmosChain.Cosmos]: "cosmos",
|
|
5501
|
+
[CosmosChain.Osmosis]: "cosmos",
|
|
5502
|
+
[CosmosChain.MayaChain]: "cosmos",
|
|
5503
|
+
[CosmosChain.Dydx]: "cosmos",
|
|
5504
|
+
[CosmosChain.Kujira]: "cosmos",
|
|
5505
|
+
[CosmosChain.Terra]: "cosmos",
|
|
5506
|
+
[CosmosChain.TerraClassic]: "cosmos",
|
|
5507
|
+
[CosmosChain.Noble]: "cosmos",
|
|
5508
|
+
[CosmosChain.Akash]: "cosmos",
|
|
5509
|
+
[OtherChain.Sui]: "sui",
|
|
5510
|
+
[OtherChain.Solana]: "solana",
|
|
5511
|
+
[OtherChain.Polkadot]: "polkadot",
|
|
5512
|
+
[OtherChain.Bittensor]: "bittensor",
|
|
5513
|
+
[OtherChain.Ton]: "ton",
|
|
5514
|
+
[OtherChain.Ripple]: "ripple",
|
|
5515
|
+
[OtherChain.Tron]: "tron",
|
|
5516
|
+
[OtherChain.Cardano]: "cardano",
|
|
5517
|
+
[OtherChain.QBTC]: "qbtc"
|
|
5518
|
+
};
|
|
5519
|
+
function getChainKind(chain) {
|
|
5520
|
+
return chainKindRecord[chain];
|
|
5521
|
+
}
|
|
6376
5522
|
|
|
6377
|
-
//
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
5523
|
+
// ../../packages/lib/utils/dist/record/recordMap.js
|
|
5524
|
+
function recordMap(record, fn) {
|
|
5525
|
+
return Object.fromEntries(Object.entries(record).map(([key, value]) => [
|
|
5526
|
+
key,
|
|
5527
|
+
fn(value, key)
|
|
5528
|
+
]));
|
|
5529
|
+
}
|
|
5530
|
+
|
|
5531
|
+
// ../../packages/lib/utils/dist/record/makeRecord/index.js
|
|
5532
|
+
var makeRecord = (keys, getValue) => {
|
|
5533
|
+
const record = {};
|
|
5534
|
+
keys.forEach((key, index) => {
|
|
5535
|
+
record[key] = getValue(key, index);
|
|
5536
|
+
});
|
|
5537
|
+
return record;
|
|
5538
|
+
};
|
|
5539
|
+
|
|
5540
|
+
// ../../packages/core/chain/dist/chains/cosmos/thor/kujira-merge/index.js
|
|
5541
|
+
var kujiraCoinsMigratedToThorChain = [
|
|
5542
|
+
"kuji",
|
|
5543
|
+
"rkuji",
|
|
5544
|
+
"fuzn",
|
|
5545
|
+
"nstk",
|
|
5546
|
+
"wink",
|
|
5547
|
+
"lvn"
|
|
5548
|
+
];
|
|
5549
|
+
var kujiraCoinsMigratedToThorChainMetadata = {
|
|
5550
|
+
kuji: {
|
|
5551
|
+
ticker: "KUJI",
|
|
5552
|
+
logo: "kuji",
|
|
5553
|
+
priceProviderId: "kujira"
|
|
5554
|
+
},
|
|
5555
|
+
rkuji: {
|
|
5556
|
+
ticker: "rKUJI",
|
|
5557
|
+
logo: "rkuji.png",
|
|
5558
|
+
priceProviderId: "kujira"
|
|
5559
|
+
},
|
|
5560
|
+
fuzn: {
|
|
5561
|
+
ticker: "FUZN",
|
|
5562
|
+
logo: "fuzn.png",
|
|
5563
|
+
priceProviderId: "fuzion"
|
|
5564
|
+
},
|
|
5565
|
+
lvn: {
|
|
5566
|
+
ticker: "LVN",
|
|
5567
|
+
logo: "levana",
|
|
5568
|
+
priceProviderId: "levana-protocol"
|
|
5569
|
+
},
|
|
5570
|
+
nstk: {
|
|
5571
|
+
ticker: "NSTK",
|
|
5572
|
+
logo: "nstk.png",
|
|
5573
|
+
priceProviderId: "unstake-fi"
|
|
5574
|
+
},
|
|
5575
|
+
wink: {
|
|
5576
|
+
ticker: "WINK",
|
|
5577
|
+
logo: "wink.png",
|
|
5578
|
+
priceProviderId: "winkhub"
|
|
5579
|
+
}
|
|
5580
|
+
};
|
|
5581
|
+
var kujiraCoinMigratedToThorChainDestinationId = makeRecord(kujiraCoinsMigratedToThorChain, (id) => `thor.${id}`);
|
|
5582
|
+
|
|
5583
|
+
// ../../packages/core/chain/dist/coin/chainFeeCoin.js
|
|
5584
|
+
var ether = {
|
|
5585
|
+
ticker: "ETH",
|
|
5586
|
+
logo: "eth",
|
|
5587
|
+
decimals: 18,
|
|
5588
|
+
priceProviderId: "ethereum"
|
|
5589
|
+
};
|
|
5590
|
+
var leanChainFeeCoin = {
|
|
5591
|
+
[Chain9.Bitcoin]: {
|
|
5592
|
+
ticker: "BTC",
|
|
5593
|
+
logo: "btc",
|
|
5594
|
+
decimals: 8,
|
|
5595
|
+
priceProviderId: "bitcoin"
|
|
5596
|
+
},
|
|
5597
|
+
[Chain9.BitcoinCash]: {
|
|
5598
|
+
ticker: "BCH",
|
|
5599
|
+
logo: "bch",
|
|
5600
|
+
decimals: 8,
|
|
5601
|
+
priceProviderId: "bitcoin-cash"
|
|
5602
|
+
},
|
|
5603
|
+
[Chain9.Litecoin]: {
|
|
5604
|
+
ticker: "LTC",
|
|
5605
|
+
logo: "ltc",
|
|
5606
|
+
decimals: 8,
|
|
5607
|
+
priceProviderId: "litecoin"
|
|
5608
|
+
},
|
|
5609
|
+
[Chain9.Dogecoin]: {
|
|
5610
|
+
ticker: "DOGE",
|
|
5611
|
+
logo: "doge",
|
|
5612
|
+
decimals: 8,
|
|
5613
|
+
priceProviderId: "dogecoin"
|
|
5614
|
+
},
|
|
5615
|
+
[Chain9.Dash]: {
|
|
5616
|
+
ticker: "DASH",
|
|
5617
|
+
logo: "dash",
|
|
5618
|
+
decimals: 8,
|
|
5619
|
+
priceProviderId: "dash"
|
|
5620
|
+
},
|
|
5621
|
+
[Chain9.Ripple]: {
|
|
5622
|
+
ticker: "XRP",
|
|
5623
|
+
logo: "xrp",
|
|
5624
|
+
decimals: 6,
|
|
5625
|
+
priceProviderId: "ripple"
|
|
5626
|
+
},
|
|
5627
|
+
[Chain9.THORChain]: {
|
|
5628
|
+
ticker: "RUNE",
|
|
5629
|
+
logo: "rune",
|
|
5630
|
+
decimals: 8,
|
|
5631
|
+
priceProviderId: "thorchain"
|
|
5632
|
+
},
|
|
5633
|
+
[Chain9.MayaChain]: {
|
|
5634
|
+
ticker: "CACAO",
|
|
5635
|
+
logo: "cacao",
|
|
5636
|
+
decimals: 10,
|
|
5637
|
+
priceProviderId: "cacao"
|
|
5638
|
+
},
|
|
5639
|
+
[Chain9.Solana]: {
|
|
5640
|
+
ticker: "SOL",
|
|
5641
|
+
logo: "solana",
|
|
5642
|
+
decimals: 9,
|
|
5643
|
+
priceProviderId: "solana"
|
|
5644
|
+
},
|
|
5645
|
+
[Chain9.Ton]: {
|
|
5646
|
+
ticker: "TON",
|
|
5647
|
+
logo: "ton",
|
|
5648
|
+
decimals: 9,
|
|
5649
|
+
priceProviderId: "the-open-network"
|
|
5650
|
+
},
|
|
5651
|
+
[Chain9.Ethereum]: ether,
|
|
5652
|
+
[Chain9.Avalanche]: {
|
|
5653
|
+
ticker: "AVAX",
|
|
5654
|
+
logo: "avax",
|
|
5655
|
+
decimals: 18,
|
|
5656
|
+
priceProviderId: "avalanche-2"
|
|
5657
|
+
},
|
|
5658
|
+
[Chain9.BSC]: {
|
|
5659
|
+
ticker: "BNB",
|
|
5660
|
+
logo: "bsc",
|
|
5661
|
+
decimals: 18,
|
|
5662
|
+
priceProviderId: "binancecoin"
|
|
5663
|
+
},
|
|
5664
|
+
[Chain9.Polygon]: {
|
|
5665
|
+
ticker: "POL",
|
|
5666
|
+
logo: "polygon",
|
|
5667
|
+
decimals: 18,
|
|
5668
|
+
priceProviderId: "polygon-ecosystem-token"
|
|
5669
|
+
},
|
|
5670
|
+
[Chain9.CronosChain]: {
|
|
5671
|
+
ticker: "CRO",
|
|
5672
|
+
logo: "cro",
|
|
5673
|
+
decimals: 18,
|
|
5674
|
+
priceProviderId: "crypto-com-chain"
|
|
5675
|
+
},
|
|
5676
|
+
[Chain9.Dydx]: {
|
|
5677
|
+
ticker: "DYDX",
|
|
5678
|
+
logo: "dydx",
|
|
5679
|
+
decimals: 18,
|
|
5680
|
+
priceProviderId: "dydx-chain"
|
|
5681
|
+
},
|
|
5682
|
+
[Chain9.Kujira]: {
|
|
5683
|
+
...kujiraCoinsMigratedToThorChainMetadata.kuji,
|
|
5684
|
+
decimals: 6
|
|
5685
|
+
},
|
|
5686
|
+
[Chain9.Terra]: {
|
|
5687
|
+
ticker: "LUNA",
|
|
5688
|
+
logo: "luna",
|
|
5689
|
+
decimals: 6,
|
|
5690
|
+
priceProviderId: "terra-luna-2"
|
|
5691
|
+
},
|
|
5692
|
+
[Chain9.TerraClassic]: {
|
|
5693
|
+
ticker: "LUNC",
|
|
5694
|
+
logo: "lunc",
|
|
5695
|
+
decimals: 6,
|
|
5696
|
+
priceProviderId: "terra-luna"
|
|
5697
|
+
},
|
|
5698
|
+
[Chain9.Sui]: {
|
|
5699
|
+
ticker: "SUI",
|
|
5700
|
+
logo: "sui",
|
|
5701
|
+
decimals: 9,
|
|
5702
|
+
priceProviderId: "sui"
|
|
5703
|
+
},
|
|
5704
|
+
[Chain9.Polkadot]: {
|
|
5705
|
+
ticker: "DOT",
|
|
5706
|
+
logo: "dot",
|
|
5707
|
+
decimals: 10,
|
|
5708
|
+
priceProviderId: "polkadot"
|
|
5709
|
+
},
|
|
5710
|
+
[Chain9.Bittensor]: {
|
|
5711
|
+
ticker: "TAO",
|
|
5712
|
+
logo: "bittensor",
|
|
5713
|
+
decimals: 9,
|
|
5714
|
+
priceProviderId: "bittensor"
|
|
5715
|
+
},
|
|
5716
|
+
[Chain9.Noble]: {
|
|
5717
|
+
ticker: "USDC",
|
|
5718
|
+
logo: "noble",
|
|
5719
|
+
decimals: 6,
|
|
5720
|
+
priceProviderId: "usd-coin"
|
|
5721
|
+
},
|
|
5722
|
+
[Chain9.Akash]: {
|
|
5723
|
+
ticker: "AKT",
|
|
5724
|
+
logo: "akash",
|
|
5725
|
+
decimals: 6,
|
|
5726
|
+
priceProviderId: "akash-network"
|
|
5727
|
+
},
|
|
5728
|
+
[Chain9.Cosmos]: {
|
|
5729
|
+
ticker: "ATOM",
|
|
5730
|
+
logo: "atom",
|
|
5731
|
+
decimals: 6,
|
|
5732
|
+
priceProviderId: "cosmos"
|
|
5733
|
+
},
|
|
5734
|
+
[Chain9.Osmosis]: {
|
|
5735
|
+
ticker: "OSMO",
|
|
5736
|
+
logo: "osmo",
|
|
5737
|
+
decimals: 6,
|
|
5738
|
+
priceProviderId: "osmosis"
|
|
5739
|
+
},
|
|
5740
|
+
[Chain9.Tron]: {
|
|
5741
|
+
ticker: "TRX",
|
|
5742
|
+
logo: "tron",
|
|
5743
|
+
decimals: 6,
|
|
5744
|
+
priceProviderId: "tron"
|
|
5745
|
+
},
|
|
5746
|
+
...recordMap(EthereumL2Chain, () => ether),
|
|
5747
|
+
[Chain9.Zcash]: {
|
|
5748
|
+
ticker: "ZEC",
|
|
5749
|
+
logo: "zec",
|
|
5750
|
+
decimals: 8,
|
|
5751
|
+
priceProviderId: "zcash"
|
|
5752
|
+
},
|
|
5753
|
+
[Chain9.Cardano]: {
|
|
5754
|
+
ticker: "ADA",
|
|
5755
|
+
logo: "ada",
|
|
5756
|
+
decimals: 6,
|
|
5757
|
+
priceProviderId: "cardano"
|
|
5758
|
+
},
|
|
5759
|
+
[Chain9.Mantle]: {
|
|
5760
|
+
ticker: "MNT",
|
|
5761
|
+
logo: "mantle",
|
|
5762
|
+
decimals: 18,
|
|
5763
|
+
priceProviderId: "mantle"
|
|
5764
|
+
},
|
|
5765
|
+
[Chain9.Hyperliquid]: {
|
|
5766
|
+
ticker: "HYPE",
|
|
5767
|
+
logo: "hyperliquid",
|
|
5768
|
+
decimals: 18,
|
|
5769
|
+
priceProviderId: "hyperliquid"
|
|
5770
|
+
},
|
|
5771
|
+
[Chain9.Sei]: {
|
|
5772
|
+
ticker: "SEI",
|
|
5773
|
+
logo: "sei",
|
|
5774
|
+
decimals: 18,
|
|
5775
|
+
priceProviderId: "sei-network"
|
|
5776
|
+
},
|
|
5777
|
+
[Chain9.QBTC]: {
|
|
5778
|
+
ticker: "QBTC",
|
|
5779
|
+
logo: "qbtc",
|
|
5780
|
+
decimals: 6,
|
|
5781
|
+
priceProviderId: "qbtc-testnet"
|
|
5782
|
+
}
|
|
5783
|
+
};
|
|
5784
|
+
var chainFeeCoin = recordMap(leanChainFeeCoin, (coin, chain) => ({
|
|
5785
|
+
...coin,
|
|
5786
|
+
chain
|
|
5787
|
+
}));
|
|
5788
|
+
|
|
5789
|
+
// src/agent/executor.ts
|
|
5790
|
+
import { Chain as Chain10, VaultError as VaultError3, VaultErrorCode as VaultErrorCode3, Vultisig as VultisigSdk } from "@vultisig/sdk";
|
|
5791
|
+
|
|
5792
|
+
// ../../node_modules/viem/_esm/index.js
|
|
5793
|
+
init_formatUnits();
|
|
5794
|
+
|
|
5795
|
+
// src/core/VaultStateStore.ts
|
|
5796
|
+
import * as fs2 from "node:fs";
|
|
5797
|
+
import * as os from "node:os";
|
|
5798
|
+
import * as path2 from "node:path";
|
|
5799
|
+
var LOCK_STALE_MS = 6e4;
|
|
5800
|
+
var LOCK_RETRY_INIT_MS = 100;
|
|
5801
|
+
var LOCK_MAX_WAIT_MS = 3e4;
|
|
5802
|
+
var STATE_TTL_MS = 10 * 6e4;
|
|
5803
|
+
var VaultStateStore = class {
|
|
5804
|
+
baseDir;
|
|
6387
5805
|
constructor(vaultId) {
|
|
6388
5806
|
const safeId = vaultId.replace(/[^a-zA-Z0-9]/g, "").slice(0, 40);
|
|
6389
5807
|
if (!safeId) {
|
|
@@ -6529,30 +5947,46 @@ function sleep2(ms) {
|
|
|
6529
5947
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6530
5948
|
}
|
|
6531
5949
|
|
|
6532
|
-
// src/agent/types.ts
|
|
6533
|
-
var AUTO_EXECUTE_ACTIONS = /* @__PURE__ */ new Set([
|
|
6534
|
-
"vault_chain",
|
|
6535
|
-
"vault_coin",
|
|
6536
|
-
"address_book",
|
|
6537
|
-
"get_address_book",
|
|
6538
|
-
"get_balances",
|
|
6539
|
-
"search_token",
|
|
6540
|
-
"list_vaults",
|
|
6541
|
-
"build_swap_tx",
|
|
6542
|
-
"build_send_tx",
|
|
6543
|
-
"build_custom_tx",
|
|
6544
|
-
"build_tx",
|
|
6545
|
-
"sign_tx",
|
|
6546
|
-
"sign_typed_data",
|
|
6547
|
-
"read_evm_contract",
|
|
6548
|
-
"scan_tx",
|
|
6549
|
-
"thorchain_pool_info",
|
|
6550
|
-
"thorchain_add_liquidity",
|
|
6551
|
-
"thorchain_remove_liquidity"
|
|
6552
|
-
]);
|
|
6553
|
-
var PASSWORD_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["sign_tx", "sign_typed_data", "build_custom_tx"]);
|
|
6554
|
-
|
|
6555
5950
|
// src/agent/executor.ts
|
|
5951
|
+
var THOR_MEMO_CHAIN_TO_ENUM = {
|
|
5952
|
+
BTC: Chain10.Bitcoin,
|
|
5953
|
+
ETH: Chain10.Ethereum,
|
|
5954
|
+
BSC: Chain10.BSC,
|
|
5955
|
+
AVAX: Chain10.Avalanche,
|
|
5956
|
+
BASE: Chain10.Base,
|
|
5957
|
+
// L2 — THORChain routinely quotes Base destinations (PR #439 review finding 1)
|
|
5958
|
+
ARB: Chain10.Arbitrum,
|
|
5959
|
+
// L1-via-bridge path (PR #439 review finding 1)
|
|
5960
|
+
BCH: Chain10.BitcoinCash,
|
|
5961
|
+
LTC: Chain10.Litecoin,
|
|
5962
|
+
DOGE: Chain10.Dogecoin,
|
|
5963
|
+
GAIA: Chain10.Cosmos,
|
|
5964
|
+
THOR: Chain10.THORChain,
|
|
5965
|
+
RUNE: Chain10.THORChain,
|
|
5966
|
+
XRP: Chain10.Ripple,
|
|
5967
|
+
DASH: Chain10.Dash,
|
|
5968
|
+
ZEC: Chain10.Zcash,
|
|
5969
|
+
MAYA: Chain10.MayaChain,
|
|
5970
|
+
CACAO: Chain10.MayaChain
|
|
5971
|
+
};
|
|
5972
|
+
var THOR_MEMO_ASSET_SHORTCUTS = {
|
|
5973
|
+
b: "BTC.BTC",
|
|
5974
|
+
e: "ETH.ETH",
|
|
5975
|
+
s: "BSC.BNB",
|
|
5976
|
+
a: "AVAX.AVAX",
|
|
5977
|
+
c: "BCH.BCH",
|
|
5978
|
+
l: "LTC.LTC",
|
|
5979
|
+
d: "DOGE.DOGE",
|
|
5980
|
+
g: "GAIA.ATOM",
|
|
5981
|
+
r: "THOR.RUNE",
|
|
5982
|
+
x: "XRP.XRP",
|
|
5983
|
+
cacao: "MAYA.CACAO",
|
|
5984
|
+
dash: "DASH.DASH",
|
|
5985
|
+
zec: "ZEC.ZEC"
|
|
5986
|
+
// BASE / ARB don't have documented single-letter shortcuts; THORChain
|
|
5987
|
+
// emits these as the full CHAIN.ASSET form in memos. Listed in
|
|
5988
|
+
// THOR_MEMO_CHAIN_TO_ENUM only.
|
|
5989
|
+
};
|
|
6556
5990
|
var EVM_CHAINS = /* @__PURE__ */ new Set([
|
|
6557
5991
|
"Ethereum",
|
|
6558
5992
|
"BSC",
|
|
@@ -6583,11 +6017,17 @@ var EVM_GAS_RPC = {
|
|
|
6583
6017
|
Hyperliquid: "https://rpc.hyperliquid.xyz/evm",
|
|
6584
6018
|
Sei: "https://evm-rpc.sei-apis.com"
|
|
6585
6019
|
};
|
|
6586
|
-
var AgentExecutor = class
|
|
6020
|
+
var AgentExecutor = class {
|
|
6587
6021
|
vault;
|
|
6588
6022
|
/** Owning SDK (optional); used for address book backed by app storage */
|
|
6589
6023
|
vultisig;
|
|
6590
6024
|
pendingPayloads = /* @__PURE__ */ new Map();
|
|
6025
|
+
/**
|
|
6026
|
+
* Buffered legs for a 2-leg mcp-ts execute_* envelope (approve + main).
|
|
6027
|
+
* Populated by storeServerTransaction when both `approvalTxArgs` and
|
|
6028
|
+
* `txArgs` are present; consumed and cleared by signMultiLeg.
|
|
6029
|
+
*/
|
|
6030
|
+
pendingLegs = [];
|
|
6591
6031
|
password = null;
|
|
6592
6032
|
verbose;
|
|
6593
6033
|
stateStore = null;
|
|
@@ -6617,13 +6057,46 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6617
6057
|
`[executor] storeServerTransaction called, keys: ${Object.keys(txReadyData || {}).join(",")}
|
|
6618
6058
|
`
|
|
6619
6059
|
);
|
|
6620
|
-
if (txReadyData?.approvalTxArgs) {
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6060
|
+
if (txReadyData?.approvalTxArgs && txReadyData?.txArgs) {
|
|
6061
|
+
const approvalChain = resolveChainFromTxReady(txReadyData.approvalTxArgs);
|
|
6062
|
+
const mainChain = resolveChainFromTxReady(txReadyData.txArgs);
|
|
6063
|
+
const parentChain = resolveChainFromTxReady(txReadyData);
|
|
6064
|
+
if (!approvalChain || !mainChain || approvalChain !== mainChain || parentChain && parentChain !== approvalChain) {
|
|
6065
|
+
if (this.verbose)
|
|
6066
|
+
process.stderr.write(
|
|
6067
|
+
`[executor] rejecting multi-leg envelope with inconsistent chain metadata: parent=${parentChain ?? "unresolved"} approval=${approvalChain ?? "unresolved"} main=${mainChain ?? "unresolved"}
|
|
6624
6068
|
`
|
|
6625
|
-
|
|
6626
|
-
|
|
6069
|
+
);
|
|
6070
|
+
return false;
|
|
6071
|
+
}
|
|
6072
|
+
const chain2 = approvalChain;
|
|
6073
|
+
if (!EVM_CHAINS.has(chain2)) {
|
|
6074
|
+
if (this.verbose)
|
|
6075
|
+
process.stderr.write(
|
|
6076
|
+
`[executor] rejecting multi-leg envelope on non-EVM chain ${chain2}: signMultiLeg is EVM-only
|
|
6077
|
+
`
|
|
6078
|
+
);
|
|
6079
|
+
return false;
|
|
6080
|
+
}
|
|
6081
|
+
this.pendingLegs = [
|
|
6082
|
+
{
|
|
6083
|
+
txArgs: txReadyData.approvalTxArgs,
|
|
6084
|
+
parent: txReadyData,
|
|
6085
|
+
kind: "approve"
|
|
6086
|
+
},
|
|
6087
|
+
{ txArgs: txReadyData.txArgs, parent: txReadyData, kind: "main" }
|
|
6088
|
+
];
|
|
6089
|
+
this.pendingPayloads.clear();
|
|
6090
|
+
this.pendingPayloads.set("latest", {
|
|
6091
|
+
payload: { __serverTx: true, __multiLeg: true, ...txReadyData },
|
|
6092
|
+
coin: { chain: chain2, address: "", decimals: 18, ticker: "" },
|
|
6093
|
+
chain: chain2,
|
|
6094
|
+
timestamp: Date.now()
|
|
6095
|
+
});
|
|
6096
|
+
if (this.verbose)
|
|
6097
|
+
process.stderr.write(`[executor] stored multi-leg envelope: chain=${chain2}, legs=2 (approve, main)
|
|
6098
|
+
`);
|
|
6099
|
+
return true;
|
|
6627
6100
|
}
|
|
6628
6101
|
const nestedTx = extractNestedTx(txReadyData);
|
|
6629
6102
|
if (nestedTx?.status === "error" || nestedTx?.error) {
|
|
@@ -6632,6 +6105,27 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6632
6105
|
`);
|
|
6633
6106
|
return false;
|
|
6634
6107
|
}
|
|
6108
|
+
if (!nestedTx && txReadyData && typeof txReadyData === "object") {
|
|
6109
|
+
const txArgs = txReadyData.txArgs;
|
|
6110
|
+
if (txArgs && typeof txArgs === "object" && typeof txArgs.to === "string" && typeof txArgs.amount === "string") {
|
|
6111
|
+
const chain2 = resolveChainFromTxReady(txReadyData) || Chain10.Ethereum;
|
|
6112
|
+
if (getChainKind(chain2) !== "evm") {
|
|
6113
|
+
this.pendingPayloads.clear();
|
|
6114
|
+
this.pendingPayloads.set("latest", {
|
|
6115
|
+
payload: { __serverTx: true, ...txReadyData },
|
|
6116
|
+
coin: { chain: chain2, address: "", decimals: 18, ticker: "" },
|
|
6117
|
+
chain: chain2,
|
|
6118
|
+
timestamp: Date.now()
|
|
6119
|
+
});
|
|
6120
|
+
if (this.verbose)
|
|
6121
|
+
process.stderr.write(
|
|
6122
|
+
`[executor] Stored non-EVM server tx for chain ${chain2} (kind=${getChainKind(chain2)})
|
|
6123
|
+
`
|
|
6124
|
+
);
|
|
6125
|
+
return true;
|
|
6126
|
+
}
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6635
6129
|
if (!nestedTx) {
|
|
6636
6130
|
if (this.verbose)
|
|
6637
6131
|
process.stderr.write(`[executor] storeServerTransaction: no swap_tx/send_tx/tx/txArgs.tx found in data
|
|
@@ -6656,137 +6150,78 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6656
6150
|
hasPendingTransaction() {
|
|
6657
6151
|
return this.pendingPayloads.has("latest");
|
|
6658
6152
|
}
|
|
6659
|
-
shouldAutoExecute(action) {
|
|
6660
|
-
return action.auto_execute === true || AUTO_EXECUTE_ACTIONS.has(action.type);
|
|
6661
|
-
}
|
|
6662
|
-
requiresPassword(action) {
|
|
6663
|
-
return PASSWORD_REQUIRED_ACTIONS.has(action.type);
|
|
6664
|
-
}
|
|
6665
6153
|
/**
|
|
6666
|
-
*
|
|
6154
|
+
* Wrap a per-tool handler body with normalised success/failure → RecentAction
|
|
6155
|
+
* conversion. Replaces the legacy executeAction → ActionResult adapter that
|
|
6156
|
+
* the dispatch chokepoint used before this refactor.
|
|
6667
6157
|
*/
|
|
6668
|
-
async
|
|
6158
|
+
async runTool(toolName, body) {
|
|
6669
6159
|
try {
|
|
6670
|
-
const data = await
|
|
6671
|
-
return {
|
|
6672
|
-
action: action.type,
|
|
6673
|
-
action_id: action.id,
|
|
6674
|
-
success: true,
|
|
6675
|
-
data
|
|
6676
|
-
};
|
|
6160
|
+
const data = await body();
|
|
6161
|
+
return { tool: toolName, success: true, data };
|
|
6677
6162
|
} catch (err) {
|
|
6678
6163
|
const { code, message } = normalizeAgentError(err);
|
|
6679
|
-
return {
|
|
6680
|
-
action: action.type,
|
|
6681
|
-
action_id: action.id,
|
|
6682
|
-
success: false,
|
|
6683
|
-
error: message,
|
|
6684
|
-
code
|
|
6685
|
-
};
|
|
6686
|
-
}
|
|
6687
|
-
}
|
|
6688
|
-
async dispatch(action) {
|
|
6689
|
-
if (this.verbose) process.stderr.write(`[dispatch] action.type=${action.type} action.id=${action.id}
|
|
6690
|
-
`);
|
|
6691
|
-
const params = action.params || {};
|
|
6692
|
-
switch (action.type) {
|
|
6693
|
-
case "get_balances":
|
|
6694
|
-
return this.getBalances(params);
|
|
6695
|
-
case "vault_chain":
|
|
6696
|
-
return this.vaultChain(params);
|
|
6697
|
-
case "vault_coin":
|
|
6698
|
-
return this.vaultCoin(params);
|
|
6699
|
-
case "build_send_tx":
|
|
6700
|
-
return this.buildSendTx(params);
|
|
6701
|
-
case "build_swap_tx":
|
|
6702
|
-
return this.buildSwapTx(params);
|
|
6703
|
-
case "build_tx":
|
|
6704
|
-
case "build_custom_tx":
|
|
6705
|
-
return this.buildTx(params);
|
|
6706
|
-
case "sign_tx":
|
|
6707
|
-
return this.signTx(params);
|
|
6708
|
-
case "get_address_book":
|
|
6709
|
-
return this.getAddressBook(params);
|
|
6710
|
-
case "address_book":
|
|
6711
|
-
return this.addressBook(params);
|
|
6712
|
-
case "search_token":
|
|
6713
|
-
return this.searchToken(params);
|
|
6714
|
-
case "list_vaults":
|
|
6715
|
-
return this.listVaults();
|
|
6716
|
-
case "sign_typed_data":
|
|
6717
|
-
return this.signTypedData(params);
|
|
6718
|
-
case "scan_tx":
|
|
6719
|
-
return this.scanTx(params);
|
|
6720
|
-
case "read_evm_contract":
|
|
6721
|
-
return this.readEvmContract(params);
|
|
6722
|
-
case "thorchain_pool_info":
|
|
6723
|
-
return this.thorchainPoolInfo(params);
|
|
6724
|
-
case "thorchain_add_liquidity":
|
|
6725
|
-
return this.thorchainAddLiquidity(params);
|
|
6726
|
-
case "thorchain_remove_liquidity":
|
|
6727
|
-
return this.thorchainRemoveLiquidity(params);
|
|
6728
|
-
default:
|
|
6729
|
-
throw new Error(
|
|
6730
|
-
`Action type '${action.type}' is not implemented locally. The backend may handle this action server-side.`
|
|
6731
|
-
);
|
|
6732
|
-
}
|
|
6733
|
-
}
|
|
6734
|
-
// ============================================================================
|
|
6735
|
-
// Balance & Portfolio
|
|
6736
|
-
// ============================================================================
|
|
6737
|
-
async getBalances(params) {
|
|
6738
|
-
const chainFilter = params.chain;
|
|
6739
|
-
const tickerFilter = params.ticker;
|
|
6740
|
-
const balanceRecord = await this.vault.balances();
|
|
6741
|
-
let entries = Object.entries(balanceRecord).map(([key, b]) => ({
|
|
6742
|
-
chain: b.chainId || key.split(":")[0] || "",
|
|
6743
|
-
symbol: b.symbol || "",
|
|
6744
|
-
amount: b.formattedAmount || b.amount?.toString() || "0",
|
|
6745
|
-
decimals: b.decimals || 18,
|
|
6746
|
-
raw_amount: b.amount?.toString()
|
|
6747
|
-
}));
|
|
6748
|
-
if (chainFilter) {
|
|
6749
|
-
const chain = resolveChain(chainFilter);
|
|
6750
|
-
if (chain) {
|
|
6751
|
-
entries = entries.filter((b) => b.chain.toLowerCase() === chain.toLowerCase());
|
|
6752
|
-
}
|
|
6753
|
-
}
|
|
6754
|
-
if (tickerFilter) {
|
|
6755
|
-
entries = entries.filter((b) => b.symbol.toLowerCase() === tickerFilter.toLowerCase());
|
|
6164
|
+
return { tool: toolName, success: false, data: { error: message, code } };
|
|
6756
6165
|
}
|
|
6757
|
-
return { balances: entries };
|
|
6758
6166
|
}
|
|
6759
6167
|
// ============================================================================
|
|
6760
6168
|
// Chain & Token Management
|
|
6761
6169
|
// ============================================================================
|
|
6762
6170
|
// vault_chain dispatcher — backend shape:
|
|
6763
6171
|
// { action: "add" | "remove", chains: [{ chain }] }
|
|
6764
|
-
//
|
|
6765
|
-
//
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6172
|
+
// Discriminator wrapper: routes to addChain / removeChain so the resulting
|
|
6173
|
+
// RecentAction is tagged tool: 'vault_chain' (matching what the agent emits)
|
|
6174
|
+
// rather than the per-action method's tool name.
|
|
6175
|
+
async vaultChain(toolCallId, input) {
|
|
6176
|
+
return this.runTool("vault_chain", async () => {
|
|
6177
|
+
const action = input.action;
|
|
6178
|
+
switch (action) {
|
|
6179
|
+
case "add":
|
|
6180
|
+
return this.addChainImpl(input);
|
|
6181
|
+
case "remove":
|
|
6182
|
+
return this.removeChainImpl(input);
|
|
6183
|
+
default:
|
|
6184
|
+
throw new Error(`vault_chain: unknown action: ${action ?? "(missing)"}`);
|
|
6185
|
+
}
|
|
6186
|
+
});
|
|
6776
6187
|
}
|
|
6777
6188
|
// vault_coin dispatcher — backend shape:
|
|
6778
|
-
// { action: "add" | "remove", coins: [{ chain, ticker, contract_address?,
|
|
6779
|
-
async vaultCoin(
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6189
|
+
// { action: "add" | "remove", coins: [{ chain, ticker, contract_address?, ... }] }
|
|
6190
|
+
async vaultCoin(toolCallId, input) {
|
|
6191
|
+
return this.runTool("vault_coin", async () => {
|
|
6192
|
+
const action = input.action;
|
|
6193
|
+
switch (action) {
|
|
6194
|
+
case "add":
|
|
6195
|
+
return this.addCoinImpl(input);
|
|
6196
|
+
case "remove":
|
|
6197
|
+
return this.removeCoinImpl(input);
|
|
6198
|
+
default:
|
|
6199
|
+
throw new Error(`vault_coin: unknown action: ${action ?? "(missing)"}`);
|
|
6200
|
+
}
|
|
6201
|
+
});
|
|
6202
|
+
}
|
|
6203
|
+
// address_book dispatcher — backend shape:
|
|
6204
|
+
// { action: "add" | "remove", entry: { name, chain, address } }
|
|
6205
|
+
async addressBook(toolCallId, input) {
|
|
6206
|
+
return this.runTool("address_book", async () => {
|
|
6207
|
+
const action = input.action;
|
|
6208
|
+
switch (action) {
|
|
6209
|
+
case "add":
|
|
6210
|
+
return this.addAddressBookImpl(input);
|
|
6211
|
+
case "remove":
|
|
6212
|
+
return this.removeAddressBookImpl(input);
|
|
6213
|
+
default:
|
|
6214
|
+
throw new Error(`address_book: unknown action: ${action ?? "(missing)"}`);
|
|
6215
|
+
}
|
|
6216
|
+
});
|
|
6789
6217
|
}
|
|
6218
|
+
async addChain(_toolCallId, input) {
|
|
6219
|
+
return this.runTool("add_chain", () => this.addChainImpl(input));
|
|
6220
|
+
}
|
|
6221
|
+
// Backend `vault_chain { action: "add", chains: [...] }` and legacy
|
|
6222
|
+
// single-chain calls both flow through this impl. The public `addChain`
|
|
6223
|
+
// wrapper above tags results as `tool: 'add_chain'`; the new `vaultChain`
|
|
6224
|
+
// wrapper (above) tags them as `tool: 'vault_chain'`.
|
|
6790
6225
|
async addChainImpl(params) {
|
|
6791
6226
|
const chains = params.chains;
|
|
6792
6227
|
if (chains && Array.isArray(chains)) {
|
|
@@ -6839,7 +6274,7 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6839
6274
|
id: t.contract_address || t.contractAddress || "",
|
|
6840
6275
|
symbol: symbol2,
|
|
6841
6276
|
name: t.name || symbol2,
|
|
6842
|
-
decimals: t.decimals
|
|
6277
|
+
decimals: t.decimals ?? 18,
|
|
6843
6278
|
contractAddress: t.contract_address || t.contractAddress,
|
|
6844
6279
|
chainId: chain2.toString()
|
|
6845
6280
|
});
|
|
@@ -6855,7 +6290,7 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6855
6290
|
id: params.contract_address || params.contractAddress || "",
|
|
6856
6291
|
symbol,
|
|
6857
6292
|
name: params.name || symbol,
|
|
6858
|
-
decimals: params.decimals
|
|
6293
|
+
decimals: params.decimals ?? 18,
|
|
6859
6294
|
contractAddress: params.contract_address || params.contractAddress,
|
|
6860
6295
|
chainId: chain.toString()
|
|
6861
6296
|
});
|
|
@@ -6883,465 +6318,59 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6883
6318
|
const chain = resolveChain(chainName);
|
|
6884
6319
|
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6885
6320
|
const tokenId = params.contract_address || params.contractAddress || params.token_id || params.id;
|
|
6886
|
-
if (!tokenId) {
|
|
6887
|
-
throw new Error(`vault_coin remove: missing contract_address for coin on ${chainName}`);
|
|
6888
|
-
}
|
|
6889
|
-
await this.vault.removeToken(chain, tokenId);
|
|
6890
|
-
return { chain: chain.toString(), removed: true };
|
|
6891
|
-
}
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
async
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
const toAddress = params.address || params.to || params.destination;
|
|
6901
|
-
const amountStr = params.amount;
|
|
6902
|
-
if (!toAddress) throw new Error("Destination address is required");
|
|
6903
|
-
if (!amountStr) throw new Error("Amount is required");
|
|
6904
|
-
await this.acquireEvmLockIfNeeded(chain);
|
|
6905
|
-
try {
|
|
6906
|
-
const address = await this.vault.address(chain);
|
|
6907
|
-
const balance = await this.vault.balance(chain, params.token_id);
|
|
6908
|
-
const coin = {
|
|
6909
|
-
chain,
|
|
6910
|
-
address,
|
|
6911
|
-
decimals: balance.decimals,
|
|
6912
|
-
ticker: symbol || balance.symbol,
|
|
6913
|
-
id: params.token_id
|
|
6914
|
-
};
|
|
6915
|
-
const amount = parseAmount(amountStr, balance.decimals);
|
|
6916
|
-
const memo = params.memo;
|
|
6917
|
-
const payload = await this.vault.prepareSendTx({
|
|
6918
|
-
coin,
|
|
6919
|
-
receiver: toAddress,
|
|
6920
|
-
amount,
|
|
6921
|
-
memo
|
|
6922
|
-
});
|
|
6923
|
-
await this.patchEvmNonce(chain, payload);
|
|
6924
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
6925
|
-
this.pendingPayloads.clear();
|
|
6926
|
-
const payloadId = `tx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6927
|
-
this.pendingPayloads.set(payloadId, {
|
|
6928
|
-
payload,
|
|
6929
|
-
coin,
|
|
6930
|
-
chain,
|
|
6931
|
-
timestamp: Date.now()
|
|
6932
|
-
});
|
|
6933
|
-
this.pendingPayloads.set("latest", {
|
|
6934
|
-
payload,
|
|
6935
|
-
coin,
|
|
6936
|
-
chain,
|
|
6937
|
-
timestamp: Date.now()
|
|
6938
|
-
});
|
|
6939
|
-
return {
|
|
6940
|
-
keysign_payload: payloadId,
|
|
6941
|
-
from_chain: chain.toString(),
|
|
6942
|
-
from_symbol: coin.ticker,
|
|
6943
|
-
amount: amountStr,
|
|
6944
|
-
sender: address,
|
|
6945
|
-
destination: toAddress,
|
|
6946
|
-
memo: memo || void 0,
|
|
6947
|
-
message_hashes: messageHashes,
|
|
6948
|
-
tx_details: {
|
|
6949
|
-
chain: chain.toString(),
|
|
6950
|
-
from: address,
|
|
6951
|
-
to: toAddress,
|
|
6952
|
-
amount: amountStr,
|
|
6953
|
-
symbol: coin.ticker
|
|
6954
|
-
}
|
|
6955
|
-
};
|
|
6956
|
-
} catch (err) {
|
|
6957
|
-
await this.releaseEvmLock(chain);
|
|
6958
|
-
throw err;
|
|
6959
|
-
}
|
|
6960
|
-
}
|
|
6961
|
-
async buildSwapTx(params) {
|
|
6962
|
-
if (this.verbose)
|
|
6963
|
-
process.stderr.write(`[build_swap_tx] called with params: ${JSON.stringify(params).slice(0, 500)}
|
|
6964
|
-
`);
|
|
6965
|
-
const fromChainName = params.from_chain || params.chain;
|
|
6966
|
-
const toChainName = params.to_chain;
|
|
6967
|
-
const fromChain = resolveChain(fromChainName);
|
|
6968
|
-
const toChain = toChainName ? resolveChain(toChainName) : null;
|
|
6969
|
-
if (!fromChain) throw new Error(`Unknown from_chain: ${fromChainName}`);
|
|
6970
|
-
await this.acquireEvmLockIfNeeded(fromChain);
|
|
6971
|
-
try {
|
|
6972
|
-
const amountStr = params.amount;
|
|
6973
|
-
const fromSymbol = params.from_symbol || params.from_token || "";
|
|
6974
|
-
const toSymbol = params.to_symbol || params.to_token || "";
|
|
6975
|
-
const fromToken = params.from_contract || params.from_token_id;
|
|
6976
|
-
const toToken = params.to_contract || params.to_token_id;
|
|
6977
|
-
const fromCoin = { chain: fromChain, token: fromToken || void 0 };
|
|
6978
|
-
const toCoin = {
|
|
6979
|
-
chain: toChain || fromChain,
|
|
6980
|
-
token: toToken || void 0
|
|
6981
|
-
};
|
|
6982
|
-
const quote = await this.vault.getSwapQuote({
|
|
6983
|
-
fromCoin,
|
|
6984
|
-
toCoin,
|
|
6985
|
-
amount: amountStr
|
|
6986
|
-
});
|
|
6987
|
-
const swapResult = await this.vault.prepareSwapTx({
|
|
6988
|
-
fromCoin,
|
|
6989
|
-
toCoin,
|
|
6990
|
-
amount: amountStr,
|
|
6991
|
-
swapQuote: quote,
|
|
6992
|
-
autoApprove: true
|
|
6993
|
-
});
|
|
6994
|
-
const chain = fromChain;
|
|
6995
|
-
const payload = swapResult.keysignPayload;
|
|
6996
|
-
await this.patchEvmNonce(chain, payload);
|
|
6997
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
6998
|
-
this.pendingPayloads.clear();
|
|
6999
|
-
const payloadId = `swap_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
7000
|
-
this.pendingPayloads.set(payloadId, {
|
|
7001
|
-
payload,
|
|
7002
|
-
coin: { chain, address: "", decimals: 18, ticker: fromSymbol },
|
|
7003
|
-
chain,
|
|
7004
|
-
timestamp: Date.now()
|
|
7005
|
-
});
|
|
7006
|
-
this.pendingPayloads.set("latest", {
|
|
7007
|
-
payload,
|
|
7008
|
-
coin: { chain, address: "", decimals: 18, ticker: fromSymbol },
|
|
7009
|
-
chain,
|
|
7010
|
-
timestamp: Date.now()
|
|
7011
|
-
});
|
|
7012
|
-
return {
|
|
7013
|
-
keysign_payload: payloadId,
|
|
7014
|
-
from_chain: fromChain.toString(),
|
|
7015
|
-
to_chain: (toChain || fromChain).toString(),
|
|
7016
|
-
from_symbol: fromSymbol,
|
|
7017
|
-
to_symbol: toSymbol,
|
|
7018
|
-
amount: amountStr,
|
|
7019
|
-
estimated_output: quote.estimatedOutput?.toString(),
|
|
7020
|
-
provider: quote.provider,
|
|
7021
|
-
message_hashes: messageHashes
|
|
7022
|
-
};
|
|
7023
|
-
} catch (err) {
|
|
7024
|
-
await this.releaseEvmLock(fromChain);
|
|
7025
|
-
throw err;
|
|
7026
|
-
}
|
|
7027
|
-
}
|
|
7028
|
-
// ============================================================================
|
|
7029
|
-
// THORChain LP (RUNE-side asym add / remove via prepareSendTx + memo)
|
|
7030
|
-
// ============================================================================
|
|
7031
|
-
/**
|
|
7032
|
-
* Pool stats from Midgard (no signing). Optional `pool` filters to one row.
|
|
7033
|
-
*/
|
|
7034
|
-
async thorchainPoolInfo(params) {
|
|
7035
|
-
const { assertValidPoolId: assertValidPoolId2, getThorchainPools: getThorchainPools2, thorchainMidgardBaseUrl: thorchainMidgardBaseUrl2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
|
|
7036
|
-
const statusRaw = params.status;
|
|
7037
|
-
let poolFetchOpts = {};
|
|
7038
|
-
if (statusRaw === null || String(statusRaw).toLowerCase() === "all") {
|
|
7039
|
-
poolFetchOpts = { status: null };
|
|
7040
|
-
} else if (statusRaw !== void 0) {
|
|
7041
|
-
poolFetchOpts = { status: String(statusRaw) };
|
|
7042
|
-
}
|
|
7043
|
-
const pools = await getThorchainPools2(poolFetchOpts);
|
|
7044
|
-
const poolArg = params.pool;
|
|
7045
|
-
if (poolArg) {
|
|
7046
|
-
const normalized = poolArg.trim().toUpperCase();
|
|
7047
|
-
assertValidPoolId2(normalized);
|
|
7048
|
-
const row = pools.find((p) => p.asset.toUpperCase() === normalized);
|
|
7049
|
-
return {
|
|
7050
|
-
found: !!row,
|
|
7051
|
-
pool_id: normalized,
|
|
7052
|
-
summary: row ?? null,
|
|
7053
|
-
midgard: thorchainMidgardBaseUrl2
|
|
7054
|
-
};
|
|
7055
|
-
}
|
|
7056
|
-
const limitRaw = params.limit;
|
|
7057
|
-
const limit = Math.min(500, Math.max(1, typeof limitRaw === "number" ? limitRaw : Number(limitRaw) || 80));
|
|
7058
|
-
return {
|
|
7059
|
-
pools: pools.slice(0, limit),
|
|
7060
|
-
total: pools.length,
|
|
7061
|
-
midgard: thorchainMidgardBaseUrl2
|
|
7062
|
-
};
|
|
7063
|
-
}
|
|
7064
|
-
async thorchainAddLiquidity(params) {
|
|
7065
|
-
const { assertValidPoolId: assertValidPoolId2, buildThorchainLpAddPayload: buildThorchainLpAddPayload2, resolvePairedAddressForLpAdd: resolvePairedAddressForLpAdd2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
|
|
7066
|
-
const { getThorchainInboundAddress: getThorchainInboundAddress2 } = await Promise.resolve().then(() => (init_getThorchainInboundAddress(), getThorchainInboundAddress_exports));
|
|
7067
|
-
const pool = this.normalizeThorchainPoolId(params.pool, assertValidPoolId2);
|
|
7068
|
-
const amountStr = String(params.amount ?? "").trim();
|
|
7069
|
-
if (!amountStr) {
|
|
7070
|
-
throw new Error('amount is required (RUNE amount as a decimal string, e.g. "0.25")');
|
|
7071
|
-
}
|
|
7072
|
-
if (!/^\d+(\.\d+)?$/.test(amountStr)) {
|
|
7073
|
-
throw new Error('amount must be a positive decimal string (no sign or scientific notation), e.g. "0.25"');
|
|
7074
|
-
}
|
|
7075
|
-
const [, frac = ""] = amountStr.split(".");
|
|
7076
|
-
if (frac.length > 8) {
|
|
7077
|
-
throw new Error("RUNE amount supports at most 8 decimal places");
|
|
7078
|
-
}
|
|
7079
|
-
const amountRuneBaseUnits = parseAmount(amountStr, 8);
|
|
7080
|
-
if (amountRuneBaseUnits <= 0n) {
|
|
7081
|
-
throw new Error("amount must be greater than zero");
|
|
7082
|
-
}
|
|
7083
|
-
let pairedAddress = params.paired_address?.trim() || void 0;
|
|
7084
|
-
const autoPairRaw = params.auto_pair ?? params.autoPair;
|
|
7085
|
-
const autoPairDisabled = autoPairRaw === false || autoPairRaw === 0 || typeof autoPairRaw === "string" && ["false", "0"].includes(autoPairRaw.toLowerCase());
|
|
7086
|
-
const autoPair = !pairedAddress && !autoPairDisabled;
|
|
7087
|
-
if (autoPair) {
|
|
7088
|
-
const vaultAddresses = await this.buildVaultAddressMap();
|
|
7089
|
-
pairedAddress = resolvePairedAddressForLpAdd2({
|
|
7090
|
-
pool,
|
|
7091
|
-
side: "rune",
|
|
7092
|
-
vaultAddresses
|
|
7093
|
-
}) || void 0;
|
|
7094
|
-
}
|
|
7095
|
-
const lpPayload = buildThorchainLpAddPayload2({
|
|
7096
|
-
pool,
|
|
7097
|
-
amountRuneBaseUnits: amountRuneBaseUnits.toString(),
|
|
7098
|
-
...pairedAddress ? { pairedAddress } : {}
|
|
7099
|
-
});
|
|
7100
|
-
const receiver = await this.getThorchainNativeInboundAddress(getThorchainInboundAddress2);
|
|
7101
|
-
const address = await this.vault.address(Chain10.THORChain);
|
|
7102
|
-
const coin = {
|
|
7103
|
-
chain: Chain10.THORChain,
|
|
7104
|
-
address,
|
|
7105
|
-
decimals: 8,
|
|
7106
|
-
ticker: "RUNE"
|
|
7107
|
-
};
|
|
7108
|
-
const payload = await this.vault.prepareSendTx({
|
|
7109
|
-
coin,
|
|
7110
|
-
receiver,
|
|
7111
|
-
amount: BigInt(lpPayload.amount),
|
|
7112
|
-
memo: lpPayload.memo
|
|
7113
|
-
});
|
|
7114
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
7115
|
-
this.pendingPayloads.clear();
|
|
7116
|
-
const payloadId = `tc_lp_add_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
7117
|
-
this.pendingPayloads.set(payloadId, {
|
|
7118
|
-
payload,
|
|
7119
|
-
coin,
|
|
7120
|
-
chain: Chain10.THORChain,
|
|
7121
|
-
timestamp: Date.now()
|
|
7122
|
-
});
|
|
7123
|
-
this.pendingPayloads.set("latest", {
|
|
7124
|
-
payload,
|
|
7125
|
-
coin,
|
|
7126
|
-
chain: Chain10.THORChain,
|
|
7127
|
-
timestamp: Date.now()
|
|
7128
|
-
});
|
|
7129
|
-
return {
|
|
7130
|
-
keysign_payload: payloadId,
|
|
7131
|
-
chain: "THORChain",
|
|
7132
|
-
pool: lpPayload.pool,
|
|
7133
|
-
memo: lpPayload.memo,
|
|
7134
|
-
amount_rune: amountStr,
|
|
7135
|
-
paired_address: pairedAddress,
|
|
7136
|
-
inbound_receiver: receiver,
|
|
7137
|
-
sender: address,
|
|
7138
|
-
message_hashes: messageHashes
|
|
7139
|
-
};
|
|
7140
|
-
}
|
|
7141
|
-
async thorchainRemoveLiquidity(params) {
|
|
7142
|
-
const { assertValidPoolId: assertValidPoolId2, buildThorchainLpRemovePayload: buildThorchainLpRemovePayload2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
|
|
7143
|
-
const { getThorchainInboundAddress: getThorchainInboundAddress2 } = await Promise.resolve().then(() => (init_getThorchainInboundAddress(), getThorchainInboundAddress_exports));
|
|
7144
|
-
const pool = this.normalizeThorchainPoolId(params.pool, assertValidPoolId2);
|
|
7145
|
-
let basisPoints;
|
|
7146
|
-
if (params.basis_points != null) {
|
|
7147
|
-
basisPoints = Number(params.basis_points);
|
|
7148
|
-
} else if (params.basisPoints != null) {
|
|
7149
|
-
basisPoints = Number(params.basisPoints);
|
|
7150
|
-
}
|
|
7151
|
-
if (basisPoints == null && params.withdraw_percent != null) {
|
|
7152
|
-
const pct = Number(params.withdraw_percent);
|
|
7153
|
-
if (Number.isFinite(pct)) {
|
|
7154
|
-
basisPoints = Math.round(pct * 100);
|
|
7155
|
-
}
|
|
7156
|
-
}
|
|
7157
|
-
if (basisPoints == null || !Number.isInteger(basisPoints)) {
|
|
7158
|
-
throw new Error("basis_points (integer 1\u201310000) or withdraw_percent (0.01\u2013100, maps to basis points) is required");
|
|
7159
|
-
}
|
|
7160
|
-
let withdrawToAsset = params.withdraw_to_asset?.trim();
|
|
7161
|
-
if (!withdrawToAsset && params.withdrawToAsset) {
|
|
7162
|
-
withdrawToAsset = String(params.withdrawToAsset).trim();
|
|
7163
|
-
}
|
|
7164
|
-
if (withdrawToAsset) {
|
|
7165
|
-
withdrawToAsset = withdrawToAsset.toUpperCase();
|
|
7166
|
-
}
|
|
7167
|
-
const lpPayload = buildThorchainLpRemovePayload2({
|
|
7168
|
-
pool,
|
|
7169
|
-
basisPoints,
|
|
7170
|
-
...withdrawToAsset ? { withdrawToAsset } : {}
|
|
7171
|
-
});
|
|
7172
|
-
const receiver = await this.getThorchainNativeInboundAddress(getThorchainInboundAddress2);
|
|
7173
|
-
const address = await this.vault.address(Chain10.THORChain);
|
|
7174
|
-
const coin = {
|
|
7175
|
-
chain: Chain10.THORChain,
|
|
7176
|
-
address,
|
|
7177
|
-
decimals: 8,
|
|
7178
|
-
ticker: "RUNE"
|
|
7179
|
-
};
|
|
7180
|
-
const payload = await this.vault.prepareSendTx({
|
|
7181
|
-
coin,
|
|
7182
|
-
receiver,
|
|
7183
|
-
amount: BigInt(lpPayload.amount),
|
|
7184
|
-
memo: lpPayload.memo
|
|
7185
|
-
});
|
|
7186
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
7187
|
-
this.pendingPayloads.clear();
|
|
7188
|
-
const payloadId = `tc_lp_rm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
7189
|
-
this.pendingPayloads.set(payloadId, {
|
|
7190
|
-
payload,
|
|
7191
|
-
coin,
|
|
7192
|
-
chain: Chain10.THORChain,
|
|
7193
|
-
timestamp: Date.now()
|
|
7194
|
-
});
|
|
7195
|
-
this.pendingPayloads.set("latest", {
|
|
7196
|
-
payload,
|
|
7197
|
-
coin,
|
|
7198
|
-
chain: Chain10.THORChain,
|
|
7199
|
-
timestamp: Date.now()
|
|
7200
|
-
});
|
|
7201
|
-
return {
|
|
7202
|
-
keysign_payload: payloadId,
|
|
7203
|
-
chain: "THORChain",
|
|
7204
|
-
pool: lpPayload.pool,
|
|
7205
|
-
memo: lpPayload.memo,
|
|
7206
|
-
basis_points: basisPoints,
|
|
7207
|
-
withdraw_to_asset: withdrawToAsset || void 0,
|
|
7208
|
-
dust_rune_base_units: lpPayload.amount,
|
|
7209
|
-
inbound_receiver: receiver,
|
|
7210
|
-
sender: address,
|
|
7211
|
-
message_hashes: messageHashes
|
|
7212
|
-
};
|
|
7213
|
-
}
|
|
7214
|
-
normalizeThorchainPoolId(raw, assertValidPoolId2) {
|
|
7215
|
-
const pool = String(raw ?? "").trim();
|
|
7216
|
-
if (!pool) {
|
|
7217
|
-
throw new Error('pool is required (e.g. "BTC.BTC")');
|
|
7218
|
-
}
|
|
7219
|
-
const upper = pool.toUpperCase();
|
|
7220
|
-
assertValidPoolId2(upper);
|
|
7221
|
-
return upper;
|
|
7222
|
-
}
|
|
7223
|
-
async buildVaultAddressMap() {
|
|
7224
|
-
const map = {};
|
|
7225
|
-
for (const c of this.vault.chains) {
|
|
7226
|
-
try {
|
|
7227
|
-
map[c] = await this.vault.address(c);
|
|
7228
|
-
} catch {
|
|
7229
|
-
}
|
|
7230
|
-
}
|
|
7231
|
-
return map;
|
|
7232
|
-
}
|
|
7233
|
-
/** THORChain protocol vault for native RUNE deposits (SWAP/LP memos). Matches SDK e2e fixture. */
|
|
7234
|
-
static THORCHAIN_RUNE_DEPOSIT_ADDRESS = "thor1g98cy3n9mmjrpn0sxmn63lztelera37n8n67c0";
|
|
7235
|
-
async getThorchainNativeInboundAddress(getInbound) {
|
|
7236
|
-
const rows = await getInbound();
|
|
7237
|
-
const thor = rows.find((r) => r.chain.toUpperCase() === "THOR");
|
|
7238
|
-
if (thor?.address) {
|
|
7239
|
-
return thor.address;
|
|
7240
|
-
}
|
|
7241
|
-
if (this.verbose) {
|
|
7242
|
-
process.stderr.write(
|
|
7243
|
-
`[thorchain_lp] THOR inbound row missing; using static RUNE deposit vault ${_AgentExecutor.THORCHAIN_RUNE_DEPOSIT_ADDRESS}
|
|
7244
|
-
`
|
|
7245
|
-
);
|
|
7246
|
-
}
|
|
7247
|
-
return _AgentExecutor.THORCHAIN_RUNE_DEPOSIT_ADDRESS;
|
|
7248
|
-
}
|
|
7249
|
-
async buildTx(params) {
|
|
7250
|
-
if (params.function_name && params.contract_address) {
|
|
7251
|
-
return this.buildContractCallTx(params);
|
|
7252
|
-
}
|
|
7253
|
-
if (params.data || params.calldata || params.hex_payload) {
|
|
7254
|
-
const txData = {
|
|
7255
|
-
to: params.to || params.address || params.contract,
|
|
7256
|
-
value: params.value || "0",
|
|
7257
|
-
data: params.data || params.calldata || params.hex_payload,
|
|
7258
|
-
chain: params.chain,
|
|
7259
|
-
chain_id: params.chain_id
|
|
7260
|
-
};
|
|
7261
|
-
const stored = this.storeServerTransaction({
|
|
7262
|
-
tx: txData,
|
|
7263
|
-
chain: params.chain,
|
|
7264
|
-
from_chain: params.chain
|
|
7265
|
-
});
|
|
7266
|
-
if (!stored) {
|
|
7267
|
-
throw new Error("Could not stage calldata transaction for signing (invalid or empty tx payload)");
|
|
7268
|
-
}
|
|
7269
|
-
const chain = resolveChain(params.chain) || Chain10.Ethereum;
|
|
7270
|
-
const address = await this.vault.address(chain);
|
|
7271
|
-
return {
|
|
7272
|
-
status: "ready",
|
|
7273
|
-
chain: chain.toString(),
|
|
7274
|
-
from: address,
|
|
7275
|
-
to: txData.to,
|
|
7276
|
-
value: txData.value,
|
|
7277
|
-
has_calldata: true,
|
|
7278
|
-
message: "Transaction built. Ready to sign."
|
|
7279
|
-
};
|
|
7280
|
-
}
|
|
7281
|
-
if (params.contract_address && !params.function_name) {
|
|
7282
|
-
const provided = Object.keys(params).join(", ");
|
|
7283
|
-
throw new Error(
|
|
7284
|
-
`build_custom_tx requires function_name and params for contract calls. Got: ${provided}. Missing: function_name, params.`
|
|
7285
|
-
);
|
|
7286
|
-
}
|
|
7287
|
-
throw new Error(
|
|
7288
|
-
`build_custom_tx: unrecognized params shape. Expected function_name + contract_address for ABI-encoding. Server-built calldata should arrive via tx_ready, not via action params. Got keys: ${Object.keys(params).join(", ")}`
|
|
7289
|
-
);
|
|
7290
|
-
}
|
|
7291
|
-
/**
|
|
7292
|
-
* Build, sign, and broadcast an EVM contract call transaction from structured params.
|
|
7293
|
-
* Encodes function_name + typed params into ABI calldata, then signs via signServerTx.
|
|
7294
|
-
*/
|
|
7295
|
-
async buildContractCallTx(params) {
|
|
7296
|
-
const chainName = params.chain || "Ethereum";
|
|
7297
|
-
const chain = resolveChain(chainName);
|
|
7298
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
7299
|
-
const contractAddress = params.contract_address;
|
|
7300
|
-
const functionName = params.function_name;
|
|
7301
|
-
const typedParams = params.params;
|
|
7302
|
-
const value = params.value || "0";
|
|
7303
|
-
const calldata = await encodeContractCall(functionName, typedParams || []);
|
|
7304
|
-
if (this.verbose)
|
|
7305
|
-
process.stderr.write(
|
|
7306
|
-
`[build_contract_tx] ${functionName}(${(typedParams || []).map((p) => p.type).join(",")}) on ${contractAddress} chain=${chain}
|
|
7307
|
-
`
|
|
7308
|
-
);
|
|
7309
|
-
const serverTxData = {
|
|
7310
|
-
__serverTx: true,
|
|
7311
|
-
tx: {
|
|
7312
|
-
to: contractAddress,
|
|
7313
|
-
value,
|
|
7314
|
-
data: calldata
|
|
7315
|
-
},
|
|
7316
|
-
chain: chainName,
|
|
7317
|
-
from_chain: chainName
|
|
7318
|
-
};
|
|
7319
|
-
this.pendingPayloads.set("latest", {
|
|
7320
|
-
payload: serverTxData,
|
|
7321
|
-
coin: { chain, address: "", decimals: 18, ticker: "" },
|
|
7322
|
-
chain,
|
|
7323
|
-
timestamp: Date.now()
|
|
7324
|
-
});
|
|
7325
|
-
return this.signServerTx(serverTxData, chain, { chain: chainName });
|
|
6321
|
+
if (!tokenId) {
|
|
6322
|
+
throw new Error(`vault_coin remove: missing contract_address for coin on ${chainName}`);
|
|
6323
|
+
}
|
|
6324
|
+
await this.vault.removeToken(chain, tokenId);
|
|
6325
|
+
return { chain: chain.toString(), removed: true };
|
|
6326
|
+
}
|
|
6327
|
+
async removeChain(_toolCallId, input) {
|
|
6328
|
+
return this.runTool("remove_chain", () => this.removeChainImpl(input));
|
|
6329
|
+
}
|
|
6330
|
+
async addCoin(_toolCallId, input) {
|
|
6331
|
+
return this.runTool("add_coin", () => this.addCoinImpl(input));
|
|
6332
|
+
}
|
|
6333
|
+
async removeCoin(_toolCallId, input) {
|
|
6334
|
+
return this.runTool("remove_coin", () => this.removeCoinImpl(input));
|
|
7326
6335
|
}
|
|
7327
6336
|
// ============================================================================
|
|
7328
6337
|
// Transaction Signing
|
|
7329
6338
|
// ============================================================================
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
`
|
|
7333
|
-
|
|
7334
|
-
|
|
6339
|
+
/**
|
|
6340
|
+
* Sign and broadcast a transaction previously buffered by
|
|
6341
|
+
* {@link storeServerTransaction} via the `tx_ready` SSE channel. Returns
|
|
6342
|
+
* a `RecentAction` to be flushed in the next `context.recent_actions`.
|
|
6343
|
+
*
|
|
6344
|
+
* Replaces the legacy `signTx(action.params)` path: there is no longer an
|
|
6345
|
+
* action wrapper, no `keysign_payload` lookup (the buffer always uses
|
|
6346
|
+
* the `'latest'` slot), and no SDK-built keysignPayload branch (the live
|
|
6347
|
+
* client-side tools no longer produce SDK-built payloads — those went
|
|
6348
|
+
* away with `buildSendTx`/`buildSwapTx`).
|
|
6349
|
+
*/
|
|
6350
|
+
async signTxFromBuffer(_toolCallId) {
|
|
6351
|
+
return this.runTool("sign_tx", async () => {
|
|
6352
|
+
if (this.verbose)
|
|
6353
|
+
process.stderr.write(`[sign_tx] pendingPayloads keys: ${[...this.pendingPayloads.keys()].join(", ")}
|
|
7335
6354
|
`);
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
6355
|
+
const stored = this.pendingPayloads.get("latest");
|
|
6356
|
+
if (!stored) {
|
|
6357
|
+
throw new Error("No pending transaction to sign. Build a transaction first.");
|
|
6358
|
+
}
|
|
6359
|
+
const { payload, chain } = stored;
|
|
6360
|
+
if (!payload.__serverTx) {
|
|
6361
|
+
throw new Error("Pending transaction is not a server-built tx (no __serverTx flag).");
|
|
6362
|
+
}
|
|
7343
6363
|
let result;
|
|
7344
|
-
if (
|
|
6364
|
+
if (payload.__multiLeg) {
|
|
6365
|
+
if (this.pendingLegs.length !== 2) {
|
|
6366
|
+
throw new VaultError3(
|
|
6367
|
+
VaultErrorCode3.InvalidConfig,
|
|
6368
|
+
`signMultiLeg: expected 2 pending legs, got ${this.pendingLegs.length}`
|
|
6369
|
+
);
|
|
6370
|
+
}
|
|
6371
|
+
result = await this.signMultiLeg(payload, chain, {});
|
|
6372
|
+
}
|
|
6373
|
+
if (!result && chain === "Solana" && (payload.swap_tx || payload.provider)) {
|
|
7345
6374
|
try {
|
|
7346
6375
|
result = await this.buildAndSignSolanaSwapLocally(payload);
|
|
7347
6376
|
} catch (e) {
|
|
@@ -7354,62 +6383,176 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7354
6383
|
}
|
|
7355
6384
|
}
|
|
7356
6385
|
}
|
|
7357
|
-
if (!result) result = await this.signServerTx(payload, chain,
|
|
6386
|
+
if (!result) result = await this.signServerTx(payload, chain, {});
|
|
7358
6387
|
if (payload.sequence_id) result.sequence_id = payload.sequence_id;
|
|
7359
6388
|
return result;
|
|
6389
|
+
});
|
|
6390
|
+
}
|
|
6391
|
+
/**
|
|
6392
|
+
* Dispatch a server-built tx_ready envelope to the chain-kind-specific
|
|
6393
|
+
* signer. EVM stays in `signEvmServerTx` (the existing PR #422 + PR #435
|
|
6394
|
+
* code, with EVM nonce/lock plumbing). Non-EVM kinds parse the envelope
|
|
6395
|
+
* via `parseNonEvmEnvelope` and route through `vault.send`, which is
|
|
6396
|
+
* already chain-agnostic via `VaultBase.prepareSendTx` virtuals.
|
|
6397
|
+
*
|
|
6398
|
+
* Phase D — see task `100526-sdk-cli-non-evm-signing.md`.
|
|
6399
|
+
*/
|
|
6400
|
+
async signServerTx(serverTxData, defaultChain, params) {
|
|
6401
|
+
const chain = resolveChainFromTxReady(serverTxData) || defaultChain;
|
|
6402
|
+
const chainKind = getChainKind(chain);
|
|
6403
|
+
if (chainKind === "evm") {
|
|
6404
|
+
return this.signEvmServerTx(serverTxData, defaultChain, params);
|
|
7360
6405
|
}
|
|
7361
|
-
return this.
|
|
6406
|
+
return this.signNonEvmServerTx(serverTxData, chain);
|
|
7362
6407
|
}
|
|
7363
6408
|
/**
|
|
7364
|
-
*
|
|
6409
|
+
* Non-EVM signing path: parse the agent's tx_ready envelope into a
|
|
6410
|
+
* `vault.send`-shaped argument bag and call through. The SDK already
|
|
6411
|
+
* handles per-chain prepare/sign/broadcast internally via
|
|
6412
|
+
* `VaultBase.prepareSendTx` virtuals — sdk-cli only owns envelope
|
|
6413
|
+
* parsing here, not chain-specific signing logic.
|
|
6414
|
+
*
|
|
6415
|
+
* THORChain / MayaChain MsgDeposit envelopes (msg_type='deposit',
|
|
6416
|
+
* to='') are routed through `vault.swap` because the agent's intent
|
|
6417
|
+
* is a swap — the memo (`=:CHAIN.ASSET:DEST::v0:slippage`) carries
|
|
6418
|
+
* the routing. We parse the memo to reconstruct vault.swap's
|
|
6419
|
+
* fromChain / fromSymbol / toChain / toSymbol / amount args. The SDK
|
|
6420
|
+
* then builds the MsgDeposit cosmos tx internally. Vultiagent uses an
|
|
6421
|
+
* equivalent custom helper (`buildSignBroadcastThorchainLpDeposit`);
|
|
6422
|
+
* we reuse the public `vault.swap` surface to avoid expanding the SDK.
|
|
7365
6423
|
*/
|
|
7366
|
-
async
|
|
7367
|
-
|
|
7368
|
-
if (this.
|
|
7369
|
-
|
|
7370
|
-
await this.vault.unlock?.(this.password);
|
|
7371
|
-
}
|
|
6424
|
+
async signNonEvmServerTx(serverTxData, chain) {
|
|
6425
|
+
if (this.vault.isEncrypted && !this.vault.isUnlocked?.()) {
|
|
6426
|
+
if (this.password) {
|
|
6427
|
+
await this.vault.unlock?.(this.password);
|
|
7372
6428
|
}
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
messageHashes
|
|
7380
|
-
},
|
|
7381
|
-
{}
|
|
6429
|
+
}
|
|
6430
|
+
const txArgs = serverTxData?.txArgs ?? {};
|
|
6431
|
+
if (typeof txArgs.chain === "string" && txArgs.chain !== chain) {
|
|
6432
|
+
throw new VaultError3(
|
|
6433
|
+
VaultErrorCode3.InvalidConfig,
|
|
6434
|
+
`signNonEvmServerTx: dispatcher chain '${chain}' disagrees with envelope chain '${txArgs.chain}'`
|
|
7382
6435
|
);
|
|
7383
|
-
const txHash = await this.vault.broadcastTx({
|
|
7384
|
-
chain,
|
|
7385
|
-
keysignPayload: payload,
|
|
7386
|
-
signature
|
|
7387
|
-
});
|
|
7388
|
-
this.evmLastBroadcast.set(chain.toString(), Date.now());
|
|
7389
|
-
try {
|
|
7390
|
-
this.recordEvmNonceFromPayload(chain, payload, messageHashes.length);
|
|
7391
|
-
} catch (nonceErr) {
|
|
7392
|
-
console.warn(`[nonce] failed to persist nonce for ${chain}:`, nonceErr);
|
|
7393
|
-
}
|
|
7394
|
-
await this.releaseEvmLock(chain);
|
|
7395
|
-
this.pendingPayloads.clear();
|
|
7396
|
-
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, txHash);
|
|
7397
|
-
return {
|
|
7398
|
-
tx_hash: txHash,
|
|
7399
|
-
chain: chain.toString(),
|
|
7400
|
-
status: "pending",
|
|
7401
|
-
explorer_url: explorerUrl
|
|
7402
|
-
};
|
|
7403
|
-
} catch (err) {
|
|
7404
|
-
await this.releaseEvmLock(chain);
|
|
7405
|
-
throw err;
|
|
7406
6436
|
}
|
|
6437
|
+
if (txArgs.msg_type === "deposit" && (chain === Chain10.THORChain || chain === Chain10.MayaChain)) {
|
|
6438
|
+
return this.signThorMsgDepositSwap(serverTxData, chain);
|
|
6439
|
+
}
|
|
6440
|
+
const args = parseNonEvmEnvelope(serverTxData, chain);
|
|
6441
|
+
if (this.verbose)
|
|
6442
|
+
process.stderr.write(
|
|
6443
|
+
`[sign_non_evm_server_tx] chain=${chain}, to=${args.to}, amount=${args.amount}${args.symbol ? ` ${args.symbol}` : ""}, memo=${args.memo ? `"${args.memo}"` : "(none)"}
|
|
6444
|
+
`
|
|
6445
|
+
);
|
|
6446
|
+
const result = await this.vault.send({
|
|
6447
|
+
chain,
|
|
6448
|
+
to: args.to,
|
|
6449
|
+
amount: args.amount,
|
|
6450
|
+
symbol: args.symbol,
|
|
6451
|
+
memo: args.memo
|
|
6452
|
+
});
|
|
6453
|
+
if (result.dryRun) {
|
|
6454
|
+
throw new VaultError3(
|
|
6455
|
+
VaultErrorCode3.InvalidConfig,
|
|
6456
|
+
"signNonEvmServerTx: vault.send unexpectedly returned dryRun result"
|
|
6457
|
+
);
|
|
6458
|
+
}
|
|
6459
|
+
this.pendingPayloads.clear();
|
|
6460
|
+
const broadcast = result;
|
|
6461
|
+
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, broadcast.txHash);
|
|
6462
|
+
return {
|
|
6463
|
+
tx_hash: broadcast.txHash,
|
|
6464
|
+
chain: chain.toString(),
|
|
6465
|
+
status: "pending",
|
|
6466
|
+
explorer_url: explorerUrl
|
|
6467
|
+
};
|
|
7407
6468
|
}
|
|
7408
6469
|
/**
|
|
7409
|
-
* Sign and broadcast a
|
|
7410
|
-
*
|
|
6470
|
+
* Sign and broadcast a THORChain / MayaChain MsgDeposit-style swap
|
|
6471
|
+
* envelope by reconstructing `vault.swap` args from the memo.
|
|
6472
|
+
*
|
|
6473
|
+
* The agent emits envelopes shaped:
|
|
6474
|
+
* { txArgs: { chain: 'THORChain', tx_encoding: 'cosmos-msg',
|
|
6475
|
+
* to: '', amount: '<base>', denom: 'rune',
|
|
6476
|
+
* memo: '=:DEST_CHAIN.DEST_ASSET:DEST_ADDR::v0:slippage_bps',
|
|
6477
|
+
* msg_type: 'deposit' } }
|
|
6478
|
+
*
|
|
6479
|
+
* The memo is THORChain's standard swap memo. We parse out the
|
|
6480
|
+
* destination chain + asset, look up the corresponding `Chain` enum,
|
|
6481
|
+
* then call `vault.swap` which builds the MsgDeposit internally.
|
|
6482
|
+
*
|
|
6483
|
+
* IMPORTANT — destination address handling: `vault.swap` re-derives the
|
|
6484
|
+
* destination address from `vault.address(toChain)` when fetching the
|
|
6485
|
+
* native swap quote (see `findSwapQuote` → `getNativeSwapQuote` —
|
|
6486
|
+
* `destination: to.address`). It does NOT honor the destination address
|
|
6487
|
+
* encoded in the envelope's memo. As a fund-safety guard we therefore
|
|
6488
|
+
* require the memo's destination address to match the vault's own
|
|
6489
|
+
* destination address (self-swap) and throw otherwise — see Phase D
|
|
6490
|
+
* review F1. Cross-account routing must wait on a Phase E SDK extension
|
|
6491
|
+
* that lets `vault.swap` accept a user-supplied destination.
|
|
7411
6492
|
*/
|
|
7412
|
-
async
|
|
6493
|
+
async signThorMsgDepositSwap(serverTxData, chain) {
|
|
6494
|
+
const txArgs = serverTxData?.txArgs ?? {};
|
|
6495
|
+
const memo = typeof txArgs.memo === "string" ? txArgs.memo : "";
|
|
6496
|
+
const parsed = parseThorSwapMemo(memo);
|
|
6497
|
+
const toChain = THOR_MEMO_CHAIN_TO_ENUM[parsed.destChainCode];
|
|
6498
|
+
if (!toChain) {
|
|
6499
|
+
throw new VaultError3(
|
|
6500
|
+
VaultErrorCode3.UnsupportedChain,
|
|
6501
|
+
`signThorMsgDepositSwap: unsupported destination chain code '${parsed.destChainCode}' in memo '${memo}'.`
|
|
6502
|
+
);
|
|
6503
|
+
}
|
|
6504
|
+
const vaultDestAddress = await this.vault.address(toChain);
|
|
6505
|
+
const normalizeForCompare = (addr) => EVM_CHAINS.has(toChain) ? addr.toLowerCase() : addr;
|
|
6506
|
+
if (parsed.destAddress && normalizeForCompare(parsed.destAddress) !== normalizeForCompare(vaultDestAddress)) {
|
|
6507
|
+
throw new VaultError3(
|
|
6508
|
+
VaultErrorCode3.NotImplemented,
|
|
6509
|
+
`signThorMsgDepositSwap: memo destination '${parsed.destAddress}' does not match vault address '${vaultDestAddress}' on ${toChain}. Phase D only supports self-swaps; cross-account routing requires a Phase E SDK extension that passes the user-supplied destination through to vault.swap.`
|
|
6510
|
+
);
|
|
6511
|
+
}
|
|
6512
|
+
const fromSymbol = chain === Chain10.THORChain ? "RUNE" : "CACAO";
|
|
6513
|
+
const amountRaw = typeof txArgs.amount === "string" ? txArgs.amount : void 0;
|
|
6514
|
+
if (!amountRaw) {
|
|
6515
|
+
throw new VaultError3(
|
|
6516
|
+
VaultErrorCode3.InvalidConfig,
|
|
6517
|
+
`signThorMsgDepositSwap: missing or non-string 'amount' field on ${chain} envelope`
|
|
6518
|
+
);
|
|
6519
|
+
}
|
|
6520
|
+
const amountDecimal = convertBaseUnitsToDecimal(chain, amountRaw, "signThorMsgDepositSwap");
|
|
6521
|
+
if (this.verbose)
|
|
6522
|
+
process.stderr.write(
|
|
6523
|
+
`[sign_thor_msg_deposit_swap] ${fromSymbol}@${chain} \u2192 ${parsed.destAsset}@${toChain}, amount=${amountDecimal}, memo='${memo}'
|
|
6524
|
+
`
|
|
6525
|
+
);
|
|
6526
|
+
const result = await this.vault.swap({
|
|
6527
|
+
fromChain: chain,
|
|
6528
|
+
fromSymbol,
|
|
6529
|
+
toChain,
|
|
6530
|
+
toSymbol: parsed.destAsset,
|
|
6531
|
+
amount: amountDecimal
|
|
6532
|
+
});
|
|
6533
|
+
if (result.dryRun) {
|
|
6534
|
+
throw new VaultError3(
|
|
6535
|
+
VaultErrorCode3.InvalidConfig,
|
|
6536
|
+
"signThorMsgDepositSwap: vault.swap unexpectedly returned dryRun result"
|
|
6537
|
+
);
|
|
6538
|
+
}
|
|
6539
|
+
this.pendingPayloads.clear();
|
|
6540
|
+
const broadcast = result;
|
|
6541
|
+
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, broadcast.txHash);
|
|
6542
|
+
return {
|
|
6543
|
+
tx_hash: broadcast.txHash,
|
|
6544
|
+
chain: chain.toString(),
|
|
6545
|
+
status: "pending",
|
|
6546
|
+
explorer_url: explorerUrl
|
|
6547
|
+
};
|
|
6548
|
+
}
|
|
6549
|
+
/**
|
|
6550
|
+
* Sign and broadcast a server-built EVM transaction (raw EVM tx from
|
|
6551
|
+
* tx_ready SSE). Uses vault.prepareSendTx with memo field to carry the
|
|
6552
|
+
* calldata, plus EVM-specific nonce/lock plumbing that Phase B's
|
|
6553
|
+
* `signMultiLeg` depends on for back-to-back approve+main broadcasts.
|
|
6554
|
+
*/
|
|
6555
|
+
async signEvmServerTx(serverTxData, defaultChain, params) {
|
|
7413
6556
|
const swapTx = extractNestedTx(serverTxData);
|
|
7414
6557
|
if (!swapTx?.to) {
|
|
7415
6558
|
throw new Error("Server transaction missing required fields (to)");
|
|
@@ -7503,6 +6646,97 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7503
6646
|
throw err;
|
|
7504
6647
|
}
|
|
7505
6648
|
}
|
|
6649
|
+
/**
|
|
6650
|
+
* Sign and broadcast a 2-leg ERC-20 approve + main flow originating from
|
|
6651
|
+
* mcp-ts `execute_*` envelopes that carry both `approvalTxArgs` and
|
|
6652
|
+
* `txArgs`. Mirrors vultiagent's `useTransactionFlow`: leg 1 (approve) is
|
|
6653
|
+
* signed and broadcast first, the receipt is awaited, then leg 2 (main)
|
|
6654
|
+
* is signed and broadcast. Fails closed if the approve doesn't confirm
|
|
6655
|
+
* — the main leg is NEVER broadcast against a stale or failed allowance.
|
|
6656
|
+
*
|
|
6657
|
+
* Phase B is intentionally EVM-only; non-EVM 2-leg flows are not a real
|
|
6658
|
+
* shape on mcp-ts today (Pattern 1 / Pattern 2 multi-leg flows are split
|
|
6659
|
+
* server-side via sequence_id and don't traverse this path).
|
|
6660
|
+
*/
|
|
6661
|
+
async signMultiLeg(_payload, chain, params) {
|
|
6662
|
+
const [approveLeg, mainLeg] = this.pendingLegs;
|
|
6663
|
+
try {
|
|
6664
|
+
const approveEnvelope = {
|
|
6665
|
+
...approveLeg.parent,
|
|
6666
|
+
txArgs: approveLeg.txArgs,
|
|
6667
|
+
approvalTxArgs: void 0,
|
|
6668
|
+
__multiLeg: void 0,
|
|
6669
|
+
swap_tx: void 0,
|
|
6670
|
+
send_tx: void 0,
|
|
6671
|
+
tx: void 0
|
|
6672
|
+
};
|
|
6673
|
+
const approveResult = await this.signServerTx(approveEnvelope, chain, params);
|
|
6674
|
+
const approveTxHash = approveResult.tx_hash;
|
|
6675
|
+
if (!approveTxHash) {
|
|
6676
|
+
throw new VaultError3(VaultErrorCode3.BroadcastFailed, "signMultiLeg: approve leg returned no tx_hash");
|
|
6677
|
+
}
|
|
6678
|
+
if (this.verbose)
|
|
6679
|
+
process.stderr.write(`[signMultiLeg] approve broadcast: ${approveTxHash}, waiting for receipt...
|
|
6680
|
+
`);
|
|
6681
|
+
try {
|
|
6682
|
+
await this.waitForEvmReceipt(chain, approveTxHash, { timeoutSec: 90 });
|
|
6683
|
+
} catch (err) {
|
|
6684
|
+
throw new VaultError3(
|
|
6685
|
+
VaultErrorCode3.Timeout,
|
|
6686
|
+
`signMultiLeg: approve leg ${approveTxHash} did not confirm: ${err?.message ?? err}`,
|
|
6687
|
+
err instanceof Error ? err : void 0
|
|
6688
|
+
);
|
|
6689
|
+
}
|
|
6690
|
+
if (this.verbose) process.stderr.write(`[signMultiLeg] approve confirmed, broadcasting main leg
|
|
6691
|
+
`);
|
|
6692
|
+
const mainEnvelope = {
|
|
6693
|
+
...mainLeg.parent,
|
|
6694
|
+
txArgs: mainLeg.txArgs,
|
|
6695
|
+
approvalTxArgs: void 0,
|
|
6696
|
+
__multiLeg: void 0,
|
|
6697
|
+
swap_tx: void 0,
|
|
6698
|
+
send_tx: void 0,
|
|
6699
|
+
tx: void 0
|
|
6700
|
+
};
|
|
6701
|
+
const mainResult = await this.signServerTx(mainEnvelope, chain, params);
|
|
6702
|
+
return {
|
|
6703
|
+
tx_hash: mainResult.tx_hash,
|
|
6704
|
+
approval_tx_hash: approveTxHash,
|
|
6705
|
+
chain: mainResult.chain,
|
|
6706
|
+
status: "pending",
|
|
6707
|
+
explorer_url: mainResult.explorer_url
|
|
6708
|
+
};
|
|
6709
|
+
} finally {
|
|
6710
|
+
this.pendingLegs = [];
|
|
6711
|
+
}
|
|
6712
|
+
}
|
|
6713
|
+
/**
|
|
6714
|
+
* Poll vault.getTxStatus until the EVM tx confirms or the timeout fires.
|
|
6715
|
+
* Mirrors VaultBase's private `waitForConfirmation` (used by `vault.swap`
|
|
6716
|
+
* for its own approve-before-swap flow) — kept at the executor layer here
|
|
6717
|
+
* so we can stub it from unit tests without exposing private SDK methods.
|
|
6718
|
+
*
|
|
6719
|
+
* Throws on timeout or on receipt status === 'error' (revert). Returns on
|
|
6720
|
+
* success.
|
|
6721
|
+
*/
|
|
6722
|
+
async waitForEvmReceipt(chain, txHash, opts) {
|
|
6723
|
+
const intervalMs = 3e3;
|
|
6724
|
+
const deadline = Date.now() + opts.timeoutSec * 1e3;
|
|
6725
|
+
while (Date.now() < deadline) {
|
|
6726
|
+
try {
|
|
6727
|
+
const result = await this.vault.getTxStatus({ chain, txHash });
|
|
6728
|
+
if (result?.status === "success") return;
|
|
6729
|
+
if (result?.status === "error") {
|
|
6730
|
+
throw new VaultError3(VaultErrorCode3.BroadcastFailed, `approve tx reverted (${txHash})`);
|
|
6731
|
+
}
|
|
6732
|
+
} catch (e) {
|
|
6733
|
+
if (e instanceof VaultError3 && e.code === VaultErrorCode3.BroadcastFailed) throw e;
|
|
6734
|
+
if (e?.message?.includes("reverted")) throw e;
|
|
6735
|
+
}
|
|
6736
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
6737
|
+
}
|
|
6738
|
+
throw new VaultError3(VaultErrorCode3.Timeout, `approve tx ${txHash} not confirmed within ${opts.timeoutSec}s`);
|
|
6739
|
+
}
|
|
7506
6740
|
/**
|
|
7507
6741
|
* Build, sign, and broadcast a Solana swap locally using the SDK's swap flow.
|
|
7508
6742
|
* Uses swap params from the tx_ready event to call vault.getSwapQuote → prepareSwapTx.
|
|
@@ -7769,37 +7003,39 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7769
7003
|
* - Payloads array: { payloads: [{id, domain, types, message, primaryType, chain}, ...] }
|
|
7770
7004
|
* Used by Polymarket which requires signing both an Order and a ClobAuth.
|
|
7771
7005
|
*/
|
|
7772
|
-
async signTypedData(
|
|
7773
|
-
|
|
7774
|
-
if (this.
|
|
7775
|
-
|
|
7006
|
+
async signTypedData(_toolCallId, input) {
|
|
7007
|
+
return this.runTool("sign_typed_data", async () => {
|
|
7008
|
+
if (this.vault.isEncrypted && !this.vault.isUnlocked?.()) {
|
|
7009
|
+
if (this.password) {
|
|
7010
|
+
await this.vault.unlock?.(this.password);
|
|
7011
|
+
}
|
|
7776
7012
|
}
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
if (this.verbose) process.stderr.write(`[sign_typed_data] payloads mode, ${payloads.length} items
|
|
7013
|
+
const payloads = input.payloads;
|
|
7014
|
+
if (payloads && Array.isArray(payloads)) {
|
|
7015
|
+
if (this.verbose) process.stderr.write(`[sign_typed_data] payloads mode, ${payloads.length} items
|
|
7781
7016
|
`);
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7017
|
+
const signatures = [];
|
|
7018
|
+
for (let i = 0; i < payloads.length; i++) {
|
|
7019
|
+
const payload = payloads[i];
|
|
7020
|
+
const id = payload.id || payload.name || "default";
|
|
7021
|
+
if (i > 0) {
|
|
7022
|
+
if (this.verbose) process.stderr.write(`[sign_typed_data] waiting 5s between MPC sessions...
|
|
7788
7023
|
`);
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7024
|
+
await new Promise((r) => setTimeout(r, 5e3));
|
|
7025
|
+
}
|
|
7026
|
+
const sig = await this.signSingleTypedData(payload);
|
|
7027
|
+
signatures.push({ id, ...sig });
|
|
7028
|
+
if (this.verbose) process.stderr.write(`[sign_typed_data] signed payload "${id}"
|
|
7794
7029
|
`);
|
|
7030
|
+
}
|
|
7031
|
+
return {
|
|
7032
|
+
signatures,
|
|
7033
|
+
pm_order_ref: input.pm_order_ref,
|
|
7034
|
+
auto_submit: !!(input.__pm_auto_submit || input.auto_submit)
|
|
7035
|
+
};
|
|
7795
7036
|
}
|
|
7796
|
-
return
|
|
7797
|
-
|
|
7798
|
-
pm_order_ref: params.pm_order_ref,
|
|
7799
|
-
auto_submit: !!(params.__pm_auto_submit || params.auto_submit)
|
|
7800
|
-
};
|
|
7801
|
-
}
|
|
7802
|
-
return this.signSingleTypedData(params);
|
|
7037
|
+
return this.signSingleTypedData(input);
|
|
7038
|
+
});
|
|
7803
7039
|
}
|
|
7804
7040
|
/**
|
|
7805
7041
|
* Sign a single EIP-712 typed data object.
|
|
@@ -7848,33 +7084,20 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7848
7084
|
}
|
|
7849
7085
|
// ============================================================================
|
|
7850
7086
|
// Address Book
|
|
7087
|
+
//
|
|
7088
|
+
// Live client-side tools — server-side `address_book_*` runs through MCP
|
|
7089
|
+
// for read; mutating writes have no local implementation yet.
|
|
7851
7090
|
// ============================================================================
|
|
7852
|
-
async
|
|
7853
|
-
|
|
7854
|
-
throw new Error(
|
|
7855
|
-
"get_address_book requires the CLI SDK instance. Ensure AgentConfig.vultisig is set when creating the session."
|
|
7856
|
-
);
|
|
7857
|
-
}
|
|
7858
|
-
const chainName = params.chain || params.chain_name;
|
|
7859
|
-
const chain = chainName ? resolveChain(chainName) : void 0;
|
|
7860
|
-
if (chainName && !chain) {
|
|
7861
|
-
throw new Error(`Unknown chain: ${chainName}`);
|
|
7862
|
-
}
|
|
7863
|
-
return await this.vultisig.getAddressBook(chain);
|
|
7091
|
+
async addressBookAdd(_toolCallId, input) {
|
|
7092
|
+
return this.runTool("address_book_add", () => this.addAddressBookImpl(input));
|
|
7864
7093
|
}
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
async addressBook(params) {
|
|
7868
|
-
const action = params.action;
|
|
7869
|
-
switch (action) {
|
|
7870
|
-
case "add":
|
|
7871
|
-
return this.addAddressBookImpl(params);
|
|
7872
|
-
case "remove":
|
|
7873
|
-
return this.removeAddressBookImpl(params);
|
|
7874
|
-
default:
|
|
7875
|
-
throw new Error(`address_book: unknown action: ${action ?? "(missing)"}`);
|
|
7876
|
-
}
|
|
7094
|
+
async addressBookRemove(_toolCallId, input) {
|
|
7095
|
+
return this.runTool("address_book_remove", () => this.removeAddressBookImpl(input));
|
|
7877
7096
|
}
|
|
7097
|
+
// Backend `address_book { action: "add", entry: {...} }` flows through
|
|
7098
|
+
// this impl. The public `addressBookAdd` wrapper above tags results as
|
|
7099
|
+
// `tool: 'address_book_add'`; the new `addressBook` wrapper tags them as
|
|
7100
|
+
// `tool: 'address_book'` (matching the discriminator tool the backend emits).
|
|
7878
7101
|
async addAddressBookImpl(params) {
|
|
7879
7102
|
if (!this.vultisig) {
|
|
7880
7103
|
throw new Error(
|
|
@@ -7938,110 +7161,7 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7938
7161
|
await this.vultisig.removeAddressBookEntry([{ chain, address }]);
|
|
7939
7162
|
return { removed: { chain: chain.toString(), address } };
|
|
7940
7163
|
}
|
|
7941
|
-
// ============================================================================
|
|
7942
|
-
// Token Search & Other
|
|
7943
|
-
// ============================================================================
|
|
7944
|
-
async searchToken(params) {
|
|
7945
|
-
const query = String(params.query ?? params.q ?? "").trim().toLowerCase();
|
|
7946
|
-
if (!query) {
|
|
7947
|
-
return { tokens: [] };
|
|
7948
|
-
}
|
|
7949
|
-
const limit = 20;
|
|
7950
|
-
const chainName = params.chain;
|
|
7951
|
-
const tokenMatchesQuery = (t) => {
|
|
7952
|
-
const tick = t.ticker.toLowerCase();
|
|
7953
|
-
const addr = (t.contractAddress ?? "").toLowerCase();
|
|
7954
|
-
const pid = (t.priceProviderId ?? "").toLowerCase();
|
|
7955
|
-
return tick.includes(query) || addr.includes(query) || pid.includes(query);
|
|
7956
|
-
};
|
|
7957
|
-
if (chainName) {
|
|
7958
|
-
const chain = resolveChain(chainName);
|
|
7959
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
7960
|
-
const tokens = VultisigSdk.getKnownTokens(chain).filter(tokenMatchesQuery).slice(0, limit);
|
|
7961
|
-
return { tokens };
|
|
7962
|
-
}
|
|
7963
|
-
const out = [];
|
|
7964
|
-
for (const c of Object.values(Chain10)) {
|
|
7965
|
-
for (const t of VultisigSdk.getKnownTokens(c)) {
|
|
7966
|
-
if (!tokenMatchesQuery(t)) continue;
|
|
7967
|
-
out.push(t);
|
|
7968
|
-
if (out.length >= limit) return { tokens: out };
|
|
7969
|
-
}
|
|
7970
|
-
}
|
|
7971
|
-
return { tokens: out };
|
|
7972
|
-
}
|
|
7973
|
-
async listVaults() {
|
|
7974
|
-
return {
|
|
7975
|
-
vaults: [
|
|
7976
|
-
{
|
|
7977
|
-
name: this.vault.name,
|
|
7978
|
-
id: this.vault.id,
|
|
7979
|
-
type: this.vault.type,
|
|
7980
|
-
chains: this.vault.chains.map((c) => c.toString())
|
|
7981
|
-
}
|
|
7982
|
-
]
|
|
7983
|
-
};
|
|
7984
|
-
}
|
|
7985
|
-
async scanTx(_params) {
|
|
7986
|
-
throw new Error("scan_tx is not yet implemented locally. The backend may handle this action server-side.");
|
|
7987
|
-
}
|
|
7988
|
-
async readEvmContract(params) {
|
|
7989
|
-
const chainName = params.chain;
|
|
7990
|
-
if (!chainName) throw new Error("read_evm_contract requires chain");
|
|
7991
|
-
const contractRaw = params.contract_address || params.contractAddress;
|
|
7992
|
-
if (!contractRaw) throw new Error("read_evm_contract requires contract_address");
|
|
7993
|
-
const functionName = params.function_name || params.functionName;
|
|
7994
|
-
if (!functionName) throw new Error("read_evm_contract requires function_name");
|
|
7995
|
-
const chain = resolveChain(chainName);
|
|
7996
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
7997
|
-
if (!EVM_CHAINS.has(chain)) {
|
|
7998
|
-
throw new Error(`read_evm_contract only supports EVM chains (got ${chain})`);
|
|
7999
|
-
}
|
|
8000
|
-
const callParams = params.params ?? [];
|
|
8001
|
-
const data = await encodeContractCall(functionName, callParams);
|
|
8002
|
-
const addr = contractRaw.startsWith("0x") ? contractRaw : `0x${contractRaw}`;
|
|
8003
|
-
const to = addr;
|
|
8004
|
-
const from = params.from;
|
|
8005
|
-
const result = await evmCall(chain, { to, data, from });
|
|
8006
|
-
return { result };
|
|
8007
|
-
}
|
|
8008
7164
|
};
|
|
8009
|
-
async function encodeContractCall(functionName, params) {
|
|
8010
|
-
const baseName = functionName.includes("(") ? functionName.split("(")[0] : functionName;
|
|
8011
|
-
const types = params.map((p) => p.type);
|
|
8012
|
-
const sig = `${baseName}(${types.join(",")})`;
|
|
8013
|
-
const selector = await keccak256Selector(sig);
|
|
8014
|
-
let encoded = "";
|
|
8015
|
-
for (const param of params) {
|
|
8016
|
-
encoded += abiEncodeParam(param.type, param.value);
|
|
8017
|
-
}
|
|
8018
|
-
return "0x" + selector + encoded;
|
|
8019
|
-
}
|
|
8020
|
-
async function keccak256Selector(sig) {
|
|
8021
|
-
const { keccak_256: keccak_2562 } = await Promise.resolve().then(() => (init_sha3(), sha3_exports));
|
|
8022
|
-
const hash = keccak_2562(new TextEncoder().encode(sig));
|
|
8023
|
-
return Buffer.from(hash).toString("hex").slice(0, 8);
|
|
8024
|
-
}
|
|
8025
|
-
function abiEncodeParam(type, value) {
|
|
8026
|
-
if (type === "address") {
|
|
8027
|
-
const addr = value.startsWith("0x") ? value.slice(2) : value;
|
|
8028
|
-
return addr.toLowerCase().padStart(64, "0");
|
|
8029
|
-
}
|
|
8030
|
-
if (type.startsWith("uint") || type.startsWith("int")) {
|
|
8031
|
-
const n = BigInt(value);
|
|
8032
|
-
const hex = n.toString(16);
|
|
8033
|
-
return hex.padStart(64, "0");
|
|
8034
|
-
}
|
|
8035
|
-
if (type === "bool") {
|
|
8036
|
-
return (value === "true" || value === "1" ? "1" : "0").padStart(64, "0");
|
|
8037
|
-
}
|
|
8038
|
-
if (type === "bytes32") {
|
|
8039
|
-
const b2 = value.startsWith("0x") ? value.slice(2) : value;
|
|
8040
|
-
return b2.padEnd(64, "0");
|
|
8041
|
-
}
|
|
8042
|
-
const b = value.startsWith("0x") ? value.slice(2) : Buffer.from(value).toString("hex");
|
|
8043
|
-
return b.padStart(64, "0");
|
|
8044
|
-
}
|
|
8045
7165
|
function resolveChain(name) {
|
|
8046
7166
|
if (!name) return null;
|
|
8047
7167
|
if (Object.values(Chain10).includes(name)) {
|
|
@@ -8079,11 +7199,6 @@ function resolveChain(name) {
|
|
|
8079
7199
|
}
|
|
8080
7200
|
return null;
|
|
8081
7201
|
}
|
|
8082
|
-
function parseAmount(amountStr, decimals) {
|
|
8083
|
-
const [whole, frac = ""] = amountStr.split(".");
|
|
8084
|
-
const paddedFrac = frac.slice(0, decimals).padEnd(decimals, "0");
|
|
8085
|
-
return BigInt(whole || "0") * 10n ** BigInt(decimals) + BigInt(paddedFrac || "0");
|
|
8086
|
-
}
|
|
8087
7202
|
function resolveChainFromTxReady(txReadyData) {
|
|
8088
7203
|
if (txReadyData.chain) {
|
|
8089
7204
|
const chain = resolveChain(txReadyData.chain);
|
|
@@ -8115,6 +7230,75 @@ function resolveChainFromTxReady(txReadyData) {
|
|
|
8115
7230
|
function extractNestedTx(txReadyData) {
|
|
8116
7231
|
return txReadyData?.swap_tx || txReadyData?.send_tx || txReadyData?.tx || txReadyData?.txArgs?.tx;
|
|
8117
7232
|
}
|
|
7233
|
+
var MAX_AMOUNT_DIGITS = 26;
|
|
7234
|
+
function convertBaseUnitsToDecimal(chain, amountRaw, context) {
|
|
7235
|
+
if (amountRaw.length > MAX_AMOUNT_DIGITS) {
|
|
7236
|
+
throw new VaultError3(
|
|
7237
|
+
VaultErrorCode3.InvalidAmount,
|
|
7238
|
+
`${context}: amount '${amountRaw}' for ${chain} exceeds ${MAX_AMOUNT_DIGITS}-digit safety bound. Likely a quote-side bug. Refusing to sign.`
|
|
7239
|
+
);
|
|
7240
|
+
}
|
|
7241
|
+
const decimals = chainFeeCoin[chain]?.decimals;
|
|
7242
|
+
if (decimals === void 0) {
|
|
7243
|
+
throw new VaultError3(VaultErrorCode3.UnsupportedChain, `${context}: no native decimals registered for ${chain}`);
|
|
7244
|
+
}
|
|
7245
|
+
try {
|
|
7246
|
+
return formatUnits(BigInt(amountRaw), decimals);
|
|
7247
|
+
} catch (err) {
|
|
7248
|
+
throw new VaultError3(
|
|
7249
|
+
VaultErrorCode3.InvalidAmount,
|
|
7250
|
+
`${context}: failed to convert amount '${amountRaw}' for ${chain}: ${err?.message ?? err}`
|
|
7251
|
+
);
|
|
7252
|
+
}
|
|
7253
|
+
}
|
|
7254
|
+
function parseNonEvmEnvelope(serverTxData, chain) {
|
|
7255
|
+
const txArgs = serverTxData?.txArgs ?? serverTxData;
|
|
7256
|
+
if (!txArgs || typeof txArgs !== "object") {
|
|
7257
|
+
throw new VaultError3(VaultErrorCode3.InvalidConfig, "parseNonEvmEnvelope: envelope missing txArgs");
|
|
7258
|
+
}
|
|
7259
|
+
const to = typeof txArgs.to === "string" ? txArgs.to : void 0;
|
|
7260
|
+
if (!to) {
|
|
7261
|
+
throw new VaultError3(VaultErrorCode3.InvalidConfig, `parseNonEvmEnvelope: missing 'to' field for ${chain}`);
|
|
7262
|
+
}
|
|
7263
|
+
const amountRaw = typeof txArgs.amount === "string" ? txArgs.amount : void 0;
|
|
7264
|
+
if (!amountRaw) {
|
|
7265
|
+
throw new VaultError3(VaultErrorCode3.InvalidConfig, `parseNonEvmEnvelope: missing 'amount' field for ${chain}`);
|
|
7266
|
+
}
|
|
7267
|
+
const amountDecimal = convertBaseUnitsToDecimal(chain, amountRaw, "parseNonEvmEnvelope");
|
|
7268
|
+
let symbol;
|
|
7269
|
+
const tokenResolved = serverTxData?.resolved?.labels?.token_resolved;
|
|
7270
|
+
const nativeTicker = chainFeeCoin[chain]?.ticker;
|
|
7271
|
+
if (typeof tokenResolved === "string" && tokenResolved !== nativeTicker) {
|
|
7272
|
+
symbol = tokenResolved;
|
|
7273
|
+
}
|
|
7274
|
+
const memo = typeof txArgs.memo === "string" && txArgs.memo.length > 0 ? txArgs.memo : void 0;
|
|
7275
|
+
return { chain, to, amount: amountDecimal, symbol, memo };
|
|
7276
|
+
}
|
|
7277
|
+
function parseThorSwapMemo(memo) {
|
|
7278
|
+
if (!memo.startsWith("=:")) {
|
|
7279
|
+
throw new VaultError3(
|
|
7280
|
+
VaultErrorCode3.NotImplemented,
|
|
7281
|
+
`parseThorSwapMemo: only swap memos (=:CHAIN.ASSET:DEST...) supported on this path; got memo='${memo}'. LP / non-swap MsgDeposit flows route through different SDK helpers (Phase E follow-up).`
|
|
7282
|
+
);
|
|
7283
|
+
}
|
|
7284
|
+
const memoBody = memo.slice(2);
|
|
7285
|
+
const parts = memoBody.split(":");
|
|
7286
|
+
let chainAsset = parts[0];
|
|
7287
|
+
if (chainAsset && !chainAsset.includes(".")) {
|
|
7288
|
+
const expanded = THOR_MEMO_ASSET_SHORTCUTS[chainAsset.toLowerCase()];
|
|
7289
|
+
if (expanded) chainAsset = expanded;
|
|
7290
|
+
}
|
|
7291
|
+
if (!chainAsset || !chainAsset.includes(".")) {
|
|
7292
|
+
throw new VaultError3(
|
|
7293
|
+
VaultErrorCode3.InvalidConfig,
|
|
7294
|
+
`parseThorSwapMemo: malformed swap memo '${memo}': missing CHAIN.ASSET in first segment.`
|
|
7295
|
+
);
|
|
7296
|
+
}
|
|
7297
|
+
const [destChainCode, destAssetRaw] = chainAsset.split(".");
|
|
7298
|
+
const destAsset = destAssetRaw?.split("-")[0] ?? "";
|
|
7299
|
+
const destAddress = typeof parts[1] === "string" ? parts[1] : "";
|
|
7300
|
+
return { destChainCode, destAsset, destAddress };
|
|
7301
|
+
}
|
|
8118
7302
|
function resolveChainId(chainId) {
|
|
8119
7303
|
const id = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
|
|
8120
7304
|
if (isNaN(id)) return null;
|
|
@@ -8507,22 +7691,14 @@ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, wri
|
|
|
8507
7691
|
import { homedir as homedir2 } from "node:os";
|
|
8508
7692
|
import { join as join2 } from "node:path";
|
|
8509
7693
|
import { MemoryStorage, PushNotificationService } from "@vultisig/sdk";
|
|
7694
|
+
var PASSWORD_REQUIRED_TOOLS = /* @__PURE__ */ new Set(["sign_typed_data", "sign_tx"]);
|
|
8510
7695
|
var CLIENT_SIDE_TOOL_DISPATCH = {
|
|
8511
|
-
sign_typed_data:
|
|
8512
|
-
vault_coin:
|
|
8513
|
-
vault_chain:
|
|
8514
|
-
address_book:
|
|
7696
|
+
sign_typed_data: (ex, id, input) => ex.signTypedData(id, input),
|
|
7697
|
+
vault_coin: (ex, id, input) => ex.vaultCoin(id, input),
|
|
7698
|
+
vault_chain: (ex, id, input) => ex.vaultChain(id, input),
|
|
7699
|
+
address_book: (ex, id, input) => ex.addressBook(id, input)
|
|
8515
7700
|
};
|
|
8516
7701
|
var MAX_MESSAGE_LOOP_DEPTH = 16;
|
|
8517
|
-
function actionResultToRecentAction(r) {
|
|
8518
|
-
if (r.success) {
|
|
8519
|
-
return { tool: r.action, success: true, data: r.data ?? {} };
|
|
8520
|
-
}
|
|
8521
|
-
const data = { ...r.data ?? {} };
|
|
8522
|
-
if (r.error) data.error = r.error;
|
|
8523
|
-
if (r.code) data.code = r.code;
|
|
8524
|
-
return { tool: r.action, success: false, data };
|
|
8525
|
-
}
|
|
8526
7702
|
var AgentSession = class {
|
|
8527
7703
|
client;
|
|
8528
7704
|
vault;
|
|
@@ -8779,21 +7955,22 @@ var AgentSession = class {
|
|
|
8779
7955
|
`[session] ${serverTxStoredFromStream} stored server tx from tx_ready, signing client-side
|
|
8780
7956
|
`
|
|
8781
7957
|
);
|
|
8782
|
-
const
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
if (
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
return;
|
|
7958
|
+
const signToolCallId = `tx_sign_${Date.now()}`;
|
|
7959
|
+
const recent = await this.runPasswordGatedTool(
|
|
7960
|
+
"sign_tx",
|
|
7961
|
+
signToolCallId,
|
|
7962
|
+
ui,
|
|
7963
|
+
() => this.executor.signTxFromBuffer(signToolCallId)
|
|
7964
|
+
);
|
|
7965
|
+
this.pendingToolResults.push(recent);
|
|
7966
|
+
if (recent.success && recent.data) {
|
|
7967
|
+
const txHash = recent.data.tx_hash;
|
|
7968
|
+
const chain = recent.data.chain;
|
|
7969
|
+
const explorerUrl = recent.data.explorer_url;
|
|
7970
|
+
if (txHash) ui.onTxStatus(txHash, chain || "", "pending", explorerUrl);
|
|
8796
7971
|
}
|
|
7972
|
+
await this.processMessageLoop(null, ui, depth + 1);
|
|
7973
|
+
return;
|
|
8797
7974
|
}
|
|
8798
7975
|
if (this.pendingToolResults.length > 0) {
|
|
8799
7976
|
await this.processMessageLoop(null, ui, depth + 1);
|
|
@@ -8801,12 +7978,59 @@ var AgentSession = class {
|
|
|
8801
7978
|
}
|
|
8802
7979
|
ui.onDone();
|
|
8803
7980
|
}
|
|
8804
|
-
|
|
7981
|
+
/**
|
|
7982
|
+
* Wrap a per-tool dispatch with the password-prompt gate (for tools in
|
|
7983
|
+
* {@link PASSWORD_REQUIRED_TOOLS}) and `ui.onToolCall` /
|
|
7984
|
+
* `ui.onToolResult` lifecycle events. Returns the `RecentAction` produced
|
|
7985
|
+
* by the executor (or a synthetic failure `RecentAction` if the password
|
|
7986
|
+
* prompt was declined).
|
|
7987
|
+
*/
|
|
7988
|
+
async runPasswordGatedTool(toolName, toolCallId, ui, body, input) {
|
|
7989
|
+
let promptedPassword;
|
|
7990
|
+
if (PASSWORD_REQUIRED_TOOLS.has(toolName) && !this.config.password) {
|
|
7991
|
+
try {
|
|
7992
|
+
promptedPassword = await ui.requestPassword();
|
|
7993
|
+
this.executor.setPassword(promptedPassword);
|
|
7994
|
+
} catch {
|
|
7995
|
+
const failure = {
|
|
7996
|
+
tool: toolName,
|
|
7997
|
+
success: false,
|
|
7998
|
+
data: { error: "Password not provided", code: "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */ }
|
|
7999
|
+
};
|
|
8000
|
+
ui.onToolCall(toolCallId, toolName, input);
|
|
8001
|
+
ui.onToolResult(
|
|
8002
|
+
toolCallId,
|
|
8003
|
+
toolName,
|
|
8004
|
+
false,
|
|
8005
|
+
failure.data,
|
|
8006
|
+
"Password not provided",
|
|
8007
|
+
"PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */
|
|
8008
|
+
);
|
|
8009
|
+
return failure;
|
|
8010
|
+
}
|
|
8011
|
+
}
|
|
8012
|
+
ui.onToolCall(toolCallId, toolName, input);
|
|
8013
|
+
let recent;
|
|
8014
|
+
try {
|
|
8015
|
+
recent = await body();
|
|
8016
|
+
} catch (err) {
|
|
8017
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8018
|
+
recent = { tool: toolName, success: false, data: { error: message } };
|
|
8019
|
+
}
|
|
8020
|
+
const errorMsg = recent.data?.error ?? void 0;
|
|
8021
|
+
const errorCode = recent.data?.code ?? void 0;
|
|
8022
|
+
ui.onToolResult(toolCallId, toolName, recent.success, recent.data, errorMsg, errorCode);
|
|
8023
|
+
if (promptedPassword && recent.success) {
|
|
8024
|
+
this.config.password = promptedPassword;
|
|
8025
|
+
}
|
|
8026
|
+
return recent;
|
|
8027
|
+
}
|
|
8028
|
+
// Routes client-side tool calls through the per-tool registry. Missing
|
|
8805
8029
|
// entries surface as a visible `[cli] unimplemented` warning + failure
|
|
8806
8030
|
// RecentAction (never silent).
|
|
8807
8031
|
async dispatchClientSideTool(toolCallId, toolName, input, ui) {
|
|
8808
|
-
const
|
|
8809
|
-
if (!
|
|
8032
|
+
const handler = CLIENT_SIDE_TOOL_DISPATCH[toolName];
|
|
8033
|
+
if (!handler) {
|
|
8810
8034
|
process.stderr.write(`[cli] unimplemented client-side tool: ${toolName}
|
|
8811
8035
|
`);
|
|
8812
8036
|
this.pendingToolResults.push({
|
|
@@ -8816,76 +8040,26 @@ var AgentSession = class {
|
|
|
8816
8040
|
});
|
|
8817
8041
|
return;
|
|
8818
8042
|
}
|
|
8819
|
-
|
|
8820
|
-
id: toolCallId,
|
|
8821
|
-
type: actionType,
|
|
8822
|
-
title: toolName,
|
|
8823
|
-
params: input,
|
|
8824
|
-
auto_execute: true
|
|
8825
|
-
};
|
|
8043
|
+
let recent;
|
|
8826
8044
|
try {
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
recent.data[key] = input[key];
|
|
8835
|
-
}
|
|
8836
|
-
}
|
|
8837
|
-
this.pendingToolResults.push(recent);
|
|
8838
|
-
}
|
|
8045
|
+
recent = await this.runPasswordGatedTool(
|
|
8046
|
+
toolName,
|
|
8047
|
+
toolCallId,
|
|
8048
|
+
ui,
|
|
8049
|
+
() => handler(this.executor, toolCallId, input),
|
|
8050
|
+
input
|
|
8051
|
+
);
|
|
8839
8052
|
} catch (err) {
|
|
8840
8053
|
const message = err instanceof Error ? err.message : String(err);
|
|
8841
|
-
|
|
8842
|
-
tool: toolName,
|
|
8843
|
-
success: false,
|
|
8844
|
-
data: { error: message }
|
|
8845
|
-
});
|
|
8054
|
+
recent = { tool: toolName, success: false, data: { error: message } };
|
|
8846
8055
|
}
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
async executeActions(actions, ui) {
|
|
8852
|
-
const results = [];
|
|
8853
|
-
for (const action of actions) {
|
|
8854
|
-
if (!this.executor.shouldAutoExecute(action)) {
|
|
8855
|
-
continue;
|
|
8856
|
-
}
|
|
8857
|
-
if (PASSWORD_REQUIRED_ACTIONS.has(action.type)) {
|
|
8858
|
-
if (!this.config.password) {
|
|
8859
|
-
try {
|
|
8860
|
-
const password = await ui.requestPassword();
|
|
8861
|
-
this.executor.setPassword(password);
|
|
8862
|
-
this.config.password = password;
|
|
8863
|
-
} catch {
|
|
8864
|
-
results.push({
|
|
8865
|
-
action: action.type,
|
|
8866
|
-
action_id: action.id,
|
|
8867
|
-
success: false,
|
|
8868
|
-
error: "Password not provided",
|
|
8869
|
-
code: "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */
|
|
8870
|
-
});
|
|
8871
|
-
continue;
|
|
8872
|
-
}
|
|
8873
|
-
}
|
|
8874
|
-
}
|
|
8875
|
-
ui.onToolCall(action.id, action.type, action.params);
|
|
8876
|
-
const result = await this.executor.executeAction(action);
|
|
8877
|
-
results.push(result);
|
|
8878
|
-
ui.onToolResult(action.id, action.type, result.success, result.data, result.error, result.code);
|
|
8879
|
-
if (action.type === "sign_tx" && result.success && result.data) {
|
|
8880
|
-
const txHash = result.data.tx_hash;
|
|
8881
|
-
const chain = result.data.chain;
|
|
8882
|
-
const explorerUrl = result.data.explorer_url;
|
|
8883
|
-
if (txHash) {
|
|
8884
|
-
ui.onTxStatus(txHash, chain, "pending", explorerUrl);
|
|
8885
|
-
}
|
|
8056
|
+
if (recent.data === void 0) recent.data = {};
|
|
8057
|
+
for (const key of Object.keys(input)) {
|
|
8058
|
+
if (key.startsWith("__") || key === "pm_order_ref") {
|
|
8059
|
+
recent.data[key] = input[key];
|
|
8886
8060
|
}
|
|
8887
8061
|
}
|
|
8888
|
-
|
|
8062
|
+
this.pendingToolResults.push(recent);
|
|
8889
8063
|
}
|
|
8890
8064
|
/**
|
|
8891
8065
|
* Cancel the current operation.
|
|
@@ -9503,7 +8677,7 @@ var cachedVersion = null;
|
|
|
9503
8677
|
function getVersion() {
|
|
9504
8678
|
if (cachedVersion) return cachedVersion;
|
|
9505
8679
|
if (true) {
|
|
9506
|
-
cachedVersion = "0.22.
|
|
8680
|
+
cachedVersion = "0.22.7";
|
|
9507
8681
|
return cachedVersion;
|
|
9508
8682
|
}
|
|
9509
8683
|
try {
|