@hypurrquant/defi-cli 1.0.12 → 1.0.13
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/README.md +9 -2
- package/config/chains.toml +6 -1
- package/config/protocols/dex/aerodrome_base.toml +2 -1
- package/config/protocols/dex/aerodrome_cl.toml +2 -1
- package/config/protocols/dex/apeswap_bnb.toml +1 -1
- package/config/protocols/dex/babydogeswap_bnb.toml +1 -1
- package/config/protocols/dex/bakeryswap_bnb.toml +2 -2
- package/config/protocols/dex/biswap_bnb.toml +1 -1
- package/config/protocols/dex/bscswap_bnb.toml +1 -1
- package/config/protocols/dex/curve_hyperevm.toml +1 -1
- package/config/protocols/dex/fstswap_bnb.toml +1 -1
- package/config/protocols/dex/hybra.toml +4 -2
- package/config/protocols/dex/hyperswap.toml +1 -1
- package/config/protocols/dex/kittenswap.toml +1 -1
- package/config/protocols/dex/merchantmoe_mantle.toml +2 -1
- package/config/protocols/dex/nest.toml +6 -5
- package/config/protocols/dex/pancakeswap_v2_bnb.toml +1 -1
- package/config/protocols/dex/pancakeswap_v3_bnb.toml +2 -1
- package/config/protocols/dex/project_x.toml +1 -1
- package/config/protocols/dex/ramses_cl.toml +1 -1
- package/config/protocols/dex/ramses_hl.toml +1 -1
- package/config/protocols/dex/thena_v1_bnb.toml +2 -1
- package/config/protocols/dex/traderjoe_monad.toml +2 -1
- package/config/protocols/dex/uniswap_v2_monad.toml +2 -1
- package/config/protocols/dex/uniswap_v3_base.toml +2 -1
- package/config/protocols/dex/uniswap_v3_bnb.toml +3 -1
- package/config/protocols/dex/uniswap_v3_mantle.toml +2 -1
- package/config/protocols/dex/uniswap_v3_monad.toml +2 -1
- package/config/protocols/lending/felix_morpho.toml +16 -0
- package/config/protocols/lending/hyperlend.toml +1 -1
- package/config/protocols/lending/hypurrfi.toml +1 -1
- package/config/protocols/lending/kinza_bnb.toml +1 -1
- package/config/protocols/lending/morpho_blue_monad.toml +17 -0
- package/config/protocols/lending/venus_flux_bnb.toml +5 -1
- package/dist/index.js +1277 -246
- package/dist/index.js.map +1 -1
- package/dist/main.js +1282 -251
- package/dist/main.js.map +1 -1
- package/dist/mcp-server.js +799 -195
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
- package/skills/defi-cli/SKILL.md +17 -4
- package/skills/defi-cli/references/commands.md +2 -2
- package/skills/defi-cli/references/protocols.md +2 -2
package/dist/mcp-server.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
4
|
var __esm = (fn, res) => function __init() {
|
|
@@ -111,11 +110,15 @@ function buildTransfer(token, to, amount) {
|
|
|
111
110
|
gas_estimate: 65e3
|
|
112
111
|
};
|
|
113
112
|
}
|
|
114
|
-
function getProvider(rpcUrl) {
|
|
115
|
-
const
|
|
113
|
+
function getProvider(rpcUrl, chain) {
|
|
114
|
+
const key = chain ? `${rpcUrl}@${chain.id}` : rpcUrl;
|
|
115
|
+
const cached = providerCache.get(key);
|
|
116
116
|
if (cached) return cached;
|
|
117
|
-
const client = createPublicClient({
|
|
118
|
-
|
|
117
|
+
const client = createPublicClient({
|
|
118
|
+
transport: http(rpcUrl),
|
|
119
|
+
...chain ? { chain } : {}
|
|
120
|
+
});
|
|
121
|
+
providerCache.set(key, client);
|
|
119
122
|
return client;
|
|
120
123
|
}
|
|
121
124
|
function clearProviderCache() {
|
|
@@ -341,6 +344,28 @@ var init_dist = __esm({
|
|
|
341
344
|
const chainEnv = this.name.toUpperCase().replace(/ /g, "_") + "_RPC_URL";
|
|
342
345
|
return process.env[chainEnv] ?? this.rpc_url;
|
|
343
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Build a viem Chain object pinned to this config so wallet/public clients
|
|
349
|
+
* can sign with an explicit chainId rather than auto-fetching it from the
|
|
350
|
+
* RPC. SSOT 7.4: anchoring chainId at client-construction time defends
|
|
351
|
+
* against an MITM RPC that returns the wrong eth_chainId, and keeps
|
|
352
|
+
* offline signing safe against RPC drift.
|
|
353
|
+
*/
|
|
354
|
+
viemChain() {
|
|
355
|
+
const rpcUrl = this.effectiveRpcUrl();
|
|
356
|
+
return {
|
|
357
|
+
id: this.chain_id,
|
|
358
|
+
name: this.name,
|
|
359
|
+
nativeCurrency: {
|
|
360
|
+
name: this.native_token,
|
|
361
|
+
symbol: this.native_token,
|
|
362
|
+
decimals: 18
|
|
363
|
+
},
|
|
364
|
+
rpcUrls: { default: { http: [rpcUrl] } },
|
|
365
|
+
...this.explorer_url ? { blockExplorers: { default: { name: this.name, url: this.explorer_url } } } : {},
|
|
366
|
+
...this.multicall3 ? { contracts: { multicall3: { address: this.multicall3 } } } : {}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
344
369
|
};
|
|
345
370
|
ProtocolCategory = /* @__PURE__ */ ((ProtocolCategory2) => {
|
|
346
371
|
ProtocolCategory2["Dex"] = "dex";
|
|
@@ -532,13 +557,13 @@ __export(dist_exports2, {
|
|
|
532
557
|
import { encodeFunctionData as encodeFunctionData3, parseAbi as parseAbi3, createPublicClient as createPublicClient2, http as http2, decodeAbiParameters } from "viem";
|
|
533
558
|
import { encodeFunctionData as encodeFunctionData22, parseAbi as parseAbi22, createPublicClient as createPublicClient22, http as http22, decodeFunctionResult as decodeFunctionResult2, decodeAbiParameters as decodeAbiParameters2 } from "viem";
|
|
534
559
|
import { encodeFunctionData as encodeFunctionData32, parseAbi as parseAbi32, createPublicClient as createPublicClient3, http as http3, decodeAbiParameters as decodeAbiParameters3, concatHex, zeroAddress } from "viem";
|
|
535
|
-
import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4
|
|
560
|
+
import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4 } from "viem";
|
|
536
561
|
import { encodeFunctionData as encodeFunctionData5, parseAbi as parseAbi5 } from "viem";
|
|
537
562
|
import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, decodeAbiParameters as decodeAbiParameters4 } from "viem";
|
|
538
|
-
import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, createPublicClient as createPublicClient4, http as http4, zeroAddress as
|
|
539
|
-
import { createPublicClient as createPublicClient5, decodeFunctionResult as decodeFunctionResult22, encodeFunctionData as encodeFunctionData8, http as http5, parseAbi as parseAbi8, zeroAddress as
|
|
540
|
-
import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, zeroAddress as
|
|
541
|
-
import { createPublicClient as createPublicClient6, decodeFunctionResult as decodeFunctionResult3, encodeFunctionData as encodeFunctionData10, http as http6, parseAbi as parseAbi10, zeroAddress as
|
|
563
|
+
import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, createPublicClient as createPublicClient4, http as http4, zeroAddress as zeroAddress2 } from "viem";
|
|
564
|
+
import { createPublicClient as createPublicClient5, decodeFunctionResult as decodeFunctionResult22, encodeFunctionData as encodeFunctionData8, http as http5, parseAbi as parseAbi8, zeroAddress as zeroAddress3 } from "viem";
|
|
565
|
+
import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, zeroAddress as zeroAddress4 } from "viem";
|
|
566
|
+
import { createPublicClient as createPublicClient6, decodeFunctionResult as decodeFunctionResult3, encodeFunctionData as encodeFunctionData10, http as http6, parseAbi as parseAbi10, zeroAddress as zeroAddress5 } from "viem";
|
|
542
567
|
import { encodeFunctionData as encodeFunctionData11, parseAbi as parseAbi11, createPublicClient as createPublicClient7, http as http7 } from "viem";
|
|
543
568
|
import {
|
|
544
569
|
encodeFunctionData as encodeFunctionData12,
|
|
@@ -556,24 +581,24 @@ import {
|
|
|
556
581
|
keccak256,
|
|
557
582
|
parseAbi as parseAbi13,
|
|
558
583
|
decodeFunctionResult as decodeFunctionResult5,
|
|
559
|
-
zeroAddress as
|
|
584
|
+
zeroAddress as zeroAddress6
|
|
560
585
|
} from "viem";
|
|
561
|
-
import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData14, decodeFunctionResult as decodeFunctionResult6, zeroAddress as
|
|
562
|
-
import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData15, zeroAddress as
|
|
586
|
+
import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData14, decodeFunctionResult as decodeFunctionResult6, zeroAddress as zeroAddress7 } from "viem";
|
|
587
|
+
import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData15, zeroAddress as zeroAddress8 } from "viem";
|
|
563
588
|
import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi16 } from "viem";
|
|
564
589
|
import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16 } from "viem";
|
|
565
590
|
import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi18, encodeFunctionData as encodeFunctionData17 } from "viem";
|
|
566
591
|
import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi19, encodeFunctionData as encodeFunctionData18 } from "viem";
|
|
567
|
-
import { parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData19, decodeFunctionResult as decodeFunctionResult7, zeroAddress as
|
|
568
|
-
import { createPublicClient as
|
|
569
|
-
import { createPublicClient as
|
|
570
|
-
import { createPublicClient as
|
|
592
|
+
import { parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData19, decodeFunctionResult as decodeFunctionResult7, zeroAddress as zeroAddress9, createPublicClient as createPublicClient16, http as http16 } from "viem";
|
|
593
|
+
import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress10 } from "viem";
|
|
594
|
+
import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi222 } from "viem";
|
|
595
|
+
import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } from "viem";
|
|
571
596
|
import { parseAbi as parseAbi24, encodeFunctionData as encodeFunctionData222 } from "viem";
|
|
572
|
-
import { createPublicClient as
|
|
573
|
-
import { createPublicClient as
|
|
597
|
+
import { createPublicClient as createPublicClient20, http as http20, parseAbi as parseAbi25, encodeFunctionData as encodeFunctionData23, zeroAddress as zeroAddress11 } from "viem";
|
|
598
|
+
import { createPublicClient as createPublicClient21, http as http21, parseAbi as parseAbi26, encodeFunctionData as encodeFunctionData24, zeroAddress as zeroAddress12 } from "viem";
|
|
574
599
|
import { parseAbi as parseAbi27, encodeFunctionData as encodeFunctionData25 } from "viem";
|
|
575
600
|
import { parseAbi as parseAbi28, encodeFunctionData as encodeFunctionData26 } from "viem";
|
|
576
|
-
import { createPublicClient as
|
|
601
|
+
import { createPublicClient as createPublicClient222, http as http222, parseAbi as parseAbi29 } from "viem";
|
|
577
602
|
function pctToTickDelta(pct) {
|
|
578
603
|
return Math.round(Math.log(1 + pct / 100) / Math.log(1.0001));
|
|
579
604
|
}
|
|
@@ -827,15 +852,6 @@ function u256ToF642(v) {
|
|
|
827
852
|
if (v > MAX_U128) return Infinity;
|
|
828
853
|
return Number(v);
|
|
829
854
|
}
|
|
830
|
-
function defaultMarketParams(loanToken = zeroAddress10) {
|
|
831
|
-
return {
|
|
832
|
-
loanToken,
|
|
833
|
-
collateralToken: zeroAddress10,
|
|
834
|
-
oracle: zeroAddress10,
|
|
835
|
-
irm: zeroAddress10,
|
|
836
|
-
lltv: 0n
|
|
837
|
-
};
|
|
838
|
-
}
|
|
839
855
|
function decodeMarket(data) {
|
|
840
856
|
if (!data) return null;
|
|
841
857
|
try {
|
|
@@ -1068,7 +1084,7 @@ function createKittenSwapFarming(entry, rpcUrl) {
|
|
|
1068
1084
|
const bonusRewardToken = entry.contracts?.["bonus_reward_token"];
|
|
1069
1085
|
return new KittenSwapFarmingAdapter(entry.name, farmingCenter, eternalFarming, positionManager, rpcUrl, factory, rewardToken, bonusRewardToken);
|
|
1070
1086
|
}
|
|
1071
|
-
var DEFAULT_FEE, swapRouterAbi, quoterAbi, ramsesQuoterAbi, positionManagerAbi, slipstreamMintAbi, UniswapV3Adapter, abi, lbQuoterAbi, UniswapV2Adapter, abi2, algebraQuoterAbi, algebraSingleQuoterAbi, algebraIntegralPmAbi, algebraV2PmAbi, algebraSharedPmAbi, AlgebraV3Adapter, abi3, BalancerV3Adapter, poolAbi, CurveStableSwapAdapter, abi4, abiV2, SolidlyAdapter, thenaPmAbi, thenaRouterAbi, thenaPoolAbi, thenaFactoryAbi, ThenaCLAdapter, _addressDecodeAbi, _symbolDecodeAbi, gaugeManagerAbi, gaugeCLAbi, nfpmAbi, veAbi, voterAbi, HybraGaugeAdapter, abi5, WooFiAdapter, gaugeAbi, veAbi2, voterAbi2, _addressDecodeAbi2, _symbolDecodeAbi2, _boolDecodeAbi, HYPEREVM_TOKENS, CL_TICK_SPACINGS, SolidlyGaugeAdapter, masterchefAbi, MasterChefAdapter, lbRouterAbi, lbFactoryAbi, lbPairAbi, lbRewarderAbi, masterChefAbi, veMoeAbi, lbPairBinAbi, lbQuoterAbi2, erc20Abi2, _addressAbi, _uint256Abi, _boolAbi, _rangeAbi, _binAbi, _uint256ArrayAbi, MerchantMoeLBAdapter, KITTEN_TOKEN, WHYPE_TOKEN, MAX_NONCE_SCAN, HYPEREVM_TOKENS2, farmingCenterAbi, positionManagerAbi2, eternalFarmingAbi, algebraFactoryAbi, _addressDecodeAbi3, nonceCache, KittenSwapFarmingAdapter, DEFAULT_BASE_URL, FALLBACK_BASE_URL, NEST_TOKEN, NEST_DECIMALS, NestOffChainAdapter, POOL_ABI, ERC20_ABI, INCENTIVES_ABI, REWARDS_CONTROLLER_ABI, POOL_PROVIDER_ABI, ADDRESSES_PROVIDER_ABI, ORACLE_ABI, ERC20_DECIMALS_ABI, AaveV3Adapter, POOL_ABI2, ERC20_ABI2, AaveV2Adapter, ORACLE_ABI2, AaveOracleAdapter, CTOKEN_ABI, BSC_BLOCKS_PER_YEAR, CompoundV2Adapter, COMET_ABI, SECONDS_PER_YEAR, CompoundV3Adapter, EULER_VAULT_ABI, SECONDS_PER_YEAR2, EulerV2Adapter, MORPHO_ABI, META_MORPHO_ABI, ERC4626_ABI, MAX_UINT256, IRM_ABI, SECONDS_PER_YEAR3, MorphoBlueAdapter, BORROWER_OPS_ABI, TROVE_MANAGER_ABI, HINT_HELPERS_ABI, SORTED_TROVES_ABI, FelixCdpAdapter, PRICE_FEED_ABI, FelixOracleAdapter, ERC4626_ABI2, ERC4626VaultAdapter, GENERIC_LST_ABI, GenericLstAdapter, STHYPE_ABI, ERC20_ABI3, StHypeAdapter, KINETIQ_ABI, ORACLE_ABI3, WHYPE, HYPERLEND_ORACLE, KinetiqAdapter, PendleAdapter, GenericYieldAdapter, HLP_ABI, HlpVaultAdapter, GenericDerivativesAdapter, RYSK_ABI, RyskAdapter, GenericOptionsAdapter, ERC721_ABI, ERC721Adapter, DexSpotPrice;
|
|
1087
|
+
var DEFAULT_FEE, swapRouterAbi, quoterAbi, ramsesQuoterAbi, positionManagerAbi, slipstreamMintAbi, ramsesMintAbi, UniswapV3Adapter, abi, lbQuoterAbi, UniswapV2Adapter, abi2, algebraQuoterAbi, algebraSingleQuoterAbi, algebraIntegralPmAbi, algebraV2PmAbi, algebraSharedPmAbi, AlgebraV3Adapter, abi3, BalancerV3Adapter, poolAbi, CurveStableSwapAdapter, abi4, abiV2, SolidlyAdapter, thenaPmAbi, thenaRouterAbi, thenaPoolAbi, thenaFactoryAbi, ThenaCLAdapter, _addressDecodeAbi, _symbolDecodeAbi, gaugeManagerAbi, gaugeCLAbi, nfpmAbi, veAbi, voterAbi, HybraGaugeAdapter, abi5, WooFiAdapter, gaugeAbi, veAbi2, voterAbi2, _addressDecodeAbi2, _symbolDecodeAbi2, _boolDecodeAbi, HYPEREVM_TOKENS, CL_TICK_SPACINGS, SolidlyGaugeAdapter, masterchefAbi, MasterChefAdapter, lbRouterAbi, lbFactoryAbi, lbPairAbi, lbRewarderAbi, masterChefAbi, veMoeAbi, lbPairBinAbi, lbQuoterAbi2, erc20Abi2, _addressAbi, _uint256Abi, _boolAbi, _rangeAbi, _binAbi, _uint256ArrayAbi, MerchantMoeLBAdapter, KITTEN_TOKEN, WHYPE_TOKEN, MAX_NONCE_SCAN, HYPEREVM_TOKENS2, farmingCenterAbi, positionManagerAbi2, eternalFarmingAbi, algebraFactoryAbi, _addressDecodeAbi3, nonceCache, KittenSwapFarmingAdapter, DEFAULT_BASE_URL, FALLBACK_BASE_URL, NEST_TOKEN, NEST_DECIMALS, NestOffChainAdapter, POOL_ABI, ERC20_ABI, INCENTIVES_ABI, REWARDS_CONTROLLER_ABI, POOL_PROVIDER_ABI, ADDRESSES_PROVIDER_ABI, ORACLE_ABI, ERC20_DECIMALS_ABI, AaveV3Adapter, POOL_ABI2, ERC20_ABI2, AaveV2Adapter, ORACLE_ABI2, AaveOracleAdapter, CTOKEN_ABI, NATIVE_CTOKEN_ABI, COMPTROLLER_ABI, NATIVE_SENTINEL, BSC_BLOCKS_PER_YEAR, CompoundV2Adapter, COMET_ABI, SECONDS_PER_YEAR, CompoundV3Adapter, EULER_VAULT_ABI, SECONDS_PER_YEAR2, EulerV2Adapter, MORPHO_ABI, META_MORPHO_ABI, ERC4626_ABI, MAX_UINT256, IRM_ABI, SECONDS_PER_YEAR3, MorphoBlueAdapter, BORROWER_OPS_ABI, TROVE_MANAGER_ABI, HINT_HELPERS_ABI, SORTED_TROVES_ABI, FelixCdpAdapter, PRICE_FEED_ABI, FelixOracleAdapter, ERC4626_ABI2, ERC4626VaultAdapter, GENERIC_LST_ABI, GenericLstAdapter, STHYPE_ABI, ERC20_ABI3, StHypeAdapter, KINETIQ_ABI, ORACLE_ABI3, WHYPE, HYPERLEND_ORACLE, KinetiqAdapter, PendleAdapter, GenericYieldAdapter, HLP_ABI, HlpVaultAdapter, GenericDerivativesAdapter, RYSK_ABI, RyskAdapter, GenericOptionsAdapter, ERC721_ABI, ERC721Adapter, DexSpotPrice;
|
|
1072
1088
|
var init_dist2 = __esm({
|
|
1073
1089
|
"../defi-protocols/dist/index.js"() {
|
|
1074
1090
|
"use strict";
|
|
@@ -1136,6 +1152,10 @@ var init_dist2 = __esm({
|
|
|
1136
1152
|
"struct SlipstreamMintParams { address token0; address token1; int24 tickSpacing; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; uint160 sqrtPriceX96; }",
|
|
1137
1153
|
"function mint(SlipstreamMintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
|
|
1138
1154
|
]);
|
|
1155
|
+
ramsesMintAbi = parseAbi3([
|
|
1156
|
+
"struct RamsesMintParams { address token0; address token1; int24 tickSpacing; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; }",
|
|
1157
|
+
"function mint(RamsesMintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
|
|
1158
|
+
]);
|
|
1139
1159
|
UniswapV3Adapter = class {
|
|
1140
1160
|
protocolName;
|
|
1141
1161
|
router;
|
|
@@ -1145,6 +1165,7 @@ var init_dist2 = __esm({
|
|
|
1145
1165
|
fee;
|
|
1146
1166
|
rpcUrl;
|
|
1147
1167
|
useTickSpacingQuoter;
|
|
1168
|
+
clStyle;
|
|
1148
1169
|
constructor(entry, rpcUrl) {
|
|
1149
1170
|
this.protocolName = entry.name;
|
|
1150
1171
|
const router = entry.contracts?.["router"];
|
|
@@ -1157,6 +1178,7 @@ var init_dist2 = __esm({
|
|
|
1157
1178
|
this.factory = entry.contracts?.["factory"];
|
|
1158
1179
|
this.fee = DEFAULT_FEE;
|
|
1159
1180
|
this.rpcUrl = rpcUrl;
|
|
1181
|
+
this.clStyle = entry.cl_style;
|
|
1160
1182
|
this.useTickSpacingQuoter = entry.cl_style === "slipstream" || entry.cl_style === "ramses" || entry.contracts?.["pool_deployer"] !== void 0 || entry.contracts?.["gauge_factory"] !== void 0;
|
|
1161
1183
|
}
|
|
1162
1184
|
name() {
|
|
@@ -1164,7 +1186,15 @@ var init_dist2 = __esm({
|
|
|
1164
1186
|
}
|
|
1165
1187
|
async buildSwap(params) {
|
|
1166
1188
|
const deadline = BigInt(params.deadline ?? 18446744073709551615n);
|
|
1167
|
-
const amountOutMinimum =
|
|
1189
|
+
const amountOutMinimum = params.amount_out_min ?? applyMinSlippage(
|
|
1190
|
+
params.slippage,
|
|
1191
|
+
(await this.quote({
|
|
1192
|
+
protocol: this.protocolName,
|
|
1193
|
+
token_in: params.token_in,
|
|
1194
|
+
token_out: params.token_out,
|
|
1195
|
+
amount_in: params.amount_in
|
|
1196
|
+
})).amount_out
|
|
1197
|
+
);
|
|
1168
1198
|
const data = encodeFunctionData3({
|
|
1169
1199
|
abi: swapRouterAbi,
|
|
1170
1200
|
functionName: "exactInputSingle",
|
|
@@ -1330,31 +1360,37 @@ var init_dist2 = __esm({
|
|
|
1330
1360
|
if (!pm) {
|
|
1331
1361
|
throw new DefiError("CONTRACT_ERROR", "Position manager address not configured");
|
|
1332
1362
|
}
|
|
1333
|
-
const
|
|
1363
|
+
const isAFirst = params.token_a.toLowerCase() < params.token_b.toLowerCase();
|
|
1364
|
+
const [token0, token1, rawAmount0, rawAmount1] = isAFirst ? [params.token_a, params.token_b, params.amount_a, params.amount_b] : [params.token_b, params.token_a, params.amount_b, params.amount_a];
|
|
1334
1365
|
const amount0 = rawAmount0 === 0n && rawAmount1 > 0n ? 1n : rawAmount0;
|
|
1335
1366
|
const amount1 = rawAmount1 === 0n && rawAmount0 > 0n ? 1n : rawAmount1;
|
|
1367
|
+
const slippage = params.slippage ?? defaultSwapSlippage();
|
|
1368
|
+
const minA = params.amount_a_min ?? applyMinSlippage(slippage, params.amount_a);
|
|
1369
|
+
const minB = params.amount_b_min ?? applyMinSlippage(slippage, params.amount_b);
|
|
1370
|
+
const [amount0Min, amount1Min] = isAFirst ? [minA, minB] : [minB, minA];
|
|
1336
1371
|
let thirdField = this.fee;
|
|
1337
1372
|
let tickLower = -887220;
|
|
1338
1373
|
let tickUpper = 887220;
|
|
1339
1374
|
if (params.pool && this.rpcUrl) {
|
|
1340
1375
|
const poolAbi2 = parseAbi3([
|
|
1341
1376
|
"function fee() view returns (uint24)",
|
|
1342
|
-
"function tickSpacing() view returns (int24)"
|
|
1343
|
-
"function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16, uint16, uint16, bool)"
|
|
1377
|
+
"function tickSpacing() view returns (int24)"
|
|
1344
1378
|
]);
|
|
1345
1379
|
const client = createPublicClient2({ transport: http2(this.rpcUrl) });
|
|
1346
|
-
const [poolFee, poolTs,
|
|
1380
|
+
const [poolFee, poolTs, slot0Raw] = await Promise.all([
|
|
1347
1381
|
client.readContract({ address: params.pool, abi: poolAbi2, functionName: "fee" }).catch(() => null),
|
|
1348
1382
|
client.readContract({ address: params.pool, abi: poolAbi2, functionName: "tickSpacing" }).catch(() => null),
|
|
1349
|
-
client.
|
|
1383
|
+
client.call({ to: params.pool, data: "0x3850c7bd" }).then((r) => r.data ?? null).catch(() => null)
|
|
1350
1384
|
]);
|
|
1351
1385
|
if (this.useTickSpacingQuoter && poolTs !== null) {
|
|
1352
1386
|
thirdField = poolTs;
|
|
1353
1387
|
} else if (poolFee !== null) {
|
|
1354
1388
|
thirdField = poolFee;
|
|
1355
1389
|
}
|
|
1356
|
-
if (params.range_pct !== void 0 &&
|
|
1357
|
-
const
|
|
1390
|
+
if (params.range_pct !== void 0 && slot0Raw && poolTs !== null) {
|
|
1391
|
+
const tickWord = slot0Raw.slice(2 + 64, 2 + 128);
|
|
1392
|
+
const tickU = BigInt("0x" + tickWord);
|
|
1393
|
+
const currentTick = tickU >= 1n << 255n ? Number(tickU - (1n << 256n)) : Number(tickU);
|
|
1358
1394
|
const rangeTicks = Math.floor(params.range_pct * 100);
|
|
1359
1395
|
tickLower = Math.floor((currentTick - rangeTicks) / poolTs) * poolTs;
|
|
1360
1396
|
tickUpper = Math.ceil((currentTick + rangeTicks) / poolTs) * poolTs;
|
|
@@ -1362,7 +1398,25 @@ var init_dist2 = __esm({
|
|
|
1362
1398
|
}
|
|
1363
1399
|
if (params.tick_lower !== void 0) tickLower = params.tick_lower;
|
|
1364
1400
|
if (params.tick_upper !== void 0) tickUpper = params.tick_upper;
|
|
1365
|
-
const data = this.
|
|
1401
|
+
const data = this.clStyle === "ramses" ? encodeFunctionData3({
|
|
1402
|
+
abi: ramsesMintAbi,
|
|
1403
|
+
functionName: "mint",
|
|
1404
|
+
args: [
|
|
1405
|
+
{
|
|
1406
|
+
token0,
|
|
1407
|
+
token1,
|
|
1408
|
+
tickSpacing: thirdField,
|
|
1409
|
+
tickLower,
|
|
1410
|
+
tickUpper,
|
|
1411
|
+
amount0Desired: amount0,
|
|
1412
|
+
amount1Desired: amount1,
|
|
1413
|
+
amount0Min,
|
|
1414
|
+
amount1Min,
|
|
1415
|
+
recipient: params.recipient,
|
|
1416
|
+
deadline: BigInt("18446744073709551615")
|
|
1417
|
+
}
|
|
1418
|
+
]
|
|
1419
|
+
}) : this.useTickSpacingQuoter ? encodeFunctionData3({
|
|
1366
1420
|
abi: slipstreamMintAbi,
|
|
1367
1421
|
functionName: "mint",
|
|
1368
1422
|
args: [
|
|
@@ -1374,8 +1428,8 @@ var init_dist2 = __esm({
|
|
|
1374
1428
|
tickUpper,
|
|
1375
1429
|
amount0Desired: amount0,
|
|
1376
1430
|
amount1Desired: amount1,
|
|
1377
|
-
amount0Min
|
|
1378
|
-
amount1Min
|
|
1431
|
+
amount0Min,
|
|
1432
|
+
amount1Min,
|
|
1379
1433
|
recipient: params.recipient,
|
|
1380
1434
|
deadline: BigInt("18446744073709551615"),
|
|
1381
1435
|
sqrtPriceX96: 0n
|
|
@@ -1393,8 +1447,8 @@ var init_dist2 = __esm({
|
|
|
1393
1447
|
tickUpper,
|
|
1394
1448
|
amount0Desired: amount0,
|
|
1395
1449
|
amount1Desired: amount1,
|
|
1396
|
-
amount0Min
|
|
1397
|
-
amount1Min
|
|
1450
|
+
amount0Min,
|
|
1451
|
+
amount1Min,
|
|
1398
1452
|
recipient: params.recipient,
|
|
1399
1453
|
deadline: BigInt("18446744073709551615")
|
|
1400
1454
|
}
|
|
@@ -1428,10 +1482,17 @@ var init_dist2 = __esm({
|
|
|
1428
1482
|
const liquidity = params.liquidity;
|
|
1429
1483
|
const MAX_UINT128 = (1n << 128n) - 1n;
|
|
1430
1484
|
const deadline = BigInt("18446744073709551615");
|
|
1485
|
+
if (params.amount_a_min === void 0 || params.amount_b_min === void 0) {
|
|
1486
|
+
throw DefiError.invalidParam(
|
|
1487
|
+
`[${this.protocolName}] V3 remove_liquidity requires amount_a_min and amount_b_min for slippage protection (SSOT 7.3). Caller must compute expected token outputs from the pool state and apply a slippage tolerance before calling buildRemoveLiquidity.`
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
const isAFirst = params.token_a.toLowerCase() < params.token_b.toLowerCase();
|
|
1491
|
+
const [amount0Min, amount1Min] = isAFirst ? [params.amount_a_min, params.amount_b_min] : [params.amount_b_min, params.amount_a_min];
|
|
1431
1492
|
const decreaseData = encodeFunctionData3({
|
|
1432
1493
|
abi: positionManagerAbi,
|
|
1433
1494
|
functionName: "decreaseLiquidity",
|
|
1434
|
-
args: [{ tokenId, liquidity, amount0Min
|
|
1495
|
+
args: [{ tokenId, liquidity, amount0Min, amount1Min, deadline }]
|
|
1435
1496
|
});
|
|
1436
1497
|
const collectData = encodeFunctionData3({
|
|
1437
1498
|
abi: positionManagerAbi,
|
|
@@ -1729,7 +1790,13 @@ var init_dist2 = __esm({
|
|
|
1729
1790
|
to: this.router,
|
|
1730
1791
|
data,
|
|
1731
1792
|
value: 0n,
|
|
1732
|
-
gas_estimate: 25e4
|
|
1793
|
+
gas_estimate: 25e4,
|
|
1794
|
+
// Same LP-approval requirement as Solidly forks: the V2 router pulls the
|
|
1795
|
+
// LP pair token via transferFrom and reverts at gas ~42k otherwise.
|
|
1796
|
+
// Caller passes --pool so we can target the pair contract for approval.
|
|
1797
|
+
// Discovered live on Uniswap V2 Monad WMON/AUSD 2026-05-08
|
|
1798
|
+
// (failed tx 0x2268659a…09ae → recovered with this fix).
|
|
1799
|
+
...params.pool ? { approvals: [{ token: params.pool, spender: this.router, amount: params.liquidity }] } : {}
|
|
1733
1800
|
};
|
|
1734
1801
|
}
|
|
1735
1802
|
};
|
|
@@ -1784,7 +1851,15 @@ var init_dist2 = __esm({
|
|
|
1784
1851
|
}
|
|
1785
1852
|
async buildSwap(params) {
|
|
1786
1853
|
const deadline = BigInt(params.deadline ?? 18446744073709551615n);
|
|
1787
|
-
const amountOutMinimum =
|
|
1854
|
+
const amountOutMinimum = params.amount_out_min ?? applyMinSlippage(
|
|
1855
|
+
params.slippage,
|
|
1856
|
+
(await this.quote({
|
|
1857
|
+
protocol: this.protocolName,
|
|
1858
|
+
token_in: params.token_in,
|
|
1859
|
+
token_out: params.token_out,
|
|
1860
|
+
amount_in: params.amount_in
|
|
1861
|
+
})).amount_out
|
|
1862
|
+
);
|
|
1788
1863
|
const data = encodeFunctionData32({
|
|
1789
1864
|
abi: abi2,
|
|
1790
1865
|
functionName: "exactInputSingle",
|
|
@@ -1898,7 +1973,12 @@ var init_dist2 = __esm({
|
|
|
1898
1973
|
if (!pm) {
|
|
1899
1974
|
throw new DefiError("CONTRACT_ERROR", "Position manager address not configured");
|
|
1900
1975
|
}
|
|
1901
|
-
const
|
|
1976
|
+
const isAFirst = params.token_a.toLowerCase() < params.token_b.toLowerCase();
|
|
1977
|
+
const [token0, token1, rawAmount0, rawAmount1] = isAFirst ? [params.token_a, params.token_b, params.amount_a, params.amount_b] : [params.token_b, params.token_a, params.amount_b, params.amount_a];
|
|
1978
|
+
const slippage = params.slippage ?? defaultSwapSlippage();
|
|
1979
|
+
const minA = params.amount_a_min ?? applyMinSlippage(slippage, params.amount_a);
|
|
1980
|
+
const minB = params.amount_b_min ?? applyMinSlippage(slippage, params.amount_b);
|
|
1981
|
+
const [amount0Min, amount1Min] = isAFirst ? [minA, minB] : [minB, minA];
|
|
1902
1982
|
let tickLower = params.tick_lower ?? -887220;
|
|
1903
1983
|
let tickUpper = params.tick_upper ?? 887220;
|
|
1904
1984
|
const isSingleSide = rawAmount0 === 0n || rawAmount1 === 0n;
|
|
@@ -1935,11 +2015,11 @@ var init_dist2 = __esm({
|
|
|
1935
2015
|
const data = this.useSingleQuoter ? encodeFunctionData32({
|
|
1936
2016
|
abi: algebraV2PmAbi,
|
|
1937
2017
|
functionName: "mint",
|
|
1938
|
-
args: [{ token0, token1, tickLower, tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min
|
|
2018
|
+
args: [{ token0, token1, tickLower, tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min, amount1Min, recipient: params.recipient, deadline: BigInt("18446744073709551615") }]
|
|
1939
2019
|
}) : encodeFunctionData32({
|
|
1940
2020
|
abi: algebraIntegralPmAbi,
|
|
1941
2021
|
functionName: "mint",
|
|
1942
|
-
args: [{ token0, token1, deployer: zeroAddress, tickLower, tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min
|
|
2022
|
+
args: [{ token0, token1, deployer: zeroAddress, tickLower, tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min, amount1Min, recipient: params.recipient, deadline: BigInt("18446744073709551615") }]
|
|
1943
2023
|
});
|
|
1944
2024
|
const approvals = [];
|
|
1945
2025
|
if (amount0 > 0n) approvals.push({ token: token0, spender: pm, amount: amount0 });
|
|
@@ -1957,12 +2037,19 @@ var init_dist2 = __esm({
|
|
|
1957
2037
|
const pm = this.positionManager;
|
|
1958
2038
|
if (!pm) throw DefiError.contractError(`[${this.protocolName}] Missing 'position_manager'`);
|
|
1959
2039
|
if (!params.token_id) throw DefiError.invalidParam(`[${this.protocolName}] V3 remove_liquidity requires --token-id`);
|
|
2040
|
+
if (params.amount_a_min === void 0 || params.amount_b_min === void 0) {
|
|
2041
|
+
throw DefiError.invalidParam(
|
|
2042
|
+
`[${this.protocolName}] remove_liquidity requires amount_a_min and amount_b_min for slippage protection (SSOT 7.3). Compute expected outputs from positions(tokenId) + pool.globalState off-chain and apply tolerance.`
|
|
2043
|
+
);
|
|
2044
|
+
}
|
|
2045
|
+
const isAFirst = params.token_a.toLowerCase() < params.token_b.toLowerCase();
|
|
2046
|
+
const [amount0Min, amount1Min] = isAFirst ? [params.amount_a_min, params.amount_b_min] : [params.amount_b_min, params.amount_a_min];
|
|
1960
2047
|
const MAX_UINT128 = (1n << 128n) - 1n;
|
|
1961
2048
|
const deadline = BigInt("18446744073709551615");
|
|
1962
2049
|
const decreaseData = encodeFunctionData32({
|
|
1963
2050
|
abi: algebraSharedPmAbi,
|
|
1964
2051
|
functionName: "decreaseLiquidity",
|
|
1965
|
-
args: [{ tokenId: params.token_id, liquidity: params.liquidity, amount0Min
|
|
2052
|
+
args: [{ tokenId: params.token_id, liquidity: params.liquidity, amount0Min, amount1Min, deadline }]
|
|
1966
2053
|
});
|
|
1967
2054
|
const collectData = encodeFunctionData32({
|
|
1968
2055
|
abi: algebraSharedPmAbi,
|
|
@@ -1989,6 +2076,7 @@ var init_dist2 = __esm({
|
|
|
1989
2076
|
BalancerV3Adapter = class {
|
|
1990
2077
|
protocolName;
|
|
1991
2078
|
router;
|
|
2079
|
+
pool;
|
|
1992
2080
|
constructor(entry, _rpcUrl) {
|
|
1993
2081
|
this.protocolName = entry.name;
|
|
1994
2082
|
const router = entry.contracts?.["router"];
|
|
@@ -1996,19 +2084,29 @@ var init_dist2 = __esm({
|
|
|
1996
2084
|
throw new DefiError("CONTRACT_ERROR", "Missing 'router' contract");
|
|
1997
2085
|
}
|
|
1998
2086
|
this.router = router;
|
|
2087
|
+
this.pool = entry.contracts?.["pool"];
|
|
1999
2088
|
}
|
|
2000
2089
|
name() {
|
|
2001
2090
|
return this.protocolName;
|
|
2002
2091
|
}
|
|
2003
2092
|
async buildSwap(params) {
|
|
2004
|
-
|
|
2093
|
+
if (params.amount_out_min === void 0) {
|
|
2094
|
+
throw DefiError.invalidParam(
|
|
2095
|
+
`[${this.protocolName}] buildSwap requires amount_out_min for slippage protection (SSOT 7.3) \u2014 Balancer V3 has no on-chain quoter wired in this adapter. Compute the floor off-chain (e.g. via the Vault's static-call simulation) and pass it explicitly.`
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
2098
|
+
if (!this.pool) {
|
|
2099
|
+
throw DefiError.invalidParam(
|
|
2100
|
+
`[${this.protocolName}] buildSwap requires a pool address. Register the pool under [protocol.contracts] as \`pool = "0x..."\` in the protocol's TOML config. Multi-pool routing is intentionally not implemented in this adapter \u2014 for that, quote against the Balancer V3 BatchRouter off-chain and route via a different surface.`
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2103
|
+
const minAmountOut = params.amount_out_min;
|
|
2005
2104
|
const deadline = BigInt(params.deadline ?? 18446744073709551615n);
|
|
2006
2105
|
const data = encodeFunctionData4({
|
|
2007
2106
|
abi: abi3,
|
|
2008
2107
|
functionName: "swapSingleTokenExactIn",
|
|
2009
2108
|
args: [
|
|
2010
|
-
|
|
2011
|
-
// TODO: resolve pool from registry
|
|
2109
|
+
this.pool,
|
|
2012
2110
|
params.token_in,
|
|
2013
2111
|
params.token_out,
|
|
2014
2112
|
params.amount_in,
|
|
@@ -2019,7 +2117,7 @@ var init_dist2 = __esm({
|
|
|
2019
2117
|
]
|
|
2020
2118
|
});
|
|
2021
2119
|
return {
|
|
2022
|
-
description: `[${this.protocolName}] Swap ${params.amount_in} via Balancer V3`,
|
|
2120
|
+
description: `[${this.protocolName}] Swap ${params.amount_in} via Balancer V3 pool ${this.pool}`,
|
|
2023
2121
|
to: this.router,
|
|
2024
2122
|
data,
|
|
2025
2123
|
value: 0n,
|
|
@@ -2039,8 +2137,8 @@ var init_dist2 = __esm({
|
|
|
2039
2137
|
poolAbi = parseAbi5([
|
|
2040
2138
|
"function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (uint256)",
|
|
2041
2139
|
"function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256)",
|
|
2042
|
-
"function add_liquidity(uint256[
|
|
2043
|
-
"function remove_liquidity(uint256 amount, uint256[
|
|
2140
|
+
"function add_liquidity(uint256[] amounts, uint256 min_mint_amount) external returns (uint256)",
|
|
2141
|
+
"function remove_liquidity(uint256 amount, uint256[] min_amounts) external returns (uint256[])"
|
|
2044
2142
|
]);
|
|
2045
2143
|
CurveStableSwapAdapter = class {
|
|
2046
2144
|
protocolName;
|
|
@@ -2075,17 +2173,22 @@ var init_dist2 = __esm({
|
|
|
2075
2173
|
throw DefiError.unsupported(`[${this.protocolName}] quote requires RPC connection`);
|
|
2076
2174
|
}
|
|
2077
2175
|
async buildAddLiquidity(params) {
|
|
2176
|
+
if (!params.pool) {
|
|
2177
|
+
throw DefiError.invalidParam(
|
|
2178
|
+
`[${this.protocolName}] Curve add_liquidity needs --pool <address>. The router does not proxy this call; it lives on the pool itself.`
|
|
2179
|
+
);
|
|
2180
|
+
}
|
|
2078
2181
|
const data = encodeFunctionData5({
|
|
2079
2182
|
abi: poolAbi,
|
|
2080
2183
|
functionName: "add_liquidity",
|
|
2081
2184
|
args: [[params.amount_a, params.amount_b], 0n]
|
|
2082
2185
|
});
|
|
2083
2186
|
const approvals = [];
|
|
2084
|
-
if (params.amount_a > 0n) approvals.push({ token: params.token_a, spender:
|
|
2085
|
-
if (params.amount_b > 0n) approvals.push({ token: params.token_b, spender:
|
|
2187
|
+
if (params.amount_a > 0n) approvals.push({ token: params.token_a, spender: params.pool, amount: params.amount_a });
|
|
2188
|
+
if (params.amount_b > 0n) approvals.push({ token: params.token_b, spender: params.pool, amount: params.amount_b });
|
|
2086
2189
|
return {
|
|
2087
|
-
description: `[${this.protocolName}] Curve add liquidity`,
|
|
2088
|
-
to:
|
|
2190
|
+
description: `[${this.protocolName}] Curve add liquidity to ${params.pool}`,
|
|
2191
|
+
to: params.pool,
|
|
2089
2192
|
data,
|
|
2090
2193
|
value: 0n,
|
|
2091
2194
|
gas_estimate: 4e5,
|
|
@@ -2093,14 +2196,19 @@ var init_dist2 = __esm({
|
|
|
2093
2196
|
};
|
|
2094
2197
|
}
|
|
2095
2198
|
async buildRemoveLiquidity(params) {
|
|
2199
|
+
if (!params.pool) {
|
|
2200
|
+
throw DefiError.invalidParam(
|
|
2201
|
+
`[${this.protocolName}] Curve remove_liquidity needs --pool <address>. The router does not proxy this call.`
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2096
2204
|
const data = encodeFunctionData5({
|
|
2097
2205
|
abi: poolAbi,
|
|
2098
2206
|
functionName: "remove_liquidity",
|
|
2099
2207
|
args: [params.liquidity, [0n, 0n]]
|
|
2100
2208
|
});
|
|
2101
2209
|
return {
|
|
2102
|
-
description: `[${this.protocolName}] Curve remove liquidity`,
|
|
2103
|
-
to:
|
|
2210
|
+
description: `[${this.protocolName}] Curve remove liquidity from ${params.pool}`,
|
|
2211
|
+
to: params.pool,
|
|
2104
2212
|
data,
|
|
2105
2213
|
value: 0n,
|
|
2106
2214
|
gas_estimate: 35e4
|
|
@@ -2266,7 +2374,12 @@ var init_dist2 = __esm({
|
|
|
2266
2374
|
to: this.router,
|
|
2267
2375
|
data,
|
|
2268
2376
|
value: 0n,
|
|
2269
|
-
gas_estimate: 3e5
|
|
2377
|
+
gas_estimate: 3e5,
|
|
2378
|
+
// The router pulls the LP token via transferFrom; without this approval
|
|
2379
|
+
// the tx reverts at gas ~42k. Caller must pass --pool so we know which
|
|
2380
|
+
// LP pair to approve. Discovered live on Aerodrome USDC/USDT 2026-05-08
|
|
2381
|
+
// (failed tx 0x6d052e0a…3298 → recovered with manual approve 0xa126fc3a).
|
|
2382
|
+
...params.pool ? { approvals: [{ token: params.pool, spender: this.router, amount: params.liquidity }] } : {}
|
|
2270
2383
|
};
|
|
2271
2384
|
}
|
|
2272
2385
|
};
|
|
@@ -2313,6 +2426,11 @@ var init_dist2 = __esm({
|
|
|
2313
2426
|
return this.protocolName;
|
|
2314
2427
|
}
|
|
2315
2428
|
async buildSwap(params) {
|
|
2429
|
+
if (params.amount_out_min === void 0) {
|
|
2430
|
+
throw DefiError.invalidParam(
|
|
2431
|
+
`[${this.protocolName}] buildSwap requires amount_out_min for slippage protection (SSOT 7.3) \u2014 Thena CL has no on-chain quoter. Compute the floor off-chain (e.g. via the router's static-call simulation) and pass it explicitly.`
|
|
2432
|
+
);
|
|
2433
|
+
}
|
|
2316
2434
|
const data = encodeFunctionData7({
|
|
2317
2435
|
abi: thenaRouterAbi,
|
|
2318
2436
|
functionName: "exactInputSingle",
|
|
@@ -2323,7 +2441,7 @@ var init_dist2 = __esm({
|
|
|
2323
2441
|
recipient: params.recipient,
|
|
2324
2442
|
deadline: BigInt(params.deadline ?? 18446744073709551615n),
|
|
2325
2443
|
amountIn: params.amount_in,
|
|
2326
|
-
amountOutMinimum:
|
|
2444
|
+
amountOutMinimum: params.amount_out_min,
|
|
2327
2445
|
sqrtPriceLimitX96: 0n
|
|
2328
2446
|
}]
|
|
2329
2447
|
});
|
|
@@ -2343,7 +2461,12 @@ var init_dist2 = __esm({
|
|
|
2343
2461
|
const pm = this.positionManager;
|
|
2344
2462
|
if (!pm) throw new DefiError("CONTRACT_ERROR", "Position manager not configured");
|
|
2345
2463
|
if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required");
|
|
2346
|
-
const
|
|
2464
|
+
const isAFirst = params.token_a.toLowerCase() < params.token_b.toLowerCase();
|
|
2465
|
+
const [token0, token1, rawAmount0, rawAmount1] = isAFirst ? [params.token_a, params.token_b, params.amount_a, params.amount_b] : [params.token_b, params.token_a, params.amount_b, params.amount_a];
|
|
2466
|
+
const slippage = params.slippage ?? defaultSwapSlippage();
|
|
2467
|
+
const minA = params.amount_a_min ?? applyMinSlippage(slippage, params.amount_a);
|
|
2468
|
+
const minB = params.amount_b_min ?? applyMinSlippage(slippage, params.amount_b);
|
|
2469
|
+
const [amount0Min, amount1Min] = isAFirst ? [minA, minB] : [minB, minA];
|
|
2347
2470
|
const client = createPublicClient4({ transport: http4(this.rpcUrl) });
|
|
2348
2471
|
const poolAddr = params.pool;
|
|
2349
2472
|
let tickSpacing = this.defaultTickSpacing;
|
|
@@ -2358,7 +2481,7 @@ var init_dist2 = __esm({
|
|
|
2358
2481
|
functionName: "getPool",
|
|
2359
2482
|
args: [token0, token1, tickSpacing]
|
|
2360
2483
|
});
|
|
2361
|
-
if (pool ===
|
|
2484
|
+
if (pool === zeroAddress2) throw new DefiError("CONTRACT_ERROR", "Pool not found");
|
|
2362
2485
|
}
|
|
2363
2486
|
if (pool) {
|
|
2364
2487
|
const [slot0, ts] = await Promise.all([
|
|
@@ -2401,8 +2524,8 @@ var init_dist2 = __esm({
|
|
|
2401
2524
|
tickUpper,
|
|
2402
2525
|
amount0Desired: rawAmount0,
|
|
2403
2526
|
amount1Desired: rawAmount1,
|
|
2404
|
-
amount0Min
|
|
2405
|
-
amount1Min
|
|
2527
|
+
amount0Min,
|
|
2528
|
+
amount1Min,
|
|
2406
2529
|
recipient: params.recipient,
|
|
2407
2530
|
deadline: BigInt("18446744073709551615"),
|
|
2408
2531
|
sqrtPriceX96: 0n
|
|
@@ -2424,12 +2547,19 @@ var init_dist2 = __esm({
|
|
|
2424
2547
|
const pm = this.positionManager;
|
|
2425
2548
|
if (!pm) throw DefiError.contractError(`[${this.protocolName}] Missing 'position_manager'`);
|
|
2426
2549
|
if (!params.token_id) throw DefiError.invalidParam(`[${this.protocolName}] V3 remove_liquidity requires --token-id`);
|
|
2550
|
+
if (params.amount_a_min === void 0 || params.amount_b_min === void 0) {
|
|
2551
|
+
throw DefiError.invalidParam(
|
|
2552
|
+
`[${this.protocolName}] remove_liquidity requires amount_a_min and amount_b_min for slippage protection (SSOT 7.3). Compute expected outputs from positions(tokenId) + pool.slot0 off-chain and apply tolerance.`
|
|
2553
|
+
);
|
|
2554
|
+
}
|
|
2555
|
+
const isAFirst = params.token_a.toLowerCase() < params.token_b.toLowerCase();
|
|
2556
|
+
const [amount0Min, amount1Min] = isAFirst ? [params.amount_a_min, params.amount_b_min] : [params.amount_b_min, params.amount_a_min];
|
|
2427
2557
|
const MAX_UINT128 = (1n << 128n) - 1n;
|
|
2428
2558
|
const deadline = BigInt("18446744073709551615");
|
|
2429
2559
|
const decreaseData = encodeFunctionData7({
|
|
2430
2560
|
abi: thenaPmAbi,
|
|
2431
2561
|
functionName: "decreaseLiquidity",
|
|
2432
|
-
args: [{ tokenId: params.token_id, liquidity: params.liquidity, amount0Min
|
|
2562
|
+
args: [{ tokenId: params.token_id, liquidity: params.liquidity, amount0Min, amount1Min, deadline }]
|
|
2433
2563
|
});
|
|
2434
2564
|
const collectData = encodeFunctionData7({
|
|
2435
2565
|
abi: thenaPmAbi,
|
|
@@ -2496,8 +2626,8 @@ var init_dist2 = __esm({
|
|
|
2496
2626
|
const ve = entry.contracts?.["ve_token"];
|
|
2497
2627
|
if (!ve) throw new DefiError("CONTRACT_ERROR", "Missing 've_token' contract");
|
|
2498
2628
|
this.veToken = ve;
|
|
2499
|
-
this.voter = entry.contracts?.["voter"] ??
|
|
2500
|
-
this.positionManager = entry.contracts?.["position_manager"] ??
|
|
2629
|
+
this.voter = entry.contracts?.["voter"] ?? zeroAddress3;
|
|
2630
|
+
this.positionManager = entry.contracts?.["position_manager"] ?? zeroAddress3;
|
|
2501
2631
|
this.poolFactory = entry.contracts?.["pool_factory"];
|
|
2502
2632
|
this.rpcUrl = rpcUrl;
|
|
2503
2633
|
}
|
|
@@ -2539,7 +2669,7 @@ var init_dist2 = __esm({
|
|
|
2539
2669
|
]);
|
|
2540
2670
|
}
|
|
2541
2671
|
const poolAddressResults = await multicallRead(this.rpcUrl, poolAddressCalls);
|
|
2542
|
-
const pools = poolAddressResults.map((r) => decodeAddress(r)).filter((a) => a !== null && a !==
|
|
2672
|
+
const pools = poolAddressResults.map((r) => decodeAddress(r)).filter((a) => a !== null && a !== zeroAddress3);
|
|
2543
2673
|
if (pools.length === 0) return [];
|
|
2544
2674
|
const gaugeCalls = pools.map((pool) => [
|
|
2545
2675
|
this.gaugeManager,
|
|
@@ -2549,7 +2679,7 @@ var init_dist2 = __esm({
|
|
|
2549
2679
|
const gaugedPools = [];
|
|
2550
2680
|
for (let i = 0; i < pools.length; i++) {
|
|
2551
2681
|
const gauge = decodeAddress(gaugeResults[i] ?? null);
|
|
2552
|
-
if (gauge && gauge !==
|
|
2682
|
+
if (gauge && gauge !== zeroAddress3) {
|
|
2553
2683
|
gaugedPools.push({ pool: pools[i], gauge });
|
|
2554
2684
|
}
|
|
2555
2685
|
}
|
|
@@ -2564,8 +2694,8 @@ var init_dist2 = __esm({
|
|
|
2564
2694
|
for (let i = 0; i < gaugedPools.length; i++) {
|
|
2565
2695
|
const t0 = decodeAddress(tokenResults[i * 2] ?? null);
|
|
2566
2696
|
const t1 = decodeAddress(tokenResults[i * 2 + 1] ?? null);
|
|
2567
|
-
if (t0 && t0 !==
|
|
2568
|
-
if (t1 && t1 !==
|
|
2697
|
+
if (t0 && t0 !== zeroAddress3) tokenAddrs.add(t0);
|
|
2698
|
+
if (t1 && t1 !== zeroAddress3) tokenAddrs.add(t1);
|
|
2569
2699
|
}
|
|
2570
2700
|
const uniqueTokens = Array.from(tokenAddrs);
|
|
2571
2701
|
const symbolCalls = uniqueTokens.map((t) => [
|
|
@@ -2604,7 +2734,7 @@ var init_dist2 = __esm({
|
|
|
2604
2734
|
functionName: "gauges",
|
|
2605
2735
|
args: [pool]
|
|
2606
2736
|
});
|
|
2607
|
-
if (gauge ===
|
|
2737
|
+
if (gauge === zeroAddress3) throw new DefiError("CONTRACT_ERROR", `No gauge for pool ${pool}`);
|
|
2608
2738
|
return gauge;
|
|
2609
2739
|
}
|
|
2610
2740
|
// ─── CL Gauge: NFT Deposit/Withdraw ──────────────────────────
|
|
@@ -2766,7 +2896,7 @@ var init_dist2 = __esm({
|
|
|
2766
2896
|
params.amount_in,
|
|
2767
2897
|
minToAmount,
|
|
2768
2898
|
params.recipient,
|
|
2769
|
-
|
|
2899
|
+
zeroAddress4
|
|
2770
2900
|
]
|
|
2771
2901
|
});
|
|
2772
2902
|
return {
|
|
@@ -2991,7 +3121,7 @@ var init_dist2 = __esm({
|
|
|
2991
3121
|
poolCalls.push([this.voter, encodeFunctionData10({ abi: voterPoolsAbi, functionName: "pools", args: [BigInt(i)] })]);
|
|
2992
3122
|
}
|
|
2993
3123
|
const poolResults = await multicallRead(this.rpcUrl, poolCalls);
|
|
2994
|
-
pairs = poolResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !==
|
|
3124
|
+
pairs = poolResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !== zeroAddress5);
|
|
2995
3125
|
} else {
|
|
2996
3126
|
const v2FactoryAbi = parseAbi10(["function allPairsLength() view returns (uint256)", "function allPairs(uint256) view returns (address)"]);
|
|
2997
3127
|
const solidlyFactoryAbi = parseAbi10(["function allPoolsLength() view returns (uint256)", "function allPools(uint256) view returns (address)"]);
|
|
@@ -3016,17 +3146,17 @@ var init_dist2 = __esm({
|
|
|
3016
3146
|
const pairCalls = [];
|
|
3017
3147
|
for (let i = startIdx; i < count; i++) pairCalls.push([this.v2Factory, encodeFunctionData10({ abi: fetchAbi, functionName: fetchFn, args: [BigInt(i)] })]);
|
|
3018
3148
|
const pairResults = await multicallRead(this.rpcUrl, pairCalls);
|
|
3019
|
-
pairs = pairResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !==
|
|
3149
|
+
pairs = pairResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !== zeroAddress5);
|
|
3020
3150
|
}
|
|
3021
3151
|
if (pairs.length === 0) return;
|
|
3022
3152
|
const gaugeCalls = pairs.map((p) => [this.voter, encodeFunctionData10({ abi: gaugeForPoolAbi, functionName: "gaugeForPool", args: [p] })]);
|
|
3023
3153
|
let gaugeResults = await multicallRead(this.rpcUrl, gaugeCalls);
|
|
3024
|
-
const allNull = gaugeResults.every((r) => !r || decodeAddress2(r) ===
|
|
3154
|
+
const allNull = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress5 || decodeAddress2(r) === null);
|
|
3025
3155
|
if (allNull) {
|
|
3026
3156
|
const fb1 = pairs.map((p) => [this.voter, encodeFunctionData10({ abi: poolToGaugeAbi, functionName: "poolToGauge", args: [p] })]);
|
|
3027
3157
|
gaugeResults = await multicallRead(this.rpcUrl, fb1);
|
|
3028
3158
|
}
|
|
3029
|
-
const allNull2 = gaugeResults.every((r) => !r || decodeAddress2(r) ===
|
|
3159
|
+
const allNull2 = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress5 || decodeAddress2(r) === null);
|
|
3030
3160
|
if (allNull2) {
|
|
3031
3161
|
const fb2 = pairs.map((p) => [this.voter, encodeFunctionData10({ abi: gaugesAbi, functionName: "gauges", args: [p] })]);
|
|
3032
3162
|
gaugeResults = await multicallRead(this.rpcUrl, fb2);
|
|
@@ -3034,7 +3164,7 @@ var init_dist2 = __esm({
|
|
|
3034
3164
|
const gaugedPairs = [];
|
|
3035
3165
|
for (let i = 0; i < pairs.length; i++) {
|
|
3036
3166
|
const gauge = decodeAddress2(gaugeResults[i] ?? null);
|
|
3037
|
-
if (gauge && gauge !==
|
|
3167
|
+
if (gauge && gauge !== zeroAddress5) {
|
|
3038
3168
|
gaugedPairs.push({ pair: pairs[i], gauge });
|
|
3039
3169
|
}
|
|
3040
3170
|
}
|
|
@@ -3050,8 +3180,8 @@ var init_dist2 = __esm({
|
|
|
3050
3180
|
for (let i = 0; i < gaugedPairs.length; i++) {
|
|
3051
3181
|
const t0 = decodeAddress2(metaResults[i * 3] ?? null);
|
|
3052
3182
|
const t1 = decodeAddress2(metaResults[i * 3 + 1] ?? null);
|
|
3053
|
-
if (t0 && t0 !==
|
|
3054
|
-
if (t1 && t1 !==
|
|
3183
|
+
if (t0 && t0 !== zeroAddress5) tokenAddrs.add(t0);
|
|
3184
|
+
if (t1 && t1 !== zeroAddress5) tokenAddrs.add(t1);
|
|
3055
3185
|
}
|
|
3056
3186
|
const uniqueTokens = Array.from(tokenAddrs);
|
|
3057
3187
|
const symbolCalls = uniqueTokens.map((t) => [
|
|
@@ -3141,7 +3271,7 @@ var init_dist2 = __esm({
|
|
|
3141
3271
|
const candidatePools = [];
|
|
3142
3272
|
for (let i = 0; i < getPoolCalls.length; i++) {
|
|
3143
3273
|
const pool = decodeAddress2(getPoolResults[i] ?? null);
|
|
3144
|
-
if (pool && pool !==
|
|
3274
|
+
if (pool && pool !== zeroAddress5) {
|
|
3145
3275
|
const { pairIdx, tickSpacing } = callMeta[i];
|
|
3146
3276
|
const [tokenA, tokenB] = pairs[pairIdx];
|
|
3147
3277
|
candidatePools.push({ pool, tokenA, tokenB, tickSpacing });
|
|
@@ -3153,7 +3283,7 @@ var init_dist2 = __esm({
|
|
|
3153
3283
|
encodeFunctionData10({ abi: gaugeForPoolAbi, functionName: "gaugeForPool", args: [pool] })
|
|
3154
3284
|
]);
|
|
3155
3285
|
let gaugeResults = await multicallRead(this.rpcUrl, gaugeCalls);
|
|
3156
|
-
const allNull = gaugeResults.every((r) => !r || decodeAddress2(r) ===
|
|
3286
|
+
const allNull = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress5 || decodeAddress2(r) === null);
|
|
3157
3287
|
if (allNull) {
|
|
3158
3288
|
const fallbackCalls = candidatePools.map(({ pool }) => [
|
|
3159
3289
|
this.voter,
|
|
@@ -3164,7 +3294,7 @@ var init_dist2 = __esm({
|
|
|
3164
3294
|
const gaugedCL = [];
|
|
3165
3295
|
for (let i = 0; i < candidatePools.length; i++) {
|
|
3166
3296
|
const gauge = decodeAddress2(gaugeResults[i] ?? null);
|
|
3167
|
-
if (gauge && gauge !==
|
|
3297
|
+
if (gauge && gauge !== zeroAddress5) {
|
|
3168
3298
|
gaugedCL.push({ ...candidatePools[i], gauge });
|
|
3169
3299
|
}
|
|
3170
3300
|
}
|
|
@@ -3194,8 +3324,8 @@ var init_dist2 = __esm({
|
|
|
3194
3324
|
const { pool, gauge, tokenA, tokenB, tickSpacing } = gaugedCL[i];
|
|
3195
3325
|
const rawT0 = decodeAddress2(poolTokenResults[i * 2] ?? null);
|
|
3196
3326
|
const rawT1 = decodeAddress2(poolTokenResults[i * 2 + 1] ?? null);
|
|
3197
|
-
const t0 = rawT0 && rawT0 !==
|
|
3198
|
-
const t1 = rawT1 && rawT1 !==
|
|
3327
|
+
const t0 = rawT0 && rawT0 !== zeroAddress5 ? rawT0 : tokenA;
|
|
3328
|
+
const t1 = rawT1 && rawT1 !== zeroAddress5 ? rawT1 : tokenB;
|
|
3199
3329
|
out.push({
|
|
3200
3330
|
pool,
|
|
3201
3331
|
gauge,
|
|
@@ -3297,7 +3427,7 @@ var init_dist2 = __esm({
|
|
|
3297
3427
|
functionName: fn,
|
|
3298
3428
|
args: [pool]
|
|
3299
3429
|
});
|
|
3300
|
-
if (gauge !==
|
|
3430
|
+
if (gauge !== zeroAddress5) return gauge;
|
|
3301
3431
|
} catch {
|
|
3302
3432
|
}
|
|
3303
3433
|
}
|
|
@@ -3351,7 +3481,7 @@ var init_dist2 = __esm({
|
|
|
3351
3481
|
abi: gaugeAbi,
|
|
3352
3482
|
functionName: "rewardToken"
|
|
3353
3483
|
});
|
|
3354
|
-
if (rt !==
|
|
3484
|
+
if (rt !== zeroAddress5) return { tokens: [rt], multiToken: false };
|
|
3355
3485
|
} catch {
|
|
3356
3486
|
}
|
|
3357
3487
|
return { tokens: [], multiToken: false };
|
|
@@ -3361,7 +3491,7 @@ var init_dist2 = __esm({
|
|
|
3361
3491
|
const data = encodeFunctionData10({
|
|
3362
3492
|
abi: gaugeAbi,
|
|
3363
3493
|
functionName: "getReward",
|
|
3364
|
-
args: [account ??
|
|
3494
|
+
args: [account ?? zeroAddress5]
|
|
3365
3495
|
});
|
|
3366
3496
|
return { description: `[${this.protocolName}] Claim gauge rewards`, to: gauge, data, value: 0n, gas_estimate: 2e5 };
|
|
3367
3497
|
}
|
|
@@ -3585,7 +3715,7 @@ var init_dist2 = __esm({
|
|
|
3585
3715
|
functionName: "earned",
|
|
3586
3716
|
args: [user]
|
|
3587
3717
|
});
|
|
3588
|
-
results.push({ token:
|
|
3718
|
+
results.push({ token: zeroAddress5, symbol: "unknown", amount: earned });
|
|
3589
3719
|
} catch {
|
|
3590
3720
|
}
|
|
3591
3721
|
}
|
|
@@ -3947,20 +4077,47 @@ var init_dist2 = __esm({
|
|
|
3947
4077
|
/**
|
|
3948
4078
|
* Build an addLiquidity transaction for a Liquidity Book pair.
|
|
3949
4079
|
* Distributes tokenX/tokenY uniformly across active bin ± numBins.
|
|
4080
|
+
*
|
|
4081
|
+
* The LB pair stores tokenX/tokenY in the order set at factory creation,
|
|
4082
|
+
* which is **not** address-sorted. Callers may pass tokens in either order;
|
|
4083
|
+
* we always re-align with the pool's `getTokenX/getTokenY` (and swap amounts
|
|
4084
|
+
* accordingly) so the router's `if (tokenX != pair.tokenX) revert` path is
|
|
4085
|
+
* never hit.
|
|
3950
4086
|
*/
|
|
3951
4087
|
async buildAddLiquidity(params) {
|
|
3952
4088
|
const numBins = params.numBins ?? 5;
|
|
3953
4089
|
const deadline = params.deadline ?? BigInt("18446744073709551615");
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
4090
|
+
const rpcUrl = this.requireRpc();
|
|
4091
|
+
const client = createPublicClient8({ transport: http8(rpcUrl) });
|
|
4092
|
+
const [poolTokenX, poolTokenY, onChainActiveId] = await Promise.all([
|
|
4093
|
+
client.readContract({ address: params.pool, abi: lbPairAbi, functionName: "getTokenX" }),
|
|
4094
|
+
client.readContract({ address: params.pool, abi: lbPairAbi, functionName: "getTokenY" }),
|
|
4095
|
+
params.activeIdDesired === void 0 ? client.readContract({ address: params.pool, abi: lbPairAbi, functionName: "getActiveId" }) : Promise.resolve(params.activeIdDesired)
|
|
4096
|
+
]);
|
|
4097
|
+
const activeIdDesired = onChainActiveId;
|
|
4098
|
+
const inX = params.tokenX.toLowerCase();
|
|
4099
|
+
const inY = params.tokenY.toLowerCase();
|
|
4100
|
+
const poolX = poolTokenX.toLowerCase();
|
|
4101
|
+
const poolY = poolTokenY.toLowerCase();
|
|
4102
|
+
let tokenX;
|
|
4103
|
+
let tokenY;
|
|
4104
|
+
let amountX;
|
|
4105
|
+
let amountY;
|
|
4106
|
+
if (inX === poolX && inY === poolY) {
|
|
4107
|
+
tokenX = params.tokenX;
|
|
4108
|
+
tokenY = params.tokenY;
|
|
4109
|
+
amountX = params.amountX;
|
|
4110
|
+
amountY = params.amountY;
|
|
4111
|
+
} else if (inX === poolY && inY === poolX) {
|
|
4112
|
+
tokenX = poolTokenX;
|
|
4113
|
+
tokenY = poolTokenY;
|
|
4114
|
+
amountX = params.amountY;
|
|
4115
|
+
amountY = params.amountX;
|
|
4116
|
+
} else {
|
|
4117
|
+
throw new DefiError(
|
|
4118
|
+
"CONTRACT_ERROR",
|
|
4119
|
+
`[${this.protocolName}] tokenX/tokenY ${params.tokenX}/${params.tokenY} do not match pool ${params.pool} (${poolTokenX}/${poolTokenY})`
|
|
4120
|
+
);
|
|
3964
4121
|
}
|
|
3965
4122
|
const deltaIds = [];
|
|
3966
4123
|
for (let d = -numBins; d <= numBins; d++) {
|
|
@@ -3972,11 +4129,11 @@ var init_dist2 = __esm({
|
|
|
3972
4129
|
functionName: "addLiquidity",
|
|
3973
4130
|
args: [
|
|
3974
4131
|
{
|
|
3975
|
-
tokenX
|
|
3976
|
-
tokenY
|
|
4132
|
+
tokenX,
|
|
4133
|
+
tokenY,
|
|
3977
4134
|
binStep: BigInt(params.binStep),
|
|
3978
|
-
amountX
|
|
3979
|
-
amountY
|
|
4135
|
+
amountX,
|
|
4136
|
+
amountY,
|
|
3980
4137
|
amountXMin: 0n,
|
|
3981
4138
|
amountYMin: 0n,
|
|
3982
4139
|
activeIdDesired: BigInt(activeIdDesired),
|
|
@@ -3991,31 +4148,63 @@ var init_dist2 = __esm({
|
|
|
3991
4148
|
]
|
|
3992
4149
|
});
|
|
3993
4150
|
return {
|
|
3994
|
-
description: `[${this.protocolName}] LB addLiquidity ${
|
|
4151
|
+
description: `[${this.protocolName}] LB addLiquidity ${amountX} tokenX + ${amountY} tokenY across ${deltaIds.length} bins`,
|
|
3995
4152
|
to: this.lbRouter,
|
|
3996
4153
|
data,
|
|
3997
4154
|
value: 0n,
|
|
3998
4155
|
gas_estimate: 8e5,
|
|
3999
4156
|
approvals: [
|
|
4000
|
-
{ token:
|
|
4001
|
-
{ token:
|
|
4157
|
+
{ token: tokenX, spender: this.lbRouter, amount: amountX },
|
|
4158
|
+
{ token: tokenY, spender: this.lbRouter, amount: amountY }
|
|
4002
4159
|
]
|
|
4003
4160
|
};
|
|
4004
4161
|
}
|
|
4005
4162
|
/**
|
|
4006
4163
|
* Build a removeLiquidity transaction for specific LB bins.
|
|
4164
|
+
*
|
|
4165
|
+
* When `pool` is supplied, the adapter realigns tokenX/tokenY (and
|
|
4166
|
+
* amountXMin/amountYMin) to the pool's actual ordering. Otherwise it trusts
|
|
4167
|
+
* the caller — the router will revert if the order is wrong.
|
|
4007
4168
|
*/
|
|
4008
4169
|
async buildRemoveLiquidity(params) {
|
|
4009
4170
|
const deadline = params.deadline ?? BigInt("18446744073709551615");
|
|
4171
|
+
let tokenX = params.tokenX;
|
|
4172
|
+
let tokenY = params.tokenY;
|
|
4173
|
+
let amountXMin = params.amountXMin ?? 0n;
|
|
4174
|
+
let amountYMin = params.amountYMin ?? 0n;
|
|
4175
|
+
if (params.pool) {
|
|
4176
|
+
const rpcUrl = this.requireRpc();
|
|
4177
|
+
const client = createPublicClient8({ transport: http8(rpcUrl) });
|
|
4178
|
+
const [poolTokenX, poolTokenY] = await Promise.all([
|
|
4179
|
+
client.readContract({ address: params.pool, abi: lbPairAbi, functionName: "getTokenX" }),
|
|
4180
|
+
client.readContract({ address: params.pool, abi: lbPairAbi, functionName: "getTokenY" })
|
|
4181
|
+
]);
|
|
4182
|
+
const inX = params.tokenX.toLowerCase();
|
|
4183
|
+
const inY = params.tokenY.toLowerCase();
|
|
4184
|
+
const poolX = poolTokenX.toLowerCase();
|
|
4185
|
+
const poolY = poolTokenY.toLowerCase();
|
|
4186
|
+
if (inX === poolY && inY === poolX) {
|
|
4187
|
+
tokenX = poolTokenX;
|
|
4188
|
+
tokenY = poolTokenY;
|
|
4189
|
+
const x = amountXMin;
|
|
4190
|
+
amountXMin = amountYMin;
|
|
4191
|
+
amountYMin = x;
|
|
4192
|
+
} else if (!(inX === poolX && inY === poolY)) {
|
|
4193
|
+
throw new DefiError(
|
|
4194
|
+
"CONTRACT_ERROR",
|
|
4195
|
+
`[${this.protocolName}] tokenX/tokenY ${params.tokenX}/${params.tokenY} do not match pool ${params.pool} (${poolTokenX}/${poolTokenY})`
|
|
4196
|
+
);
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4010
4199
|
const data = encodeFunctionData12({
|
|
4011
4200
|
abi: lbRouterAbi,
|
|
4012
4201
|
functionName: "removeLiquidity",
|
|
4013
4202
|
args: [
|
|
4014
|
-
|
|
4015
|
-
|
|
4203
|
+
tokenX,
|
|
4204
|
+
tokenY,
|
|
4016
4205
|
params.binStep,
|
|
4017
|
-
|
|
4018
|
-
|
|
4206
|
+
amountXMin,
|
|
4207
|
+
amountYMin,
|
|
4019
4208
|
params.binIds.map(BigInt),
|
|
4020
4209
|
params.amounts,
|
|
4021
4210
|
params.recipient,
|
|
@@ -4925,7 +5114,7 @@ var init_dist2 = __esm({
|
|
|
4925
5114
|
const poolSet = /* @__PURE__ */ new Set();
|
|
4926
5115
|
for (const data of poolResults) {
|
|
4927
5116
|
const addr = decodeAddress3(data);
|
|
4928
|
-
if (addr && addr !==
|
|
5117
|
+
if (addr && addr !== zeroAddress6) {
|
|
4929
5118
|
poolSet.add(addr.toLowerCase());
|
|
4930
5119
|
}
|
|
4931
5120
|
}
|
|
@@ -5090,6 +5279,34 @@ var init_dist2 = __esm({
|
|
|
5090
5279
|
}
|
|
5091
5280
|
return apr;
|
|
5092
5281
|
}
|
|
5282
|
+
/**
|
|
5283
|
+
* Snapshot of all NEST gauged pools from the off-chain blaze API. The
|
|
5284
|
+
* on-chain ve(3,3) gauges return `rewardRate=0` (emissions are credited
|
|
5285
|
+
* off-chain via signed claim tickets), so the on-chain Solidly gauge
|
|
5286
|
+
* reader cannot surface real emission APR. This API is the canonical
|
|
5287
|
+
* read source — used by `lp discover` to expose non-zero NEST yields.
|
|
5288
|
+
*/
|
|
5289
|
+
async getLiquidityPools() {
|
|
5290
|
+
const raw = await this.fetchJson("/liquidity-pools");
|
|
5291
|
+
const out = [];
|
|
5292
|
+
for (const p of raw) {
|
|
5293
|
+
const t0 = p.token0?.basetoken;
|
|
5294
|
+
const t1 = p.token1?.basetoken;
|
|
5295
|
+
if (!t0?.address || !t1?.address) continue;
|
|
5296
|
+
out.push({
|
|
5297
|
+
pool: p.id,
|
|
5298
|
+
gauge: p.gauge ?? null,
|
|
5299
|
+
token0: { address: t0.address, symbol: t0.symbol ?? "?" },
|
|
5300
|
+
token1: { address: t1.address, symbol: t1.symbol ?? "?" },
|
|
5301
|
+
tvlUSD: Number(p.tvlUSD ?? 0),
|
|
5302
|
+
aprPercent: Number(p.apr ?? 0),
|
|
5303
|
+
curEpochEmissionRewardsUSD: Number(p.curEpochEmissionRewardsUSD ?? 0),
|
|
5304
|
+
poolType: p.poolType,
|
|
5305
|
+
isStable: p.isStable
|
|
5306
|
+
});
|
|
5307
|
+
}
|
|
5308
|
+
return out;
|
|
5309
|
+
}
|
|
5093
5310
|
/** Pending NEST emissions as IGauge-compatible RewardInfo[] */
|
|
5094
5311
|
async getPendingRewards(user) {
|
|
5095
5312
|
const status = await this.getClaimStatus(user);
|
|
@@ -5245,6 +5462,16 @@ var init_dist2 = __esm({
|
|
|
5245
5462
|
"function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
|
|
5246
5463
|
"function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) external returns (uint256)",
|
|
5247
5464
|
"function withdraw(address asset, uint256 amount, address to) external returns (uint256)",
|
|
5465
|
+
// Toggles required to actually borrow against an isolation-mode reserve
|
|
5466
|
+
// (https://aave.com/docs/aave-v3/smart-contracts/pool):
|
|
5467
|
+
// - setUserUseReserveAsCollateral: an isolation reserve can be enabled
|
|
5468
|
+
// only if no other asset is enabled; LTV=0 reserves can never be
|
|
5469
|
+
// enabled; disable reverts if the resulting HF would drop below the
|
|
5470
|
+
// liquidation threshold.
|
|
5471
|
+
// - setUserEMode: reverts if the user is borrowing a non-eMode-
|
|
5472
|
+
// compatible asset, or if the change would push HF below threshold.
|
|
5473
|
+
"function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external",
|
|
5474
|
+
"function setUserEMode(uint8 categoryId) external",
|
|
5248
5475
|
"function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
|
|
5249
5476
|
"function getReservesList() external view returns (address[])",
|
|
5250
5477
|
"function getReserveData(address asset) external view returns (uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityRate, uint128 variableBorrowIndex, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt)"
|
|
@@ -5370,6 +5597,34 @@ var init_dist2 = __esm({
|
|
|
5370
5597
|
gas_estimate: 25e4
|
|
5371
5598
|
};
|
|
5372
5599
|
}
|
|
5600
|
+
async buildSetUseReserveAsCollateral(asset, useAsCollateral) {
|
|
5601
|
+
const data = encodeFunctionData14({
|
|
5602
|
+
abi: POOL_ABI,
|
|
5603
|
+
functionName: "setUserUseReserveAsCollateral",
|
|
5604
|
+
args: [asset, useAsCollateral]
|
|
5605
|
+
});
|
|
5606
|
+
return {
|
|
5607
|
+
description: `[${this.protocolName}] ${useAsCollateral ? "Enable" : "Disable"} ${asset} as collateral`,
|
|
5608
|
+
to: this.pool,
|
|
5609
|
+
data,
|
|
5610
|
+
value: 0n,
|
|
5611
|
+
gas_estimate: 1e5
|
|
5612
|
+
};
|
|
5613
|
+
}
|
|
5614
|
+
async buildSetEMode(categoryId) {
|
|
5615
|
+
const data = encodeFunctionData14({
|
|
5616
|
+
abi: POOL_ABI,
|
|
5617
|
+
functionName: "setUserEMode",
|
|
5618
|
+
args: [categoryId]
|
|
5619
|
+
});
|
|
5620
|
+
return {
|
|
5621
|
+
description: `[${this.protocolName}] Set eMode category to ${categoryId}${categoryId === 0 ? " (opt out)" : ""}`,
|
|
5622
|
+
to: this.pool,
|
|
5623
|
+
data,
|
|
5624
|
+
value: 0n,
|
|
5625
|
+
gas_estimate: 15e4
|
|
5626
|
+
};
|
|
5627
|
+
}
|
|
5373
5628
|
async getRates(asset) {
|
|
5374
5629
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
5375
5630
|
const reserveCallData = encodeFunctionData14({
|
|
@@ -5414,7 +5669,7 @@ var init_dist2 = __esm({
|
|
|
5414
5669
|
[aTokenAddress, encodeFunctionData14({ abi: INCENTIVES_ABI, functionName: "getIncentivesController" })]
|
|
5415
5670
|
]);
|
|
5416
5671
|
const controllerAddr = decodeAddress4(controllerRaw ?? null);
|
|
5417
|
-
if (controllerAddr && controllerAddr !==
|
|
5672
|
+
if (controllerAddr && controllerAddr !== zeroAddress7) {
|
|
5418
5673
|
const [supplyRewardsRaw, borrowRewardsRaw] = await multicallRead(this.rpcUrl, [
|
|
5419
5674
|
[controllerAddr, encodeFunctionData14({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [aTokenAddress] })],
|
|
5420
5675
|
[controllerAddr, encodeFunctionData14({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [variableDebtTokenAddress] })]
|
|
@@ -5610,8 +5865,8 @@ var init_dist2 = __esm({
|
|
|
5610
5865
|
if (p.value.borrow > 0n) borrows.push({ asset: p.value.asset, symbol: p.value.symbol, amount: p.value.borrow });
|
|
5611
5866
|
}
|
|
5612
5867
|
} catch {
|
|
5613
|
-
if (collateralUsd > 0) supplies.push({ asset:
|
|
5614
|
-
if (debtUsd > 0) borrows.push({ asset:
|
|
5868
|
+
if (collateralUsd > 0) supplies.push({ asset: zeroAddress7, symbol: "Total Collateral (per-asset breakdown unavailable)", amount: totalCollateralBase });
|
|
5869
|
+
if (debtUsd > 0) borrows.push({ asset: zeroAddress7, symbol: "Total Debt (per-asset breakdown unavailable)", amount: totalDebtBase });
|
|
5615
5870
|
}
|
|
5616
5871
|
return {
|
|
5617
5872
|
protocol: this.protocolName,
|
|
@@ -5778,8 +6033,8 @@ var init_dist2 = __esm({
|
|
|
5778
6033
|
const collateralUsd = u256ToF642(totalCollateralBase) / 1e18;
|
|
5779
6034
|
const debtUsd = u256ToF642(totalDebtBase) / 1e18;
|
|
5780
6035
|
const ltvBps = u256ToF642(ltv);
|
|
5781
|
-
const supplies = collateralUsd > 0 ? [{ asset:
|
|
5782
|
-
const borrows = debtUsd > 0 ? [{ asset:
|
|
6036
|
+
const supplies = collateralUsd > 0 ? [{ asset: zeroAddress8, symbol: "Total Collateral", amount: totalCollateralBase, value_usd: collateralUsd }] : [];
|
|
6037
|
+
const borrows = debtUsd > 0 ? [{ asset: zeroAddress8, symbol: "Total Debt", amount: totalDebtBase, value_usd: debtUsd }] : [];
|
|
5783
6038
|
return {
|
|
5784
6039
|
protocol: this.protocolName,
|
|
5785
6040
|
user,
|
|
@@ -5882,14 +6137,31 @@ var init_dist2 = __esm({
|
|
|
5882
6137
|
"function borrow(uint256 borrowAmount) external returns (uint256)",
|
|
5883
6138
|
"function repayBorrow(uint256 repayAmount) external returns (uint256)"
|
|
5884
6139
|
]);
|
|
6140
|
+
NATIVE_CTOKEN_ABI = parseAbi17([
|
|
6141
|
+
"function mint() external payable",
|
|
6142
|
+
"function repayBorrow() external payable"
|
|
6143
|
+
]);
|
|
6144
|
+
COMPTROLLER_ABI = parseAbi17([
|
|
6145
|
+
"function enterMarkets(address[] cTokens) external returns (uint256[])",
|
|
6146
|
+
"function exitMarket(address cToken) external returns (uint256)"
|
|
6147
|
+
]);
|
|
6148
|
+
NATIVE_SENTINEL = "0x0000000000000000000000000000000000000000";
|
|
5885
6149
|
BSC_BLOCKS_PER_YEAR = 10512e3;
|
|
5886
6150
|
CompoundV2Adapter = class {
|
|
5887
6151
|
protocolName;
|
|
5888
6152
|
defaultVtoken;
|
|
5889
6153
|
vTokenCandidates;
|
|
6154
|
+
comptroller;
|
|
5890
6155
|
rpcUrl;
|
|
5891
|
-
// Lazy cache: underlying asset address (lowercased) → vToken address
|
|
6156
|
+
// Lazy cache: underlying asset address (lowercased) → vToken address.
|
|
6157
|
+
// The native sentinel (0x0…) is mapped to the cETH/vBNB-style vToken
|
|
6158
|
+
// when one is detected during resolveVtoken().
|
|
5892
6159
|
vTokenByAsset = null;
|
|
6160
|
+
// The cETH/vBNB-style vToken whose underlying() reverts (it has no
|
|
6161
|
+
// ERC20 underlying — the underlying is the chain's native gas token).
|
|
6162
|
+
// Set lazily by resolveVtoken() and consulted by buildSupply/buildRepay
|
|
6163
|
+
// to switch to the payable mint() / repayBorrow() variants.
|
|
6164
|
+
nativeVtoken = null;
|
|
5893
6165
|
constructor(entry, rpcUrl) {
|
|
5894
6166
|
this.protocolName = entry.name;
|
|
5895
6167
|
this.rpcUrl = rpcUrl;
|
|
@@ -5897,6 +6169,7 @@ var init_dist2 = __esm({
|
|
|
5897
6169
|
const vtoken = contracts["vusdt"] ?? contracts["vusdc"] ?? contracts["vbnb"] ?? contracts["comptroller"];
|
|
5898
6170
|
if (!vtoken) throw DefiError.contractError("Missing vToken or comptroller address");
|
|
5899
6171
|
this.defaultVtoken = vtoken;
|
|
6172
|
+
this.comptroller = contracts["comptroller"];
|
|
5900
6173
|
this.vTokenCandidates = Object.entries(contracts).filter(([k]) => /^v[a-z][a-z0-9]*$/i.test(k)).map(([, v]) => v);
|
|
5901
6174
|
if (this.vTokenCandidates.length === 0) this.vTokenCandidates = [vtoken];
|
|
5902
6175
|
}
|
|
@@ -5905,19 +6178,38 @@ var init_dist2 = __esm({
|
|
|
5905
6178
|
if (!this.vTokenByAsset) {
|
|
5906
6179
|
const client = createPublicClient13({ transport: http13(this.rpcUrl) });
|
|
5907
6180
|
const map = /* @__PURE__ */ new Map();
|
|
6181
|
+
let nativeVtoken = null;
|
|
5908
6182
|
const lookups = await Promise.allSettled(
|
|
5909
6183
|
this.vTokenCandidates.map(async (v) => {
|
|
5910
|
-
|
|
5911
|
-
|
|
6184
|
+
try {
|
|
6185
|
+
const u = await client.readContract({ address: v, abi: CTOKEN_ABI, functionName: "underlying" });
|
|
6186
|
+
return { vtoken: v, underlying: u };
|
|
6187
|
+
} catch {
|
|
6188
|
+
return { vtoken: v, underlying: null };
|
|
6189
|
+
}
|
|
5912
6190
|
})
|
|
5913
6191
|
);
|
|
5914
6192
|
for (const r of lookups) {
|
|
5915
|
-
if (r.status
|
|
6193
|
+
if (r.status !== "fulfilled") continue;
|
|
6194
|
+
const { vtoken, underlying } = r.value;
|
|
6195
|
+
if (underlying) {
|
|
6196
|
+
map.set(underlying.toLowerCase(), vtoken);
|
|
6197
|
+
} else if (!nativeVtoken) {
|
|
6198
|
+
nativeVtoken = vtoken;
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
if (nativeVtoken) {
|
|
6202
|
+
map.set(NATIVE_SENTINEL, nativeVtoken);
|
|
5916
6203
|
}
|
|
5917
6204
|
this.vTokenByAsset = map;
|
|
6205
|
+
this.nativeVtoken = nativeVtoken;
|
|
5918
6206
|
}
|
|
5919
6207
|
return this.vTokenByAsset.get(asset.toLowerCase()) ?? null;
|
|
5920
6208
|
}
|
|
6209
|
+
/** True iff `vtoken` is the cETH/vBNB-style native cToken for this protocol. */
|
|
6210
|
+
isNativeVtoken(vtoken) {
|
|
6211
|
+
return this.nativeVtoken !== null && vtoken.toLowerCase() === this.nativeVtoken.toLowerCase();
|
|
6212
|
+
}
|
|
5921
6213
|
name() {
|
|
5922
6214
|
return this.protocolName;
|
|
5923
6215
|
}
|
|
@@ -5931,6 +6223,16 @@ var init_dist2 = __esm({
|
|
|
5931
6223
|
}
|
|
5932
6224
|
async buildSupply(params) {
|
|
5933
6225
|
const vtoken = await this.vtokenFor(params.asset);
|
|
6226
|
+
if (this.isNativeVtoken(vtoken)) {
|
|
6227
|
+
const data2 = encodeFunctionData16({ abi: NATIVE_CTOKEN_ABI, functionName: "mint" });
|
|
6228
|
+
return {
|
|
6229
|
+
description: `[${this.protocolName}] Supply ${params.amount} (native) to Venus`,
|
|
6230
|
+
to: vtoken,
|
|
6231
|
+
data: data2,
|
|
6232
|
+
value: params.amount,
|
|
6233
|
+
gas_estimate: 3e5
|
|
6234
|
+
};
|
|
6235
|
+
}
|
|
5934
6236
|
const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "mint", args: [params.amount] });
|
|
5935
6237
|
return {
|
|
5936
6238
|
description: `[${this.protocolName}] Supply ${params.amount} of ${params.asset} to Venus`,
|
|
@@ -5954,6 +6256,16 @@ var init_dist2 = __esm({
|
|
|
5954
6256
|
}
|
|
5955
6257
|
async buildRepay(params) {
|
|
5956
6258
|
const vtoken = await this.vtokenFor(params.asset);
|
|
6259
|
+
if (this.isNativeVtoken(vtoken)) {
|
|
6260
|
+
const data2 = encodeFunctionData16({ abi: NATIVE_CTOKEN_ABI, functionName: "repayBorrow" });
|
|
6261
|
+
return {
|
|
6262
|
+
description: `[${this.protocolName}] Repay ${params.amount} (native) to Venus`,
|
|
6263
|
+
to: vtoken,
|
|
6264
|
+
data: data2,
|
|
6265
|
+
value: params.amount,
|
|
6266
|
+
gas_estimate: 3e5
|
|
6267
|
+
};
|
|
6268
|
+
}
|
|
5957
6269
|
const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "repayBorrow", args: [params.amount] });
|
|
5958
6270
|
return {
|
|
5959
6271
|
description: `[${this.protocolName}] Repay ${params.amount} of ${params.asset} to Venus`,
|
|
@@ -5966,6 +6278,37 @@ var init_dist2 = __esm({
|
|
|
5966
6278
|
}
|
|
5967
6279
|
async buildWithdraw(params) {
|
|
5968
6280
|
const vtoken = await this.vtokenFor(params.asset);
|
|
6281
|
+
const MAX_UINT2562 = (1n << 256n) - 1n;
|
|
6282
|
+
if (params.amount === MAX_UINT2562 && this.rpcUrl) {
|
|
6283
|
+
const client = createPublicClient13({ transport: http13(this.rpcUrl) });
|
|
6284
|
+
const [vtokenBalance, borrowBalance] = await Promise.all([
|
|
6285
|
+
client.readContract({
|
|
6286
|
+
address: vtoken,
|
|
6287
|
+
abi: CTOKEN_ABI,
|
|
6288
|
+
functionName: "balanceOf",
|
|
6289
|
+
args: [params.to]
|
|
6290
|
+
}),
|
|
6291
|
+
client.readContract({
|
|
6292
|
+
address: vtoken,
|
|
6293
|
+
abi: CTOKEN_ABI,
|
|
6294
|
+
functionName: "borrowBalanceStored",
|
|
6295
|
+
args: [params.to]
|
|
6296
|
+
}).catch(() => 0n)
|
|
6297
|
+
]);
|
|
6298
|
+
if (borrowBalance > 0n) {
|
|
6299
|
+
throw DefiError.contractError(
|
|
6300
|
+
`[${this.protocolName}] Cannot withdraw all (uint256.max) \u2014 wallet has an outstanding borrow of ${borrowBalance} on this market. Repay the borrow first, or pass an explicit --amount that leaves enough collateral.`
|
|
6301
|
+
);
|
|
6302
|
+
}
|
|
6303
|
+
const redeemData = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "redeem", args: [vtokenBalance] });
|
|
6304
|
+
return {
|
|
6305
|
+
description: `[${this.protocolName}] Withdraw all (auto-max, ${vtokenBalance} vTokens) of ${params.asset} from Venus`,
|
|
6306
|
+
to: vtoken,
|
|
6307
|
+
data: redeemData,
|
|
6308
|
+
value: 0n,
|
|
6309
|
+
gas_estimate: 35e4
|
|
6310
|
+
};
|
|
6311
|
+
}
|
|
5969
6312
|
const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "redeemUnderlying", args: [params.amount] });
|
|
5970
6313
|
return {
|
|
5971
6314
|
description: `[${this.protocolName}] Withdraw ${params.amount} of ${params.asset} from Venus`,
|
|
@@ -5975,6 +6318,37 @@ var init_dist2 = __esm({
|
|
|
5975
6318
|
gas_estimate: 25e4
|
|
5976
6319
|
};
|
|
5977
6320
|
}
|
|
6321
|
+
/**
|
|
6322
|
+
* Compound V2 family: enter cTokens as collateral via Comptroller.
|
|
6323
|
+
* Without this call, supplied assets sit dormant in the Comptroller's
|
|
6324
|
+
* accountAssets[] and `getAccountLiquidity` reports zero collateral —
|
|
6325
|
+
* any borrow then reverts. Mirrors the role of Aave V3's
|
|
6326
|
+
* setUserUseReserveAsCollateral, but the API is batch-by-cToken.
|
|
6327
|
+
*/
|
|
6328
|
+
async buildEnterMarkets(cTokens) {
|
|
6329
|
+
if (!this.comptroller) {
|
|
6330
|
+
throw DefiError.contractError(
|
|
6331
|
+
`[${this.protocolName}] enterMarkets requires the Comptroller address to be registered under [protocol.contracts] as 'comptroller'.`
|
|
6332
|
+
);
|
|
6333
|
+
}
|
|
6334
|
+
if (cTokens.length === 0) {
|
|
6335
|
+
throw DefiError.invalidParam(
|
|
6336
|
+
`[${this.protocolName}] enterMarkets requires at least one cToken address.`
|
|
6337
|
+
);
|
|
6338
|
+
}
|
|
6339
|
+
const data = encodeFunctionData16({
|
|
6340
|
+
abi: COMPTROLLER_ABI,
|
|
6341
|
+
functionName: "enterMarkets",
|
|
6342
|
+
args: [cTokens]
|
|
6343
|
+
});
|
|
6344
|
+
return {
|
|
6345
|
+
description: `[${this.protocolName}] Enter ${cTokens.length} market(s) as collateral`,
|
|
6346
|
+
to: this.comptroller,
|
|
6347
|
+
data,
|
|
6348
|
+
value: 0n,
|
|
6349
|
+
gas_estimate: 2e5
|
|
6350
|
+
};
|
|
6351
|
+
}
|
|
5978
6352
|
async getRates(asset) {
|
|
5979
6353
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
5980
6354
|
const client = createPublicClient13({ transport: http13(this.rpcUrl) });
|
|
@@ -6342,9 +6716,11 @@ var init_dist2 = __esm({
|
|
|
6342
6716
|
"function market(bytes32 id) external view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
|
|
6343
6717
|
"function idToMarketParams(bytes32 id) external view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)",
|
|
6344
6718
|
"function supply((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external returns (uint256 assetsSupplied, uint256 sharesSupplied)",
|
|
6719
|
+
"function supplyCollateral((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, bytes data) external",
|
|
6345
6720
|
"function borrow((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed)",
|
|
6346
6721
|
"function repay((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external returns (uint256 assetsRepaid, uint256 sharesRepaid)",
|
|
6347
|
-
"function withdraw((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn)"
|
|
6722
|
+
"function withdraw((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn)",
|
|
6723
|
+
"function withdrawCollateral((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, address onBehalf, address receiver) external"
|
|
6348
6724
|
]);
|
|
6349
6725
|
META_MORPHO_ABI = parseAbi20([
|
|
6350
6726
|
"function supplyQueueLength() external view returns (uint256)",
|
|
@@ -6371,6 +6747,8 @@ var init_dist2 = __esm({
|
|
|
6371
6747
|
rpcUrl;
|
|
6372
6748
|
metaMorphoVaults;
|
|
6373
6749
|
metaMorphoVaultEntries;
|
|
6750
|
+
namedMarkets;
|
|
6751
|
+
namedMarketByName;
|
|
6374
6752
|
vaultAssetMap = null;
|
|
6375
6753
|
constructor(entry, rpcUrl) {
|
|
6376
6754
|
this.protocolName = entry.name;
|
|
@@ -6382,6 +6760,26 @@ var init_dist2 = __esm({
|
|
|
6382
6760
|
this.defaultVault = contracts["fehype"] ?? contracts["vault"] ?? contracts["feusdc"];
|
|
6383
6761
|
this.metaMorphoVaultEntries = Object.entries(contracts).filter(([key]) => /^fe[a-z0-9_]+$/i.test(key) || key === "vault").map(([key, addr]) => ({ key, addr }));
|
|
6384
6762
|
this.metaMorphoVaults = this.metaMorphoVaultEntries.map((e) => e.addr);
|
|
6763
|
+
this.namedMarkets = entry.markets ?? [];
|
|
6764
|
+
const byName = /* @__PURE__ */ new Map();
|
|
6765
|
+
for (const m of this.namedMarkets) byName.set(m.name.toLowerCase(), m.id);
|
|
6766
|
+
this.namedMarketByName = byName;
|
|
6767
|
+
}
|
|
6768
|
+
/**
|
|
6769
|
+
* Resolve a friendly market name (e.g. `WMON-AUSD`) to its 32-byte
|
|
6770
|
+
* marketId via the per-protocol TOML registry. Returns null when the
|
|
6771
|
+
* adapter has no markets[] block or the name doesn't match any entry —
|
|
6772
|
+
* callers fall back to treating the input as a raw hex marketId.
|
|
6773
|
+
*/
|
|
6774
|
+
resolveMarketIdByName(name) {
|
|
6775
|
+
return this.namedMarketByName.get(name.toLowerCase()) ?? null;
|
|
6776
|
+
}
|
|
6777
|
+
/**
|
|
6778
|
+
* Returns the registered named markets for diagnostics (e.g. CLI error
|
|
6779
|
+
* messages listing valid choices when the user passes an unknown name).
|
|
6780
|
+
*/
|
|
6781
|
+
listNamedMarkets() {
|
|
6782
|
+
return this.namedMarkets;
|
|
6385
6783
|
}
|
|
6386
6784
|
async resolveVault(asset, preferKey) {
|
|
6387
6785
|
if (this.metaMorphoVaultEntries.length === 0 || !this.rpcUrl) return null;
|
|
@@ -6415,10 +6813,61 @@ var init_dist2 = __esm({
|
|
|
6415
6813
|
name() {
|
|
6416
6814
|
return this.protocolName;
|
|
6417
6815
|
}
|
|
6816
|
+
/**
|
|
6817
|
+
* Resolve a Morpho Blue marketId into the full MarketParams tuple by
|
|
6818
|
+
* calling Morpho.idToMarketParams(id). Used by every direct-market
|
|
6819
|
+
* method (supply / borrow / repay / withdraw / supplyCollateral /
|
|
6820
|
+
* withdrawCollateral) so the caller only has to pass the 32-byte
|
|
6821
|
+
* marketId — same shape as the Morpho UI / API.
|
|
6822
|
+
*/
|
|
6823
|
+
async resolveMarketParams(marketId) {
|
|
6824
|
+
if (!this.rpcUrl) {
|
|
6825
|
+
throw DefiError.rpcError(
|
|
6826
|
+
`[${this.protocolName}] No RPC URL configured \u2014 cannot resolve marketId ${marketId}`
|
|
6827
|
+
);
|
|
6828
|
+
}
|
|
6829
|
+
const client = createPublicClient16({ transport: http16(this.rpcUrl) });
|
|
6830
|
+
let result;
|
|
6831
|
+
try {
|
|
6832
|
+
result = await client.readContract({
|
|
6833
|
+
address: this.morpho,
|
|
6834
|
+
abi: MORPHO_ABI,
|
|
6835
|
+
functionName: "idToMarketParams",
|
|
6836
|
+
args: [marketId]
|
|
6837
|
+
});
|
|
6838
|
+
} catch (e) {
|
|
6839
|
+
throw DefiError.rpcError(
|
|
6840
|
+
`[${this.protocolName}] idToMarketParams(${marketId}) failed: ${e}`
|
|
6841
|
+
);
|
|
6842
|
+
}
|
|
6843
|
+
const [loanToken, collateralToken, oracle, irm, lltv] = result;
|
|
6844
|
+
if (loanToken === zeroAddress9 || collateralToken === zeroAddress9 || lltv === 0n) {
|
|
6845
|
+
throw DefiError.invalidParam(
|
|
6846
|
+
`[${this.protocolName}] marketId ${marketId} resolves to an empty MarketParams (loan=${loanToken}, collateral=${collateralToken}, lltv=${lltv}). Verify the id matches a registered market on this chain.`
|
|
6847
|
+
);
|
|
6848
|
+
}
|
|
6849
|
+
return { loanToken, collateralToken, oracle, irm, lltv };
|
|
6850
|
+
}
|
|
6418
6851
|
async buildSupply(params) {
|
|
6852
|
+
if (params.market_id) {
|
|
6853
|
+
const market = await this.resolveMarketParams(params.market_id);
|
|
6854
|
+
const data = encodeFunctionData19({
|
|
6855
|
+
abi: MORPHO_ABI,
|
|
6856
|
+
functionName: "supply",
|
|
6857
|
+
args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
|
|
6858
|
+
});
|
|
6859
|
+
return {
|
|
6860
|
+
description: `[${this.protocolName}] Supply ${params.amount} of ${params.asset} to market ${params.market_id.slice(0, 10)}\u2026`,
|
|
6861
|
+
to: this.morpho,
|
|
6862
|
+
data,
|
|
6863
|
+
value: 0n,
|
|
6864
|
+
gas_estimate: 35e4,
|
|
6865
|
+
approvals: [{ token: params.asset, spender: this.morpho, amount: params.amount }]
|
|
6866
|
+
};
|
|
6867
|
+
}
|
|
6419
6868
|
const vault = await this.resolveVault(params.asset);
|
|
6420
6869
|
if (vault) {
|
|
6421
|
-
const
|
|
6870
|
+
const data = encodeFunctionData19({
|
|
6422
6871
|
abi: ERC4626_ABI,
|
|
6423
6872
|
functionName: "deposit",
|
|
6424
6873
|
args: [params.amount, params.on_behalf_of]
|
|
@@ -6426,50 +6875,118 @@ var init_dist2 = __esm({
|
|
|
6426
6875
|
return {
|
|
6427
6876
|
description: `[${this.protocolName}] Deposit ${params.amount} into MetaMorpho vault`,
|
|
6428
6877
|
to: vault,
|
|
6429
|
-
data
|
|
6878
|
+
data,
|
|
6430
6879
|
value: 0n,
|
|
6431
6880
|
gas_estimate: 4e5,
|
|
6432
6881
|
approvals: [{ token: params.asset, spender: vault, amount: params.amount }]
|
|
6433
6882
|
};
|
|
6434
6883
|
}
|
|
6435
|
-
|
|
6884
|
+
throw DefiError.invalidParam(
|
|
6885
|
+
`[${this.protocolName}] supply requires either a registered MetaMorpho vault for ${params.asset} or an explicit --market <marketId>. The legacy zero-MarketParams stub was removed (it always reverted on-chain).`
|
|
6886
|
+
);
|
|
6887
|
+
}
|
|
6888
|
+
async buildBorrow(params) {
|
|
6889
|
+
if (!params.market_id) {
|
|
6890
|
+
throw DefiError.invalidParam(
|
|
6891
|
+
`[${this.protocolName}] Morpho Blue borrow requires --market <marketId>. Find one via the Morpho API (https://blue-api.morpho.org/graphql).`
|
|
6892
|
+
);
|
|
6893
|
+
}
|
|
6894
|
+
const market = await this.resolveMarketParams(params.market_id);
|
|
6895
|
+
const data = encodeFunctionData19({
|
|
6896
|
+
abi: MORPHO_ABI,
|
|
6897
|
+
functionName: "borrow",
|
|
6898
|
+
args: [market, params.amount, 0n, params.on_behalf_of, params.on_behalf_of]
|
|
6899
|
+
});
|
|
6900
|
+
return {
|
|
6901
|
+
description: `[${this.protocolName}] Borrow ${params.amount} of ${params.asset} from market ${params.market_id.slice(0, 10)}\u2026`,
|
|
6902
|
+
to: this.morpho,
|
|
6903
|
+
data,
|
|
6904
|
+
value: 0n,
|
|
6905
|
+
gas_estimate: 4e5
|
|
6906
|
+
};
|
|
6907
|
+
}
|
|
6908
|
+
async buildRepay(params) {
|
|
6909
|
+
if (!params.market_id) {
|
|
6910
|
+
throw DefiError.invalidParam(
|
|
6911
|
+
`[${this.protocolName}] Morpho Blue repay requires --market <marketId>.`
|
|
6912
|
+
);
|
|
6913
|
+
}
|
|
6914
|
+
const market = await this.resolveMarketParams(params.market_id);
|
|
6915
|
+
if (params.amount === MAX_UINT256) {
|
|
6916
|
+
if (!this.rpcUrl) {
|
|
6917
|
+
throw DefiError.rpcError(
|
|
6918
|
+
`[${this.protocolName}] max-repay requires an RPC URL to read borrowShares.`
|
|
6919
|
+
);
|
|
6920
|
+
}
|
|
6921
|
+
const client = createPublicClient16({ transport: http16(this.rpcUrl) });
|
|
6922
|
+
const positionAbi = parseAbi20([
|
|
6923
|
+
"function position(bytes32 id, address user) external view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral)"
|
|
6924
|
+
]);
|
|
6925
|
+
const pos = await client.readContract({
|
|
6926
|
+
address: this.morpho,
|
|
6927
|
+
abi: positionAbi,
|
|
6928
|
+
functionName: "position",
|
|
6929
|
+
args: [params.market_id, params.on_behalf_of]
|
|
6930
|
+
});
|
|
6931
|
+
const [, borrowShares] = pos;
|
|
6932
|
+
if (borrowShares === 0n) {
|
|
6933
|
+
throw DefiError.invalidParam(
|
|
6934
|
+
`[${this.protocolName}] cannot repay max \u2014 user has no borrow position in market ${params.market_id}.`
|
|
6935
|
+
);
|
|
6936
|
+
}
|
|
6937
|
+
const data2 = encodeFunctionData19({
|
|
6938
|
+
abi: MORPHO_ABI,
|
|
6939
|
+
functionName: "repay",
|
|
6940
|
+
args: [market, 0n, borrowShares, params.on_behalf_of, "0x"]
|
|
6941
|
+
});
|
|
6942
|
+
return {
|
|
6943
|
+
description: `[${this.protocolName}] Repay max (${borrowShares} shares) to market ${params.market_id.slice(0, 10)}\u2026`,
|
|
6944
|
+
to: this.morpho,
|
|
6945
|
+
data: data2,
|
|
6946
|
+
value: 0n,
|
|
6947
|
+
gas_estimate: 35e4,
|
|
6948
|
+
approvals: [{ token: params.asset, spender: this.morpho, amount: MAX_UINT256 }]
|
|
6949
|
+
};
|
|
6950
|
+
}
|
|
6436
6951
|
const data = encodeFunctionData19({
|
|
6437
6952
|
abi: MORPHO_ABI,
|
|
6438
|
-
functionName: "
|
|
6953
|
+
functionName: "repay",
|
|
6439
6954
|
args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
|
|
6440
6955
|
});
|
|
6441
6956
|
return {
|
|
6442
|
-
description: `[${this.protocolName}]
|
|
6957
|
+
description: `[${this.protocolName}] Repay ${params.amount} of ${params.asset} to market ${params.market_id.slice(0, 10)}\u2026`,
|
|
6443
6958
|
to: this.morpho,
|
|
6444
6959
|
data,
|
|
6445
6960
|
value: 0n,
|
|
6446
|
-
gas_estimate:
|
|
6961
|
+
gas_estimate: 35e4,
|
|
6962
|
+
approvals: [{ token: params.asset, spender: this.morpho, amount: params.amount }]
|
|
6447
6963
|
};
|
|
6448
6964
|
}
|
|
6449
|
-
async
|
|
6450
|
-
const market =
|
|
6965
|
+
async buildSupplyCollateral(params) {
|
|
6966
|
+
const market = await this.resolveMarketParams(params.market_id);
|
|
6451
6967
|
const data = encodeFunctionData19({
|
|
6452
6968
|
abi: MORPHO_ABI,
|
|
6453
|
-
functionName: "
|
|
6454
|
-
args: [market, params.amount,
|
|
6969
|
+
functionName: "supplyCollateral",
|
|
6970
|
+
args: [market, params.amount, params.on_behalf_of, "0x"]
|
|
6455
6971
|
});
|
|
6456
6972
|
return {
|
|
6457
|
-
description: `[${this.protocolName}]
|
|
6973
|
+
description: `[${this.protocolName}] Supply collateral ${params.amount} of ${params.asset} to market ${params.market_id.slice(0, 10)}\u2026`,
|
|
6458
6974
|
to: this.morpho,
|
|
6459
6975
|
data,
|
|
6460
6976
|
value: 0n,
|
|
6461
|
-
gas_estimate: 35e4
|
|
6977
|
+
gas_estimate: 35e4,
|
|
6978
|
+
approvals: [{ token: params.asset, spender: this.morpho, amount: params.amount }]
|
|
6462
6979
|
};
|
|
6463
6980
|
}
|
|
6464
|
-
async
|
|
6465
|
-
const market =
|
|
6981
|
+
async buildWithdrawCollateral(params) {
|
|
6982
|
+
const market = await this.resolveMarketParams(params.market_id);
|
|
6466
6983
|
const data = encodeFunctionData19({
|
|
6467
6984
|
abi: MORPHO_ABI,
|
|
6468
|
-
functionName: "
|
|
6469
|
-
args: [market, params.amount,
|
|
6985
|
+
functionName: "withdrawCollateral",
|
|
6986
|
+
args: [market, params.amount, params.to, params.to]
|
|
6470
6987
|
});
|
|
6471
6988
|
return {
|
|
6472
|
-
description: `[${this.protocolName}]
|
|
6989
|
+
description: `[${this.protocolName}] Withdraw collateral ${params.amount} of ${params.asset} from market ${params.market_id.slice(0, 10)}\u2026`,
|
|
6473
6990
|
to: this.morpho,
|
|
6474
6991
|
data,
|
|
6475
6992
|
value: 0n,
|
|
@@ -6477,6 +6994,21 @@ var init_dist2 = __esm({
|
|
|
6477
6994
|
};
|
|
6478
6995
|
}
|
|
6479
6996
|
async buildWithdraw(params) {
|
|
6997
|
+
if (params.market_id) {
|
|
6998
|
+
const market = await this.resolveMarketParams(params.market_id);
|
|
6999
|
+
const data = encodeFunctionData19({
|
|
7000
|
+
abi: MORPHO_ABI,
|
|
7001
|
+
functionName: "withdraw",
|
|
7002
|
+
args: [market, params.amount, 0n, params.to, params.to]
|
|
7003
|
+
});
|
|
7004
|
+
return {
|
|
7005
|
+
description: `[${this.protocolName}] Withdraw ${params.amount} of ${params.asset} from market ${params.market_id.slice(0, 10)}\u2026`,
|
|
7006
|
+
to: this.morpho,
|
|
7007
|
+
data,
|
|
7008
|
+
value: 0n,
|
|
7009
|
+
gas_estimate: 3e5
|
|
7010
|
+
};
|
|
7011
|
+
}
|
|
6480
7012
|
const vault = await this.resolveVault(params.asset);
|
|
6481
7013
|
if (vault) {
|
|
6482
7014
|
if (params.amount === MAX_UINT256) {
|
|
@@ -6485,7 +7017,7 @@ var init_dist2 = __esm({
|
|
|
6485
7017
|
[vault, encodeFunctionData19({ abi: ERC4626_ABI, functionName: "balanceOf", args: [params.to] })]
|
|
6486
7018
|
]);
|
|
6487
7019
|
const shares = decodeU256(balRaw ?? null);
|
|
6488
|
-
const
|
|
7020
|
+
const data2 = encodeFunctionData19({
|
|
6489
7021
|
abi: ERC4626_ABI,
|
|
6490
7022
|
functionName: "redeem",
|
|
6491
7023
|
args: [shares, params.to, params.to]
|
|
@@ -6493,12 +7025,12 @@ var init_dist2 = __esm({
|
|
|
6493
7025
|
return {
|
|
6494
7026
|
description: `[${this.protocolName}] Redeem all shares (${shares}) from MetaMorpho vault`,
|
|
6495
7027
|
to: vault,
|
|
6496
|
-
data:
|
|
7028
|
+
data: data2,
|
|
6497
7029
|
value: 0n,
|
|
6498
7030
|
gas_estimate: 4e5
|
|
6499
7031
|
};
|
|
6500
7032
|
}
|
|
6501
|
-
const
|
|
7033
|
+
const data = encodeFunctionData19({
|
|
6502
7034
|
abi: ERC4626_ABI,
|
|
6503
7035
|
functionName: "withdraw",
|
|
6504
7036
|
args: [params.amount, params.to, params.to]
|
|
@@ -6506,24 +7038,14 @@ var init_dist2 = __esm({
|
|
|
6506
7038
|
return {
|
|
6507
7039
|
description: `[${this.protocolName}] Withdraw ${params.amount} assets from MetaMorpho vault`,
|
|
6508
7040
|
to: vault,
|
|
6509
|
-
data
|
|
7041
|
+
data,
|
|
6510
7042
|
value: 0n,
|
|
6511
7043
|
gas_estimate: 4e5
|
|
6512
7044
|
};
|
|
6513
7045
|
}
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
functionName: "withdraw",
|
|
6518
|
-
args: [market, params.amount, 0n, params.to, params.to]
|
|
6519
|
-
});
|
|
6520
|
-
return {
|
|
6521
|
-
description: `[${this.protocolName}] Withdraw ${params.amount} from Morpho market`,
|
|
6522
|
-
to: this.morpho,
|
|
6523
|
-
data,
|
|
6524
|
-
value: 0n,
|
|
6525
|
-
gas_estimate: 25e4
|
|
6526
|
-
};
|
|
7046
|
+
throw DefiError.invalidParam(
|
|
7047
|
+
`[${this.protocolName}] withdraw requires either a registered MetaMorpho vault for ${params.asset} or an explicit --market <marketId>. The legacy zero-MarketParams stub was removed (it always reverted on-chain).`
|
|
7048
|
+
);
|
|
6527
7049
|
}
|
|
6528
7050
|
async getRates(asset) {
|
|
6529
7051
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
@@ -6640,7 +7162,7 @@ var init_dist2 = __esm({
|
|
|
6640
7162
|
if (!this.hintHelpers || !this.sortedTroves || !this.rpcUrl) {
|
|
6641
7163
|
return [0n, 0n];
|
|
6642
7164
|
}
|
|
6643
|
-
const client =
|
|
7165
|
+
const client = createPublicClient17({ transport: http17(this.rpcUrl) });
|
|
6644
7166
|
const approxResult = await client.readContract({
|
|
6645
7167
|
address: this.hintHelpers,
|
|
6646
7168
|
abi: HINT_HELPERS_ABI,
|
|
@@ -6731,7 +7253,7 @@ var init_dist2 = __esm({
|
|
|
6731
7253
|
async getCdpInfo(cdpId) {
|
|
6732
7254
|
if (!this.rpcUrl) throw DefiError.rpcError(`[${this.protocolName}] getCdpInfo requires RPC \u2014 set HYPEREVM_RPC_URL`);
|
|
6733
7255
|
if (!this.troveManager) throw DefiError.contractError(`[${this.protocolName}] trove_manager contract not configured`);
|
|
6734
|
-
const client =
|
|
7256
|
+
const client = createPublicClient17({ transport: http17(this.rpcUrl) });
|
|
6735
7257
|
const data = await client.readContract({
|
|
6736
7258
|
address: this.troveManager,
|
|
6737
7259
|
abi: TROVE_MANAGER_ABI,
|
|
@@ -6749,13 +7271,13 @@ var init_dist2 = __esm({
|
|
|
6749
7271
|
protocol: this.protocolName,
|
|
6750
7272
|
cdp_id: cdpId,
|
|
6751
7273
|
collateral: {
|
|
6752
|
-
token:
|
|
7274
|
+
token: zeroAddress10,
|
|
6753
7275
|
symbol: "WHYPE",
|
|
6754
7276
|
amount: entireColl,
|
|
6755
7277
|
decimals: 18
|
|
6756
7278
|
},
|
|
6757
7279
|
debt: {
|
|
6758
|
-
token:
|
|
7280
|
+
token: zeroAddress10,
|
|
6759
7281
|
symbol: "feUSD",
|
|
6760
7282
|
amount: entireDebt,
|
|
6761
7283
|
decimals: 18
|
|
@@ -6790,7 +7312,7 @@ var init_dist2 = __esm({
|
|
|
6790
7312
|
if (asset !== this.asset && this.asset !== "0x0000000000000000000000000000000000000000") {
|
|
6791
7313
|
throw DefiError.unsupported(`[${this.protocolName}] Felix PriceFeed only supports asset ${this.asset}`);
|
|
6792
7314
|
}
|
|
6793
|
-
const client =
|
|
7315
|
+
const client = createPublicClient18({ transport: http18(this.rpcUrl) });
|
|
6794
7316
|
let priceVal;
|
|
6795
7317
|
try {
|
|
6796
7318
|
const result = await client.readContract({
|
|
@@ -6882,7 +7404,7 @@ var init_dist2 = __esm({
|
|
|
6882
7404
|
}
|
|
6883
7405
|
async totalAssets() {
|
|
6884
7406
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
6885
|
-
const client =
|
|
7407
|
+
const client = createPublicClient19({ transport: http19(this.rpcUrl) });
|
|
6886
7408
|
return client.readContract({
|
|
6887
7409
|
address: this.vaultAddress,
|
|
6888
7410
|
abi: ERC4626_ABI2,
|
|
@@ -6893,7 +7415,7 @@ var init_dist2 = __esm({
|
|
|
6893
7415
|
}
|
|
6894
7416
|
async convertToShares(assets) {
|
|
6895
7417
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
6896
|
-
const client =
|
|
7418
|
+
const client = createPublicClient19({ transport: http19(this.rpcUrl) });
|
|
6897
7419
|
return client.readContract({
|
|
6898
7420
|
address: this.vaultAddress,
|
|
6899
7421
|
abi: ERC4626_ABI2,
|
|
@@ -6905,7 +7427,7 @@ var init_dist2 = __esm({
|
|
|
6905
7427
|
}
|
|
6906
7428
|
async convertToAssets(shares) {
|
|
6907
7429
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
6908
|
-
const client =
|
|
7430
|
+
const client = createPublicClient19({ transport: http19(this.rpcUrl) });
|
|
6909
7431
|
return client.readContract({
|
|
6910
7432
|
address: this.vaultAddress,
|
|
6911
7433
|
abi: ERC4626_ABI2,
|
|
@@ -6917,7 +7439,7 @@ var init_dist2 = __esm({
|
|
|
6917
7439
|
}
|
|
6918
7440
|
async getVaultInfo() {
|
|
6919
7441
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
6920
|
-
const client =
|
|
7442
|
+
const client = createPublicClient19({ transport: http19(this.rpcUrl) });
|
|
6921
7443
|
const [totalAssets, totalSupply, asset] = await Promise.all([
|
|
6922
7444
|
client.readContract({ address: this.vaultAddress, abi: ERC4626_ABI2, functionName: "totalAssets" }).catch((e) => {
|
|
6923
7445
|
throw DefiError.rpcError(`[${this.protocolName}] totalAssets failed: ${e}`);
|
|
@@ -7009,7 +7531,7 @@ var init_dist2 = __esm({
|
|
|
7009
7531
|
const data = encodeFunctionData23({
|
|
7010
7532
|
abi: STHYPE_ABI,
|
|
7011
7533
|
functionName: "submit",
|
|
7012
|
-
args: [
|
|
7534
|
+
args: [zeroAddress11]
|
|
7013
7535
|
});
|
|
7014
7536
|
return {
|
|
7015
7537
|
description: `[${this.protocolName}] Stake ${params.amount} HYPE for stHYPE`,
|
|
@@ -7035,7 +7557,7 @@ var init_dist2 = __esm({
|
|
|
7035
7557
|
}
|
|
7036
7558
|
async getInfo() {
|
|
7037
7559
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
7038
|
-
const client =
|
|
7560
|
+
const client = createPublicClient20({ transport: http20(this.rpcUrl) });
|
|
7039
7561
|
const tokenAddr = this.sthypeToken ?? this.staking;
|
|
7040
7562
|
const totalSupply = await client.readContract({
|
|
7041
7563
|
address: tokenAddr,
|
|
@@ -7046,7 +7568,7 @@ var init_dist2 = __esm({
|
|
|
7046
7568
|
});
|
|
7047
7569
|
return {
|
|
7048
7570
|
protocol: this.protocolName,
|
|
7049
|
-
staked_token:
|
|
7571
|
+
staked_token: zeroAddress11,
|
|
7050
7572
|
liquid_token: tokenAddr,
|
|
7051
7573
|
exchange_rate: 1,
|
|
7052
7574
|
total_staked: totalSupply
|
|
@@ -7105,7 +7627,7 @@ var init_dist2 = __esm({
|
|
|
7105
7627
|
}
|
|
7106
7628
|
async getInfo() {
|
|
7107
7629
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
7108
|
-
const client =
|
|
7630
|
+
const client = createPublicClient21({ transport: http21(this.rpcUrl) });
|
|
7109
7631
|
const totalStaked = await client.readContract({
|
|
7110
7632
|
address: this.staking,
|
|
7111
7633
|
abi: KINETIQ_ABI,
|
|
@@ -7120,7 +7642,7 @@ var init_dist2 = __esm({
|
|
|
7120
7642
|
const rateF64 = hypePrice > 0n && khypePrice > 0n ? Number(khypePrice * 10n ** 18n / hypePrice) / 1e18 : 1;
|
|
7121
7643
|
return {
|
|
7122
7644
|
protocol: this.protocolName,
|
|
7123
|
-
staked_token:
|
|
7645
|
+
staked_token: zeroAddress12,
|
|
7124
7646
|
liquid_token: this.liquidToken,
|
|
7125
7647
|
exchange_rate: rateF64,
|
|
7126
7648
|
total_staked: totalStaked
|
|
@@ -7340,7 +7862,7 @@ var init_dist2 = __esm({
|
|
|
7340
7862
|
}
|
|
7341
7863
|
async getCollectionInfo(collection) {
|
|
7342
7864
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
7343
|
-
const client =
|
|
7865
|
+
const client = createPublicClient222({ transport: http222(this.rpcUrl) });
|
|
7344
7866
|
const [collectionName, symbol, totalSupply] = await Promise.all([
|
|
7345
7867
|
client.readContract({ address: collection, abi: ERC721_ABI, functionName: "name" }).catch((e) => {
|
|
7346
7868
|
throw DefiError.rpcError(`[${this.protocolName}] name failed: ${e}`);
|
|
@@ -7359,7 +7881,7 @@ var init_dist2 = __esm({
|
|
|
7359
7881
|
}
|
|
7360
7882
|
async getTokenInfo(collection, tokenId) {
|
|
7361
7883
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
7362
|
-
const client =
|
|
7884
|
+
const client = createPublicClient222({ transport: http222(this.rpcUrl) });
|
|
7363
7885
|
const [owner, tokenUri] = await Promise.all([
|
|
7364
7886
|
client.readContract({ address: collection, abi: ERC721_ABI, functionName: "ownerOf", args: [tokenId] }).catch((e) => {
|
|
7365
7887
|
throw DefiError.rpcError(`[${this.protocolName}] ownerOf failed: ${e}`);
|
|
@@ -7375,7 +7897,7 @@ var init_dist2 = __esm({
|
|
|
7375
7897
|
}
|
|
7376
7898
|
async getBalance(owner, collection) {
|
|
7377
7899
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
7378
|
-
const client =
|
|
7900
|
+
const client = createPublicClient222({ transport: http222(this.rpcUrl) });
|
|
7379
7901
|
return client.readContract({ address: collection, abi: ERC721_ABI, functionName: "balanceOf", args: [owner] }).catch((e) => {
|
|
7380
7902
|
throw DefiError.rpcError(`[${this.protocolName}] balanceOf failed: ${e}`);
|
|
7381
7903
|
});
|
|
@@ -7445,10 +7967,22 @@ var Executor = class _Executor {
|
|
|
7445
7967
|
dryRun;
|
|
7446
7968
|
rpcUrl;
|
|
7447
7969
|
explorerUrl;
|
|
7448
|
-
|
|
7970
|
+
/**
|
|
7971
|
+
* Optional viem Chain object. When set, all wallet/public clients built
|
|
7972
|
+
* inside this executor anchor to the explicit chainId at construction
|
|
7973
|
+
* time, defending against MITM RPCs that lie about eth_chainId and
|
|
7974
|
+
* keeping offline-signing safe under RPC drift (SSOT 7.4).
|
|
7975
|
+
*/
|
|
7976
|
+
chain;
|
|
7977
|
+
constructor(broadcast, rpcUrl, explorerUrl, chain) {
|
|
7449
7978
|
this.dryRun = !broadcast;
|
|
7450
7979
|
this.rpcUrl = rpcUrl;
|
|
7451
7980
|
this.explorerUrl = explorerUrl;
|
|
7981
|
+
this.chain = chain;
|
|
7982
|
+
}
|
|
7983
|
+
/** Returns the optional `{ chain }` spread for viem client constructors. */
|
|
7984
|
+
chainOpt() {
|
|
7985
|
+
return this.chain ? { chain: this.chain } : {};
|
|
7452
7986
|
}
|
|
7453
7987
|
/** Apply 20% buffer to a gas estimate */
|
|
7454
7988
|
static applyGasBuffer(gas) {
|
|
@@ -7572,7 +8106,7 @@ var Executor = class _Executor {
|
|
|
7572
8106
|
*/
|
|
7573
8107
|
async fetchEip1559Fees(rpcUrl) {
|
|
7574
8108
|
try {
|
|
7575
|
-
const client = createPublicClient23({ transport: http23(rpcUrl) });
|
|
8109
|
+
const client = createPublicClient23({ transport: http23(rpcUrl), ...this.chainOpt() });
|
|
7576
8110
|
let priorityFee = DEFAULT_PRIORITY_FEE_WEI;
|
|
7577
8111
|
try {
|
|
7578
8112
|
priorityFee = await client.estimateMaxPriorityFeePerGas();
|
|
@@ -7594,7 +8128,7 @@ var Executor = class _Executor {
|
|
|
7594
8128
|
/** Estimate gas dynamically with buffer, falling back to a hardcoded estimate */
|
|
7595
8129
|
async estimateGasWithBuffer(rpcUrl, tx, from) {
|
|
7596
8130
|
try {
|
|
7597
|
-
const client = createPublicClient23({ transport: http23(rpcUrl) });
|
|
8131
|
+
const client = createPublicClient23({ transport: http23(rpcUrl), ...this.chainOpt() });
|
|
7598
8132
|
const estimated = await client.estimateGas({
|
|
7599
8133
|
to: tx.to,
|
|
7600
8134
|
data: tx.data,
|
|
@@ -7618,7 +8152,7 @@ var Executor = class _Executor {
|
|
|
7618
8152
|
if (!rpcUrl) {
|
|
7619
8153
|
throw DefiError.rpcError("No RPC URL \u2014 cannot simulate. Set HYPEREVM_RPC_URL.");
|
|
7620
8154
|
}
|
|
7621
|
-
const client = createPublicClient23({ transport: http23(rpcUrl) });
|
|
8155
|
+
const client = createPublicClient23({ transport: http23(rpcUrl), ...this.chainOpt() });
|
|
7622
8156
|
const privateKey = process.env["DEFI_PRIVATE_KEY"];
|
|
7623
8157
|
const from = privateKey ? privateKeyToAccount(privateKey).address : "0x0000000000000000000000000000000000000001";
|
|
7624
8158
|
if (tx.approvals && tx.approvals.length > 0) {
|
|
@@ -7732,8 +8266,8 @@ var Executor = class _Executor {
|
|
|
7732
8266
|
if (!rpcUrl) {
|
|
7733
8267
|
throw DefiError.rpcError("No RPC URL configured for broadcasting");
|
|
7734
8268
|
}
|
|
7735
|
-
const publicClient = createPublicClient23({ transport: http23(rpcUrl) });
|
|
7736
|
-
const walletClient = createWalletClient({ account, transport: http23(rpcUrl) });
|
|
8269
|
+
const publicClient = createPublicClient23({ transport: http23(rpcUrl), ...this.chainOpt() });
|
|
8270
|
+
const walletClient = createWalletClient({ account, transport: http23(rpcUrl), ...this.chainOpt() });
|
|
7737
8271
|
if (tx.pre_txs && tx.pre_txs.length > 0) {
|
|
7738
8272
|
for (const preTx of tx.pre_txs) {
|
|
7739
8273
|
process.stderr.write(` Pre-tx: ${preTx.description}...
|
|
@@ -8120,19 +8654,20 @@ server.tool(
|
|
|
8120
8654
|
);
|
|
8121
8655
|
server.tool(
|
|
8122
8656
|
"defi_bridge",
|
|
8123
|
-
"Get a cross-chain bridge quote via LI.FI
|
|
8657
|
+
"Get a cross-chain bridge quote via LI.FI (default) or Relay. Returns estimated output and fees. For deBridge / CCTP quotes plus broadcast use the `defi bridge --provider <name>` CLI directly.",
|
|
8124
8658
|
{
|
|
8125
8659
|
from_chain: z.string().describe("Source chain name (supported source chains: hyperevm, mantle, base, bnb, monad)"),
|
|
8126
|
-
to_chain: z.string().describe("Destination chain name. CCTP V2 destinations include ethereum, arbitrum, optimism, polygon, avalanche; LI.FI/deBridge accept any chain"),
|
|
8127
|
-
token: z.string().optional().describe("Token symbol to bridge (default: USDC). Use
|
|
8660
|
+
to_chain: z.string().describe("Destination chain name. CCTP V2 destinations include ethereum, arbitrum, optimism, polygon, avalanche; LI.FI/Relay/deBridge accept any chain they route to"),
|
|
8661
|
+
token: z.string().optional().describe("Token symbol or address to bridge (default: USDC). Use 0x0\u20260 for native gas token. Relay rejects some ERC20s (e.g. BNB USDC/USDT) with INVALID_INPUT_CURRENCY \u2014 fall back to native or LI.FI"),
|
|
8128
8662
|
amount: z.string().describe("Amount in human-readable units, e.g. '100' for 100 USDC"),
|
|
8129
|
-
recipient: z.string().optional().describe("Recipient address on destination chain")
|
|
8663
|
+
recipient: z.string().optional().describe("Recipient address on destination chain"),
|
|
8664
|
+
provider: z.enum(["lifi", "relay"]).optional().describe("Bridge provider for the quote (default: lifi). For debridge/cctp use the CLI.")
|
|
8130
8665
|
},
|
|
8131
|
-
async ({ from_chain, to_chain, token, amount, recipient }) => {
|
|
8666
|
+
async ({ from_chain, to_chain, token, amount, recipient, provider }) => {
|
|
8132
8667
|
try {
|
|
8133
8668
|
const tokenSymbol = token ?? "USDC";
|
|
8134
8669
|
const recipientAddr = recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
|
|
8135
|
-
const
|
|
8670
|
+
const selectedProvider = provider ?? "lifi";
|
|
8136
8671
|
const registry = getRegistry();
|
|
8137
8672
|
let fromChainId;
|
|
8138
8673
|
let toChainId;
|
|
@@ -8144,14 +8679,81 @@ server.tool(
|
|
|
8144
8679
|
toChainId = registry.getChain(to_chain).chain_id;
|
|
8145
8680
|
} catch {
|
|
8146
8681
|
}
|
|
8682
|
+
const isAddr = tokenSymbol.startsWith("0x");
|
|
8683
|
+
const NATIVE = "0x0000000000000000000000000000000000000000";
|
|
8684
|
+
let srcTokenAddr;
|
|
8685
|
+
let dstTokenAddr;
|
|
8686
|
+
let tokenDecimals = 18;
|
|
8687
|
+
let dstTokenDecimals = 18;
|
|
8688
|
+
if (isAddr) {
|
|
8689
|
+
srcTokenAddr = tokenSymbol;
|
|
8690
|
+
dstTokenAddr = tokenSymbol;
|
|
8691
|
+
} else {
|
|
8692
|
+
try {
|
|
8693
|
+
const srcResolved = registry.resolveToken(from_chain, tokenSymbol);
|
|
8694
|
+
srcTokenAddr = srcResolved.address;
|
|
8695
|
+
tokenDecimals = srcResolved.decimals ?? 18;
|
|
8696
|
+
} catch {
|
|
8697
|
+
srcTokenAddr = NATIVE;
|
|
8698
|
+
tokenDecimals = 18;
|
|
8699
|
+
}
|
|
8700
|
+
try {
|
|
8701
|
+
const dstResolved = registry.resolveToken(to_chain, tokenSymbol);
|
|
8702
|
+
dstTokenAddr = dstResolved.address;
|
|
8703
|
+
dstTokenDecimals = dstResolved.decimals ?? tokenDecimals;
|
|
8704
|
+
} catch {
|
|
8705
|
+
dstTokenAddr = srcTokenAddr;
|
|
8706
|
+
dstTokenDecimals = tokenDecimals;
|
|
8707
|
+
}
|
|
8708
|
+
}
|
|
8709
|
+
if (selectedProvider === "relay") {
|
|
8710
|
+
const RELAY_API = "https://api.relay.link";
|
|
8711
|
+
if (!fromChainId || !toChainId) {
|
|
8712
|
+
throw new Error("Relay requires resolvable numeric chain IDs for both source and destination");
|
|
8713
|
+
}
|
|
8714
|
+
const amountRaw = String(BigInt(Math.round(parseFloat(amount) * Math.pow(10, tokenDecimals))));
|
|
8715
|
+
const res2 = await fetch(`${RELAY_API}/quote`, {
|
|
8716
|
+
method: "POST",
|
|
8717
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
8718
|
+
body: JSON.stringify({
|
|
8719
|
+
user: recipientAddr,
|
|
8720
|
+
recipient: recipientAddr,
|
|
8721
|
+
originChainId: fromChainId,
|
|
8722
|
+
destinationChainId: toChainId,
|
|
8723
|
+
originCurrency: srcTokenAddr,
|
|
8724
|
+
destinationCurrency: dstTokenAddr,
|
|
8725
|
+
tradeType: "EXACT_INPUT",
|
|
8726
|
+
amount: amountRaw
|
|
8727
|
+
})
|
|
8728
|
+
});
|
|
8729
|
+
if (!res2.ok) {
|
|
8730
|
+
const text = await res2.text();
|
|
8731
|
+
throw new Error(`Relay quote failed (${res2.status}): ${text.slice(0, 200)}`);
|
|
8732
|
+
}
|
|
8733
|
+
const data2 = await res2.json();
|
|
8734
|
+
const details = data2.details;
|
|
8735
|
+
const fees = data2.fees;
|
|
8736
|
+
const quote2 = {
|
|
8737
|
+
from_chain,
|
|
8738
|
+
to_chain,
|
|
8739
|
+
token: tokenSymbol,
|
|
8740
|
+
amount_in: amount,
|
|
8741
|
+
amount_out: details?.currencyOut?.amountFormatted ?? "unknown",
|
|
8742
|
+
fees,
|
|
8743
|
+
execution_duration_seconds: details?.timeEstimate ?? "unknown",
|
|
8744
|
+
tool: "relay",
|
|
8745
|
+
raw: data2
|
|
8746
|
+
};
|
|
8747
|
+
return { content: [{ type: "text", text: ok(quote2, { from_chain, to_chain, token: tokenSymbol, provider: "relay" }) }] };
|
|
8748
|
+
}
|
|
8749
|
+
const LIFI_API = "https://li.quest/v1";
|
|
8147
8750
|
const params = new URLSearchParams({
|
|
8148
8751
|
fromChain: fromChainId ? String(fromChainId) : from_chain,
|
|
8149
8752
|
toChain: toChainId ? String(toChainId) : to_chain,
|
|
8150
|
-
fromToken:
|
|
8151
|
-
toToken:
|
|
8152
|
-
fromAmount: String(Math.round(parseFloat(amount) *
|
|
8153
|
-
|
|
8154
|
-
toAddress: recipientAddr
|
|
8753
|
+
fromToken: srcTokenAddr,
|
|
8754
|
+
toToken: dstTokenAddr,
|
|
8755
|
+
fromAmount: String(BigInt(Math.round(parseFloat(amount) * Math.pow(10, tokenDecimals)))),
|
|
8756
|
+
fromAddress: recipientAddr
|
|
8155
8757
|
});
|
|
8156
8758
|
const res = await fetch(`${LIFI_API}/quote?${params}`, {
|
|
8157
8759
|
headers: { Accept: "application/json" }
|
|
@@ -8162,19 +8764,21 @@ server.tool(
|
|
|
8162
8764
|
}
|
|
8163
8765
|
const data = await res.json();
|
|
8164
8766
|
const estimate = data.estimate;
|
|
8767
|
+
const lifiDstDecimals = estimate?.toToken?.decimals;
|
|
8768
|
+
const amountOutDivisor = Math.pow(10, lifiDstDecimals ?? dstTokenDecimals);
|
|
8165
8769
|
const quote = {
|
|
8166
8770
|
from_chain,
|
|
8167
8771
|
to_chain,
|
|
8168
8772
|
token: tokenSymbol,
|
|
8169
8773
|
amount_in: amount,
|
|
8170
|
-
amount_out: estimate?.toAmount ? String(Number(estimate.toAmount) /
|
|
8774
|
+
amount_out: estimate?.toAmount ? String(Number(estimate.toAmount) / amountOutDivisor) : "unknown",
|
|
8171
8775
|
fee_costs: estimate?.feeCosts ?? [],
|
|
8172
8776
|
gas_costs: estimate?.gasCosts ?? [],
|
|
8173
8777
|
execution_duration_seconds: estimate?.executionDuration ?? "unknown",
|
|
8174
8778
|
tool: data.tool ?? "unknown",
|
|
8175
8779
|
raw: data
|
|
8176
8780
|
};
|
|
8177
|
-
return { content: [{ type: "text", text: ok(quote, { from_chain, to_chain, token: tokenSymbol }) }] };
|
|
8781
|
+
return { content: [{ type: "text", text: ok(quote, { from_chain, to_chain, token: tokenSymbol, provider: "lifi" }) }] };
|
|
8178
8782
|
} catch (e) {
|
|
8179
8783
|
return { content: [{ type: "text", text: err(e instanceof Error ? e.message : String(e), { from_chain, to_chain }) }], isError: true };
|
|
8180
8784
|
}
|