@vultisig/cli 0.22.3 → 0.22.5
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 +28 -0
- package/dist/index.js +397 -1913
- package/package.json +6 -6
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://midgard.thorchain.network";
|
|
1658
|
-
POOL_ID_RE = /^[A-Z0-9]+\.[A-Z0-9]+(-[A-Z0-9]+)?$/;
|
|
1659
|
-
assertValidPoolId = (pool) => {
|
|
1660
|
-
if (typeof pool !== "string" || pool.length === 0) {
|
|
1661
|
-
throw new Error(`assertValidPoolId: pool id must be a non-empty string, got ${typeof pool} ${pool === "" ? '""' : ""}`);
|
|
1662
|
-
}
|
|
1663
|
-
if (!POOL_ID_RE.test(pool)) {
|
|
1664
|
-
throw new Error(`assertValidPoolId: ${JSON.stringify(pool)} is not a valid THORChain pool id. Expected uppercase CHAIN.ASSET (e.g. "BTC.BTC") or CHAIN.ASSET-CONTRACT (e.g. "ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48").`);
|
|
1665
|
-
}
|
|
1666
|
-
};
|
|
1667
|
-
isValidPoolId = (pool) => {
|
|
1668
|
-
if (typeof pool !== "string" || pool.length === 0)
|
|
1669
|
-
return false;
|
|
1670
|
-
return POOL_ID_RE.test(pool);
|
|
1671
|
-
};
|
|
1672
|
-
normalizePool = (raw) => ({
|
|
1673
|
-
asset: raw.asset ?? "",
|
|
1674
|
-
status: raw.status ?? "",
|
|
1675
|
-
assetDepth: raw.assetDepth ?? "0",
|
|
1676
|
-
runeDepth: raw.runeDepth ?? "0",
|
|
1677
|
-
liquidityUnits: raw.liquidityUnits ?? "0",
|
|
1678
|
-
volume24h: raw.volume24h ?? "0",
|
|
1679
|
-
annualPercentageRate: raw.annualPercentageRate ?? "0"
|
|
1680
|
-
});
|
|
1681
|
-
getThorchainPools = async (options = {}) => {
|
|
1682
|
-
const status = options.status === void 0 ? "available" : options.status;
|
|
1683
|
-
const url = status === null ? `${thorchainMidgardBaseUrl}/v2/pools` : `${thorchainMidgardBaseUrl}/v2/pools?status=${encodeURIComponent(status)}`;
|
|
1684
|
-
const raw = await queryUrl(url);
|
|
1685
|
-
if (!Array.isArray(raw)) {
|
|
1686
|
-
throw new Error(`getThorchainPools: expected an array from ${url}, got ${typeof raw}`);
|
|
1687
|
-
}
|
|
1688
|
-
return raw.map(normalizePool);
|
|
1689
|
-
};
|
|
1690
|
-
}
|
|
1691
|
-
});
|
|
1692
|
-
|
|
1693
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/memo.js
|
|
1694
|
-
var assertMemoSegmentSafe, addLpMemo, removeLpMemo;
|
|
1695
|
-
var init_memo = __esm({
|
|
1696
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/memo.js"() {
|
|
1697
|
-
init_pools();
|
|
1698
|
-
assertMemoSegmentSafe = (value, fieldName) => {
|
|
1699
|
-
if (typeof value !== "string") {
|
|
1700
|
-
throw new Error(`${fieldName} must be a string, got ${typeof value}`);
|
|
1701
|
-
}
|
|
1702
|
-
if (value.includes(":")) {
|
|
1703
|
-
throw new Error(`${fieldName} must not contain \`:\` (would inject extra memo segments), got ${JSON.stringify(value)}`);
|
|
1704
|
-
}
|
|
1705
|
-
if (/\s/.test(value)) {
|
|
1706
|
-
throw new Error(`${fieldName} must not contain whitespace, got ${JSON.stringify(value)}`);
|
|
1707
|
-
}
|
|
1708
|
-
};
|
|
1709
|
-
addLpMemo = ({ pool, pairedAddress }) => {
|
|
1710
|
-
assertValidPoolId(pool);
|
|
1711
|
-
if (pairedAddress && pairedAddress.length > 0) {
|
|
1712
|
-
assertMemoSegmentSafe(pairedAddress, "pairedAddress");
|
|
1713
|
-
return `+:${pool}:${pairedAddress}`;
|
|
1714
|
-
}
|
|
1715
|
-
return `+:${pool}`;
|
|
1716
|
-
};
|
|
1717
|
-
removeLpMemo = ({ pool, basisPoints, withdrawToAsset }) => {
|
|
1718
|
-
assertValidPoolId(pool);
|
|
1719
|
-
if (!Number.isInteger(basisPoints) || basisPoints < 1 || basisPoints > 1e4) {
|
|
1720
|
-
throw new Error(`removeLpMemo: basisPoints must be an integer in [1, 10000], got ${basisPoints}`);
|
|
1721
|
-
}
|
|
1722
|
-
if (withdrawToAsset && withdrawToAsset.length > 0) {
|
|
1723
|
-
assertMemoSegmentSafe(withdrawToAsset, "withdrawToAsset");
|
|
1724
|
-
return `-:${pool}:${basisPoints}:${withdrawToAsset}`;
|
|
1725
|
-
}
|
|
1726
|
-
return `-:${pool}:${basisPoints}`;
|
|
1727
|
-
};
|
|
1728
|
-
}
|
|
1729
|
-
});
|
|
1730
|
-
|
|
1731
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/payload.js
|
|
1732
|
-
var LP_REMOVE_DUST_RUNE_BASE_UNITS, isPositiveBaseUnitString, buildThorchainLpAddPayload, buildThorchainLpRemovePayload;
|
|
1733
|
-
var init_payload = __esm({
|
|
1734
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/payload.js"() {
|
|
1735
|
-
init_memo();
|
|
1736
|
-
LP_REMOVE_DUST_RUNE_BASE_UNITS = "2000000";
|
|
1737
|
-
isPositiveBaseUnitString = (value) => /^\d+$/.test(value) && BigInt(value) > 0n;
|
|
1738
|
-
buildThorchainLpAddPayload = ({ pool, amountRuneBaseUnits, pairedAddress }) => {
|
|
1739
|
-
if (!isPositiveBaseUnitString(amountRuneBaseUnits)) {
|
|
1740
|
-
throw new Error(`buildThorchainLpAddPayload: amountRuneBaseUnits must be a positive integer string, got ${amountRuneBaseUnits}`);
|
|
1741
|
-
}
|
|
1742
|
-
const memo = addLpMemo({ pool, pairedAddress });
|
|
1743
|
-
return {
|
|
1744
|
-
kind: "thorchain_lp_add",
|
|
1745
|
-
chain: "THORChain",
|
|
1746
|
-
denom: "rune",
|
|
1747
|
-
amount: amountRuneBaseUnits,
|
|
1748
|
-
memo,
|
|
1749
|
-
pool,
|
|
1750
|
-
...pairedAddress ? { pairedAddress } : {}
|
|
1751
|
-
};
|
|
1752
|
-
};
|
|
1753
|
-
buildThorchainLpRemovePayload = ({ pool, basisPoints, withdrawToAsset }) => {
|
|
1754
|
-
if (!Number.isInteger(basisPoints) || basisPoints < 1 || basisPoints > 1e4) {
|
|
1755
|
-
throw new Error(`buildThorchainLpRemovePayload: basisPoints must be an integer in [1, 10000], got ${basisPoints}`);
|
|
1756
|
-
}
|
|
1757
|
-
const memo = removeLpMemo({ pool, basisPoints, withdrawToAsset });
|
|
1758
|
-
return {
|
|
1759
|
-
kind: "thorchain_lp_remove",
|
|
1760
|
-
chain: "THORChain",
|
|
1761
|
-
denom: "rune",
|
|
1762
|
-
amount: LP_REMOVE_DUST_RUNE_BASE_UNITS,
|
|
1763
|
-
memo,
|
|
1764
|
-
pool,
|
|
1765
|
-
basisPoints,
|
|
1766
|
-
...withdrawToAsset ? { withdrawToAsset } : {}
|
|
1767
|
-
};
|
|
1768
|
-
};
|
|
1769
|
-
}
|
|
1770
|
-
});
|
|
1771
|
-
|
|
1772
|
-
// ../../packages/core/chain/dist/Chain.js
|
|
1773
|
-
var EthereumL2Chain, EvmChain, UtxoChain, cosmosChainsByKind, IbcEnabledCosmosChain, VaultBasedCosmosChain, CosmosChain, OtherChain, Chain9, UtxoBasedChain, defaultChains;
|
|
1774
|
-
var init_Chain = __esm({
|
|
1775
|
-
"../../packages/core/chain/dist/Chain.js"() {
|
|
1776
|
-
EthereumL2Chain = {
|
|
1777
|
-
Arbitrum: "Arbitrum",
|
|
1778
|
-
Base: "Base",
|
|
1779
|
-
Blast: "Blast",
|
|
1780
|
-
Optimism: "Optimism",
|
|
1781
|
-
Zksync: "Zksync",
|
|
1782
|
-
Mantle: "Mantle"
|
|
1783
|
-
};
|
|
1784
|
-
EvmChain = {
|
|
1785
|
-
...EthereumL2Chain,
|
|
1786
|
-
Avalanche: "Avalanche",
|
|
1787
|
-
CronosChain: "CronosChain",
|
|
1788
|
-
BSC: "BSC",
|
|
1789
|
-
Ethereum: "Ethereum",
|
|
1790
|
-
Polygon: "Polygon",
|
|
1791
|
-
Hyperliquid: "Hyperliquid",
|
|
1792
|
-
Sei: "Sei"
|
|
1793
|
-
};
|
|
1794
|
-
(function(UtxoChain2) {
|
|
1795
|
-
UtxoChain2["Bitcoin"] = "Bitcoin";
|
|
1796
|
-
UtxoChain2["BitcoinCash"] = "Bitcoin-Cash";
|
|
1797
|
-
UtxoChain2["Litecoin"] = "Litecoin";
|
|
1798
|
-
UtxoChain2["Dogecoin"] = "Dogecoin";
|
|
1799
|
-
UtxoChain2["Dash"] = "Dash";
|
|
1800
|
-
UtxoChain2["Zcash"] = "Zcash";
|
|
1801
|
-
})(UtxoChain || (UtxoChain = {}));
|
|
1802
|
-
cosmosChainsByKind = {
|
|
1803
|
-
ibcEnabled: {
|
|
1804
|
-
Cosmos: "Cosmos",
|
|
1805
|
-
Osmosis: "Osmosis",
|
|
1806
|
-
Dydx: "Dydx",
|
|
1807
|
-
Kujira: "Kujira",
|
|
1808
|
-
Terra: "Terra",
|
|
1809
|
-
TerraClassic: "TerraClassic",
|
|
1810
|
-
Noble: "Noble",
|
|
1811
|
-
Akash: "Akash"
|
|
1812
|
-
},
|
|
1813
|
-
vaultBased: {
|
|
1814
|
-
THORChain: "THORChain",
|
|
1815
|
-
MayaChain: "MayaChain"
|
|
1816
|
-
}
|
|
1817
|
-
};
|
|
1818
|
-
IbcEnabledCosmosChain = cosmosChainsByKind.ibcEnabled;
|
|
1819
|
-
VaultBasedCosmosChain = cosmosChainsByKind.vaultBased;
|
|
1820
|
-
CosmosChain = {
|
|
1821
|
-
...IbcEnabledCosmosChain,
|
|
1822
|
-
...VaultBasedCosmosChain
|
|
1823
|
-
};
|
|
1824
|
-
(function(OtherChain2) {
|
|
1825
|
-
OtherChain2["Sui"] = "Sui";
|
|
1826
|
-
OtherChain2["Solana"] = "Solana";
|
|
1827
|
-
OtherChain2["Polkadot"] = "Polkadot";
|
|
1828
|
-
OtherChain2["Bittensor"] = "Bittensor";
|
|
1829
|
-
OtherChain2["Ton"] = "Ton";
|
|
1830
|
-
OtherChain2["Ripple"] = "Ripple";
|
|
1831
|
-
OtherChain2["Tron"] = "Tron";
|
|
1832
|
-
OtherChain2["Cardano"] = "Cardano";
|
|
1833
|
-
OtherChain2["QBTC"] = "QBTC";
|
|
1834
|
-
})(OtherChain || (OtherChain = {}));
|
|
1835
|
-
Chain9 = {
|
|
1836
|
-
...EvmChain,
|
|
1837
|
-
...UtxoChain,
|
|
1838
|
-
...CosmosChain,
|
|
1839
|
-
...OtherChain
|
|
1840
|
-
};
|
|
1841
|
-
UtxoBasedChain = [
|
|
1842
|
-
...Object.values(UtxoChain),
|
|
1843
|
-
OtherChain.Cardano
|
|
1844
|
-
];
|
|
1845
|
-
defaultChains = [
|
|
1846
|
-
Chain9.Bitcoin,
|
|
1847
|
-
Chain9.Ethereum,
|
|
1848
|
-
Chain9.THORChain,
|
|
1849
|
-
Chain9.Solana,
|
|
1850
|
-
Chain9.BSC
|
|
1851
|
-
];
|
|
1852
|
-
}
|
|
1853
|
-
});
|
|
1854
|
-
|
|
1855
|
-
// ../../packages/core/chain/dist/chains/cosmos/cosmosRpcUrl.js
|
|
1856
|
-
var cosmosRpcUrl;
|
|
1857
|
-
var init_cosmosRpcUrl = __esm({
|
|
1858
|
-
"../../packages/core/chain/dist/chains/cosmos/cosmosRpcUrl.js"() {
|
|
1859
|
-
cosmosRpcUrl = {
|
|
1860
|
-
Cosmos: "https://cosmos-rest.publicnode.com",
|
|
1861
|
-
Osmosis: "https://osmosis-rest.publicnode.com",
|
|
1862
|
-
Dydx: "https://dydx-rest.publicnode.com",
|
|
1863
|
-
Kujira: "https://kujira-rest.publicnode.com",
|
|
1864
|
-
Terra: "https://terra-lcd.publicnode.com",
|
|
1865
|
-
TerraClassic: "https://terra-classic-lcd.publicnode.com",
|
|
1866
|
-
Noble: "https://noble-api.polkachu.com",
|
|
1867
|
-
THORChain: "https://thornode.thorchain.network",
|
|
1868
|
-
MayaChain: "https://mayanode.mayachain.info",
|
|
1869
|
-
Akash: "https://akash-rest.publicnode.com"
|
|
1870
|
-
};
|
|
1871
|
-
}
|
|
1872
|
-
});
|
|
1873
|
-
|
|
1874
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/memberPool.js
|
|
1875
|
-
var isNonZeroBaseUnit, normalizeMemberPool;
|
|
1876
|
-
var init_memberPool = __esm({
|
|
1877
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/memberPool.js"() {
|
|
1878
|
-
isNonZeroBaseUnit = (value) => {
|
|
1879
|
-
if (!value)
|
|
1880
|
-
return false;
|
|
1881
|
-
try {
|
|
1882
|
-
return BigInt(value) > 0n;
|
|
1883
|
-
} catch {
|
|
1884
|
-
return false;
|
|
1885
|
-
}
|
|
1886
|
-
};
|
|
1887
|
-
normalizeMemberPool = (raw) => ({
|
|
1888
|
-
pool: raw.pool ?? "",
|
|
1889
|
-
liquidityUnits: raw.liquidityUnits ?? "0",
|
|
1890
|
-
runeAdded: raw.runeAdded ?? "0",
|
|
1891
|
-
assetAdded: raw.assetAdded ?? "0",
|
|
1892
|
-
runePending: raw.runePending ?? "0",
|
|
1893
|
-
assetPending: raw.assetPending ?? "0",
|
|
1894
|
-
runeAddress: raw.runeAddress ?? "",
|
|
1895
|
-
assetAddress: raw.assetAddress ?? "",
|
|
1896
|
-
dateLastAdded: raw.dateLastAdded ?? "0",
|
|
1897
|
-
lastAddHeight: "",
|
|
1898
|
-
isPending: isNonZeroBaseUnit(raw.runePending) || isNonZeroBaseUnit(raw.assetPending)
|
|
1899
|
-
});
|
|
1900
|
-
}
|
|
1901
|
-
});
|
|
1902
|
-
|
|
1903
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/position.js
|
|
1904
|
-
var isMidgardNotFoundError, getThorchainLpPosition, getThorchainLpPositionFromThornode;
|
|
1905
|
-
var init_position = __esm({
|
|
1906
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/position.js"() {
|
|
1907
|
-
init_Chain();
|
|
1908
|
-
init_cosmosRpcUrl();
|
|
1909
|
-
init_HttpResponseError();
|
|
1910
|
-
init_queryUrl();
|
|
1911
|
-
init_memberPool();
|
|
1912
|
-
init_pools();
|
|
1913
|
-
isMidgardNotFoundError = (err) => err instanceof HttpResponseError && err.status === 404;
|
|
1914
|
-
getThorchainLpPosition = async ({ thorAddress, pool }) => {
|
|
1915
|
-
assertValidPoolId(pool);
|
|
1916
|
-
const url = `${thorchainMidgardBaseUrl}/v2/member/${encodeURIComponent(thorAddress)}`;
|
|
1917
|
-
let midgardNotFound = false;
|
|
1918
|
-
let raw = {};
|
|
1919
|
-
try {
|
|
1920
|
-
raw = await queryUrl(url);
|
|
1921
|
-
} catch (err) {
|
|
1922
|
-
if (isMidgardNotFoundError(err)) {
|
|
1923
|
-
midgardNotFound = true;
|
|
1924
|
-
} else {
|
|
1925
|
-
throw err;
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
if (!midgardNotFound) {
|
|
1929
|
-
const pools = Array.isArray(raw.pools) ? raw.pools : [];
|
|
1930
|
-
const found = pools.find((p) => p.pool === pool);
|
|
1931
|
-
if (found)
|
|
1932
|
-
return normalizeMemberPool(found);
|
|
1933
|
-
}
|
|
1934
|
-
return getThorchainLpPositionFromThornode({ thorAddress, pool });
|
|
1935
|
-
};
|
|
1936
|
-
getThorchainLpPositionFromThornode = async ({ thorAddress, pool }) => {
|
|
1937
|
-
assertValidPoolId(pool);
|
|
1938
|
-
const url = `${cosmosRpcUrl[Chain9.THORChain]}/thorchain/pool/${encodeURIComponent(pool)}/liquidity_provider/${encodeURIComponent(thorAddress)}`;
|
|
1939
|
-
let raw;
|
|
1940
|
-
try {
|
|
1941
|
-
raw = await queryUrl(url);
|
|
1942
|
-
} catch (err) {
|
|
1943
|
-
if (err instanceof HttpResponseError && err.status === 404)
|
|
1944
|
-
return null;
|
|
1945
|
-
throw err;
|
|
1946
|
-
}
|
|
1947
|
-
const units = raw.units ?? "0";
|
|
1948
|
-
const pendingRune = raw.pending_rune ?? "0";
|
|
1949
|
-
const pendingAsset = raw.pending_asset ?? "0";
|
|
1950
|
-
if (!isNonZeroBaseUnit(units) && !isNonZeroBaseUnit(pendingRune) && !isNonZeroBaseUnit(pendingAsset)) {
|
|
1951
|
-
return null;
|
|
1952
|
-
}
|
|
1953
|
-
return {
|
|
1954
|
-
pool: raw.asset ?? pool,
|
|
1955
|
-
liquidityUnits: units,
|
|
1956
|
-
// Thornode doesn't track historical added amounts — those are a
|
|
1957
|
-
// Midgard-only enrichment. Surface them as 0; the caller can still
|
|
1958
|
-
// act on units/pending.
|
|
1959
|
-
runeAdded: "0",
|
|
1960
|
-
assetAdded: "0",
|
|
1961
|
-
runePending: pendingRune,
|
|
1962
|
-
assetPending: pendingAsset,
|
|
1963
|
-
runeAddress: raw.rune_address ?? thorAddress,
|
|
1964
|
-
assetAddress: raw.asset_address ?? "",
|
|
1965
|
-
// Thornode exposes the last-add block height, not a Unix timestamp.
|
|
1966
|
-
// Keep `dateLastAdded` semantically Unix-seconds-or-0 and expose the
|
|
1967
|
-
// block height via the dedicated `lastAddHeight` field so lockup
|
|
1968
|
-
// checks can use either source.
|
|
1969
|
-
dateLastAdded: "0",
|
|
1970
|
-
lastAddHeight: typeof raw.last_add_height === "number" ? String(raw.last_add_height) : "",
|
|
1971
|
-
isPending: isNonZeroBaseUnit(pendingRune) || isNonZeroBaseUnit(pendingAsset)
|
|
1972
|
-
};
|
|
1973
|
-
};
|
|
1974
|
-
}
|
|
1975
|
-
});
|
|
1976
|
-
|
|
1977
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/validation.js
|
|
1978
|
-
var extractPoolStatus, poolPauseMimirKey, getThorchainMimir, assertPoolDepositable;
|
|
1979
|
-
var init_validation = __esm({
|
|
1980
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/validation.js"() {
|
|
1981
|
-
init_Chain();
|
|
1982
|
-
init_cosmosRpcUrl();
|
|
1983
|
-
init_queryUrl();
|
|
1984
|
-
init_pools();
|
|
1985
|
-
extractPoolStatus = (raw) => {
|
|
1986
|
-
if (raw && typeof raw === "object" && "status" in raw) {
|
|
1987
|
-
const status = raw.status;
|
|
1988
|
-
return typeof status === "string" ? status : void 0;
|
|
1989
|
-
}
|
|
1990
|
-
return void 0;
|
|
1991
|
-
};
|
|
1992
|
-
poolPauseMimirKey = (pool) => {
|
|
1993
|
-
const dotIdx = pool.indexOf(".");
|
|
1994
|
-
if (dotIdx <= 0 || dotIdx >= pool.length - 1) {
|
|
1995
|
-
throw new Error(`poolPauseMimirKey: invalid pool id ${pool}`);
|
|
1996
|
-
}
|
|
1997
|
-
const chain = pool.slice(0, dotIdx);
|
|
1998
|
-
const asset = pool.slice(dotIdx + 1);
|
|
1999
|
-
return `PAUSELPDEPOSIT-${chain}-${asset}`;
|
|
2000
|
-
};
|
|
2001
|
-
getThorchainMimir = async () => {
|
|
2002
|
-
const url = `${cosmosRpcUrl[Chain9.THORChain]}/thorchain/mimir`;
|
|
2003
|
-
const raw = await queryUrl(url);
|
|
2004
|
-
if (!raw || typeof raw !== "object") {
|
|
2005
|
-
throw new Error(`getThorchainMimir: unexpected response shape from ${url}`);
|
|
2006
|
-
}
|
|
2007
|
-
const out = {};
|
|
2008
|
-
for (const [k, v] of Object.entries(raw)) {
|
|
2009
|
-
if (typeof v === "number" && Number.isFinite(v)) {
|
|
2010
|
-
out[k] = v;
|
|
2011
|
-
} else if (typeof v === "string" && /^-?\d+$/.test(v)) {
|
|
2012
|
-
out[k] = Number(v);
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
return out;
|
|
2016
|
-
};
|
|
2017
|
-
assertPoolDepositable = async (pool) => {
|
|
2018
|
-
assertValidPoolId(pool);
|
|
2019
|
-
const [poolRaw, mimir] = await Promise.all([
|
|
2020
|
-
queryUrl(`${cosmosRpcUrl[Chain9.THORChain]}/thorchain/pool/${encodeURIComponent(pool)}`),
|
|
2021
|
-
getThorchainMimir()
|
|
2022
|
-
]);
|
|
2023
|
-
const status = extractPoolStatus(poolRaw);
|
|
2024
|
-
if (status === void 0) {
|
|
2025
|
-
throw new Error(`assertPoolDepositable: pool ${pool} response from thornode did not include a string \`status\` field`);
|
|
2026
|
-
}
|
|
2027
|
-
if (status !== "Available") {
|
|
2028
|
-
throw new Error(`assertPoolDepositable: pool ${pool} status is ${status}, must be Available for LP add`);
|
|
2029
|
-
}
|
|
2030
|
-
const pauseKey = poolPauseMimirKey(pool);
|
|
2031
|
-
const pauseValue = mimir[pauseKey];
|
|
2032
|
-
if (typeof pauseValue === "number" && pauseValue > 0) {
|
|
2033
|
-
throw new Error(`assertPoolDepositable: pool ${pool} has LP deposits paused on-chain via mimir ${pauseKey}=${pauseValue}. THORChain validators have disabled new adds for this pool; any tx would be rejected at handler execution time.`);
|
|
2034
|
-
}
|
|
2035
|
-
};
|
|
2036
|
-
}
|
|
2037
|
-
});
|
|
2038
|
-
|
|
2039
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/thorchainLp.js
|
|
2040
|
-
var thorchainLpChainCode;
|
|
2041
|
-
var init_thorchainLp = __esm({
|
|
2042
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/thorchainLp.js"() {
|
|
2043
|
-
init_Chain();
|
|
2044
|
-
thorchainLpChainCode = {
|
|
2045
|
-
[Chain9.Avalanche]: "AVAX",
|
|
2046
|
-
[Chain9.Base]: "BASE",
|
|
2047
|
-
[Chain9.BitcoinCash]: "BCH",
|
|
2048
|
-
[Chain9.BSC]: "BSC",
|
|
2049
|
-
[Chain9.Bitcoin]: "BTC",
|
|
2050
|
-
[Chain9.Dash]: "DASH",
|
|
2051
|
-
[Chain9.Dogecoin]: "DOGE",
|
|
2052
|
-
[Chain9.Ethereum]: "ETH",
|
|
2053
|
-
[Chain9.Cosmos]: "GAIA",
|
|
2054
|
-
[Chain9.Kujira]: "KUJI",
|
|
2055
|
-
[Chain9.Litecoin]: "LTC",
|
|
2056
|
-
[Chain9.THORChain]: "THOR",
|
|
2057
|
-
[Chain9.Tron]: "TRON",
|
|
2058
|
-
[Chain9.Ripple]: "XRP",
|
|
2059
|
-
[Chain9.Arbitrum]: "ARB",
|
|
2060
|
-
[Chain9.Zcash]: "ZEC"
|
|
2061
|
-
};
|
|
2062
|
-
}
|
|
2063
|
-
});
|
|
2064
|
-
|
|
2065
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/lpChainMap.js
|
|
2066
|
-
var lpChainMap, chainPrefixToChain, chainToLpPrefix;
|
|
2067
|
-
var init_lpChainMap = __esm({
|
|
2068
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/lpChainMap.js"() {
|
|
2069
|
-
init_thorchainLp();
|
|
2070
|
-
lpChainMap = Object.freeze(Object.entries(thorchainLpChainCode).reduce((acc, [chainKey, prefix]) => {
|
|
2071
|
-
if (prefix) {
|
|
2072
|
-
acc[prefix] = chainKey;
|
|
2073
|
-
}
|
|
2074
|
-
return acc;
|
|
2075
|
-
}, {}));
|
|
2076
|
-
chainPrefixToChain = (prefix) => lpChainMap[prefix.toUpperCase()];
|
|
2077
|
-
chainToLpPrefix = (chain) => thorchainLpChainCode[chain];
|
|
2078
|
-
}
|
|
2079
|
-
});
|
|
2080
|
-
|
|
2081
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/pairing.js
|
|
2082
|
-
var resolvePairedAddressForLpAdd;
|
|
2083
|
-
var init_pairing = __esm({
|
|
2084
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/pairing.js"() {
|
|
2085
|
-
init_Chain();
|
|
2086
|
-
init_lpChainMap();
|
|
2087
|
-
init_pools();
|
|
2088
|
-
resolvePairedAddressForLpAdd = ({ pool, side, vaultAddresses }) => {
|
|
2089
|
-
assertValidPoolId(pool);
|
|
2090
|
-
const [chainPrefix] = pool.split(".");
|
|
2091
|
-
if (!chainPrefix)
|
|
2092
|
-
return void 0;
|
|
2093
|
-
const assetChain = chainPrefixToChain(chainPrefix);
|
|
2094
|
-
if (!assetChain)
|
|
2095
|
-
return void 0;
|
|
2096
|
-
if (side === "asset") {
|
|
2097
|
-
return vaultAddresses[Chain9.THORChain];
|
|
2098
|
-
}
|
|
2099
|
-
return vaultAddresses[assetChain];
|
|
2100
|
-
};
|
|
2101
|
-
}
|
|
2102
|
-
});
|
|
2103
|
-
|
|
2104
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/math.js
|
|
2105
|
-
var assertBaseUnitString, getLiquidityUnits, getPoolShare, getLpAddSlippage, estimateLpAdd;
|
|
2106
|
-
var init_math = __esm({
|
|
2107
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/math.js"() {
|
|
2108
|
-
init_Chain();
|
|
2109
|
-
init_cosmosRpcUrl();
|
|
2110
|
-
init_queryUrl();
|
|
2111
|
-
init_pools();
|
|
2112
|
-
assertBaseUnitString = (value, fieldName) => {
|
|
2113
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
2114
|
-
throw new Error(`${fieldName} must be a non-empty base-unit string, got ${typeof value === "string" ? JSON.stringify(value) : typeof value}`);
|
|
2115
|
-
}
|
|
2116
|
-
if (!/^\d+$/.test(value)) {
|
|
2117
|
-
throw new Error(`${fieldName} must be a non-negative integer base-unit string, got ${JSON.stringify(value)}`);
|
|
2118
|
-
}
|
|
2119
|
-
return BigInt(value);
|
|
2120
|
-
};
|
|
2121
|
-
getLiquidityUnits = ({ pool, assetAmountBaseUnit, runeAmountBaseUnit }) => {
|
|
2122
|
-
const P = assertBaseUnitString(pool.poolUnits, "pool.poolUnits");
|
|
2123
|
-
const R = assertBaseUnitString(pool.runeDepth, "pool.runeDepth");
|
|
2124
|
-
const A = assertBaseUnitString(pool.assetDepth, "pool.assetDepth");
|
|
2125
|
-
const r = assertBaseUnitString(runeAmountBaseUnit, "runeAmountBaseUnit");
|
|
2126
|
-
const a = assertBaseUnitString(assetAmountBaseUnit, "assetAmountBaseUnit");
|
|
2127
|
-
if (R === 0n || A === 0n || P === 0n) {
|
|
2128
|
-
return "0";
|
|
2129
|
-
}
|
|
2130
|
-
const numerator = P * (R * a + r * A);
|
|
2131
|
-
const denominator = 2n * R * A;
|
|
2132
|
-
return (numerator / denominator).toString();
|
|
2133
|
-
};
|
|
2134
|
-
getPoolShare = ({ pool, liquidityUnits }) => {
|
|
2135
|
-
const P = assertBaseUnitString(pool.poolUnits, "pool.poolUnits");
|
|
2136
|
-
const L = assertBaseUnitString(liquidityUnits, "liquidityUnits");
|
|
2137
|
-
if (P === 0n || L === 0n) {
|
|
2138
|
-
return { poolShareDecimal: "0" };
|
|
2139
|
-
}
|
|
2140
|
-
const totalAfter = P + L;
|
|
2141
|
-
const SCALE = 10n ** 18n;
|
|
2142
|
-
const scaled = L * SCALE / totalAfter;
|
|
2143
|
-
const decimal = scaled.toString().padStart(19, "0");
|
|
2144
|
-
const intPart = decimal.slice(0, -18) || "0";
|
|
2145
|
-
const fracPart = decimal.slice(-18).replace(/0+$/, "");
|
|
2146
|
-
return {
|
|
2147
|
-
poolShareDecimal: fracPart.length > 0 ? `${intPart}.${fracPart}` : intPart
|
|
2148
|
-
};
|
|
2149
|
-
};
|
|
2150
|
-
getLpAddSlippage = ({ pool, assetAmountBaseUnit, runeAmountBaseUnit }) => {
|
|
2151
|
-
const R = assertBaseUnitString(pool.runeDepth, "pool.runeDepth");
|
|
2152
|
-
const A = assertBaseUnitString(pool.assetDepth, "pool.assetDepth");
|
|
2153
|
-
const r = assertBaseUnitString(runeAmountBaseUnit, "runeAmountBaseUnit");
|
|
2154
|
-
const a = assertBaseUnitString(assetAmountBaseUnit, "assetAmountBaseUnit");
|
|
2155
|
-
if (R === 0n || A === 0n) {
|
|
2156
|
-
return { decimalPercent: "0", slippageInRuneBaseUnit: "0" };
|
|
2157
|
-
}
|
|
2158
|
-
const ra = R * a;
|
|
2159
|
-
const ar = A * r;
|
|
2160
|
-
const numerator = ra > ar ? ra - ar : ar - ra;
|
|
2161
|
-
const denominator = A * r + R * A;
|
|
2162
|
-
if (denominator === 0n) {
|
|
2163
|
-
return { decimalPercent: "0", slippageInRuneBaseUnit: "0" };
|
|
2164
|
-
}
|
|
2165
|
-
const SCALE = 10n ** 18n;
|
|
2166
|
-
const scaled = numerator * SCALE / denominator;
|
|
2167
|
-
const decimal = scaled.toString().padStart(19, "0");
|
|
2168
|
-
const intPart = decimal.slice(0, -18) || "0";
|
|
2169
|
-
const fracPart = decimal.slice(-18).replace(/0+$/, "");
|
|
2170
|
-
const decimalPercent = fracPart.length > 0 ? `${intPart}.${fracPart}` : intPart;
|
|
2171
|
-
const imbalanceNumerator = ra > ar ? ra - ar : ar - ra;
|
|
2172
|
-
const imbalanceInRune = A === 0n ? 0n : imbalanceNumerator / (2n * A);
|
|
2173
|
-
const slippageInRune = imbalanceInRune * scaled / SCALE;
|
|
2174
|
-
return {
|
|
2175
|
-
decimalPercent,
|
|
2176
|
-
slippageInRuneBaseUnit: slippageInRune.toString()
|
|
2177
|
-
};
|
|
2178
|
-
};
|
|
2179
|
-
estimateLpAdd = async ({ pool, assetAmountBaseUnit, runeAmountBaseUnit, thornodeBaseUrl }) => {
|
|
2180
|
-
assertValidPoolId(pool);
|
|
2181
|
-
const base = thornodeBaseUrl ?? cosmosRpcUrl[Chain9.THORChain];
|
|
2182
|
-
const url = `${base}/thorchain/pool/${encodeURIComponent(pool)}`;
|
|
2183
|
-
const raw = await queryUrl(url);
|
|
2184
|
-
if (!raw || typeof raw !== "object" || typeof raw.balance_asset !== "string" || typeof raw.balance_rune !== "string") {
|
|
2185
|
-
throw new Error(`estimateLpAdd: pool ${pool} response from ${url} missing balance fields`);
|
|
2186
|
-
}
|
|
2187
|
-
const poolUnitsRaw = raw.pool_units ?? raw.LP_units;
|
|
2188
|
-
if (typeof poolUnitsRaw !== "string" || poolUnitsRaw.length === 0) {
|
|
2189
|
-
throw new Error(`estimateLpAdd: pool ${pool} response from ${url} missing pool_units / LP_units`);
|
|
2190
|
-
}
|
|
2191
|
-
const poolState = {
|
|
2192
|
-
assetDepth: raw.balance_asset,
|
|
2193
|
-
runeDepth: raw.balance_rune,
|
|
2194
|
-
poolUnits: poolUnitsRaw
|
|
2195
|
-
};
|
|
2196
|
-
const liquidityUnits = getLiquidityUnits({
|
|
2197
|
-
pool: poolState,
|
|
2198
|
-
assetAmountBaseUnit,
|
|
2199
|
-
runeAmountBaseUnit
|
|
2200
|
-
});
|
|
2201
|
-
const share = getPoolShare({
|
|
2202
|
-
pool: poolState,
|
|
2203
|
-
liquidityUnits
|
|
2204
|
-
});
|
|
2205
|
-
const slip = getLpAddSlippage({
|
|
2206
|
-
pool: poolState,
|
|
2207
|
-
assetAmountBaseUnit,
|
|
2208
|
-
runeAmountBaseUnit
|
|
2209
|
-
});
|
|
2210
|
-
const R = BigInt(poolState.runeDepth);
|
|
2211
|
-
const A = BigInt(poolState.assetDepth);
|
|
2212
|
-
const P = BigInt(poolState.poolUnits);
|
|
2213
|
-
const r = BigInt(runeAmountBaseUnit);
|
|
2214
|
-
const a = BigInt(assetAmountBaseUnit);
|
|
2215
|
-
const L = BigInt(liquidityUnits);
|
|
2216
|
-
const totalAfter = P + L;
|
|
2217
|
-
const runeDepthAfter = R + r;
|
|
2218
|
-
const assetDepthAfter = A + a;
|
|
2219
|
-
const runeShareBaseUnit = totalAfter === 0n ? "0" : (runeDepthAfter * L / totalAfter).toString();
|
|
2220
|
-
const assetShareBaseUnit = totalAfter === 0n ? "0" : (assetDepthAfter * L / totalAfter).toString();
|
|
2221
|
-
return {
|
|
2222
|
-
liquidityUnits,
|
|
2223
|
-
poolShareDecimal: share.poolShareDecimal,
|
|
2224
|
-
runeShareBaseUnit,
|
|
2225
|
-
assetShareBaseUnit,
|
|
2226
|
-
slippageDecimal: slip.decimalPercent,
|
|
2227
|
-
slippageRuneBaseUnit: slip.slippageInRuneBaseUnit
|
|
2228
|
-
};
|
|
2229
|
-
};
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
|
|
2233
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/positions.js
|
|
2234
|
-
var getThorchainLpPositions;
|
|
2235
|
-
var init_positions = __esm({
|
|
2236
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/positions.js"() {
|
|
2237
|
-
init_HttpResponseError();
|
|
2238
|
-
init_queryUrl();
|
|
2239
|
-
init_memberPool();
|
|
2240
|
-
init_pools();
|
|
2241
|
-
getThorchainLpPositions = async ({ thorAddress }) => {
|
|
2242
|
-
const url = `${thorchainMidgardBaseUrl}/v2/member/${encodeURIComponent(thorAddress)}`;
|
|
2243
|
-
let raw;
|
|
2244
|
-
try {
|
|
2245
|
-
raw = await queryUrl(url);
|
|
2246
|
-
} catch (err) {
|
|
2247
|
-
if (err instanceof HttpResponseError && err.status === 404)
|
|
2248
|
-
return [];
|
|
2249
|
-
throw err;
|
|
2250
|
-
}
|
|
2251
|
-
if (!raw || typeof raw !== "object") {
|
|
2252
|
-
throw new Error(`getThorchainLpPositions: unexpected Midgard response shape from ${url}`);
|
|
2253
|
-
}
|
|
2254
|
-
if (raw.pools === void 0) {
|
|
2255
|
-
return [];
|
|
2256
|
-
}
|
|
2257
|
-
if (!Array.isArray(raw.pools)) {
|
|
2258
|
-
throw new Error(`getThorchainLpPositions: Midgard response ${url} has non-array \`pools\` field`);
|
|
2259
|
-
}
|
|
2260
|
-
return raw.pools.map(normalizeMemberPool);
|
|
2261
|
-
};
|
|
2262
|
-
}
|
|
2263
|
-
});
|
|
2264
|
-
|
|
2265
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/lockup.js
|
|
2266
|
-
var THORCHAIN_BLOCK_TIME_SECONDS, getThorchainLpLockupSeconds, getLpWithdrawReadiness;
|
|
2267
|
-
var init_lockup = __esm({
|
|
2268
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/lockup.js"() {
|
|
2269
|
-
init_validation();
|
|
2270
|
-
THORCHAIN_BLOCK_TIME_SECONDS = 6;
|
|
2271
|
-
getThorchainLpLockupSeconds = async () => {
|
|
2272
|
-
const mimir = await getThorchainMimir();
|
|
2273
|
-
const blocks = mimir["LIQUIDITYLOCKUPBLOCKS"];
|
|
2274
|
-
if (typeof blocks !== "number" || !Number.isFinite(blocks) || blocks < 0) {
|
|
2275
|
-
throw new Error(`getThorchainLpLockupSeconds: mimir did not include a valid LIQUIDITYLOCKUPBLOCKS value`);
|
|
2276
|
-
}
|
|
2277
|
-
return blocks * THORCHAIN_BLOCK_TIME_SECONDS;
|
|
2278
|
-
};
|
|
2279
|
-
getLpWithdrawReadiness = async ({ position, lockupSeconds: providedLockupSeconds, nowUnix = Math.floor(Date.now() / 1e3) }) => {
|
|
2280
|
-
const lockupSeconds = providedLockupSeconds ?? await getThorchainLpLockupSeconds();
|
|
2281
|
-
const lastAdded = Number(position.dateLastAdded);
|
|
2282
|
-
if (!Number.isFinite(lastAdded) || lastAdded <= 0) {
|
|
2283
|
-
return {
|
|
2284
|
-
isWithdrawable: true,
|
|
2285
|
-
unlockAtUnix: 0,
|
|
2286
|
-
remainingSeconds: 0
|
|
2287
|
-
};
|
|
2288
|
-
}
|
|
2289
|
-
const unlockAtUnix = lastAdded + lockupSeconds;
|
|
2290
|
-
const remainingSeconds = Math.max(unlockAtUnix - nowUnix, 0);
|
|
2291
|
-
return {
|
|
2292
|
-
isWithdrawable: remainingSeconds === 0,
|
|
2293
|
-
unlockAtUnix,
|
|
2294
|
-
remainingSeconds
|
|
2295
|
-
};
|
|
2296
|
-
};
|
|
2297
|
-
}
|
|
2298
|
-
});
|
|
2299
|
-
|
|
2300
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/getThorchainInboundAddress.js
|
|
2301
|
-
var getThorchainInboundAddress_exports = {};
|
|
2302
|
-
__export(getThorchainInboundAddress_exports, {
|
|
2303
|
-
getThorchainInboundAddress: () => getThorchainInboundAddress
|
|
2304
|
-
});
|
|
2305
|
-
var thorchainInboundAddressApi, getThorchainInboundAddress;
|
|
2306
|
-
var init_getThorchainInboundAddress = __esm({
|
|
2307
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/getThorchainInboundAddress.js"() {
|
|
2308
|
-
init_queryUrl();
|
|
2309
|
-
init_Chain();
|
|
2310
|
-
init_cosmosRpcUrl();
|
|
2311
|
-
thorchainInboundAddressApi = `${cosmosRpcUrl[Chain9.THORChain]}/thorchain/inbound_addresses`;
|
|
2312
|
-
getThorchainInboundAddress = () => queryUrl(thorchainInboundAddressApi);
|
|
2313
|
-
}
|
|
2314
|
-
});
|
|
2315
|
-
|
|
2316
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/halts.js
|
|
2317
|
-
var buildStatus, getThorchainLpHaltStatusAll, getThorchainLpHaltStatus, getThorchainLpPoolPauseStatus;
|
|
2318
|
-
var init_halts = __esm({
|
|
2319
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/halts.js"() {
|
|
2320
|
-
init_getThorchainInboundAddress();
|
|
2321
|
-
init_validation();
|
|
2322
|
-
buildStatus = (raw) => {
|
|
2323
|
-
const reasons = [];
|
|
2324
|
-
if (raw.halted)
|
|
2325
|
-
reasons.push(`${raw.chain} chain is halted`);
|
|
2326
|
-
if (raw.global_trading_paused)
|
|
2327
|
-
reasons.push("global trading paused");
|
|
2328
|
-
if (raw.chain_trading_paused)
|
|
2329
|
-
reasons.push(`${raw.chain} chain trading paused`);
|
|
2330
|
-
if (raw.chain_lp_actions_paused)
|
|
2331
|
-
reasons.push(`${raw.chain} LP actions paused`);
|
|
2332
|
-
const depositable = !raw.halted && !raw.chain_lp_actions_paused && !raw.chain_trading_paused && !raw.global_trading_paused;
|
|
2333
|
-
const withdrawable = !raw.halted && !raw.chain_lp_actions_paused;
|
|
2334
|
-
return {
|
|
2335
|
-
chain: raw.chain,
|
|
2336
|
-
depositable,
|
|
2337
|
-
withdrawable,
|
|
2338
|
-
reasons,
|
|
2339
|
-
raw: {
|
|
2340
|
-
halted: raw.halted,
|
|
2341
|
-
chain_trading_paused: raw.chain_trading_paused,
|
|
2342
|
-
chain_lp_actions_paused: raw.chain_lp_actions_paused,
|
|
2343
|
-
global_trading_paused: raw.global_trading_paused
|
|
2344
|
-
}
|
|
2345
|
-
};
|
|
2346
|
-
};
|
|
2347
|
-
getThorchainLpHaltStatusAll = async () => {
|
|
2348
|
-
const addresses = await getThorchainInboundAddress();
|
|
2349
|
-
return addresses.map((a) => buildStatus({
|
|
2350
|
-
chain: a.chain,
|
|
2351
|
-
halted: a.halted,
|
|
2352
|
-
chain_trading_paused: a.chain_trading_paused,
|
|
2353
|
-
chain_lp_actions_paused: a.chain_lp_actions_paused,
|
|
2354
|
-
global_trading_paused: a.global_trading_paused
|
|
2355
|
-
}));
|
|
2356
|
-
};
|
|
2357
|
-
getThorchainLpHaltStatus = async (chain) => {
|
|
2358
|
-
const all = await getThorchainLpHaltStatusAll();
|
|
2359
|
-
const upper = chain.toUpperCase();
|
|
2360
|
-
const match = all.find((s) => s.chain.toUpperCase() === upper);
|
|
2361
|
-
if (!match) {
|
|
2362
|
-
throw new Error(`getThorchainLpHaltStatus: chain ${chain} not found in inbound_addresses`);
|
|
2363
|
-
}
|
|
2364
|
-
return match;
|
|
2365
|
-
};
|
|
2366
|
-
getThorchainLpPoolPauseStatus = async (pool) => {
|
|
2367
|
-
const mimir = await getThorchainMimir();
|
|
2368
|
-
const mimirKey = poolPauseMimirKey(pool);
|
|
2369
|
-
const mimirValue = mimir[mimirKey];
|
|
2370
|
-
if (typeof mimirValue === "number" && mimirValue > 0) {
|
|
2371
|
-
return { paused: true, mimirKey, mimirValue };
|
|
2372
|
-
}
|
|
2373
|
-
return { paused: false };
|
|
2374
|
-
};
|
|
2375
|
-
}
|
|
2376
|
-
});
|
|
2377
|
-
|
|
2378
|
-
// ../../packages/core/chain/dist/chains/cosmos/thor/lp/index.js
|
|
2379
|
-
var lp_exports = {};
|
|
2380
|
-
__export(lp_exports, {
|
|
2381
|
-
THORCHAIN_BLOCK_TIME_SECONDS: () => THORCHAIN_BLOCK_TIME_SECONDS,
|
|
2382
|
-
addLpMemo: () => addLpMemo,
|
|
2383
|
-
assertPoolDepositable: () => assertPoolDepositable,
|
|
2384
|
-
assertValidPoolId: () => assertValidPoolId,
|
|
2385
|
-
buildThorchainLpAddPayload: () => buildThorchainLpAddPayload,
|
|
2386
|
-
buildThorchainLpRemovePayload: () => buildThorchainLpRemovePayload,
|
|
2387
|
-
chainPrefixToChain: () => chainPrefixToChain,
|
|
2388
|
-
chainToLpPrefix: () => chainToLpPrefix,
|
|
2389
|
-
estimateLpAdd: () => estimateLpAdd,
|
|
2390
|
-
getLiquidityUnits: () => getLiquidityUnits,
|
|
2391
|
-
getLpAddSlippage: () => getLpAddSlippage,
|
|
2392
|
-
getLpWithdrawReadiness: () => getLpWithdrawReadiness,
|
|
2393
|
-
getPoolShare: () => getPoolShare,
|
|
2394
|
-
getThorchainLpHaltStatus: () => getThorchainLpHaltStatus,
|
|
2395
|
-
getThorchainLpHaltStatusAll: () => getThorchainLpHaltStatusAll,
|
|
2396
|
-
getThorchainLpLockupSeconds: () => getThorchainLpLockupSeconds,
|
|
2397
|
-
getThorchainLpPoolPauseStatus: () => getThorchainLpPoolPauseStatus,
|
|
2398
|
-
getThorchainLpPosition: () => getThorchainLpPosition,
|
|
2399
|
-
getThorchainLpPositionFromThornode: () => getThorchainLpPositionFromThornode,
|
|
2400
|
-
getThorchainLpPositions: () => getThorchainLpPositions,
|
|
2401
|
-
getThorchainMimir: () => getThorchainMimir,
|
|
2402
|
-
getThorchainPools: () => getThorchainPools,
|
|
2403
|
-
isValidPoolId: () => isValidPoolId,
|
|
2404
|
-
lpChainMap: () => lpChainMap,
|
|
2405
|
-
poolPauseMimirKey: () => poolPauseMimirKey,
|
|
2406
|
-
removeLpMemo: () => removeLpMemo,
|
|
2407
|
-
resolvePairedAddressForLpAdd: () => resolvePairedAddressForLpAdd,
|
|
2408
|
-
thorchainMidgardBaseUrl: () => thorchainMidgardBaseUrl
|
|
2409
|
-
});
|
|
2410
|
-
var init_lp = __esm({
|
|
2411
|
-
"../../packages/core/chain/dist/chains/cosmos/thor/lp/index.js"() {
|
|
2412
|
-
init_memo();
|
|
2413
|
-
init_payload();
|
|
2414
|
-
init_pools();
|
|
2415
|
-
init_position();
|
|
2416
|
-
init_validation();
|
|
2417
|
-
init_pairing();
|
|
2418
|
-
init_lpChainMap();
|
|
2419
|
-
init_math();
|
|
2420
|
-
init_positions();
|
|
2421
|
-
init_lockup();
|
|
2422
|
-
init_halts();
|
|
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;
|
|
@@ -5931,6 +4958,7 @@ function sseErrorToMessage(value) {
|
|
|
5931
4958
|
var AgentClient = class {
|
|
5932
4959
|
baseUrl;
|
|
5933
4960
|
authToken = null;
|
|
4961
|
+
profile = "";
|
|
5934
4962
|
verbose = false;
|
|
5935
4963
|
constructor(baseUrl) {
|
|
5936
4964
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
@@ -5938,13 +4966,21 @@ var AgentClient = class {
|
|
|
5938
4966
|
setAuthToken(token) {
|
|
5939
4967
|
this.authToken = token;
|
|
5940
4968
|
}
|
|
4969
|
+
/** Set the billing-profile slug sent as X-Vultisig-Abe-Profile on every
|
|
4970
|
+
* request. Empty falls back to the backend's default profile. */
|
|
4971
|
+
setProfile(profile) {
|
|
4972
|
+
this.profile = profile;
|
|
4973
|
+
}
|
|
4974
|
+
profileHeader() {
|
|
4975
|
+
return this.profile ? { "X-Vultisig-Abe-Profile": this.profile } : {};
|
|
4976
|
+
}
|
|
5941
4977
|
// ============================================================================
|
|
5942
4978
|
// Authentication
|
|
5943
4979
|
// ============================================================================
|
|
5944
4980
|
async authenticate(req) {
|
|
5945
4981
|
const res = await fetch(`${this.baseUrl}/auth/token`, {
|
|
5946
4982
|
method: "POST",
|
|
5947
|
-
headers: { "Content-Type": "application/json" },
|
|
4983
|
+
headers: { "Content-Type": "application/json", ...this.profileHeader() },
|
|
5948
4984
|
body: JSON.stringify(req)
|
|
5949
4985
|
});
|
|
5950
4986
|
if (!res.ok) {
|
|
@@ -6001,7 +5037,8 @@ var AgentClient = class {
|
|
|
6001
5037
|
headers: {
|
|
6002
5038
|
"Content-Type": "application/json",
|
|
6003
5039
|
Accept: "text/event-stream",
|
|
6004
|
-
...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}
|
|
5040
|
+
...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {},
|
|
5041
|
+
...this.profileHeader()
|
|
6005
5042
|
},
|
|
6006
5043
|
body: JSON.stringify(req),
|
|
6007
5044
|
signal
|
|
@@ -6176,18 +5213,6 @@ var AgentClient = class {
|
|
|
6176
5213
|
}
|
|
6177
5214
|
}
|
|
6178
5215
|
// ============================================================================
|
|
6179
|
-
// Calldata
|
|
6180
|
-
// ============================================================================
|
|
6181
|
-
async getCalldata(id) {
|
|
6182
|
-
const res = await fetch(`${this.baseUrl}/agent/calldata/${id}`, {
|
|
6183
|
-
headers: this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}
|
|
6184
|
-
});
|
|
6185
|
-
if (!res.ok) {
|
|
6186
|
-
throw new Error(`Failed to resolve calldata_id ${id}: ${res.status} ${res.statusText}`);
|
|
6187
|
-
}
|
|
6188
|
-
return res.json();
|
|
6189
|
-
}
|
|
6190
|
-
// ============================================================================
|
|
6191
5216
|
// Private helpers
|
|
6192
5217
|
// ============================================================================
|
|
6193
5218
|
async post(path4, body) {
|
|
@@ -6195,7 +5220,8 @@ var AgentClient = class {
|
|
|
6195
5220
|
method: "POST",
|
|
6196
5221
|
headers: {
|
|
6197
5222
|
"Content-Type": "application/json",
|
|
6198
|
-
...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}
|
|
5223
|
+
...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {},
|
|
5224
|
+
...this.profileHeader()
|
|
6199
5225
|
},
|
|
6200
5226
|
body: JSON.stringify(body)
|
|
6201
5227
|
});
|
|
@@ -6210,7 +5236,8 @@ var AgentClient = class {
|
|
|
6210
5236
|
method: "DELETE",
|
|
6211
5237
|
headers: {
|
|
6212
5238
|
"Content-Type": "application/json",
|
|
6213
|
-
...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}
|
|
5239
|
+
...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {},
|
|
5240
|
+
...this.profileHeader()
|
|
6214
5241
|
},
|
|
6215
5242
|
body: JSON.stringify(body)
|
|
6216
5243
|
});
|
|
@@ -6369,7 +5396,7 @@ function getNativeTokenDecimals(chain) {
|
|
|
6369
5396
|
}
|
|
6370
5397
|
|
|
6371
5398
|
// src/agent/executor.ts
|
|
6372
|
-
import { Chain as
|
|
5399
|
+
import { Chain as Chain9, Vultisig as VultisigSdk } from "@vultisig/sdk";
|
|
6373
5400
|
|
|
6374
5401
|
// ../../node_modules/viem/_esm/index.js
|
|
6375
5402
|
init_formatUnits();
|
|
@@ -6529,32 +5556,6 @@ function sleep2(ms) {
|
|
|
6529
5556
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6530
5557
|
}
|
|
6531
5558
|
|
|
6532
|
-
// src/agent/types.ts
|
|
6533
|
-
var AUTO_EXECUTE_ACTIONS = /* @__PURE__ */ new Set([
|
|
6534
|
-
"add_chain",
|
|
6535
|
-
"add_coin",
|
|
6536
|
-
"remove_coin",
|
|
6537
|
-
"remove_chain",
|
|
6538
|
-
"address_book_add",
|
|
6539
|
-
"address_book_remove",
|
|
6540
|
-
"get_address_book",
|
|
6541
|
-
"get_balances",
|
|
6542
|
-
"search_token",
|
|
6543
|
-
"list_vaults",
|
|
6544
|
-
"build_swap_tx",
|
|
6545
|
-
"build_send_tx",
|
|
6546
|
-
"build_custom_tx",
|
|
6547
|
-
"build_tx",
|
|
6548
|
-
"sign_tx",
|
|
6549
|
-
"sign_typed_data",
|
|
6550
|
-
"read_evm_contract",
|
|
6551
|
-
"scan_tx",
|
|
6552
|
-
"thorchain_pool_info",
|
|
6553
|
-
"thorchain_add_liquidity",
|
|
6554
|
-
"thorchain_remove_liquidity"
|
|
6555
|
-
]);
|
|
6556
|
-
var PASSWORD_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["sign_tx", "sign_typed_data", "build_custom_tx"]);
|
|
6557
|
-
|
|
6558
5559
|
// src/agent/executor.ts
|
|
6559
5560
|
var EVM_CHAINS = /* @__PURE__ */ new Set([
|
|
6560
5561
|
"Ethereum",
|
|
@@ -6586,7 +5587,7 @@ var EVM_GAS_RPC = {
|
|
|
6586
5587
|
Hyperliquid: "https://rpc.hyperliquid.xyz/evm",
|
|
6587
5588
|
Sei: "https://evm-rpc.sei-apis.com"
|
|
6588
5589
|
};
|
|
6589
|
-
var AgentExecutor = class
|
|
5590
|
+
var AgentExecutor = class {
|
|
6590
5591
|
vault;
|
|
6591
5592
|
/** Owning SDK (optional); used for address book backed by app storage */
|
|
6592
5593
|
vultisig;
|
|
@@ -6597,8 +5598,6 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6597
5598
|
/** Held chain lock release functions, keyed by chain name */
|
|
6598
5599
|
chainLockReleases = /* @__PURE__ */ new Map();
|
|
6599
5600
|
evmLastBroadcast = /* @__PURE__ */ new Map();
|
|
6600
|
-
/** Backend client for resolving calldata_id references. */
|
|
6601
|
-
backendClient = null;
|
|
6602
5601
|
constructor(vault, verbose = false, vaultId, vultisig) {
|
|
6603
5602
|
this.vault = vault;
|
|
6604
5603
|
this.verbose = verbose;
|
|
@@ -6610,9 +5609,6 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6610
5609
|
setPassword(password) {
|
|
6611
5610
|
this.password = password;
|
|
6612
5611
|
}
|
|
6613
|
-
setBackendClient(client) {
|
|
6614
|
-
this.backendClient = client;
|
|
6615
|
-
}
|
|
6616
5612
|
/**
|
|
6617
5613
|
* Store a server-built transaction (from tx_ready SSE event).
|
|
6618
5614
|
* This allows sign_tx to find and sign it when the backend requests signing.
|
|
@@ -6625,7 +5621,15 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6625
5621
|
`[executor] storeServerTransaction called, keys: ${Object.keys(txReadyData || {}).join(",")}
|
|
6626
5622
|
`
|
|
6627
5623
|
);
|
|
6628
|
-
|
|
5624
|
+
if (txReadyData?.approvalTxArgs) {
|
|
5625
|
+
if (this.verbose)
|
|
5626
|
+
process.stderr.write(
|
|
5627
|
+
`[executor] skipping multi-leg execute_swap envelope (approvalTxArgs present): not yet supported in sdk-cli \u2014 Phase B
|
|
5628
|
+
`
|
|
5629
|
+
);
|
|
5630
|
+
return false;
|
|
5631
|
+
}
|
|
5632
|
+
const nestedTx = extractNestedTx(txReadyData);
|
|
6629
5633
|
if (nestedTx?.status === "error" || nestedTx?.error) {
|
|
6630
5634
|
if (this.verbose)
|
|
6631
5635
|
process.stderr.write(`[executor] skipping error tx_ready: ${nestedTx.error || "unknown error"}
|
|
@@ -6633,11 +5637,12 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6633
5637
|
return false;
|
|
6634
5638
|
}
|
|
6635
5639
|
if (!nestedTx) {
|
|
6636
|
-
if (this.verbose)
|
|
5640
|
+
if (this.verbose)
|
|
5641
|
+
process.stderr.write(`[executor] storeServerTransaction: no swap_tx/send_tx/tx/txArgs.tx found in data
|
|
6637
5642
|
`);
|
|
6638
5643
|
return false;
|
|
6639
5644
|
}
|
|
6640
|
-
const chain = resolveChainFromTxReady(txReadyData) ||
|
|
5645
|
+
const chain = resolveChainFromTxReady(txReadyData) || Chain9.Ethereum;
|
|
6641
5646
|
this.pendingPayloads.clear();
|
|
6642
5647
|
this.pendingPayloads.set("latest", {
|
|
6643
5648
|
payload: { __serverTx: true, ...txReadyData },
|
|
@@ -6655,116 +5660,79 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6655
5660
|
hasPendingTransaction() {
|
|
6656
5661
|
return this.pendingPayloads.has("latest");
|
|
6657
5662
|
}
|
|
6658
|
-
shouldAutoExecute(action) {
|
|
6659
|
-
return action.auto_execute === true || AUTO_EXECUTE_ACTIONS.has(action.type);
|
|
6660
|
-
}
|
|
6661
|
-
requiresPassword(action) {
|
|
6662
|
-
return PASSWORD_REQUIRED_ACTIONS.has(action.type);
|
|
6663
|
-
}
|
|
6664
5663
|
/**
|
|
6665
|
-
*
|
|
5664
|
+
* Wrap a per-tool handler body with normalised success/failure → RecentAction
|
|
5665
|
+
* conversion. Replaces the legacy executeAction → ActionResult adapter that
|
|
5666
|
+
* the dispatch chokepoint used before this refactor.
|
|
6666
5667
|
*/
|
|
6667
|
-
async
|
|
5668
|
+
async runTool(toolName, body) {
|
|
6668
5669
|
try {
|
|
6669
|
-
const data = await
|
|
6670
|
-
return {
|
|
6671
|
-
action: action.type,
|
|
6672
|
-
action_id: action.id,
|
|
6673
|
-
success: true,
|
|
6674
|
-
data
|
|
6675
|
-
};
|
|
5670
|
+
const data = await body();
|
|
5671
|
+
return { tool: toolName, success: true, data };
|
|
6676
5672
|
} catch (err) {
|
|
6677
5673
|
const { code, message } = normalizeAgentError(err);
|
|
6678
|
-
return {
|
|
6679
|
-
action: action.type,
|
|
6680
|
-
action_id: action.id,
|
|
6681
|
-
success: false,
|
|
6682
|
-
error: message,
|
|
6683
|
-
code
|
|
6684
|
-
};
|
|
6685
|
-
}
|
|
6686
|
-
}
|
|
6687
|
-
async dispatch(action) {
|
|
6688
|
-
if (this.verbose) process.stderr.write(`[dispatch] action.type=${action.type} action.id=${action.id}
|
|
6689
|
-
`);
|
|
6690
|
-
const params = action.params || {};
|
|
6691
|
-
switch (action.type) {
|
|
6692
|
-
case "get_balances":
|
|
6693
|
-
return this.getBalances(params);
|
|
6694
|
-
case "add_chain":
|
|
6695
|
-
return this.addChain(params);
|
|
6696
|
-
case "remove_chain":
|
|
6697
|
-
return this.removeChain(params);
|
|
6698
|
-
case "add_coin":
|
|
6699
|
-
return this.addCoin(params);
|
|
6700
|
-
case "remove_coin":
|
|
6701
|
-
return this.removeCoin(params);
|
|
6702
|
-
case "build_send_tx":
|
|
6703
|
-
return this.buildSendTx(params);
|
|
6704
|
-
case "build_swap_tx":
|
|
6705
|
-
return this.buildSwapTx(params);
|
|
6706
|
-
case "build_tx":
|
|
6707
|
-
case "build_custom_tx":
|
|
6708
|
-
return this.buildTx(params);
|
|
6709
|
-
case "sign_tx":
|
|
6710
|
-
return this.signTx(params);
|
|
6711
|
-
case "get_address_book":
|
|
6712
|
-
return this.getAddressBook(params);
|
|
6713
|
-
case "address_book_add":
|
|
6714
|
-
return this.addAddressBookEntry(params);
|
|
6715
|
-
case "address_book_remove":
|
|
6716
|
-
return this.removeAddressBookEntry(params);
|
|
6717
|
-
case "search_token":
|
|
6718
|
-
return this.searchToken(params);
|
|
6719
|
-
case "list_vaults":
|
|
6720
|
-
return this.listVaults();
|
|
6721
|
-
case "sign_typed_data":
|
|
6722
|
-
return this.signTypedData(params);
|
|
6723
|
-
case "scan_tx":
|
|
6724
|
-
return this.scanTx(params);
|
|
6725
|
-
case "read_evm_contract":
|
|
6726
|
-
return this.readEvmContract(params);
|
|
6727
|
-
case "thorchain_pool_info":
|
|
6728
|
-
return this.thorchainPoolInfo(params);
|
|
6729
|
-
case "thorchain_add_liquidity":
|
|
6730
|
-
return this.thorchainAddLiquidity(params);
|
|
6731
|
-
case "thorchain_remove_liquidity":
|
|
6732
|
-
return this.thorchainRemoveLiquidity(params);
|
|
6733
|
-
default:
|
|
6734
|
-
throw new Error(
|
|
6735
|
-
`Action type '${action.type}' is not implemented locally. The backend may handle this action server-side.`
|
|
6736
|
-
);
|
|
5674
|
+
return { tool: toolName, success: false, data: { error: message, code } };
|
|
6737
5675
|
}
|
|
6738
5676
|
}
|
|
6739
5677
|
// ============================================================================
|
|
6740
|
-
//
|
|
5678
|
+
// Chain & Token Management
|
|
6741
5679
|
// ============================================================================
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
5680
|
+
// vault_chain dispatcher — backend shape:
|
|
5681
|
+
// { action: "add" | "remove", chains: [{ chain }] }
|
|
5682
|
+
// Discriminator wrapper: routes to addChain / removeChain so the resulting
|
|
5683
|
+
// RecentAction is tagged tool: 'vault_chain' (matching what the agent emits)
|
|
5684
|
+
// rather than the per-action method's tool name.
|
|
5685
|
+
async vaultChain(toolCallId, input) {
|
|
5686
|
+
return this.runTool("vault_chain", async () => {
|
|
5687
|
+
const action = input.action;
|
|
5688
|
+
switch (action) {
|
|
5689
|
+
case "add":
|
|
5690
|
+
return this.addChainImpl(input);
|
|
5691
|
+
case "remove":
|
|
5692
|
+
return this.removeChainImpl(input);
|
|
5693
|
+
default:
|
|
5694
|
+
throw new Error(`vault_chain: unknown action: ${action ?? "(missing)"}`);
|
|
6757
5695
|
}
|
|
6758
|
-
}
|
|
6759
|
-
if (tickerFilter) {
|
|
6760
|
-
entries = entries.filter((b) => b.symbol.toLowerCase() === tickerFilter.toLowerCase());
|
|
6761
|
-
}
|
|
6762
|
-
return { balances: entries };
|
|
5696
|
+
});
|
|
6763
5697
|
}
|
|
6764
|
-
//
|
|
6765
|
-
//
|
|
6766
|
-
|
|
6767
|
-
|
|
5698
|
+
// vault_coin dispatcher — backend shape:
|
|
5699
|
+
// { action: "add" | "remove", coins: [{ chain, ticker, contract_address?, ... }] }
|
|
5700
|
+
async vaultCoin(toolCallId, input) {
|
|
5701
|
+
return this.runTool("vault_coin", async () => {
|
|
5702
|
+
const action = input.action;
|
|
5703
|
+
switch (action) {
|
|
5704
|
+
case "add":
|
|
5705
|
+
return this.addCoinImpl(input);
|
|
5706
|
+
case "remove":
|
|
5707
|
+
return this.removeCoinImpl(input);
|
|
5708
|
+
default:
|
|
5709
|
+
throw new Error(`vault_coin: unknown action: ${action ?? "(missing)"}`);
|
|
5710
|
+
}
|
|
5711
|
+
});
|
|
5712
|
+
}
|
|
5713
|
+
// address_book dispatcher — backend shape:
|
|
5714
|
+
// { action: "add" | "remove", entry: { name, chain, address } }
|
|
5715
|
+
async addressBook(toolCallId, input) {
|
|
5716
|
+
return this.runTool("address_book", async () => {
|
|
5717
|
+
const action = input.action;
|
|
5718
|
+
switch (action) {
|
|
5719
|
+
case "add":
|
|
5720
|
+
return this.addAddressBookImpl(input);
|
|
5721
|
+
case "remove":
|
|
5722
|
+
return this.removeAddressBookImpl(input);
|
|
5723
|
+
default:
|
|
5724
|
+
throw new Error(`address_book: unknown action: ${action ?? "(missing)"}`);
|
|
5725
|
+
}
|
|
5726
|
+
});
|
|
5727
|
+
}
|
|
5728
|
+
async addChain(_toolCallId, input) {
|
|
5729
|
+
return this.runTool("add_chain", () => this.addChainImpl(input));
|
|
5730
|
+
}
|
|
5731
|
+
// Backend `vault_chain { action: "add", chains: [...] }` and legacy
|
|
5732
|
+
// single-chain calls both flow through this impl. The public `addChain`
|
|
5733
|
+
// wrapper above tags results as `tool: 'add_chain'`; the new `vaultChain`
|
|
5734
|
+
// wrapper (above) tags them as `tool: 'vault_chain'`.
|
|
5735
|
+
async addChainImpl(params) {
|
|
6768
5736
|
const chains = params.chains;
|
|
6769
5737
|
if (chains && Array.isArray(chains)) {
|
|
6770
5738
|
const results = [];
|
|
@@ -6785,26 +5753,38 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6785
5753
|
const address = await this.vault.address(chain);
|
|
6786
5754
|
return { chain: chain.toString(), address, added: true };
|
|
6787
5755
|
}
|
|
6788
|
-
async
|
|
5756
|
+
async removeChainImpl(params) {
|
|
5757
|
+
const chains = params.chains;
|
|
5758
|
+
if (chains && Array.isArray(chains)) {
|
|
5759
|
+
const results = [];
|
|
5760
|
+
for (const c of chains) {
|
|
5761
|
+
const name = typeof c === "string" ? c : c.chain;
|
|
5762
|
+
const chain2 = resolveChain(name);
|
|
5763
|
+
if (!chain2) throw new Error(`Unknown chain: ${name}`);
|
|
5764
|
+
await this.vault.removeChain(chain2);
|
|
5765
|
+
results.push({ chain: chain2.toString() });
|
|
5766
|
+
}
|
|
5767
|
+
return { removed: results };
|
|
5768
|
+
}
|
|
6789
5769
|
const chainName = params.chain;
|
|
6790
5770
|
const chain = resolveChain(chainName);
|
|
6791
5771
|
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6792
5772
|
await this.vault.removeChain(chain);
|
|
6793
5773
|
return { chain: chain.toString(), removed: true };
|
|
6794
5774
|
}
|
|
6795
|
-
async
|
|
6796
|
-
const
|
|
6797
|
-
if (
|
|
5775
|
+
async addCoinImpl(params) {
|
|
5776
|
+
const coins = params.coins ?? params.tokens;
|
|
5777
|
+
if (coins && Array.isArray(coins)) {
|
|
6798
5778
|
const results = [];
|
|
6799
|
-
for (const t of
|
|
5779
|
+
for (const t of coins) {
|
|
6800
5780
|
const chain2 = resolveChain(t.chain);
|
|
6801
5781
|
if (!chain2) throw new Error(`Unknown chain: ${t.chain}`);
|
|
6802
|
-
const symbol2 = t.
|
|
5782
|
+
const symbol2 = t.ticker || t.symbol || "";
|
|
6803
5783
|
await this.vault.addToken(chain2, {
|
|
6804
5784
|
id: t.contract_address || t.contractAddress || "",
|
|
6805
5785
|
symbol: symbol2,
|
|
6806
5786
|
name: t.name || symbol2,
|
|
6807
|
-
decimals: t.decimals
|
|
5787
|
+
decimals: t.decimals ?? 18,
|
|
6808
5788
|
contractAddress: t.contract_address || t.contractAddress,
|
|
6809
5789
|
chainId: chain2.toString()
|
|
6810
5790
|
});
|
|
@@ -6815,485 +5795,81 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
6815
5795
|
const chainName = params.chain;
|
|
6816
5796
|
const chain = resolveChain(chainName);
|
|
6817
5797
|
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6818
|
-
const symbol = params.
|
|
5798
|
+
const symbol = params.ticker || params.symbol;
|
|
6819
5799
|
await this.vault.addToken(chain, {
|
|
6820
5800
|
id: params.contract_address || params.contractAddress || "",
|
|
6821
5801
|
symbol,
|
|
6822
5802
|
name: params.name || symbol,
|
|
6823
|
-
decimals: params.decimals
|
|
5803
|
+
decimals: params.decimals ?? 18,
|
|
6824
5804
|
contractAddress: params.contract_address || params.contractAddress,
|
|
6825
5805
|
chainId: chain.toString()
|
|
6826
5806
|
});
|
|
6827
5807
|
return { chain: chain.toString(), symbol, added: true };
|
|
6828
5808
|
}
|
|
6829
|
-
async
|
|
5809
|
+
async removeCoinImpl(params) {
|
|
5810
|
+
const coins = params.coins ?? params.tokens;
|
|
5811
|
+
if (coins && Array.isArray(coins)) {
|
|
5812
|
+
const results = [];
|
|
5813
|
+
for (const t of coins) {
|
|
5814
|
+
const chain2 = resolveChain(t.chain);
|
|
5815
|
+
if (!chain2) throw new Error(`Unknown chain: ${t.chain}`);
|
|
5816
|
+
const tokenId2 = t.contract_address || t.contractAddress || t.token_id || t.id;
|
|
5817
|
+
if (!tokenId2) {
|
|
5818
|
+
throw new Error(
|
|
5819
|
+
`vault_coin remove: missing contract_address for ${t.ticker || t.symbol || "coin"} on ${t.chain}`
|
|
5820
|
+
);
|
|
5821
|
+
}
|
|
5822
|
+
await this.vault.removeToken(chain2, tokenId2);
|
|
5823
|
+
results.push({ chain: chain2.toString(), tokenId: tokenId2 });
|
|
5824
|
+
}
|
|
5825
|
+
return { removed: results };
|
|
5826
|
+
}
|
|
6830
5827
|
const chainName = params.chain;
|
|
6831
5828
|
const chain = resolveChain(chainName);
|
|
6832
5829
|
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6833
|
-
const tokenId = params.
|
|
5830
|
+
const tokenId = params.contract_address || params.contractAddress || params.token_id || params.id;
|
|
5831
|
+
if (!tokenId) {
|
|
5832
|
+
throw new Error(`vault_coin remove: missing contract_address for coin on ${chainName}`);
|
|
5833
|
+
}
|
|
6834
5834
|
await this.vault.removeToken(chain, tokenId);
|
|
6835
5835
|
return { chain: chain.toString(), removed: true };
|
|
6836
5836
|
}
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
// ============================================================================
|
|
6840
|
-
async buildSendTx(params) {
|
|
6841
|
-
const chainName = params.chain || params.from_chain;
|
|
6842
|
-
const chain = resolveChain(chainName);
|
|
6843
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6844
|
-
const symbol = params.symbol || params.ticker;
|
|
6845
|
-
const toAddress = params.address || params.to || params.destination;
|
|
6846
|
-
const amountStr = params.amount;
|
|
6847
|
-
if (!toAddress) throw new Error("Destination address is required");
|
|
6848
|
-
if (!amountStr) throw new Error("Amount is required");
|
|
6849
|
-
await this.acquireEvmLockIfNeeded(chain);
|
|
6850
|
-
try {
|
|
6851
|
-
const address = await this.vault.address(chain);
|
|
6852
|
-
const balance = await this.vault.balance(chain, params.token_id);
|
|
6853
|
-
const coin = {
|
|
6854
|
-
chain,
|
|
6855
|
-
address,
|
|
6856
|
-
decimals: balance.decimals,
|
|
6857
|
-
ticker: symbol || balance.symbol,
|
|
6858
|
-
id: params.token_id
|
|
6859
|
-
};
|
|
6860
|
-
const amount = parseAmount(amountStr, balance.decimals);
|
|
6861
|
-
const memo = params.memo;
|
|
6862
|
-
const payload = await this.vault.prepareSendTx({
|
|
6863
|
-
coin,
|
|
6864
|
-
receiver: toAddress,
|
|
6865
|
-
amount,
|
|
6866
|
-
memo
|
|
6867
|
-
});
|
|
6868
|
-
await this.patchEvmNonce(chain, payload);
|
|
6869
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
6870
|
-
this.pendingPayloads.clear();
|
|
6871
|
-
const payloadId = `tx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6872
|
-
this.pendingPayloads.set(payloadId, {
|
|
6873
|
-
payload,
|
|
6874
|
-
coin,
|
|
6875
|
-
chain,
|
|
6876
|
-
timestamp: Date.now()
|
|
6877
|
-
});
|
|
6878
|
-
this.pendingPayloads.set("latest", {
|
|
6879
|
-
payload,
|
|
6880
|
-
coin,
|
|
6881
|
-
chain,
|
|
6882
|
-
timestamp: Date.now()
|
|
6883
|
-
});
|
|
6884
|
-
return {
|
|
6885
|
-
keysign_payload: payloadId,
|
|
6886
|
-
from_chain: chain.toString(),
|
|
6887
|
-
from_symbol: coin.ticker,
|
|
6888
|
-
amount: amountStr,
|
|
6889
|
-
sender: address,
|
|
6890
|
-
destination: toAddress,
|
|
6891
|
-
memo: memo || void 0,
|
|
6892
|
-
message_hashes: messageHashes,
|
|
6893
|
-
tx_details: {
|
|
6894
|
-
chain: chain.toString(),
|
|
6895
|
-
from: address,
|
|
6896
|
-
to: toAddress,
|
|
6897
|
-
amount: amountStr,
|
|
6898
|
-
symbol: coin.ticker
|
|
6899
|
-
}
|
|
6900
|
-
};
|
|
6901
|
-
} catch (err) {
|
|
6902
|
-
await this.releaseEvmLock(chain);
|
|
6903
|
-
throw err;
|
|
6904
|
-
}
|
|
5837
|
+
async removeChain(_toolCallId, input) {
|
|
5838
|
+
return this.runTool("remove_chain", () => this.removeChainImpl(input));
|
|
6905
5839
|
}
|
|
6906
|
-
async
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
const toChainName = params.to_chain;
|
|
6912
|
-
const fromChain = resolveChain(fromChainName);
|
|
6913
|
-
const toChain = toChainName ? resolveChain(toChainName) : null;
|
|
6914
|
-
if (!fromChain) throw new Error(`Unknown from_chain: ${fromChainName}`);
|
|
6915
|
-
await this.acquireEvmLockIfNeeded(fromChain);
|
|
6916
|
-
try {
|
|
6917
|
-
const amountStr = params.amount;
|
|
6918
|
-
const fromSymbol = params.from_symbol || params.from_token || "";
|
|
6919
|
-
const toSymbol = params.to_symbol || params.to_token || "";
|
|
6920
|
-
const fromToken = params.from_contract || params.from_token_id;
|
|
6921
|
-
const toToken = params.to_contract || params.to_token_id;
|
|
6922
|
-
const fromCoin = { chain: fromChain, token: fromToken || void 0 };
|
|
6923
|
-
const toCoin = {
|
|
6924
|
-
chain: toChain || fromChain,
|
|
6925
|
-
token: toToken || void 0
|
|
6926
|
-
};
|
|
6927
|
-
const quote = await this.vault.getSwapQuote({
|
|
6928
|
-
fromCoin,
|
|
6929
|
-
toCoin,
|
|
6930
|
-
amount: amountStr
|
|
6931
|
-
});
|
|
6932
|
-
const swapResult = await this.vault.prepareSwapTx({
|
|
6933
|
-
fromCoin,
|
|
6934
|
-
toCoin,
|
|
6935
|
-
amount: amountStr,
|
|
6936
|
-
swapQuote: quote,
|
|
6937
|
-
autoApprove: true
|
|
6938
|
-
});
|
|
6939
|
-
const chain = fromChain;
|
|
6940
|
-
const payload = swapResult.keysignPayload;
|
|
6941
|
-
await this.patchEvmNonce(chain, payload);
|
|
6942
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
6943
|
-
this.pendingPayloads.clear();
|
|
6944
|
-
const payloadId = `swap_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6945
|
-
this.pendingPayloads.set(payloadId, {
|
|
6946
|
-
payload,
|
|
6947
|
-
coin: { chain, address: "", decimals: 18, ticker: fromSymbol },
|
|
6948
|
-
chain,
|
|
6949
|
-
timestamp: Date.now()
|
|
6950
|
-
});
|
|
6951
|
-
this.pendingPayloads.set("latest", {
|
|
6952
|
-
payload,
|
|
6953
|
-
coin: { chain, address: "", decimals: 18, ticker: fromSymbol },
|
|
6954
|
-
chain,
|
|
6955
|
-
timestamp: Date.now()
|
|
6956
|
-
});
|
|
6957
|
-
return {
|
|
6958
|
-
keysign_payload: payloadId,
|
|
6959
|
-
from_chain: fromChain.toString(),
|
|
6960
|
-
to_chain: (toChain || fromChain).toString(),
|
|
6961
|
-
from_symbol: fromSymbol,
|
|
6962
|
-
to_symbol: toSymbol,
|
|
6963
|
-
amount: amountStr,
|
|
6964
|
-
estimated_output: quote.estimatedOutput?.toString(),
|
|
6965
|
-
provider: quote.provider,
|
|
6966
|
-
message_hashes: messageHashes
|
|
6967
|
-
};
|
|
6968
|
-
} catch (err) {
|
|
6969
|
-
await this.releaseEvmLock(fromChain);
|
|
6970
|
-
throw err;
|
|
6971
|
-
}
|
|
5840
|
+
async addCoin(_toolCallId, input) {
|
|
5841
|
+
return this.runTool("add_coin", () => this.addCoinImpl(input));
|
|
5842
|
+
}
|
|
5843
|
+
async removeCoin(_toolCallId, input) {
|
|
5844
|
+
return this.runTool("remove_coin", () => this.removeCoinImpl(input));
|
|
6972
5845
|
}
|
|
6973
5846
|
// ============================================================================
|
|
6974
|
-
//
|
|
5847
|
+
// Transaction Signing
|
|
6975
5848
|
// ============================================================================
|
|
6976
5849
|
/**
|
|
6977
|
-
*
|
|
5850
|
+
* Sign and broadcast a transaction previously buffered by
|
|
5851
|
+
* {@link storeServerTransaction} via the `tx_ready` SSE channel. Returns
|
|
5852
|
+
* a `RecentAction` to be flushed in the next `context.recent_actions`.
|
|
5853
|
+
*
|
|
5854
|
+
* Replaces the legacy `signTx(action.params)` path: there is no longer an
|
|
5855
|
+
* action wrapper, no `keysign_payload` lookup (the buffer always uses
|
|
5856
|
+
* the `'latest'` slot), and no SDK-built keysignPayload branch (the live
|
|
5857
|
+
* client-side tools no longer produce SDK-built payloads — those went
|
|
5858
|
+
* away with `buildSendTx`/`buildSwapTx`).
|
|
6978
5859
|
*/
|
|
6979
|
-
async
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
if (statusRaw === null || String(statusRaw).toLowerCase() === "all") {
|
|
6984
|
-
poolFetchOpts = { status: null };
|
|
6985
|
-
} else if (statusRaw !== void 0) {
|
|
6986
|
-
poolFetchOpts = { status: String(statusRaw) };
|
|
6987
|
-
}
|
|
6988
|
-
const pools = await getThorchainPools2(poolFetchOpts);
|
|
6989
|
-
const poolArg = params.pool;
|
|
6990
|
-
if (poolArg) {
|
|
6991
|
-
const normalized = poolArg.trim().toUpperCase();
|
|
6992
|
-
assertValidPoolId2(normalized);
|
|
6993
|
-
const row = pools.find((p) => p.asset.toUpperCase() === normalized);
|
|
6994
|
-
return {
|
|
6995
|
-
found: !!row,
|
|
6996
|
-
pool_id: normalized,
|
|
6997
|
-
summary: row ?? null,
|
|
6998
|
-
midgard: thorchainMidgardBaseUrl2
|
|
6999
|
-
};
|
|
7000
|
-
}
|
|
7001
|
-
const limitRaw = params.limit;
|
|
7002
|
-
const limit = Math.min(500, Math.max(1, typeof limitRaw === "number" ? limitRaw : Number(limitRaw) || 80));
|
|
7003
|
-
return {
|
|
7004
|
-
pools: pools.slice(0, limit),
|
|
7005
|
-
total: pools.length,
|
|
7006
|
-
midgard: thorchainMidgardBaseUrl2
|
|
7007
|
-
};
|
|
7008
|
-
}
|
|
7009
|
-
async thorchainAddLiquidity(params) {
|
|
7010
|
-
const { assertValidPoolId: assertValidPoolId2, buildThorchainLpAddPayload: buildThorchainLpAddPayload2, resolvePairedAddressForLpAdd: resolvePairedAddressForLpAdd2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
|
|
7011
|
-
const { getThorchainInboundAddress: getThorchainInboundAddress2 } = await Promise.resolve().then(() => (init_getThorchainInboundAddress(), getThorchainInboundAddress_exports));
|
|
7012
|
-
const pool = this.normalizeThorchainPoolId(params.pool, assertValidPoolId2);
|
|
7013
|
-
const amountStr = String(params.amount ?? "").trim();
|
|
7014
|
-
if (!amountStr) {
|
|
7015
|
-
throw new Error('amount is required (RUNE amount as a decimal string, e.g. "0.25")');
|
|
7016
|
-
}
|
|
7017
|
-
if (!/^\d+(\.\d+)?$/.test(amountStr)) {
|
|
7018
|
-
throw new Error('amount must be a positive decimal string (no sign or scientific notation), e.g. "0.25"');
|
|
7019
|
-
}
|
|
7020
|
-
const [, frac = ""] = amountStr.split(".");
|
|
7021
|
-
if (frac.length > 8) {
|
|
7022
|
-
throw new Error("RUNE amount supports at most 8 decimal places");
|
|
7023
|
-
}
|
|
7024
|
-
const amountRuneBaseUnits = parseAmount(amountStr, 8);
|
|
7025
|
-
if (amountRuneBaseUnits <= 0n) {
|
|
7026
|
-
throw new Error("amount must be greater than zero");
|
|
7027
|
-
}
|
|
7028
|
-
let pairedAddress = params.paired_address?.trim() || void 0;
|
|
7029
|
-
const autoPairRaw = params.auto_pair ?? params.autoPair;
|
|
7030
|
-
const autoPairDisabled = autoPairRaw === false || autoPairRaw === 0 || typeof autoPairRaw === "string" && ["false", "0"].includes(autoPairRaw.toLowerCase());
|
|
7031
|
-
const autoPair = !pairedAddress && !autoPairDisabled;
|
|
7032
|
-
if (autoPair) {
|
|
7033
|
-
const vaultAddresses = await this.buildVaultAddressMap();
|
|
7034
|
-
pairedAddress = resolvePairedAddressForLpAdd2({
|
|
7035
|
-
pool,
|
|
7036
|
-
side: "rune",
|
|
7037
|
-
vaultAddresses
|
|
7038
|
-
}) || void 0;
|
|
7039
|
-
}
|
|
7040
|
-
const lpPayload = buildThorchainLpAddPayload2({
|
|
7041
|
-
pool,
|
|
7042
|
-
amountRuneBaseUnits: amountRuneBaseUnits.toString(),
|
|
7043
|
-
...pairedAddress ? { pairedAddress } : {}
|
|
7044
|
-
});
|
|
7045
|
-
const receiver = await this.getThorchainNativeInboundAddress(getThorchainInboundAddress2);
|
|
7046
|
-
const address = await this.vault.address(Chain10.THORChain);
|
|
7047
|
-
const coin = {
|
|
7048
|
-
chain: Chain10.THORChain,
|
|
7049
|
-
address,
|
|
7050
|
-
decimals: 8,
|
|
7051
|
-
ticker: "RUNE"
|
|
7052
|
-
};
|
|
7053
|
-
const payload = await this.vault.prepareSendTx({
|
|
7054
|
-
coin,
|
|
7055
|
-
receiver,
|
|
7056
|
-
amount: BigInt(lpPayload.amount),
|
|
7057
|
-
memo: lpPayload.memo
|
|
7058
|
-
});
|
|
7059
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
7060
|
-
this.pendingPayloads.clear();
|
|
7061
|
-
const payloadId = `tc_lp_add_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
7062
|
-
this.pendingPayloads.set(payloadId, {
|
|
7063
|
-
payload,
|
|
7064
|
-
coin,
|
|
7065
|
-
chain: Chain10.THORChain,
|
|
7066
|
-
timestamp: Date.now()
|
|
7067
|
-
});
|
|
7068
|
-
this.pendingPayloads.set("latest", {
|
|
7069
|
-
payload,
|
|
7070
|
-
coin,
|
|
7071
|
-
chain: Chain10.THORChain,
|
|
7072
|
-
timestamp: Date.now()
|
|
7073
|
-
});
|
|
7074
|
-
return {
|
|
7075
|
-
keysign_payload: payloadId,
|
|
7076
|
-
chain: "THORChain",
|
|
7077
|
-
pool: lpPayload.pool,
|
|
7078
|
-
memo: lpPayload.memo,
|
|
7079
|
-
amount_rune: amountStr,
|
|
7080
|
-
paired_address: pairedAddress,
|
|
7081
|
-
inbound_receiver: receiver,
|
|
7082
|
-
sender: address,
|
|
7083
|
-
message_hashes: messageHashes
|
|
7084
|
-
};
|
|
7085
|
-
}
|
|
7086
|
-
async thorchainRemoveLiquidity(params) {
|
|
7087
|
-
const { assertValidPoolId: assertValidPoolId2, buildThorchainLpRemovePayload: buildThorchainLpRemovePayload2 } = await Promise.resolve().then(() => (init_lp(), lp_exports));
|
|
7088
|
-
const { getThorchainInboundAddress: getThorchainInboundAddress2 } = await Promise.resolve().then(() => (init_getThorchainInboundAddress(), getThorchainInboundAddress_exports));
|
|
7089
|
-
const pool = this.normalizeThorchainPoolId(params.pool, assertValidPoolId2);
|
|
7090
|
-
let basisPoints;
|
|
7091
|
-
if (params.basis_points != null) {
|
|
7092
|
-
basisPoints = Number(params.basis_points);
|
|
7093
|
-
} else if (params.basisPoints != null) {
|
|
7094
|
-
basisPoints = Number(params.basisPoints);
|
|
7095
|
-
}
|
|
7096
|
-
if (basisPoints == null && params.withdraw_percent != null) {
|
|
7097
|
-
const pct = Number(params.withdraw_percent);
|
|
7098
|
-
if (Number.isFinite(pct)) {
|
|
7099
|
-
basisPoints = Math.round(pct * 100);
|
|
7100
|
-
}
|
|
7101
|
-
}
|
|
7102
|
-
if (basisPoints == null || !Number.isInteger(basisPoints)) {
|
|
7103
|
-
throw new Error("basis_points (integer 1\u201310000) or withdraw_percent (0.01\u2013100, maps to basis points) is required");
|
|
7104
|
-
}
|
|
7105
|
-
let withdrawToAsset = params.withdraw_to_asset?.trim();
|
|
7106
|
-
if (!withdrawToAsset && params.withdrawToAsset) {
|
|
7107
|
-
withdrawToAsset = String(params.withdrawToAsset).trim();
|
|
7108
|
-
}
|
|
7109
|
-
if (withdrawToAsset) {
|
|
7110
|
-
withdrawToAsset = withdrawToAsset.toUpperCase();
|
|
7111
|
-
}
|
|
7112
|
-
const lpPayload = buildThorchainLpRemovePayload2({
|
|
7113
|
-
pool,
|
|
7114
|
-
basisPoints,
|
|
7115
|
-
...withdrawToAsset ? { withdrawToAsset } : {}
|
|
7116
|
-
});
|
|
7117
|
-
const receiver = await this.getThorchainNativeInboundAddress(getThorchainInboundAddress2);
|
|
7118
|
-
const address = await this.vault.address(Chain10.THORChain);
|
|
7119
|
-
const coin = {
|
|
7120
|
-
chain: Chain10.THORChain,
|
|
7121
|
-
address,
|
|
7122
|
-
decimals: 8,
|
|
7123
|
-
ticker: "RUNE"
|
|
7124
|
-
};
|
|
7125
|
-
const payload = await this.vault.prepareSendTx({
|
|
7126
|
-
coin,
|
|
7127
|
-
receiver,
|
|
7128
|
-
amount: BigInt(lpPayload.amount),
|
|
7129
|
-
memo: lpPayload.memo
|
|
7130
|
-
});
|
|
7131
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
7132
|
-
this.pendingPayloads.clear();
|
|
7133
|
-
const payloadId = `tc_lp_rm_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
7134
|
-
this.pendingPayloads.set(payloadId, {
|
|
7135
|
-
payload,
|
|
7136
|
-
coin,
|
|
7137
|
-
chain: Chain10.THORChain,
|
|
7138
|
-
timestamp: Date.now()
|
|
7139
|
-
});
|
|
7140
|
-
this.pendingPayloads.set("latest", {
|
|
7141
|
-
payload,
|
|
7142
|
-
coin,
|
|
7143
|
-
chain: Chain10.THORChain,
|
|
7144
|
-
timestamp: Date.now()
|
|
7145
|
-
});
|
|
7146
|
-
return {
|
|
7147
|
-
keysign_payload: payloadId,
|
|
7148
|
-
chain: "THORChain",
|
|
7149
|
-
pool: lpPayload.pool,
|
|
7150
|
-
memo: lpPayload.memo,
|
|
7151
|
-
basis_points: basisPoints,
|
|
7152
|
-
withdraw_to_asset: withdrawToAsset || void 0,
|
|
7153
|
-
dust_rune_base_units: lpPayload.amount,
|
|
7154
|
-
inbound_receiver: receiver,
|
|
7155
|
-
sender: address,
|
|
7156
|
-
message_hashes: messageHashes
|
|
7157
|
-
};
|
|
7158
|
-
}
|
|
7159
|
-
normalizeThorchainPoolId(raw, assertValidPoolId2) {
|
|
7160
|
-
const pool = String(raw ?? "").trim();
|
|
7161
|
-
if (!pool) {
|
|
7162
|
-
throw new Error('pool is required (e.g. "BTC.BTC")');
|
|
7163
|
-
}
|
|
7164
|
-
const upper = pool.toUpperCase();
|
|
7165
|
-
assertValidPoolId2(upper);
|
|
7166
|
-
return upper;
|
|
7167
|
-
}
|
|
7168
|
-
async buildVaultAddressMap() {
|
|
7169
|
-
const map = {};
|
|
7170
|
-
for (const c of this.vault.chains) {
|
|
7171
|
-
try {
|
|
7172
|
-
map[c] = await this.vault.address(c);
|
|
7173
|
-
} catch {
|
|
7174
|
-
}
|
|
7175
|
-
}
|
|
7176
|
-
return map;
|
|
7177
|
-
}
|
|
7178
|
-
/** THORChain protocol vault for native RUNE deposits (SWAP/LP memos). Matches SDK e2e fixture. */
|
|
7179
|
-
static THORCHAIN_RUNE_DEPOSIT_ADDRESS = "thor1g98cy3n9mmjrpn0sxmn63lztelera37n8n67c0";
|
|
7180
|
-
async getThorchainNativeInboundAddress(getInbound) {
|
|
7181
|
-
const rows = await getInbound();
|
|
7182
|
-
const thor = rows.find((r) => r.chain.toUpperCase() === "THOR");
|
|
7183
|
-
if (thor?.address) {
|
|
7184
|
-
return thor.address;
|
|
7185
|
-
}
|
|
7186
|
-
if (this.verbose) {
|
|
7187
|
-
process.stderr.write(
|
|
7188
|
-
`[thorchain_lp] THOR inbound row missing; using static RUNE deposit vault ${_AgentExecutor.THORCHAIN_RUNE_DEPOSIT_ADDRESS}
|
|
7189
|
-
`
|
|
7190
|
-
);
|
|
7191
|
-
}
|
|
7192
|
-
return _AgentExecutor.THORCHAIN_RUNE_DEPOSIT_ADDRESS;
|
|
7193
|
-
}
|
|
7194
|
-
async buildTx(params) {
|
|
7195
|
-
if (params.calldata_id && !params.data && this.backendClient) {
|
|
7196
|
-
const id = params.calldata_id;
|
|
7197
|
-
if (this.verbose) process.stderr.write(`[executor] resolving calldata_id ${id}
|
|
7198
|
-
`);
|
|
7199
|
-
const entry = await this.backendClient.getCalldata(id);
|
|
7200
|
-
params = { ...params, data: entry.data };
|
|
7201
|
-
if (!params.to && entry.to) params = { ...params, to: entry.to };
|
|
7202
|
-
delete params.calldata_id;
|
|
7203
|
-
if (this.verbose) process.stderr.write(`[executor] calldata_id resolved, data len=${entry.data.length}
|
|
5860
|
+
async signTxFromBuffer(_toolCallId) {
|
|
5861
|
+
return this.runTool("sign_tx", async () => {
|
|
5862
|
+
if (this.verbose)
|
|
5863
|
+
process.stderr.write(`[sign_tx] pendingPayloads keys: ${[...this.pendingPayloads.keys()].join(", ")}
|
|
7204
5864
|
`);
|
|
7205
|
-
|
|
7206
|
-
if (params.function_name && params.contract_address) {
|
|
7207
|
-
return this.buildContractCallTx(params);
|
|
7208
|
-
}
|
|
7209
|
-
if (params.data || params.calldata || params.hex_payload) {
|
|
7210
|
-
const txData = {
|
|
7211
|
-
to: params.to || params.address || params.contract,
|
|
7212
|
-
value: params.value || "0",
|
|
7213
|
-
data: params.data || params.calldata || params.hex_payload,
|
|
7214
|
-
chain: params.chain,
|
|
7215
|
-
chain_id: params.chain_id
|
|
7216
|
-
};
|
|
7217
|
-
const stored = this.storeServerTransaction({
|
|
7218
|
-
tx: txData,
|
|
7219
|
-
chain: params.chain,
|
|
7220
|
-
from_chain: params.chain
|
|
7221
|
-
});
|
|
5865
|
+
const stored = this.pendingPayloads.get("latest");
|
|
7222
5866
|
if (!stored) {
|
|
7223
|
-
throw new Error("
|
|
5867
|
+
throw new Error("No pending transaction to sign. Build a transaction first.");
|
|
5868
|
+
}
|
|
5869
|
+
const { payload, chain } = stored;
|
|
5870
|
+
if (!payload.__serverTx) {
|
|
5871
|
+
throw new Error("Pending transaction is not a server-built tx (no __serverTx flag).");
|
|
7224
5872
|
}
|
|
7225
|
-
const chain = resolveChain(params.chain) || Chain10.Ethereum;
|
|
7226
|
-
const address = await this.vault.address(chain);
|
|
7227
|
-
return {
|
|
7228
|
-
status: "ready",
|
|
7229
|
-
chain: chain.toString(),
|
|
7230
|
-
from: address,
|
|
7231
|
-
to: txData.to,
|
|
7232
|
-
value: txData.value,
|
|
7233
|
-
has_calldata: true,
|
|
7234
|
-
message: "Transaction built. Ready to sign."
|
|
7235
|
-
};
|
|
7236
|
-
}
|
|
7237
|
-
if (params.contract_address && !params.function_name) {
|
|
7238
|
-
const provided = Object.keys(params).join(", ");
|
|
7239
|
-
throw new Error(
|
|
7240
|
-
`build_custom_tx requires function_name and params for contract calls. Got: ${provided}. Missing: function_name, params.`
|
|
7241
|
-
);
|
|
7242
|
-
}
|
|
7243
|
-
return this.buildSendTx(params);
|
|
7244
|
-
}
|
|
7245
|
-
/**
|
|
7246
|
-
* Build, sign, and broadcast an EVM contract call transaction from structured params.
|
|
7247
|
-
* Encodes function_name + typed params into ABI calldata, then signs via signServerTx.
|
|
7248
|
-
*/
|
|
7249
|
-
async buildContractCallTx(params) {
|
|
7250
|
-
const chainName = params.chain || "Ethereum";
|
|
7251
|
-
const chain = resolveChain(chainName);
|
|
7252
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
7253
|
-
const contractAddress = params.contract_address;
|
|
7254
|
-
const functionName = params.function_name;
|
|
7255
|
-
const typedParams = params.params;
|
|
7256
|
-
const value = params.value || "0";
|
|
7257
|
-
const calldata = await encodeContractCall(functionName, typedParams || []);
|
|
7258
|
-
if (this.verbose)
|
|
7259
|
-
process.stderr.write(
|
|
7260
|
-
`[build_contract_tx] ${functionName}(${(typedParams || []).map((p) => p.type).join(",")}) on ${contractAddress} chain=${chain}
|
|
7261
|
-
`
|
|
7262
|
-
);
|
|
7263
|
-
const serverTxData = {
|
|
7264
|
-
__serverTx: true,
|
|
7265
|
-
tx: {
|
|
7266
|
-
to: contractAddress,
|
|
7267
|
-
value,
|
|
7268
|
-
data: calldata
|
|
7269
|
-
},
|
|
7270
|
-
chain: chainName,
|
|
7271
|
-
from_chain: chainName
|
|
7272
|
-
};
|
|
7273
|
-
this.pendingPayloads.set("latest", {
|
|
7274
|
-
payload: serverTxData,
|
|
7275
|
-
coin: { chain, address: "", decimals: 18, ticker: "" },
|
|
7276
|
-
chain,
|
|
7277
|
-
timestamp: Date.now()
|
|
7278
|
-
});
|
|
7279
|
-
return this.signServerTx(serverTxData, chain, { chain: chainName });
|
|
7280
|
-
}
|
|
7281
|
-
// ============================================================================
|
|
7282
|
-
// Transaction Signing
|
|
7283
|
-
// ============================================================================
|
|
7284
|
-
async signTx(params) {
|
|
7285
|
-
if (this.verbose) process.stderr.write(`[sign_tx] params: ${JSON.stringify(params).slice(0, 500)}
|
|
7286
|
-
`);
|
|
7287
|
-
if (this.verbose)
|
|
7288
|
-
process.stderr.write(`[sign_tx] pendingPayloads keys: ${[...this.pendingPayloads.keys()].join(", ")}
|
|
7289
|
-
`);
|
|
7290
|
-
const payloadId = params.keysign_payload || params.payload_id || "latest";
|
|
7291
|
-
const stored = this.pendingPayloads.get(payloadId);
|
|
7292
|
-
if (!stored) {
|
|
7293
|
-
throw new Error("No pending transaction to sign. Build a transaction first.");
|
|
7294
|
-
}
|
|
7295
|
-
const { payload, chain } = stored;
|
|
7296
|
-
if (payload.__serverTx) {
|
|
7297
5873
|
let result;
|
|
7298
5874
|
if (chain === "Solana" && (payload.swap_tx || payload.provider)) {
|
|
7299
5875
|
try {
|
|
@@ -7308,68 +5884,22 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7308
5884
|
}
|
|
7309
5885
|
}
|
|
7310
5886
|
}
|
|
7311
|
-
if (!result) result = await this.signServerTx(payload, chain,
|
|
5887
|
+
if (!result) result = await this.signServerTx(payload, chain, {});
|
|
7312
5888
|
if (payload.sequence_id) result.sequence_id = payload.sequence_id;
|
|
7313
5889
|
return result;
|
|
7314
|
-
}
|
|
7315
|
-
return this.signSdkTx(payload, chain, payloadId);
|
|
7316
|
-
}
|
|
7317
|
-
/**
|
|
7318
|
-
* Sign and broadcast an SDK-built transaction (keysign payload from local build methods).
|
|
7319
|
-
*/
|
|
7320
|
-
async signSdkTx(payload, chain, _payloadId) {
|
|
7321
|
-
try {
|
|
7322
|
-
if (this.vault.isEncrypted && !this.vault.isUnlocked?.()) {
|
|
7323
|
-
if (this.password) {
|
|
7324
|
-
await this.vault.unlock?.(this.password);
|
|
7325
|
-
}
|
|
7326
|
-
}
|
|
7327
|
-
await this.patchEvmGas(chain, payload);
|
|
7328
|
-
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
7329
|
-
const signature = await this.vault.sign(
|
|
7330
|
-
{
|
|
7331
|
-
transaction: payload,
|
|
7332
|
-
chain: payload.coin?.chain || chain,
|
|
7333
|
-
messageHashes
|
|
7334
|
-
},
|
|
7335
|
-
{}
|
|
7336
|
-
);
|
|
7337
|
-
const txHash = await this.vault.broadcastTx({
|
|
7338
|
-
chain,
|
|
7339
|
-
keysignPayload: payload,
|
|
7340
|
-
signature
|
|
7341
|
-
});
|
|
7342
|
-
this.evmLastBroadcast.set(chain.toString(), Date.now());
|
|
7343
|
-
try {
|
|
7344
|
-
this.recordEvmNonceFromPayload(chain, payload, messageHashes.length);
|
|
7345
|
-
} catch (nonceErr) {
|
|
7346
|
-
console.warn(`[nonce] failed to persist nonce for ${chain}:`, nonceErr);
|
|
7347
|
-
}
|
|
7348
|
-
await this.releaseEvmLock(chain);
|
|
7349
|
-
this.pendingPayloads.clear();
|
|
7350
|
-
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, txHash);
|
|
7351
|
-
return {
|
|
7352
|
-
tx_hash: txHash,
|
|
7353
|
-
chain: chain.toString(),
|
|
7354
|
-
status: "pending",
|
|
7355
|
-
explorer_url: explorerUrl
|
|
7356
|
-
};
|
|
7357
|
-
} catch (err) {
|
|
7358
|
-
await this.releaseEvmLock(chain);
|
|
7359
|
-
throw err;
|
|
7360
|
-
}
|
|
5890
|
+
});
|
|
7361
5891
|
}
|
|
7362
5892
|
/**
|
|
7363
5893
|
* Sign and broadcast a server-built transaction (raw EVM tx from tx_ready SSE).
|
|
7364
5894
|
* Uses vault.prepareSendTx with memo field to carry the calldata.
|
|
7365
5895
|
*/
|
|
7366
5896
|
async signServerTx(serverTxData, defaultChain, params) {
|
|
7367
|
-
const swapTx = serverTxData
|
|
5897
|
+
const swapTx = extractNestedTx(serverTxData);
|
|
7368
5898
|
if (!swapTx?.to) {
|
|
7369
5899
|
throw new Error("Server transaction missing required fields (to)");
|
|
7370
5900
|
}
|
|
7371
|
-
const chainName = params.chain || serverTxData.chain || serverTxData.from_chain;
|
|
7372
|
-
const chainId = serverTxData.chain_id || swapTx.chainId;
|
|
5901
|
+
const chainName = params.chain || serverTxData.chain || serverTxData.from_chain || serverTxData.txArgs?.chain;
|
|
5902
|
+
const chainId = serverTxData.chain_id || serverTxData.txArgs?.chain_id || swapTx.chainId;
|
|
7373
5903
|
let chain = defaultChain;
|
|
7374
5904
|
if (chainName) {
|
|
7375
5905
|
chain = resolveChain(chainName) || defaultChain;
|
|
@@ -7723,37 +6253,39 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7723
6253
|
* - Payloads array: { payloads: [{id, domain, types, message, primaryType, chain}, ...] }
|
|
7724
6254
|
* Used by Polymarket which requires signing both an Order and a ClobAuth.
|
|
7725
6255
|
*/
|
|
7726
|
-
async signTypedData(
|
|
7727
|
-
|
|
7728
|
-
if (this.
|
|
7729
|
-
|
|
6256
|
+
async signTypedData(_toolCallId, input) {
|
|
6257
|
+
return this.runTool("sign_typed_data", async () => {
|
|
6258
|
+
if (this.vault.isEncrypted && !this.vault.isUnlocked?.()) {
|
|
6259
|
+
if (this.password) {
|
|
6260
|
+
await this.vault.unlock?.(this.password);
|
|
6261
|
+
}
|
|
7730
6262
|
}
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
if (this.verbose) process.stderr.write(`[sign_typed_data] payloads mode, ${payloads.length} items
|
|
6263
|
+
const payloads = input.payloads;
|
|
6264
|
+
if (payloads && Array.isArray(payloads)) {
|
|
6265
|
+
if (this.verbose) process.stderr.write(`[sign_typed_data] payloads mode, ${payloads.length} items
|
|
7735
6266
|
`);
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
6267
|
+
const signatures = [];
|
|
6268
|
+
for (let i = 0; i < payloads.length; i++) {
|
|
6269
|
+
const payload = payloads[i];
|
|
6270
|
+
const id = payload.id || payload.name || "default";
|
|
6271
|
+
if (i > 0) {
|
|
6272
|
+
if (this.verbose) process.stderr.write(`[sign_typed_data] waiting 5s between MPC sessions...
|
|
7742
6273
|
`);
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
6274
|
+
await new Promise((r) => setTimeout(r, 5e3));
|
|
6275
|
+
}
|
|
6276
|
+
const sig = await this.signSingleTypedData(payload);
|
|
6277
|
+
signatures.push({ id, ...sig });
|
|
6278
|
+
if (this.verbose) process.stderr.write(`[sign_typed_data] signed payload "${id}"
|
|
7748
6279
|
`);
|
|
6280
|
+
}
|
|
6281
|
+
return {
|
|
6282
|
+
signatures,
|
|
6283
|
+
pm_order_ref: input.pm_order_ref,
|
|
6284
|
+
auto_submit: !!(input.__pm_auto_submit || input.auto_submit)
|
|
6285
|
+
};
|
|
7749
6286
|
}
|
|
7750
|
-
return
|
|
7751
|
-
|
|
7752
|
-
pm_order_ref: params.pm_order_ref,
|
|
7753
|
-
auto_submit: !!(params.__pm_auto_submit || params.auto_submit)
|
|
7754
|
-
};
|
|
7755
|
-
}
|
|
7756
|
-
return this.signSingleTypedData(params);
|
|
6287
|
+
return this.signSingleTypedData(input);
|
|
6288
|
+
});
|
|
7757
6289
|
}
|
|
7758
6290
|
/**
|
|
7759
6291
|
* Sign a single EIP-712 typed data object.
|
|
@@ -7773,11 +6305,11 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7773
6305
|
`);
|
|
7774
6306
|
const chainName = params.chain;
|
|
7775
6307
|
const chainId = domain.chainId;
|
|
7776
|
-
let chain =
|
|
6308
|
+
let chain = Chain9.Ethereum;
|
|
7777
6309
|
if (chainName) {
|
|
7778
|
-
chain = resolveChain(chainName) ||
|
|
6310
|
+
chain = resolveChain(chainName) || Chain9.Ethereum;
|
|
7779
6311
|
} else if (chainId) {
|
|
7780
|
-
chain = resolveChainId(chainId) ||
|
|
6312
|
+
chain = resolveChainId(chainId) || Chain9.Ethereum;
|
|
7781
6313
|
}
|
|
7782
6314
|
const sigResult = await this.vault.signBytes({
|
|
7783
6315
|
data: eip712Hash,
|
|
@@ -7802,139 +6334,91 @@ var AgentExecutor = class _AgentExecutor {
|
|
|
7802
6334
|
}
|
|
7803
6335
|
// ============================================================================
|
|
7804
6336
|
// Address Book
|
|
6337
|
+
//
|
|
6338
|
+
// Live client-side tools — server-side `address_book_*` runs through MCP
|
|
6339
|
+
// for read; mutating writes have no local implementation yet.
|
|
7805
6340
|
// ============================================================================
|
|
7806
|
-
async
|
|
6341
|
+
async addressBookAdd(_toolCallId, input) {
|
|
6342
|
+
return this.runTool("address_book_add", () => this.addAddressBookImpl(input));
|
|
6343
|
+
}
|
|
6344
|
+
async addressBookRemove(_toolCallId, input) {
|
|
6345
|
+
return this.runTool("address_book_remove", () => this.removeAddressBookImpl(input));
|
|
6346
|
+
}
|
|
6347
|
+
// Backend `address_book { action: "add", entry: {...} }` flows through
|
|
6348
|
+
// this impl. The public `addressBookAdd` wrapper above tags results as
|
|
6349
|
+
// `tool: 'address_book_add'`; the new `addressBook` wrapper tags them as
|
|
6350
|
+
// `tool: 'address_book'` (matching the discriminator tool the backend emits).
|
|
6351
|
+
async addAddressBookImpl(params) {
|
|
7807
6352
|
if (!this.vultisig) {
|
|
7808
6353
|
throw new Error(
|
|
7809
|
-
"
|
|
6354
|
+
"address_book add requires the CLI SDK instance. Ensure AgentConfig.vultisig is set when creating the session."
|
|
7810
6355
|
);
|
|
7811
6356
|
}
|
|
7812
|
-
const
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
throw new Error(`Unknown chain: ${chainName}`);
|
|
6357
|
+
const entry = params.entry;
|
|
6358
|
+
if (!entry || typeof entry !== "object") {
|
|
6359
|
+
throw new Error("address_book add: missing entry");
|
|
7816
6360
|
}
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
6361
|
+
const chainName = entry.chain;
|
|
6362
|
+
const chain = chainName ? resolveChain(chainName) : void 0;
|
|
6363
|
+
if (!chain) throw new Error(`address_book add: unknown chain: ${chainName ?? "(missing)"}`);
|
|
6364
|
+
const address = entry.address;
|
|
6365
|
+
if (!address) throw new Error("address_book add: entry.address is required");
|
|
6366
|
+
const name = entry.name ?? "";
|
|
6367
|
+
await this.vultisig.addAddressBookEntry([
|
|
6368
|
+
{
|
|
6369
|
+
chain,
|
|
6370
|
+
address,
|
|
6371
|
+
name,
|
|
6372
|
+
source: "saved",
|
|
6373
|
+
dateAdded: Date.now()
|
|
6374
|
+
}
|
|
6375
|
+
]);
|
|
6376
|
+
return { added: { chain: chain.toString(), address, name } };
|
|
7826
6377
|
}
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
if (!query) {
|
|
7833
|
-
return { tokens: [] };
|
|
6378
|
+
async removeAddressBookImpl(params) {
|
|
6379
|
+
if (!this.vultisig) {
|
|
6380
|
+
throw new Error(
|
|
6381
|
+
"address_book remove requires the CLI SDK instance. Ensure AgentConfig.vultisig is set when creating the session."
|
|
6382
|
+
);
|
|
7834
6383
|
}
|
|
7835
|
-
const
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
const tick = t.ticker.toLowerCase();
|
|
7839
|
-
const addr = (t.contractAddress ?? "").toLowerCase();
|
|
7840
|
-
const pid = (t.priceProviderId ?? "").toLowerCase();
|
|
7841
|
-
return tick.includes(query) || addr.includes(query) || pid.includes(query);
|
|
7842
|
-
};
|
|
7843
|
-
if (chainName) {
|
|
7844
|
-
const chain = resolveChain(chainName);
|
|
7845
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
7846
|
-
const tokens = VultisigSdk.getKnownTokens(chain).filter(tokenMatchesQuery).slice(0, limit);
|
|
7847
|
-
return { tokens };
|
|
6384
|
+
const entry = params.entry;
|
|
6385
|
+
if (!entry || typeof entry !== "object") {
|
|
6386
|
+
throw new Error("address_book remove: missing entry");
|
|
7848
6387
|
}
|
|
7849
|
-
const
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
6388
|
+
const chainName = entry.chain;
|
|
6389
|
+
const chain = chainName ? resolveChain(chainName) : void 0;
|
|
6390
|
+
if (!chain) throw new Error(`address_book remove: unknown chain: ${chainName ?? "(missing)"}`);
|
|
6391
|
+
let address = entry.address;
|
|
6392
|
+
if (!address) {
|
|
6393
|
+
const name = entry.name;
|
|
6394
|
+
if (!name) {
|
|
6395
|
+
throw new Error("address_book remove: entry.address or entry.name is required");
|
|
7855
6396
|
}
|
|
6397
|
+
const book = await this.vultisig.getAddressBook(chain);
|
|
6398
|
+
const lower = name.toLowerCase();
|
|
6399
|
+
const matches = book.saved.filter((e) => e.name.toLowerCase() === lower && e.chain === chain);
|
|
6400
|
+
if (matches.length === 0) {
|
|
6401
|
+
throw new Error(`address_book remove: no saved entry named "${name}" on ${chainName}`);
|
|
6402
|
+
}
|
|
6403
|
+
if (matches.length > 1) {
|
|
6404
|
+
const addrs = matches.map((m) => m.address).join(", ");
|
|
6405
|
+
throw new Error(
|
|
6406
|
+
`address_book remove: ambiguous name "${name}" on ${chainName} \u2014 multiple addresses: ${addrs}. Specify entry.address explicitly.`
|
|
6407
|
+
);
|
|
6408
|
+
}
|
|
6409
|
+
address = matches[0].address;
|
|
7856
6410
|
}
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
async listVaults() {
|
|
7860
|
-
return {
|
|
7861
|
-
vaults: [
|
|
7862
|
-
{
|
|
7863
|
-
name: this.vault.name,
|
|
7864
|
-
id: this.vault.id,
|
|
7865
|
-
type: this.vault.type,
|
|
7866
|
-
chains: this.vault.chains.map((c) => c.toString())
|
|
7867
|
-
}
|
|
7868
|
-
]
|
|
7869
|
-
};
|
|
7870
|
-
}
|
|
7871
|
-
async scanTx(_params) {
|
|
7872
|
-
throw new Error("scan_tx is not yet implemented locally. The backend may handle this action server-side.");
|
|
7873
|
-
}
|
|
7874
|
-
async readEvmContract(params) {
|
|
7875
|
-
const chainName = params.chain;
|
|
7876
|
-
if (!chainName) throw new Error("read_evm_contract requires chain");
|
|
7877
|
-
const contractRaw = params.contract_address || params.contractAddress;
|
|
7878
|
-
if (!contractRaw) throw new Error("read_evm_contract requires contract_address");
|
|
7879
|
-
const functionName = params.function_name || params.functionName;
|
|
7880
|
-
if (!functionName) throw new Error("read_evm_contract requires function_name");
|
|
7881
|
-
const chain = resolveChain(chainName);
|
|
7882
|
-
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
7883
|
-
if (!EVM_CHAINS.has(chain)) {
|
|
7884
|
-
throw new Error(`read_evm_contract only supports EVM chains (got ${chain})`);
|
|
7885
|
-
}
|
|
7886
|
-
const callParams = params.params ?? [];
|
|
7887
|
-
const data = await encodeContractCall(functionName, callParams);
|
|
7888
|
-
const addr = contractRaw.startsWith("0x") ? contractRaw : `0x${contractRaw}`;
|
|
7889
|
-
const to = addr;
|
|
7890
|
-
const from = params.from;
|
|
7891
|
-
const result = await evmCall(chain, { to, data, from });
|
|
7892
|
-
return { result };
|
|
6411
|
+
await this.vultisig.removeAddressBookEntry([{ chain, address }]);
|
|
6412
|
+
return { removed: { chain: chain.toString(), address } };
|
|
7893
6413
|
}
|
|
7894
6414
|
};
|
|
7895
|
-
async function encodeContractCall(functionName, params) {
|
|
7896
|
-
const baseName = functionName.includes("(") ? functionName.split("(")[0] : functionName;
|
|
7897
|
-
const types = params.map((p) => p.type);
|
|
7898
|
-
const sig = `${baseName}(${types.join(",")})`;
|
|
7899
|
-
const selector = await keccak256Selector(sig);
|
|
7900
|
-
let encoded = "";
|
|
7901
|
-
for (const param of params) {
|
|
7902
|
-
encoded += abiEncodeParam(param.type, param.value);
|
|
7903
|
-
}
|
|
7904
|
-
return "0x" + selector + encoded;
|
|
7905
|
-
}
|
|
7906
|
-
async function keccak256Selector(sig) {
|
|
7907
|
-
const { keccak_256: keccak_2562 } = await Promise.resolve().then(() => (init_sha3(), sha3_exports));
|
|
7908
|
-
const hash = keccak_2562(new TextEncoder().encode(sig));
|
|
7909
|
-
return Buffer.from(hash).toString("hex").slice(0, 8);
|
|
7910
|
-
}
|
|
7911
|
-
function abiEncodeParam(type, value) {
|
|
7912
|
-
if (type === "address") {
|
|
7913
|
-
const addr = value.startsWith("0x") ? value.slice(2) : value;
|
|
7914
|
-
return addr.toLowerCase().padStart(64, "0");
|
|
7915
|
-
}
|
|
7916
|
-
if (type.startsWith("uint") || type.startsWith("int")) {
|
|
7917
|
-
const n = BigInt(value);
|
|
7918
|
-
const hex = n.toString(16);
|
|
7919
|
-
return hex.padStart(64, "0");
|
|
7920
|
-
}
|
|
7921
|
-
if (type === "bool") {
|
|
7922
|
-
return (value === "true" || value === "1" ? "1" : "0").padStart(64, "0");
|
|
7923
|
-
}
|
|
7924
|
-
if (type === "bytes32") {
|
|
7925
|
-
const b2 = value.startsWith("0x") ? value.slice(2) : value;
|
|
7926
|
-
return b2.padEnd(64, "0");
|
|
7927
|
-
}
|
|
7928
|
-
const b = value.startsWith("0x") ? value.slice(2) : Buffer.from(value).toString("hex");
|
|
7929
|
-
return b.padStart(64, "0");
|
|
7930
|
-
}
|
|
7931
6415
|
function resolveChain(name) {
|
|
7932
6416
|
if (!name) return null;
|
|
7933
|
-
if (Object.values(
|
|
6417
|
+
if (Object.values(Chain9).includes(name)) {
|
|
7934
6418
|
return name;
|
|
7935
6419
|
}
|
|
7936
6420
|
const lower = name.toLowerCase();
|
|
7937
|
-
for (const [, value] of Object.entries(
|
|
6421
|
+
for (const [, value] of Object.entries(Chain9)) {
|
|
7938
6422
|
if (typeof value === "string" && value.toLowerCase() === lower) {
|
|
7939
6423
|
return value;
|
|
7940
6424
|
}
|
|
@@ -7960,16 +6444,11 @@ function resolveChain(name) {
|
|
|
7960
6444
|
xrp: "Ripple"
|
|
7961
6445
|
};
|
|
7962
6446
|
const aliased = aliases[lower];
|
|
7963
|
-
if (aliased && Object.values(
|
|
6447
|
+
if (aliased && Object.values(Chain9).includes(aliased)) {
|
|
7964
6448
|
return aliased;
|
|
7965
6449
|
}
|
|
7966
6450
|
return null;
|
|
7967
6451
|
}
|
|
7968
|
-
function parseAmount(amountStr, decimals) {
|
|
7969
|
-
const [whole, frac = ""] = amountStr.split(".");
|
|
7970
|
-
const paddedFrac = frac.slice(0, decimals).padEnd(decimals, "0");
|
|
7971
|
-
return BigInt(whole || "0") * 10n ** BigInt(decimals) + BigInt(paddedFrac || "0");
|
|
7972
|
-
}
|
|
7973
6452
|
function resolveChainFromTxReady(txReadyData) {
|
|
7974
6453
|
if (txReadyData.chain) {
|
|
7975
6454
|
const chain = resolveChain(txReadyData.chain);
|
|
@@ -7983,27 +6462,38 @@ function resolveChainFromTxReady(txReadyData) {
|
|
|
7983
6462
|
const chain = resolveChainId(txReadyData.chain_id);
|
|
7984
6463
|
if (chain) return chain;
|
|
7985
6464
|
}
|
|
7986
|
-
|
|
6465
|
+
if (txReadyData.txArgs?.chain) {
|
|
6466
|
+
const chain = resolveChain(txReadyData.txArgs.chain);
|
|
6467
|
+
if (chain) return chain;
|
|
6468
|
+
}
|
|
6469
|
+
if (txReadyData.txArgs?.chain_id) {
|
|
6470
|
+
const chain = resolveChainId(txReadyData.txArgs.chain_id);
|
|
6471
|
+
if (chain) return chain;
|
|
6472
|
+
}
|
|
6473
|
+
const swapTx = extractNestedTx(txReadyData);
|
|
7987
6474
|
if (swapTx?.chainId) {
|
|
7988
6475
|
const chain = resolveChainId(swapTx.chainId);
|
|
7989
6476
|
if (chain) return chain;
|
|
7990
6477
|
}
|
|
7991
6478
|
return null;
|
|
7992
6479
|
}
|
|
6480
|
+
function extractNestedTx(txReadyData) {
|
|
6481
|
+
return txReadyData?.swap_tx || txReadyData?.send_tx || txReadyData?.tx || txReadyData?.txArgs?.tx;
|
|
6482
|
+
}
|
|
7993
6483
|
function resolveChainId(chainId) {
|
|
7994
6484
|
const id = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
|
|
7995
6485
|
if (isNaN(id)) return null;
|
|
7996
6486
|
const chainIdMap = {
|
|
7997
|
-
1:
|
|
7998
|
-
56:
|
|
7999
|
-
137:
|
|
8000
|
-
43114:
|
|
8001
|
-
42161:
|
|
8002
|
-
10:
|
|
8003
|
-
8453:
|
|
8004
|
-
81457:
|
|
8005
|
-
324:
|
|
8006
|
-
25:
|
|
6487
|
+
1: Chain9.Ethereum,
|
|
6488
|
+
56: Chain9.BSC,
|
|
6489
|
+
137: Chain9.Polygon,
|
|
6490
|
+
43114: Chain9.Avalanche,
|
|
6491
|
+
42161: Chain9.Arbitrum,
|
|
6492
|
+
10: Chain9.Optimism,
|
|
6493
|
+
8453: Chain9.Base,
|
|
6494
|
+
81457: Chain9.Blast,
|
|
6495
|
+
324: Chain9.Zksync,
|
|
6496
|
+
25: Chain9.CronosChain
|
|
8007
6497
|
};
|
|
8008
6498
|
return chainIdMap[id] || null;
|
|
8009
6499
|
}
|
|
@@ -8382,25 +6872,14 @@ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, wri
|
|
|
8382
6872
|
import { homedir as homedir2 } from "node:os";
|
|
8383
6873
|
import { join as join2 } from "node:path";
|
|
8384
6874
|
import { MemoryStorage, PushNotificationService } from "@vultisig/sdk";
|
|
6875
|
+
var PASSWORD_REQUIRED_TOOLS = /* @__PURE__ */ new Set(["sign_typed_data", "sign_tx"]);
|
|
8385
6876
|
var CLIENT_SIDE_TOOL_DISPATCH = {
|
|
8386
|
-
sign_typed_data:
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
remove_chain: "remove_chain",
|
|
8391
|
-
address_book_add: "address_book_add",
|
|
8392
|
-
address_book_remove: "address_book_remove"
|
|
6877
|
+
sign_typed_data: (ex, id, input) => ex.signTypedData(id, input),
|
|
6878
|
+
vault_coin: (ex, id, input) => ex.vaultCoin(id, input),
|
|
6879
|
+
vault_chain: (ex, id, input) => ex.vaultChain(id, input),
|
|
6880
|
+
address_book: (ex, id, input) => ex.addressBook(id, input)
|
|
8393
6881
|
};
|
|
8394
6882
|
var MAX_MESSAGE_LOOP_DEPTH = 16;
|
|
8395
|
-
function actionResultToRecentAction(r) {
|
|
8396
|
-
if (r.success) {
|
|
8397
|
-
return { tool: r.action, success: true, data: r.data ?? {} };
|
|
8398
|
-
}
|
|
8399
|
-
const data = { ...r.data ?? {} };
|
|
8400
|
-
if (r.error) data.error = r.error;
|
|
8401
|
-
if (r.code) data.code = r.code;
|
|
8402
|
-
return { tool: r.action, success: false, data };
|
|
8403
|
-
}
|
|
8404
6883
|
var AgentSession = class {
|
|
8405
6884
|
client;
|
|
8406
6885
|
vault;
|
|
@@ -8419,6 +6898,9 @@ var AgentSession = class {
|
|
|
8419
6898
|
this.config = config;
|
|
8420
6899
|
this.client = new AgentClient(config.backendUrl);
|
|
8421
6900
|
this.client.verbose = !!config.verbose;
|
|
6901
|
+
if (config.profile) {
|
|
6902
|
+
this.client.setProfile(config.profile);
|
|
6903
|
+
}
|
|
8422
6904
|
this.executor = new AgentExecutor(vault, !!config.verbose, vault.publicKeys.ecdsa, config.vultisig);
|
|
8423
6905
|
this.publicKey = vault.publicKeys.ecdsa;
|
|
8424
6906
|
if (config.password) {
|
|
@@ -8447,7 +6929,6 @@ var AgentSession = class {
|
|
|
8447
6929
|
this.client.setAuthToken(auth.token);
|
|
8448
6930
|
saveCachedToken(this.publicKey, auth.token, auth.expiresAt);
|
|
8449
6931
|
}
|
|
8450
|
-
this.executor.setBackendClient(this.client);
|
|
8451
6932
|
} catch (err) {
|
|
8452
6933
|
throw new Error(`Authentication failed: ${err.message}`);
|
|
8453
6934
|
}
|
|
@@ -8655,21 +7136,22 @@ var AgentSession = class {
|
|
|
8655
7136
|
`[session] ${serverTxStoredFromStream} stored server tx from tx_ready, signing client-side
|
|
8656
7137
|
`
|
|
8657
7138
|
);
|
|
8658
|
-
const
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
if (
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
return;
|
|
7139
|
+
const signToolCallId = `tx_sign_${Date.now()}`;
|
|
7140
|
+
const recent = await this.runPasswordGatedTool(
|
|
7141
|
+
"sign_tx",
|
|
7142
|
+
signToolCallId,
|
|
7143
|
+
ui,
|
|
7144
|
+
() => this.executor.signTxFromBuffer(signToolCallId)
|
|
7145
|
+
);
|
|
7146
|
+
this.pendingToolResults.push(recent);
|
|
7147
|
+
if (recent.success && recent.data) {
|
|
7148
|
+
const txHash = recent.data.tx_hash;
|
|
7149
|
+
const chain = recent.data.chain;
|
|
7150
|
+
const explorerUrl = recent.data.explorer_url;
|
|
7151
|
+
if (txHash) ui.onTxStatus(txHash, chain || "", "pending", explorerUrl);
|
|
8672
7152
|
}
|
|
7153
|
+
await this.processMessageLoop(null, ui, depth + 1);
|
|
7154
|
+
return;
|
|
8673
7155
|
}
|
|
8674
7156
|
if (this.pendingToolResults.length > 0) {
|
|
8675
7157
|
await this.processMessageLoop(null, ui, depth + 1);
|
|
@@ -8677,12 +7159,59 @@ var AgentSession = class {
|
|
|
8677
7159
|
}
|
|
8678
7160
|
ui.onDone();
|
|
8679
7161
|
}
|
|
8680
|
-
|
|
7162
|
+
/**
|
|
7163
|
+
* Wrap a per-tool dispatch with the password-prompt gate (for tools in
|
|
7164
|
+
* {@link PASSWORD_REQUIRED_TOOLS}) and `ui.onToolCall` /
|
|
7165
|
+
* `ui.onToolResult` lifecycle events. Returns the `RecentAction` produced
|
|
7166
|
+
* by the executor (or a synthetic failure `RecentAction` if the password
|
|
7167
|
+
* prompt was declined).
|
|
7168
|
+
*/
|
|
7169
|
+
async runPasswordGatedTool(toolName, toolCallId, ui, body, input) {
|
|
7170
|
+
let promptedPassword;
|
|
7171
|
+
if (PASSWORD_REQUIRED_TOOLS.has(toolName) && !this.config.password) {
|
|
7172
|
+
try {
|
|
7173
|
+
promptedPassword = await ui.requestPassword();
|
|
7174
|
+
this.executor.setPassword(promptedPassword);
|
|
7175
|
+
} catch {
|
|
7176
|
+
const failure = {
|
|
7177
|
+
tool: toolName,
|
|
7178
|
+
success: false,
|
|
7179
|
+
data: { error: "Password not provided", code: "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */ }
|
|
7180
|
+
};
|
|
7181
|
+
ui.onToolCall(toolCallId, toolName, input);
|
|
7182
|
+
ui.onToolResult(
|
|
7183
|
+
toolCallId,
|
|
7184
|
+
toolName,
|
|
7185
|
+
false,
|
|
7186
|
+
failure.data,
|
|
7187
|
+
"Password not provided",
|
|
7188
|
+
"PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */
|
|
7189
|
+
);
|
|
7190
|
+
return failure;
|
|
7191
|
+
}
|
|
7192
|
+
}
|
|
7193
|
+
ui.onToolCall(toolCallId, toolName, input);
|
|
7194
|
+
let recent;
|
|
7195
|
+
try {
|
|
7196
|
+
recent = await body();
|
|
7197
|
+
} catch (err) {
|
|
7198
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7199
|
+
recent = { tool: toolName, success: false, data: { error: message } };
|
|
7200
|
+
}
|
|
7201
|
+
const errorMsg = recent.data?.error ?? void 0;
|
|
7202
|
+
const errorCode = recent.data?.code ?? void 0;
|
|
7203
|
+
ui.onToolResult(toolCallId, toolName, recent.success, recent.data, errorMsg, errorCode);
|
|
7204
|
+
if (promptedPassword && recent.success) {
|
|
7205
|
+
this.config.password = promptedPassword;
|
|
7206
|
+
}
|
|
7207
|
+
return recent;
|
|
7208
|
+
}
|
|
7209
|
+
// Routes client-side tool calls through the per-tool registry. Missing
|
|
8681
7210
|
// entries surface as a visible `[cli] unimplemented` warning + failure
|
|
8682
7211
|
// RecentAction (never silent).
|
|
8683
7212
|
async dispatchClientSideTool(toolCallId, toolName, input, ui) {
|
|
8684
|
-
const
|
|
8685
|
-
if (!
|
|
7213
|
+
const handler = CLIENT_SIDE_TOOL_DISPATCH[toolName];
|
|
7214
|
+
if (!handler) {
|
|
8686
7215
|
process.stderr.write(`[cli] unimplemented client-side tool: ${toolName}
|
|
8687
7216
|
`);
|
|
8688
7217
|
this.pendingToolResults.push({
|
|
@@ -8692,76 +7221,26 @@ var AgentSession = class {
|
|
|
8692
7221
|
});
|
|
8693
7222
|
return;
|
|
8694
7223
|
}
|
|
8695
|
-
|
|
8696
|
-
id: toolCallId,
|
|
8697
|
-
type: actionType,
|
|
8698
|
-
title: toolName,
|
|
8699
|
-
params: input,
|
|
8700
|
-
auto_execute: true
|
|
8701
|
-
};
|
|
7224
|
+
let recent;
|
|
8702
7225
|
try {
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
recent.data[key] = input[key];
|
|
8711
|
-
}
|
|
8712
|
-
}
|
|
8713
|
-
this.pendingToolResults.push(recent);
|
|
8714
|
-
}
|
|
7226
|
+
recent = await this.runPasswordGatedTool(
|
|
7227
|
+
toolName,
|
|
7228
|
+
toolCallId,
|
|
7229
|
+
ui,
|
|
7230
|
+
() => handler(this.executor, toolCallId, input),
|
|
7231
|
+
input
|
|
7232
|
+
);
|
|
8715
7233
|
} catch (err) {
|
|
8716
7234
|
const message = err instanceof Error ? err.message : String(err);
|
|
8717
|
-
|
|
8718
|
-
tool: toolName,
|
|
8719
|
-
success: false,
|
|
8720
|
-
data: { error: message }
|
|
8721
|
-
});
|
|
7235
|
+
recent = { tool: toolName, success: false, data: { error: message } };
|
|
8722
7236
|
}
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
async executeActions(actions, ui) {
|
|
8728
|
-
const results = [];
|
|
8729
|
-
for (const action of actions) {
|
|
8730
|
-
if (!this.executor.shouldAutoExecute(action)) {
|
|
8731
|
-
continue;
|
|
8732
|
-
}
|
|
8733
|
-
if (PASSWORD_REQUIRED_ACTIONS.has(action.type)) {
|
|
8734
|
-
if (!this.config.password) {
|
|
8735
|
-
try {
|
|
8736
|
-
const password = await ui.requestPassword();
|
|
8737
|
-
this.executor.setPassword(password);
|
|
8738
|
-
this.config.password = password;
|
|
8739
|
-
} catch {
|
|
8740
|
-
results.push({
|
|
8741
|
-
action: action.type,
|
|
8742
|
-
action_id: action.id,
|
|
8743
|
-
success: false,
|
|
8744
|
-
error: "Password not provided",
|
|
8745
|
-
code: "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */
|
|
8746
|
-
});
|
|
8747
|
-
continue;
|
|
8748
|
-
}
|
|
8749
|
-
}
|
|
8750
|
-
}
|
|
8751
|
-
ui.onToolCall(action.id, action.type, action.params);
|
|
8752
|
-
const result = await this.executor.executeAction(action);
|
|
8753
|
-
results.push(result);
|
|
8754
|
-
ui.onToolResult(action.id, action.type, result.success, result.data, result.error, result.code);
|
|
8755
|
-
if (action.type === "sign_tx" && result.success && result.data) {
|
|
8756
|
-
const txHash = result.data.tx_hash;
|
|
8757
|
-
const chain = result.data.chain;
|
|
8758
|
-
const explorerUrl = result.data.explorer_url;
|
|
8759
|
-
if (txHash) {
|
|
8760
|
-
ui.onTxStatus(txHash, chain, "pending", explorerUrl);
|
|
8761
|
-
}
|
|
7237
|
+
if (recent.data === void 0) recent.data = {};
|
|
7238
|
+
for (const key of Object.keys(input)) {
|
|
7239
|
+
if (key.startsWith("__") || key === "pm_order_ref") {
|
|
7240
|
+
recent.data[key] = input[key];
|
|
8762
7241
|
}
|
|
8763
7242
|
}
|
|
8764
|
-
|
|
7243
|
+
this.pendingToolResults.push(recent);
|
|
8765
7244
|
}
|
|
8766
7245
|
/**
|
|
8767
7246
|
* Cancel the current operation.
|
|
@@ -9204,7 +7683,8 @@ async function executeAgent(ctx2, options) {
|
|
|
9204
7683
|
viaAgent: options.viaAgent,
|
|
9205
7684
|
sessionId: options.sessionId,
|
|
9206
7685
|
verbose: options.verbose,
|
|
9207
|
-
notificationUrl: options.notificationUrl || process.env.VULTISIG_NOTIFICATION_URL || ""
|
|
7686
|
+
notificationUrl: options.notificationUrl || process.env.VULTISIG_NOTIFICATION_URL || "",
|
|
7687
|
+
profile: options.profile ?? process.env.VULTISIG_AGENT_PROFILE ?? ""
|
|
9208
7688
|
};
|
|
9209
7689
|
const session = new AgentSession(vault, config);
|
|
9210
7690
|
if (options.viaAgent) {
|
|
@@ -9247,7 +7727,8 @@ async function executeAgentAsk(ctx2, message, options) {
|
|
|
9247
7727
|
password: options.password,
|
|
9248
7728
|
sessionId: options.session,
|
|
9249
7729
|
verbose: options.verbose,
|
|
9250
|
-
askMode: true
|
|
7730
|
+
askMode: true,
|
|
7731
|
+
profile: options.profile ?? process.env.VULTISIG_AGENT_PROFILE ?? ""
|
|
9251
7732
|
};
|
|
9252
7733
|
const session = new AgentSession(vault, config);
|
|
9253
7734
|
const ask = new AskInterface(session, !!config.verbose);
|
|
@@ -9377,7 +7858,7 @@ var cachedVersion = null;
|
|
|
9377
7858
|
function getVersion() {
|
|
9378
7859
|
if (cachedVersion) return cachedVersion;
|
|
9379
7860
|
if (true) {
|
|
9380
|
-
cachedVersion = "0.22.
|
|
7861
|
+
cachedVersion = "0.22.5";
|
|
9381
7862
|
return cachedVersion;
|
|
9382
7863
|
}
|
|
9383
7864
|
try {
|
|
@@ -9660,7 +8141,7 @@ function readArgValue(args, optionName) {
|
|
|
9660
8141
|
}
|
|
9661
8142
|
|
|
9662
8143
|
// src/interactive/completer.ts
|
|
9663
|
-
import { Chain as
|
|
8144
|
+
import { Chain as Chain10 } from "@vultisig/sdk";
|
|
9664
8145
|
import fs3 from "fs";
|
|
9665
8146
|
import path3 from "path";
|
|
9666
8147
|
var COMMANDS = [
|
|
@@ -9804,7 +8285,7 @@ function completeVaultName(ctx2, partial) {
|
|
|
9804
8285
|
return [show, partial];
|
|
9805
8286
|
}
|
|
9806
8287
|
function completeChainName(partial) {
|
|
9807
|
-
const allChains = Object.values(
|
|
8288
|
+
const allChains = Object.values(Chain10);
|
|
9808
8289
|
const partialLower = partial.toLowerCase();
|
|
9809
8290
|
const matches = allChains.filter((chain) => chain.toLowerCase().startsWith(partialLower));
|
|
9810
8291
|
matches.sort();
|
|
@@ -9812,7 +8293,7 @@ function completeChainName(partial) {
|
|
|
9812
8293
|
return [show, partial];
|
|
9813
8294
|
}
|
|
9814
8295
|
function findChainByName(name) {
|
|
9815
|
-
const allChains = Object.values(
|
|
8296
|
+
const allChains = Object.values(Chain10);
|
|
9816
8297
|
const nameLower = name.toLowerCase();
|
|
9817
8298
|
const found = allChains.find((chain) => chain.toLowerCase() === nameLower);
|
|
9818
8299
|
return found ? found : null;
|
|
@@ -12071,7 +10552,7 @@ rujiraCmd.command("withdraw <asset> <amount> <l1Address>").description("Withdraw
|
|
|
12071
10552
|
}
|
|
12072
10553
|
)
|
|
12073
10554
|
);
|
|
12074
|
-
var agentCmd = program.command("agent").description("AI-powered chat interface for wallet operations").option("--via-agent", "Use NDJSON pipe mode for agent-to-agent communication").option("--verbose", "Show detailed tool call parameters and debug output").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--password-ttl <ms>", "Password cache TTL in milliseconds (default: 300000, 86400000/24h for --via-agent)").option("--session-id <id>", "Resume an existing session").option("--notification-url <url>", "Notification service URL for push notifications").action(
|
|
10555
|
+
var agentCmd = program.command("agent").description("AI-powered chat interface for wallet operations").option("--via-agent", "Use NDJSON pipe mode for agent-to-agent communication").option("--verbose", "Show detailed tool call parameters and debug output").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--password-ttl <ms>", "Password cache TTL in milliseconds (default: 300000, 86400000/24h for --via-agent)").option("--session-id <id>", "Resume an existing session").option("--notification-url <url>", "Notification service URL for push notifications").option("--profile <api_id>", "Billing profile slug sent as X-Vultisig-Abe-Profile header").action(
|
|
12075
10556
|
async (options) => {
|
|
12076
10557
|
const MAX_TTL = 864e5;
|
|
12077
10558
|
let passwordTTL;
|
|
@@ -12093,16 +10574,18 @@ var agentCmd = program.command("agent").description("AI-powered chat interface f
|
|
|
12093
10574
|
backendUrl: options.backendUrl,
|
|
12094
10575
|
password: options.password,
|
|
12095
10576
|
sessionId: options.sessionId,
|
|
12096
|
-
notificationUrl: options.notificationUrl
|
|
10577
|
+
notificationUrl: options.notificationUrl,
|
|
10578
|
+
profile: options.profile
|
|
12097
10579
|
});
|
|
12098
10580
|
}
|
|
12099
10581
|
);
|
|
12100
|
-
agentCmd.command("ask <message>").description("Send a single message and get the response (for AI agent integration)").option("--session <id>", "Continue an existing conversation").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--verbose", "Show tool calls and debug info on stderr").option("--json", "Output structured JSON (deprecated: use --output json)").addHelpText(
|
|
10582
|
+
agentCmd.command("ask <message>").description("Send a single message and get the response (for AI agent integration)").option("--session <id>", "Continue an existing conversation").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--verbose", "Show tool calls and debug info on stderr").option("--json", "Output structured JSON (deprecated: use --output json)").option("--profile <api_id>", "Billing profile slug sent as X-Vultisig-Abe-Profile header").addHelpText(
|
|
12101
10583
|
"after",
|
|
12102
10584
|
`
|
|
12103
10585
|
Examples:
|
|
12104
10586
|
vultisig agent ask "What is my ETH balance?" --output json
|
|
12105
|
-
vultisig agent ask "Send 0.1 ETH to 0x..." --session abc123
|
|
10587
|
+
vultisig agent ask "Send 0.1 ETH to 0x..." --session abc123
|
|
10588
|
+
vultisig agent ask "..." --profile station-wallet`
|
|
12106
10589
|
).action(
|
|
12107
10590
|
async (message, options) => {
|
|
12108
10591
|
const parentOpts = agentCmd.opts();
|
|
@@ -12111,7 +10594,8 @@ Examples:
|
|
|
12111
10594
|
...options,
|
|
12112
10595
|
backendUrl: options.backendUrl || parentOpts.backendUrl,
|
|
12113
10596
|
password: options.password || parentOpts.password,
|
|
12114
|
-
verbose: options.verbose || parentOpts.verbose
|
|
10597
|
+
verbose: options.verbose || parentOpts.verbose,
|
|
10598
|
+
profile: options.profile ?? parentOpts.profile
|
|
12115
10599
|
});
|
|
12116
10600
|
}
|
|
12117
10601
|
);
|