@hypurrquant/defi-cli 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7511 -6043
- package/dist/index.js.map +1 -1
- package/dist/main.js +7552 -6082
- package/dist/main.js.map +1 -1
- package/dist/mcp-server.js +206 -42
- package/dist/mcp-server.js.map +1 -1
- package/package.json +3 -3
package/dist/mcp-server.js
CHANGED
|
@@ -436,9 +436,9 @@ var init_dist = __esm({
|
|
|
436
436
|
getProtocolsByCategory(category) {
|
|
437
437
|
return this.protocols.filter((p) => p.category === category);
|
|
438
438
|
}
|
|
439
|
-
getProtocolsForChain(chain) {
|
|
439
|
+
getProtocolsForChain(chain, includeUnverified = false) {
|
|
440
440
|
return this.protocols.filter(
|
|
441
|
-
(p) => p.chain.toLowerCase() === chain.toLowerCase()
|
|
441
|
+
(p) => p.chain.toLowerCase() === chain.toLowerCase() && (includeUnverified || p.verified !== false)
|
|
442
442
|
);
|
|
443
443
|
}
|
|
444
444
|
resolveToken(chain, symbol) {
|
|
@@ -932,7 +932,7 @@ function createLiquidStaking(entry, rpcUrl) {
|
|
|
932
932
|
return new GenericLstAdapter(entry, rpcUrl);
|
|
933
933
|
}
|
|
934
934
|
}
|
|
935
|
-
function createGauge(entry, rpcUrl) {
|
|
935
|
+
function createGauge(entry, rpcUrl, tokens) {
|
|
936
936
|
if (entry.interface === "hybra" || entry.contracts?.["gauge_manager"]) {
|
|
937
937
|
return new HybraGaugeAdapter(entry, rpcUrl);
|
|
938
938
|
}
|
|
@@ -940,7 +940,11 @@ function createGauge(entry, rpcUrl) {
|
|
|
940
940
|
case "solidly_v2":
|
|
941
941
|
case "solidly_cl":
|
|
942
942
|
case "algebra_v3":
|
|
943
|
-
return new SolidlyGaugeAdapter(entry, rpcUrl);
|
|
943
|
+
return new SolidlyGaugeAdapter(entry, rpcUrl, tokens);
|
|
944
|
+
// uniswap_v3 with voter = ve(3,3) CL (e.g., Aerodrome Slipstream, Ramses CL)
|
|
945
|
+
case "uniswap_v3":
|
|
946
|
+
if (entry.contracts?.["voter"]) return new SolidlyGaugeAdapter(entry, rpcUrl, tokens);
|
|
947
|
+
throw DefiError.unsupported(`Gauge interface '${entry.interface}' not supported (no voter contract)`);
|
|
944
948
|
default:
|
|
945
949
|
throw DefiError.unsupported(`Gauge interface '${entry.interface}' not supported`);
|
|
946
950
|
}
|
|
@@ -2295,6 +2299,8 @@ var init_dist2 = __esm({
|
|
|
2295
2299
|
gauge,
|
|
2296
2300
|
token0: t0 ? symbolMap.get(t0) ?? t0.slice(0, 10) : "?",
|
|
2297
2301
|
token1: t1 ? symbolMap.get(t1) ?? t1.slice(0, 10) : "?",
|
|
2302
|
+
token0Addr: t0 ?? void 0,
|
|
2303
|
+
token1Addr: t1 ?? void 0,
|
|
2298
2304
|
type: "CL"
|
|
2299
2305
|
});
|
|
2300
2306
|
}
|
|
@@ -2500,6 +2506,7 @@ var init_dist2 = __esm({
|
|
|
2500
2506
|
"function getReward(address account, address[] tokens) external",
|
|
2501
2507
|
"function getReward(uint256 tokenId) external",
|
|
2502
2508
|
"function earned(address account) external view returns (uint256)",
|
|
2509
|
+
"function earned(address account, uint256 tokenId) external view returns (uint256)",
|
|
2503
2510
|
"function earned(address token, address account) external view returns (uint256)",
|
|
2504
2511
|
"function earned(uint256 tokenId) external view returns (uint256)",
|
|
2505
2512
|
"function rewardRate() external view returns (uint256)",
|
|
@@ -2550,7 +2557,8 @@ var init_dist2 = __esm({
|
|
|
2550
2557
|
rpcUrl;
|
|
2551
2558
|
clFactory;
|
|
2552
2559
|
v2Factory;
|
|
2553
|
-
|
|
2560
|
+
tokens;
|
|
2561
|
+
constructor(entry, rpcUrl, tokens) {
|
|
2554
2562
|
this.protocolName = entry.name;
|
|
2555
2563
|
const voter = entry.contracts?.["voter"];
|
|
2556
2564
|
if (!voter) {
|
|
@@ -2563,6 +2571,7 @@ var init_dist2 = __esm({
|
|
|
2563
2571
|
this.voter = voter;
|
|
2564
2572
|
this.veToken = veToken;
|
|
2565
2573
|
this.rpcUrl = rpcUrl;
|
|
2574
|
+
this.tokens = tokens;
|
|
2566
2575
|
this.clFactory = entry.contracts?.["cl_factory"] ?? entry.contracts?.["factory"];
|
|
2567
2576
|
this.v2Factory = entry.contracts?.["pair_factory"] ?? entry.contracts?.["factory"];
|
|
2568
2577
|
}
|
|
@@ -2577,57 +2586,148 @@ var init_dist2 = __esm({
|
|
|
2577
2586
|
this._discoverV2GaugedPools(results),
|
|
2578
2587
|
this._discoverCLGaugedPools(results)
|
|
2579
2588
|
]);
|
|
2589
|
+
await this._enrichGaugeMetrics(results);
|
|
2580
2590
|
return results;
|
|
2581
2591
|
}
|
|
2592
|
+
/**
|
|
2593
|
+
* Batch query rewardRate, totalSupply, rewardToken for all discovered gauges.
|
|
2594
|
+
* Handles both single-token (rewardRate) and multi-token (rewardData) gauges.
|
|
2595
|
+
*/
|
|
2596
|
+
async _enrichGaugeMetrics(pools) {
|
|
2597
|
+
if (!this.rpcUrl || pools.length === 0) return;
|
|
2598
|
+
const _u256Abi = parseAbi10(["function f() view returns (uint256)"]);
|
|
2599
|
+
const calls = [];
|
|
2600
|
+
for (const p of pools) {
|
|
2601
|
+
calls.push([p.gauge, encodeFunctionData10({ abi: gaugeAbi, functionName: "rewardRate" })]);
|
|
2602
|
+
calls.push([p.gauge, encodeFunctionData10({ abi: gaugeAbi, functionName: "totalSupply" })]);
|
|
2603
|
+
calls.push([p.gauge, encodeFunctionData10({ abi: gaugeAbi, functionName: "rewardToken" })]);
|
|
2604
|
+
}
|
|
2605
|
+
const results = await multicallRead(this.rpcUrl, calls).catch(() => []);
|
|
2606
|
+
for (let i = 0; i < pools.length; i++) {
|
|
2607
|
+
const base = i * 3;
|
|
2608
|
+
try {
|
|
2609
|
+
pools[i].rewardRate = results[base] ? decodeFunctionResult3({ abi: _u256Abi, functionName: "f", data: results[base] }) : 0n;
|
|
2610
|
+
} catch {
|
|
2611
|
+
pools[i].rewardRate = 0n;
|
|
2612
|
+
}
|
|
2613
|
+
try {
|
|
2614
|
+
pools[i].totalStaked = results[base + 1] ? decodeFunctionResult3({ abi: _u256Abi, functionName: "f", data: results[base + 1] }) : 0n;
|
|
2615
|
+
} catch {
|
|
2616
|
+
pools[i].totalStaked = 0n;
|
|
2617
|
+
}
|
|
2618
|
+
try {
|
|
2619
|
+
pools[i].rewardToken = results[base + 2] ? decodeAddress2(results[base + 2]) ?? void 0 : void 0;
|
|
2620
|
+
} catch {
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
const KNOWN_REWARD_TOKENS = [
|
|
2624
|
+
"0x555570a286F15EbDFE42B66eDE2f724Aa1AB5555",
|
|
2625
|
+
// xRAM
|
|
2626
|
+
"0x5555555555555555555555555555555555555555",
|
|
2627
|
+
// WHYPE
|
|
2628
|
+
"0x067b0C72aa4C6Bd3BFEFfF443c536DCd6a25a9C8",
|
|
2629
|
+
// HYBR
|
|
2630
|
+
"0x07c57E32a3C29D5659bda1d3EFC2E7BF004E3035"
|
|
2631
|
+
// NEST
|
|
2632
|
+
];
|
|
2633
|
+
const needsFallback = pools.filter((p) => (p.rewardRate ?? 0n) === 0n && (p.totalStaked ?? 0n) > 0n);
|
|
2634
|
+
if (needsFallback.length === 0) return;
|
|
2635
|
+
const rdCalls = [];
|
|
2636
|
+
const rdMeta = [];
|
|
2637
|
+
for (const p of needsFallback) {
|
|
2638
|
+
const poolIdx = pools.indexOf(p);
|
|
2639
|
+
for (const token of KNOWN_REWARD_TOKENS) {
|
|
2640
|
+
rdCalls.push([p.gauge, encodeFunctionData10({ abi: gaugeAbi, functionName: "rewardData", args: [token] })]);
|
|
2641
|
+
rdMeta.push({ poolIdx, token });
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
const rdResults = await multicallRead(this.rpcUrl, rdCalls).catch(() => []);
|
|
2645
|
+
const _rdAbi = parseAbi10(["function f() view returns (uint256, uint256, uint256, uint256)"]);
|
|
2646
|
+
for (let i = 0; i < rdMeta.length; i++) {
|
|
2647
|
+
const { poolIdx, token } = rdMeta[i];
|
|
2648
|
+
const pool = pools[poolIdx];
|
|
2649
|
+
if ((pool.rewardRate ?? 0n) > 0n) continue;
|
|
2650
|
+
try {
|
|
2651
|
+
if (!rdResults[i]) continue;
|
|
2652
|
+
const decoded = decodeFunctionResult3({ abi: _rdAbi, functionName: "f", data: rdResults[i] });
|
|
2653
|
+
const [periodFinish, rewardRate] = decoded;
|
|
2654
|
+
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2655
|
+
if (rewardRate > 0n && periodFinish > now) {
|
|
2656
|
+
pool.rewardRate = rewardRate;
|
|
2657
|
+
pool.rewardToken = token;
|
|
2658
|
+
}
|
|
2659
|
+
} catch {
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2582
2663
|
async _discoverV2GaugedPools(out) {
|
|
2583
2664
|
if (!this.rpcUrl || !this.v2Factory) return;
|
|
2584
|
-
const v2FactoryAbi = parseAbi10([
|
|
2585
|
-
"function allPairsLength() external view returns (uint256)",
|
|
2586
|
-
"function allPairs(uint256) external view returns (address)"
|
|
2587
|
-
]);
|
|
2588
2665
|
const pairAbi = parseAbi10([
|
|
2589
2666
|
"function token0() external view returns (address)",
|
|
2590
2667
|
"function token1() external view returns (address)",
|
|
2591
2668
|
"function stable() external view returns (bool)"
|
|
2592
2669
|
]);
|
|
2593
2670
|
const erc20SymbolAbi = parseAbi10(["function symbol() external view returns (string)"]);
|
|
2671
|
+
const voterLengthAbi = parseAbi10(["function length() external view returns (uint256)"]);
|
|
2672
|
+
const voterPoolsAbi = parseAbi10(["function pools(uint256) external view returns (address)"]);
|
|
2673
|
+
const gaugeForPoolAbi = parseAbi10(["function gaugeForPool(address) external view returns (address)"]);
|
|
2674
|
+
const poolToGaugeAbi = parseAbi10(["function poolToGauge(address) external view returns (address)"]);
|
|
2675
|
+
const gaugesAbi = parseAbi10(["function gauges(address) external view returns (address)"]);
|
|
2594
2676
|
const client = createPublicClient6({ transport: http6(this.rpcUrl) });
|
|
2595
|
-
let
|
|
2677
|
+
let pairs = [];
|
|
2678
|
+
let voterPoolCount = 0;
|
|
2596
2679
|
try {
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
abi: v2FactoryAbi,
|
|
2600
|
-
functionName: "allPairsLength"
|
|
2601
|
-
});
|
|
2680
|
+
const len = await client.readContract({ address: this.voter, abi: voterLengthAbi, functionName: "length" });
|
|
2681
|
+
voterPoolCount = Number(len);
|
|
2602
2682
|
} catch {
|
|
2603
|
-
return;
|
|
2604
2683
|
}
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
this.
|
|
2611
|
-
|
|
2612
|
-
|
|
2684
|
+
if (voterPoolCount > 0) {
|
|
2685
|
+
const MAX_SCAN = 500;
|
|
2686
|
+
const startIdx = Math.max(0, voterPoolCount - MAX_SCAN);
|
|
2687
|
+
const poolCalls = [];
|
|
2688
|
+
for (let i = startIdx; i < voterPoolCount; i++) {
|
|
2689
|
+
poolCalls.push([this.voter, encodeFunctionData10({ abi: voterPoolsAbi, functionName: "pools", args: [BigInt(i)] })]);
|
|
2690
|
+
}
|
|
2691
|
+
const poolResults = await multicallRead(this.rpcUrl, poolCalls);
|
|
2692
|
+
pairs = poolResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !== zeroAddress6);
|
|
2693
|
+
} else {
|
|
2694
|
+
const v2FactoryAbi = parseAbi10(["function allPairsLength() view returns (uint256)", "function allPairs(uint256) view returns (address)"]);
|
|
2695
|
+
const solidlyFactoryAbi = parseAbi10(["function allPoolsLength() view returns (uint256)", "function allPools(uint256) view returns (address)"]);
|
|
2696
|
+
let pairCount = 0n;
|
|
2697
|
+
let useSolidly = false;
|
|
2698
|
+
try {
|
|
2699
|
+
pairCount = await client.readContract({ address: this.v2Factory, abi: v2FactoryAbi, functionName: "allPairsLength" });
|
|
2700
|
+
} catch {
|
|
2701
|
+
try {
|
|
2702
|
+
pairCount = await client.readContract({ address: this.v2Factory, abi: solidlyFactoryAbi, functionName: "allPoolsLength" });
|
|
2703
|
+
useSolidly = true;
|
|
2704
|
+
} catch {
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
const count = Number(pairCount);
|
|
2709
|
+
if (count === 0) return;
|
|
2710
|
+
const MAX_SCAN = 500;
|
|
2711
|
+
const startIdx = Math.max(0, count - MAX_SCAN);
|
|
2712
|
+
const fetchAbi = useSolidly ? solidlyFactoryAbi : v2FactoryAbi;
|
|
2713
|
+
const fetchFn = useSolidly ? "allPools" : "allPairs";
|
|
2714
|
+
const pairCalls = [];
|
|
2715
|
+
for (let i = startIdx; i < count; i++) pairCalls.push([this.v2Factory, encodeFunctionData10({ abi: fetchAbi, functionName: fetchFn, args: [BigInt(i)] })]);
|
|
2716
|
+
const pairResults = await multicallRead(this.rpcUrl, pairCalls);
|
|
2717
|
+
pairs = pairResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !== zeroAddress6);
|
|
2613
2718
|
}
|
|
2614
|
-
const pairAddressResults = await multicallRead(this.rpcUrl, pairAddressCalls);
|
|
2615
|
-
const pairs = pairAddressResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !== zeroAddress6);
|
|
2616
2719
|
if (pairs.length === 0) return;
|
|
2617
|
-
const
|
|
2618
|
-
const poolToGaugeAbi = parseAbi10(["function poolToGauge(address) external view returns (address)"]);
|
|
2619
|
-
const gaugeCalls = pairs.map((pair) => [
|
|
2620
|
-
this.voter,
|
|
2621
|
-
encodeFunctionData10({ abi: gaugeForPoolAbi, functionName: "gaugeForPool", args: [pair] })
|
|
2622
|
-
]);
|
|
2720
|
+
const gaugeCalls = pairs.map((p) => [this.voter, encodeFunctionData10({ abi: gaugeForPoolAbi, functionName: "gaugeForPool", args: [p] })]);
|
|
2623
2721
|
let gaugeResults = await multicallRead(this.rpcUrl, gaugeCalls);
|
|
2624
|
-
const
|
|
2625
|
-
if (
|
|
2626
|
-
const
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2722
|
+
const allNull = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress6 || decodeAddress2(r) === null);
|
|
2723
|
+
if (allNull) {
|
|
2724
|
+
const fb1 = pairs.map((p) => [this.voter, encodeFunctionData10({ abi: poolToGaugeAbi, functionName: "poolToGauge", args: [p] })]);
|
|
2725
|
+
gaugeResults = await multicallRead(this.rpcUrl, fb1);
|
|
2726
|
+
}
|
|
2727
|
+
const allNull2 = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress6 || decodeAddress2(r) === null);
|
|
2728
|
+
if (allNull2) {
|
|
2729
|
+
const fb2 = pairs.map((p) => [this.voter, encodeFunctionData10({ abi: gaugesAbi, functionName: "gauges", args: [p] })]);
|
|
2730
|
+
gaugeResults = await multicallRead(this.rpcUrl, fb2);
|
|
2631
2731
|
}
|
|
2632
2732
|
const gaugedPairs = [];
|
|
2633
2733
|
for (let i = 0; i < pairs.length; i++) {
|
|
@@ -2672,6 +2772,8 @@ var init_dist2 = __esm({
|
|
|
2672
2772
|
gauge,
|
|
2673
2773
|
token0: t0 ? symbolMap.get(t0) ?? t0.slice(0, 10) : "?",
|
|
2674
2774
|
token1: t1 ? symbolMap.get(t1) ?? t1.slice(0, 10) : "?",
|
|
2775
|
+
token0Addr: t0 ?? void 0,
|
|
2776
|
+
token1Addr: t1 ?? void 0,
|
|
2675
2777
|
type: "V2",
|
|
2676
2778
|
stable
|
|
2677
2779
|
});
|
|
@@ -2692,8 +2794,7 @@ var init_dist2 = __esm({
|
|
|
2692
2794
|
const erc20SymbolAbi = parseAbi10(["function symbol() external view returns (string)"]);
|
|
2693
2795
|
const gaugeForPoolAbi = parseAbi10(["function gaugeForPool(address) external view returns (address)"]);
|
|
2694
2796
|
const poolToGaugeAbi = parseAbi10(["function poolToGauge(address) external view returns (address)"]);
|
|
2695
|
-
const
|
|
2696
|
-
const tokenAddresses = tokenEntries.map(([, addr]) => addr);
|
|
2797
|
+
const tokenAddresses = this.tokens ?? Object.values(HYPEREVM_TOKENS);
|
|
2697
2798
|
const pairs = [];
|
|
2698
2799
|
for (let i = 0; i < tokenAddresses.length; i++) {
|
|
2699
2800
|
for (let j = i + 1; j < tokenAddresses.length; j++) {
|
|
@@ -2798,6 +2899,8 @@ var init_dist2 = __esm({
|
|
|
2798
2899
|
gauge,
|
|
2799
2900
|
token0: symbolMap.get(t0) ?? t0.slice(0, 10),
|
|
2800
2901
|
token1: symbolMap.get(t1) ?? t1.slice(0, 10),
|
|
2902
|
+
token0Addr: t0,
|
|
2903
|
+
token1Addr: t1,
|
|
2801
2904
|
type: "CL",
|
|
2802
2905
|
tickSpacing
|
|
2803
2906
|
});
|
|
@@ -3032,6 +3135,21 @@ var init_dist2 = __esm({
|
|
|
3032
3135
|
args: [tokenId]
|
|
3033
3136
|
});
|
|
3034
3137
|
}
|
|
3138
|
+
/**
|
|
3139
|
+
* Get pending rewards for an Aerodrome Slipstream CL gauge NFT position.
|
|
3140
|
+
* Uses the earned(address account, uint256 tokenId) overload, which is required
|
|
3141
|
+
* for CL gauges — the single-param earned(address) reverts on these contracts.
|
|
3142
|
+
*/
|
|
3143
|
+
async getPendingRewardsByCLTokenId(gauge, user, tokenId) {
|
|
3144
|
+
if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required");
|
|
3145
|
+
const client = createPublicClient6({ transport: http6(this.rpcUrl) });
|
|
3146
|
+
return await client.readContract({
|
|
3147
|
+
address: gauge,
|
|
3148
|
+
abi: gaugeAbi,
|
|
3149
|
+
functionName: "earned",
|
|
3150
|
+
args: [user, tokenId]
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3035
3153
|
// IVoteEscrow
|
|
3036
3154
|
async buildCreateLock(amount, lockDuration) {
|
|
3037
3155
|
const data = encodeFunctionData10({
|
|
@@ -5324,7 +5442,7 @@ var init_dist2 = __esm({
|
|
|
5324
5442
|
async getRates(asset) {
|
|
5325
5443
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
5326
5444
|
if (!this.defaultVault) {
|
|
5327
|
-
|
|
5445
|
+
return { protocol: this.protocolName, asset, supply_apy: 0, borrow_variable_apy: 0, borrow_stable_apy: 0, utilization: 0, total_supply: 0n, total_borrow: 0n };
|
|
5328
5446
|
}
|
|
5329
5447
|
const [queueLenRaw] = await multicallRead(this.rpcUrl, [
|
|
5330
5448
|
[this.defaultVault, encodeFunctionData19({ abi: META_MORPHO_ABI, functionName: "supplyQueueLength" })]
|
|
@@ -7469,6 +7587,52 @@ server.tool(
|
|
|
7469
7587
|
}
|
|
7470
7588
|
}
|
|
7471
7589
|
);
|
|
7590
|
+
server.tool(
|
|
7591
|
+
"defi_yield_scan",
|
|
7592
|
+
"Scan all configured chains for the best lending yield opportunities for a given asset. Compares supply APY across Aave V3, Compound, Venus, Morpho, etc. Returns ranked results with chain, protocol, supply_apy, borrow_apy, utilization.",
|
|
7593
|
+
{
|
|
7594
|
+
asset: z.string().optional().describe("Token symbol to scan (default: USDC)")
|
|
7595
|
+
},
|
|
7596
|
+
async ({ asset }) => {
|
|
7597
|
+
const registry = Registry.loadEmbedded();
|
|
7598
|
+
const symbol = asset ?? "USDC";
|
|
7599
|
+
const results = [];
|
|
7600
|
+
const chains = Array.from(registry.chains.keys());
|
|
7601
|
+
await Promise.allSettled(
|
|
7602
|
+
chains.map(async (chainName) => {
|
|
7603
|
+
const chain = registry.getChain(chainName);
|
|
7604
|
+
const rpcUrl = chain.effectiveRpcUrl();
|
|
7605
|
+
const lendingProtos = registry.getProtocolsForChain(chainName).filter((p) => p.category === "lending");
|
|
7606
|
+
for (const proto of lendingProtos) {
|
|
7607
|
+
try {
|
|
7608
|
+
const adapter = createLending(proto, rpcUrl);
|
|
7609
|
+
const tokens = registry.tokens.get(chainName);
|
|
7610
|
+
const token = tokens?.find((t) => t.symbol.toUpperCase() === symbol.toUpperCase());
|
|
7611
|
+
if (!token) continue;
|
|
7612
|
+
const rates = await adapter.getRates(token.address);
|
|
7613
|
+
results.push({
|
|
7614
|
+
chain: chainName,
|
|
7615
|
+
protocol: proto.name,
|
|
7616
|
+
slug: proto.slug,
|
|
7617
|
+
asset: token.symbol,
|
|
7618
|
+
asset_address: token.address,
|
|
7619
|
+
supply_apy: rates.supply_apy,
|
|
7620
|
+
borrow_variable_apy: rates.borrow_variable_apy,
|
|
7621
|
+
utilization: rates.utilization,
|
|
7622
|
+
total_supply: rates.total_supply?.toString(),
|
|
7623
|
+
total_borrow: rates.total_borrow?.toString()
|
|
7624
|
+
});
|
|
7625
|
+
} catch {
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7628
|
+
})
|
|
7629
|
+
);
|
|
7630
|
+
results.sort((a, b) => b.supply_apy - a.supply_apy);
|
|
7631
|
+
return {
|
|
7632
|
+
content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
|
|
7633
|
+
};
|
|
7634
|
+
}
|
|
7635
|
+
);
|
|
7472
7636
|
var transport = new StdioServerTransport();
|
|
7473
7637
|
await server.connect(transport);
|
|
7474
7638
|
//# sourceMappingURL=mcp-server.js.map
|