@1delta/margin-fetcher 5.0.100 → 5.0.102
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.d.ts +6 -1
- package/dist/index.js +371 -139
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -7186,10 +7186,7 @@ var calculateRateForCompoundType = (n, chainId, scale3 = 1 /* SECOND */, unitSec
|
|
|
7186
7186
|
const perUnit = unitSeconds && unitSeconds > 0 ? unitSeconds : scale3 === 0 /* BLOCK */ ? Number(BLOCK_TIMES[chainId] ?? 1) : 1;
|
|
7187
7187
|
return (Math.pow(rate * 60 * 60 * 24 / perUnit + 1, 365) - 1) * 100;
|
|
7188
7188
|
};
|
|
7189
|
-
var
|
|
7190
|
-
const apy = formatAaveYieldToNumber(raw);
|
|
7191
|
-
return apyToApr(apy / 100) * 100;
|
|
7192
|
-
};
|
|
7189
|
+
var formatAaveRayToApr = (raw) => formatAaveYieldToNumber(raw);
|
|
7193
7190
|
var convertRateToApr = (ratePerSecond) => {
|
|
7194
7191
|
const rps = Number(ratePerSecond);
|
|
7195
7192
|
if (isNaN(rps)) return 0;
|
|
@@ -7277,13 +7274,13 @@ var getAaveV2ReservesDataConverter = (lender, chainId, prices, additionalYields,
|
|
|
7277
7274
|
reserveData?.[8 /* variableBorrowIndex */]
|
|
7278
7275
|
),
|
|
7279
7276
|
// rates
|
|
7280
|
-
depositRate:
|
|
7277
|
+
depositRate: formatAaveRayToApr(
|
|
7281
7278
|
reserveData?.[3 /* liquidityRate */]?.toString()
|
|
7282
7279
|
),
|
|
7283
|
-
variableBorrowRate:
|
|
7280
|
+
variableBorrowRate: formatAaveRayToApr(
|
|
7284
7281
|
reserveData?.[4 /* variableBorrowRate */]?.toString()
|
|
7285
7282
|
),
|
|
7286
|
-
stableBorrowRate:
|
|
7283
|
+
stableBorrowRate: formatAaveRayToApr(
|
|
7287
7284
|
reserveData?.[5 /* stableBorrowRate */]?.toString()
|
|
7288
7285
|
),
|
|
7289
7286
|
intrinsicYield: additionalYields?.intrinsicYields?.[oracleKey] ?? 0,
|
|
@@ -7504,13 +7501,13 @@ var getAaveV3ReservesDataConverter = (lender, chainId, prices, additionalYields,
|
|
|
7504
7501
|
reserveData?.[10 /* variableBorrowIndex */]
|
|
7505
7502
|
),
|
|
7506
7503
|
// rates
|
|
7507
|
-
depositRate:
|
|
7504
|
+
depositRate: formatAaveRayToApr(
|
|
7508
7505
|
reserveData?.[5 /* liquidityRate */]?.toString()
|
|
7509
7506
|
),
|
|
7510
|
-
variableBorrowRate:
|
|
7507
|
+
variableBorrowRate: formatAaveRayToApr(
|
|
7511
7508
|
reserveData?.[6 /* variableBorrowRate */]?.toString()
|
|
7512
7509
|
),
|
|
7513
|
-
stableBorrowRate:
|
|
7510
|
+
stableBorrowRate: formatAaveRayToApr(
|
|
7514
7511
|
reserveData?.[7 /* stableBorrowRate */]?.toString()
|
|
7515
7512
|
),
|
|
7516
7513
|
intrinsicYield: additionalYields?.intrinsicYields?.[toOracleKey(assetMeta?.assetGroup)] ?? 0,
|
|
@@ -7766,10 +7763,10 @@ function parseYLDRCall(chainId, lender, additionalYields, prices, tokenList) {
|
|
|
7766
7763
|
reserveData?.[6 /* variableBorrowIndex */]
|
|
7767
7764
|
),
|
|
7768
7765
|
// rates
|
|
7769
|
-
depositRate:
|
|
7766
|
+
depositRate: formatAaveRayToApr(
|
|
7770
7767
|
reserveData?.[3 /* liquidityRate */]?.toString()
|
|
7771
7768
|
),
|
|
7772
|
-
variableBorrowRate:
|
|
7769
|
+
variableBorrowRate: formatAaveRayToApr(
|
|
7773
7770
|
reserveData?.[4 /* variableBorrowRate */]?.toString()
|
|
7774
7771
|
),
|
|
7775
7772
|
stableBorrowRate: 0,
|
|
@@ -7941,13 +7938,13 @@ function parseAave32(chainId, lender, prices, additionalYields, tokenList) {
|
|
|
7941
7938
|
reserveData?.[10 /* variableBorrowIndex */]
|
|
7942
7939
|
),
|
|
7943
7940
|
// rates
|
|
7944
|
-
depositRate:
|
|
7941
|
+
depositRate: formatAaveRayToApr(
|
|
7945
7942
|
reserveData?.[5 /* liquidityRate */]?.toString()
|
|
7946
7943
|
),
|
|
7947
|
-
variableBorrowRate:
|
|
7944
|
+
variableBorrowRate: formatAaveRayToApr(
|
|
7948
7945
|
reserveData?.[6 /* variableBorrowRate */]?.toString()
|
|
7949
7946
|
),
|
|
7950
|
-
stableBorrowRate:
|
|
7947
|
+
stableBorrowRate: formatAaveRayToApr(
|
|
7951
7948
|
reserveData?.[7 /* stableBorrowRate */]?.toString()
|
|
7952
7949
|
),
|
|
7953
7950
|
intrinsicYield: additionalYields?.intrinsicYields?.[toOracleKey(assetMeta?.assetGroup)] ?? 0,
|
|
@@ -10732,11 +10729,11 @@ async function resolveListaBrokers(chainId, marketKeys, getClient = getEvmClient
|
|
|
10732
10729
|
const moolah = morphoPools()?.LISTA_DAO?.[chainId];
|
|
10733
10730
|
const out = {};
|
|
10734
10731
|
if (!moolah || marketKeys.length === 0) return out;
|
|
10735
|
-
const
|
|
10732
|
+
const cache7 = BROKER_CACHE[chainId] ??= {};
|
|
10736
10733
|
const missing = [];
|
|
10737
10734
|
for (const key3 of marketKeys) {
|
|
10738
10735
|
const id = toBytes32MarketId(key3);
|
|
10739
|
-
if (
|
|
10736
|
+
if (cache7[id] === void 0) missing.push(id);
|
|
10740
10737
|
}
|
|
10741
10738
|
if (missing.length > 0) {
|
|
10742
10739
|
try {
|
|
@@ -10752,7 +10749,7 @@ async function resolveListaBrokers(chainId, marketKeys, getClient = getEvmClient
|
|
|
10752
10749
|
);
|
|
10753
10750
|
results.forEach((addr4, i) => {
|
|
10754
10751
|
if (addr4 === void 0) return;
|
|
10755
|
-
|
|
10752
|
+
cache7[missing[i]] = addr4.toLowerCase();
|
|
10756
10753
|
});
|
|
10757
10754
|
} catch (e) {
|
|
10758
10755
|
console.warn(
|
|
@@ -10763,7 +10760,7 @@ async function resolveListaBrokers(chainId, marketKeys, getClient = getEvmClient
|
|
|
10763
10760
|
}
|
|
10764
10761
|
for (const key3 of marketKeys) {
|
|
10765
10762
|
const id = toBytes32MarketId(key3);
|
|
10766
|
-
const broker =
|
|
10763
|
+
const broker = cache7[id];
|
|
10767
10764
|
if (broker && broker !== zeroAddress) out[id] = broker;
|
|
10768
10765
|
}
|
|
10769
10766
|
return out;
|
|
@@ -10791,7 +10788,7 @@ async function fetchListaFixedTerms(chainId, marketKeys, multicallRetry) {
|
|
|
10791
10788
|
})),
|
|
10792
10789
|
multicallRetry
|
|
10793
10790
|
);
|
|
10794
|
-
const
|
|
10791
|
+
const cache7 = FIXED_TERMS_CACHE[chainId] ??= {};
|
|
10795
10792
|
results.forEach((raw, i) => {
|
|
10796
10793
|
if (!raw) return;
|
|
10797
10794
|
const id = ids[i];
|
|
@@ -10805,7 +10802,7 @@ async function fetchListaFixedTerms(chainId, marketKeys, multicallRetry) {
|
|
|
10805
10802
|
};
|
|
10806
10803
|
});
|
|
10807
10804
|
out[id] = terms;
|
|
10808
|
-
|
|
10805
|
+
cache7[id] = terms;
|
|
10809
10806
|
});
|
|
10810
10807
|
} catch (e) {
|
|
10811
10808
|
console.warn(
|
|
@@ -12310,6 +12307,39 @@ function formatNr(n, d) {
|
|
|
12310
12307
|
return Number(formatUnits(BigInt(n ?? 0), d));
|
|
12311
12308
|
}
|
|
12312
12309
|
|
|
12310
|
+
// src/lending/public-data/morpho/unlisted.ts
|
|
12311
|
+
var MORPHO_UNLISTED_CHAINS = /* @__PURE__ */ new Set([
|
|
12312
|
+
// Robinhood Chain. 189 of its 194 markets are unlisted and essentially all of
|
|
12313
|
+
// them are Longbow — a curated Morpho Blue deployment (tokenized equities and
|
|
12314
|
+
// RWAs against USDG) that Morpho's own frontend does not carry, so `listed`
|
|
12315
|
+
// here says nothing about the market's quality. Enabled 2026-09-08 together
|
|
12316
|
+
// with the three things a chain needs before it can be:
|
|
12317
|
+
// 1. its collateral tokens in `token-lists` (wsNET was the last gap — the
|
|
12318
|
+
// collateral of the chain's LARGEST market), or the rows price at $0,
|
|
12319
|
+
// 2. `lender-metadata`'s `SERVES_UNLISTED_CHAINS` carrying the same chain
|
|
12320
|
+
// id, so the markets get a NAME and an oracle roster (5 -> 188 rows),
|
|
12321
|
+
// 3. a look at what the unlisted book actually holds — here 56 real
|
|
12322
|
+
// markets, $524k supplied / $351k borrowed, no runaway rates (the
|
|
12323
|
+
// highest borrow APR on the chain is 21.9 %).
|
|
12324
|
+
// See LONGBOW.md.
|
|
12325
|
+
"4663",
|
|
12326
|
+
// World Chain. blue-api indexes it, but 0 of its 30 markets are listed —
|
|
12327
|
+
// Morpho's frontend simply does not carry the chain, so `listed` says
|
|
12328
|
+
// nothing about the book (the Longbow shape again). Looked at 2026-09-16:
|
|
12329
|
+
// $59.5M supplied / $45.0M borrowed, of which the real two-sided markets are
|
|
12330
|
+
// USDC/WBTC $3.9M, USDC/WETH $3.6M, WETH/WBTC $2.1M, USDC/WLD $1.6M and
|
|
12331
|
+
// WETH/ezETH $1.1M at 0.1–4.6 % borrow APY; the $35.8M USDC/sdeUSD market is
|
|
12332
|
+
// pinned at 100 % utilization (297,994 % APY, $0 liquid) and is exactly what
|
|
12333
|
+
// `earn/rateSanity.ts` exists to drop. Token-list gaps on 480 at enablement:
|
|
12334
|
+
// sdeUSD and ezETH (collateral of two markets) — those rows price at $0 with
|
|
12335
|
+
// a blank LTV until token-lists carries them. `lender-metadata`'s
|
|
12336
|
+
// `SERVES_UNLISTED_CHAINS` was updated in the same change.
|
|
12337
|
+
"480"
|
|
12338
|
+
]);
|
|
12339
|
+
function morphoIncludesUnlisted(chainId) {
|
|
12340
|
+
return MORPHO_UNLISTED_CHAINS.has(chainId);
|
|
12341
|
+
}
|
|
12342
|
+
|
|
12313
12343
|
// src/lending/public-data/morpho/convertPublic.ts
|
|
12314
12344
|
function convertMarketsToMorphoResponse(response, chainId, additionalYields = {
|
|
12315
12345
|
intrinsicYields: {},
|
|
@@ -12319,6 +12349,7 @@ function convertMarketsToMorphoResponse(response, chainId, additionalYields = {
|
|
|
12319
12349
|
const data = {};
|
|
12320
12350
|
const items = response?.markets?.items;
|
|
12321
12351
|
if (!items) return data;
|
|
12352
|
+
const listedFlagMeaningful = !morphoIncludesUnlisted(chainId);
|
|
12322
12353
|
items.forEach((market) => {
|
|
12323
12354
|
const {
|
|
12324
12355
|
uniqueKey,
|
|
@@ -12483,7 +12514,7 @@ function convertMarketsToMorphoResponse(response, chainId, additionalYields = {
|
|
|
12483
12514
|
irm: irmAddress,
|
|
12484
12515
|
collateralAddress: collateralAssetAddress,
|
|
12485
12516
|
loanAddress: loanAssetAddress,
|
|
12486
|
-
isListed: whitelisted,
|
|
12517
|
+
isListed: whitelisted || listedFlagMeaningful ? whitelisted : void 0,
|
|
12487
12518
|
fee: state.fee,
|
|
12488
12519
|
rateAtTarget: state?.rateAtTarget?.toString()
|
|
12489
12520
|
}
|
|
@@ -12493,18 +12524,220 @@ function convertMarketsToMorphoResponse(response, chainId, additionalYields = {
|
|
|
12493
12524
|
});
|
|
12494
12525
|
return data;
|
|
12495
12526
|
}
|
|
12496
|
-
|
|
12527
|
+
|
|
12528
|
+
// src/lending/public-data/morpho/vaultFunded.ts
|
|
12529
|
+
var MORPHO_VAULT_FUNDED_MIN_USD = 1e4;
|
|
12530
|
+
var MORPHO_VAULT_FUNDED_MIN_VAULT_USD = 1e3;
|
|
12531
|
+
var BASE_URL = "https://blue-api.morpho.org/graphql";
|
|
12532
|
+
var V1_PAGE = 100;
|
|
12533
|
+
var V2_PAGE = 50;
|
|
12534
|
+
var MAX_PAGES = 20;
|
|
12535
|
+
var CACHE_TTL_MS = 15 * 6e4;
|
|
12536
|
+
var FAIL_TTL_MS = 6e4;
|
|
12537
|
+
var V1_VAULT_ALLOCATIONS_QUERY = (first, skip, chainId) => `
|
|
12538
|
+
query VaultFundedV1 {
|
|
12539
|
+
vaults(first: ${first}, skip: ${skip}, where: {
|
|
12540
|
+
chainId_in: [${chainId}],
|
|
12541
|
+
totalAssetsUsd_gte: ${MORPHO_VAULT_FUNDED_MIN_VAULT_USD}
|
|
12542
|
+
}) {
|
|
12543
|
+
items {
|
|
12544
|
+
address
|
|
12545
|
+
state {
|
|
12546
|
+
allocation {
|
|
12547
|
+
supplyAssetsUsd
|
|
12548
|
+
market { marketId listed collateralAsset { address } }
|
|
12549
|
+
}
|
|
12550
|
+
}
|
|
12551
|
+
}
|
|
12552
|
+
}
|
|
12553
|
+
}
|
|
12554
|
+
`;
|
|
12555
|
+
var V2_VAULT_CAPS_QUERY = (first, skip, chainId) => `
|
|
12556
|
+
query VaultFundedV2 {
|
|
12557
|
+
vaultV2s(first: ${first}, skip: ${skip}, where: {
|
|
12558
|
+
chainId_in: [${chainId}],
|
|
12559
|
+
totalAssetsUsd_gte: ${MORPHO_VAULT_FUNDED_MIN_VAULT_USD}
|
|
12560
|
+
}) {
|
|
12561
|
+
items {
|
|
12562
|
+
address
|
|
12563
|
+
totalAssets
|
|
12564
|
+
totalAssetsUsd
|
|
12565
|
+
asset { decimals price { usd } }
|
|
12566
|
+
caps {
|
|
12567
|
+
items {
|
|
12568
|
+
type
|
|
12569
|
+
allocation
|
|
12570
|
+
data {
|
|
12571
|
+
__typename
|
|
12572
|
+
... on MarketV1CapData {
|
|
12573
|
+
market { marketId listed collateralAsset { address } }
|
|
12574
|
+
}
|
|
12575
|
+
}
|
|
12576
|
+
}
|
|
12577
|
+
}
|
|
12578
|
+
}
|
|
12579
|
+
}
|
|
12580
|
+
}
|
|
12581
|
+
`;
|
|
12582
|
+
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
12583
|
+
var isUnlistedLendable = (m) => {
|
|
12584
|
+
if (m?.listed !== false) return false;
|
|
12585
|
+
const coll = m.collateralAsset?.address?.toLowerCase();
|
|
12586
|
+
return !!coll && coll !== ZERO;
|
|
12587
|
+
};
|
|
12588
|
+
function sumVaultFundedUnlisted(v1Vaults, v2Vaults, minUsd = MORPHO_VAULT_FUNDED_MIN_USD) {
|
|
12589
|
+
const byMarket = /* @__PURE__ */ new Map();
|
|
12590
|
+
const add = (marketId, usd) => {
|
|
12591
|
+
if (!marketId || usd == null || !Number.isFinite(usd) || usd <= 0) return;
|
|
12592
|
+
const k = marketId.toLowerCase();
|
|
12593
|
+
byMarket.set(k, (byMarket.get(k) ?? 0) + usd);
|
|
12594
|
+
};
|
|
12595
|
+
for (const v of v1Vaults) {
|
|
12596
|
+
for (const a of v?.state?.allocation ?? []) {
|
|
12597
|
+
if (!isUnlistedLendable(a?.market)) continue;
|
|
12598
|
+
add(a.market.marketId, typeof a.supplyAssetsUsd === "number" ? a.supplyAssetsUsd : null);
|
|
12599
|
+
}
|
|
12600
|
+
}
|
|
12601
|
+
for (const v of v2Vaults) {
|
|
12602
|
+
const decimals = typeof v?.asset?.decimals === "number" ? v.asset.decimals : null;
|
|
12603
|
+
let price2 = typeof v?.asset?.price?.usd === "number" ? v.asset.price.usd : null;
|
|
12604
|
+
const total = Number(v?.totalAssets ?? 0);
|
|
12605
|
+
if (price2 == null && decimals != null && total > 0 && typeof v?.totalAssetsUsd === "number")
|
|
12606
|
+
price2 = v.totalAssetsUsd / (total / 10 ** decimals);
|
|
12607
|
+
for (const c of v?.caps?.items ?? []) {
|
|
12608
|
+
if (c?.type !== "MarketV1") continue;
|
|
12609
|
+
const m = c.data?.market;
|
|
12610
|
+
if (!isUnlistedLendable(m)) continue;
|
|
12611
|
+
const raw = Number(c.allocation ?? 0);
|
|
12612
|
+
add(m.marketId, price2 != null && decimals != null ? raw / 10 ** decimals * price2 : null);
|
|
12613
|
+
}
|
|
12614
|
+
}
|
|
12615
|
+
return [...byMarket].filter(([, usd]) => usd >= minUsd).map(([marketId, vaultUsd]) => ({ marketId, vaultUsd })).sort((a, b) => b.vaultUsd - a.vaultUsd || a.marketId.localeCompare(b.marketId));
|
|
12616
|
+
}
|
|
12617
|
+
async function post(query3) {
|
|
12618
|
+
const res = await fetch(BASE_URL, {
|
|
12619
|
+
method: "POST",
|
|
12620
|
+
headers: { "Content-Type": "application/json" },
|
|
12621
|
+
body: JSON.stringify({ query: query3 })
|
|
12622
|
+
});
|
|
12623
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
12624
|
+
const json = await res.json();
|
|
12625
|
+
if (json?.errors?.length)
|
|
12626
|
+
throw new Error(json.errors.map((e) => e?.message).join("; "));
|
|
12627
|
+
return json.data;
|
|
12628
|
+
}
|
|
12629
|
+
async function pageAll(build6, field13, pageSize) {
|
|
12630
|
+
const out = [];
|
|
12631
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
12632
|
+
const items = (await post(build6(pageSize, page * pageSize)))?.[field13]?.items;
|
|
12633
|
+
if (!Array.isArray(items)) throw new Error(`unexpected ${field13} shape`);
|
|
12634
|
+
out.push(...items);
|
|
12635
|
+
if (items.length < pageSize) return out;
|
|
12636
|
+
}
|
|
12637
|
+
console.warn(`[morpho-vault-funded] ${field13}: hit MAX_PAGES, result truncated`);
|
|
12638
|
+
return out;
|
|
12639
|
+
}
|
|
12640
|
+
async function discover(chainId) {
|
|
12641
|
+
const [v1, v2] = await Promise.all([
|
|
12642
|
+
pageAll((f, s) => V1_VAULT_ALLOCATIONS_QUERY(f, s, chainId), "vaults", V1_PAGE),
|
|
12643
|
+
pageAll((f, s) => V2_VAULT_CAPS_QUERY(f, s, chainId), "vaultV2s", V2_PAGE)
|
|
12644
|
+
]);
|
|
12645
|
+
return sumVaultFundedUnlisted(v1, v2);
|
|
12646
|
+
}
|
|
12647
|
+
var cache = /* @__PURE__ */ new Map();
|
|
12648
|
+
function morphoVaultFundedUnlistedMarkets(chainId) {
|
|
12649
|
+
if (morphoIncludesUnlisted(chainId)) return Promise.resolve([]);
|
|
12650
|
+
const now = Date.now();
|
|
12651
|
+
const hit = cache.get(chainId);
|
|
12652
|
+
if (hit && now - hit.at < hit.ttl) return hit.promise;
|
|
12653
|
+
const entry = { at: now, ttl: CACHE_TTL_MS, promise: Promise.resolve([]) };
|
|
12654
|
+
entry.promise = discover(chainId).catch((e) => {
|
|
12655
|
+
entry.ttl = FAIL_TTL_MS;
|
|
12656
|
+
console.warn(
|
|
12657
|
+
`[morpho-vault-funded] chain ${chainId}: discovery failed, serving listed markets only:`,
|
|
12658
|
+
e?.message ?? e
|
|
12659
|
+
);
|
|
12660
|
+
return [];
|
|
12661
|
+
});
|
|
12662
|
+
cache.set(chainId, entry);
|
|
12663
|
+
return entry.promise;
|
|
12664
|
+
}
|
|
12665
|
+
async function morphoVaultFundedUnlistedMarketIds(chainId) {
|
|
12666
|
+
return (await morphoVaultFundedUnlistedMarkets(chainId)).map((m) => m.marketId);
|
|
12667
|
+
}
|
|
12668
|
+
var uniqueKeyInFilter = (keys) => `uniqueKey_in: [${keys.map((k) => JSON.stringify(k.toLowerCase())).join(", ")}]`;
|
|
12669
|
+
function mergeMarketItemsByKey(base, extra) {
|
|
12670
|
+
const have = new Set(base.map((m) => m?.uniqueKey?.toLowerCase()));
|
|
12671
|
+
const out = [...base];
|
|
12672
|
+
for (const m of extra) {
|
|
12673
|
+
const k = m?.uniqueKey?.toLowerCase();
|
|
12674
|
+
if (!k || have.has(k)) continue;
|
|
12675
|
+
have.add(k);
|
|
12676
|
+
out.push(m);
|
|
12677
|
+
}
|
|
12678
|
+
return out;
|
|
12679
|
+
}
|
|
12680
|
+
var BY_KEY_CHUNK = 100;
|
|
12681
|
+
async function appendVaultFundedMarkets(chainId, base, buildByKeys) {
|
|
12682
|
+
const ids = await morphoVaultFundedUnlistedMarketIds(chainId);
|
|
12683
|
+
if (ids.length === 0) return base;
|
|
12684
|
+
const have = new Set(base.map((m) => m?.uniqueKey?.toLowerCase()));
|
|
12685
|
+
const missing = ids.filter((id) => !have.has(id));
|
|
12686
|
+
if (missing.length === 0) return base;
|
|
12687
|
+
try {
|
|
12688
|
+
const extra = [];
|
|
12689
|
+
for (let i = 0; i < missing.length; i += BY_KEY_CHUNK) {
|
|
12690
|
+
const items = (await post(buildByKeys(missing.slice(i, i + BY_KEY_CHUNK))))?.markets?.items;
|
|
12691
|
+
if (!Array.isArray(items)) throw new Error("unexpected markets shape");
|
|
12692
|
+
extra.push(...items);
|
|
12693
|
+
}
|
|
12694
|
+
return mergeMarketItemsByKey(base, extra);
|
|
12695
|
+
} catch (e) {
|
|
12696
|
+
console.warn(
|
|
12697
|
+
`[morpho-vault-funded] chain ${chainId}: by-key fetch of ${missing.length} markets failed:`,
|
|
12698
|
+
e?.message ?? e
|
|
12699
|
+
);
|
|
12700
|
+
return base;
|
|
12701
|
+
}
|
|
12702
|
+
}
|
|
12703
|
+
|
|
12704
|
+
// src/lending/public-data/morpho/apiFields.ts
|
|
12705
|
+
function normalizeMorphoApiMarket(item) {
|
|
12706
|
+
if (!item || typeof item !== "object") return item;
|
|
12707
|
+
const out = { ...item };
|
|
12708
|
+
if ("oracle" in out) {
|
|
12709
|
+
out.oracleAddress = out.oracle?.address ?? void 0;
|
|
12710
|
+
delete out.oracle;
|
|
12711
|
+
}
|
|
12712
|
+
for (const side of ["loanAsset", "collateralAsset"]) {
|
|
12713
|
+
const a = out[side];
|
|
12714
|
+
if (a && typeof a === "object" && "price" in a) {
|
|
12715
|
+
const { price: price2, ...rest } = a;
|
|
12716
|
+
out[side] = { ...rest, priceUsd: price2?.usd ?? null };
|
|
12717
|
+
}
|
|
12718
|
+
}
|
|
12719
|
+
return out;
|
|
12720
|
+
}
|
|
12721
|
+
function normalizeMorphoApiMarkets(items) {
|
|
12722
|
+
return items.map(normalizeMorphoApiMarket);
|
|
12723
|
+
}
|
|
12724
|
+
|
|
12725
|
+
// src/lending/public-data/morpho/fetchPublic.ts
|
|
12726
|
+
var query = (first, skip, chainId, includeUnlisted = false, uniqueKeys) => `
|
|
12497
12727
|
query GetMarkets {
|
|
12498
12728
|
markets(first: ${first}, skip: ${skip}, where: {
|
|
12499
|
-
chainId_in: [${chainId}]${
|
|
12729
|
+
chainId_in: [${chainId}]${uniqueKeys ? `,
|
|
12730
|
+
${uniqueKeyInFilter(uniqueKeys)}` : includeUnlisted ? "" : ",\n listed: true"}
|
|
12500
12731
|
},
|
|
12501
|
-
orderBy: SupplyAssetsUsd,
|
|
12732
|
+
orderBy: ${uniqueKeys ? "UniqueKey" : "SupplyAssetsUsd"},
|
|
12502
12733
|
orderDirection: Desc
|
|
12503
12734
|
) {
|
|
12504
12735
|
items {
|
|
12505
12736
|
uniqueKey: marketId
|
|
12506
12737
|
irmAddress
|
|
12507
|
-
|
|
12738
|
+
oracle {
|
|
12739
|
+
address
|
|
12740
|
+
}
|
|
12508
12741
|
lltv
|
|
12509
12742
|
whitelisted: listed
|
|
12510
12743
|
loanAsset {
|
|
@@ -12512,14 +12745,18 @@ query GetMarkets {
|
|
|
12512
12745
|
name
|
|
12513
12746
|
symbol
|
|
12514
12747
|
decimals
|
|
12515
|
-
|
|
12748
|
+
price {
|
|
12749
|
+
usd
|
|
12750
|
+
}
|
|
12516
12751
|
}
|
|
12517
12752
|
collateralAsset {
|
|
12518
12753
|
address
|
|
12519
12754
|
name
|
|
12520
12755
|
symbol
|
|
12521
12756
|
decimals
|
|
12522
|
-
|
|
12757
|
+
price {
|
|
12758
|
+
usd
|
|
12759
|
+
}
|
|
12523
12760
|
}
|
|
12524
12761
|
state {
|
|
12525
12762
|
borrowApy
|
|
@@ -12547,7 +12784,7 @@ query GetMarkets {
|
|
|
12547
12784
|
}
|
|
12548
12785
|
}
|
|
12549
12786
|
`;
|
|
12550
|
-
var
|
|
12787
|
+
var BASE_URL2 = "https://blue-api.morpho.org/graphql";
|
|
12551
12788
|
function assertNoGraphQLErrors(json) {
|
|
12552
12789
|
if (json?.errors?.length) {
|
|
12553
12790
|
throw new Error(
|
|
@@ -12556,12 +12793,25 @@ function assertNoGraphQLErrors(json) {
|
|
|
12556
12793
|
}
|
|
12557
12794
|
}
|
|
12558
12795
|
async function fetchMorphoMarkets(chainId, includeUnlisted = false) {
|
|
12796
|
+
const data = await fetchMorphoMarketsBase(chainId, includeUnlisted);
|
|
12797
|
+
if (!Array.isArray(data?.markets?.items)) return data;
|
|
12798
|
+
const items = includeUnlisted ? data.markets.items : await appendVaultFundedMarkets(
|
|
12799
|
+
chainId,
|
|
12800
|
+
data.markets.items,
|
|
12801
|
+
(keys) => query(keys.length, 0, chainId, false, keys)
|
|
12802
|
+
);
|
|
12803
|
+
return {
|
|
12804
|
+
...data,
|
|
12805
|
+
markets: { ...data.markets, items: normalizeMorphoApiMarkets(items) }
|
|
12806
|
+
};
|
|
12807
|
+
}
|
|
12808
|
+
async function fetchMorphoMarketsBase(chainId, includeUnlisted) {
|
|
12559
12809
|
if (chainId !== Chain.ETHEREUM_MAINNET) {
|
|
12560
12810
|
const requestBody = {
|
|
12561
12811
|
query: query(200, 0, chainId, includeUnlisted),
|
|
12562
12812
|
variables: {}
|
|
12563
12813
|
};
|
|
12564
|
-
const response = await fetch(
|
|
12814
|
+
const response = await fetch(BASE_URL2, {
|
|
12565
12815
|
method: "POST",
|
|
12566
12816
|
headers: {
|
|
12567
12817
|
"Content-Type": "application/json"
|
|
@@ -12586,14 +12836,14 @@ async function fetchMorphoMarkets(chainId, includeUnlisted = false) {
|
|
|
12586
12836
|
variables: {}
|
|
12587
12837
|
};
|
|
12588
12838
|
const [data0, data1] = await Promise.all([
|
|
12589
|
-
fetch(
|
|
12839
|
+
fetch(BASE_URL2, {
|
|
12590
12840
|
method: "POST",
|
|
12591
12841
|
headers: {
|
|
12592
12842
|
"Content-Type": "application/json"
|
|
12593
12843
|
},
|
|
12594
12844
|
body: JSON.stringify(requestBody0)
|
|
12595
12845
|
}).then((x) => x.json()),
|
|
12596
|
-
fetch(
|
|
12846
|
+
fetch(BASE_URL2, {
|
|
12597
12847
|
method: "POST",
|
|
12598
12848
|
headers: {
|
|
12599
12849
|
"Content-Type": "application/json"
|
|
@@ -20184,7 +20434,7 @@ var FLUID_API_BASE = "https://api.fluid.instadapp.io/v2";
|
|
|
20184
20434
|
var SUPPORTED_CHAINS = /* @__PURE__ */ new Set(["1", "56", "137", "8453", "9745", "42161"]);
|
|
20185
20435
|
var TTL_MS2 = 6e4;
|
|
20186
20436
|
var ZERO_ADDRESS4 = "0x0000000000000000000000000000000000000000";
|
|
20187
|
-
var
|
|
20437
|
+
var cache2 = {};
|
|
20188
20438
|
var inflight = /* @__PURE__ */ new Map();
|
|
20189
20439
|
var isRealDex = (d) => !!d && String(d.id ?? "0") !== "0" && String(d.address ?? ZERO_ADDRESS4).toLowerCase() !== ZERO_ADDRESS4;
|
|
20190
20440
|
var toBigInt7 = (v) => {
|
|
@@ -20229,7 +20479,7 @@ var parseChainPayload = (raw) => {
|
|
|
20229
20479
|
};
|
|
20230
20480
|
var fetchFluidApiData = async (chainId) => {
|
|
20231
20481
|
if (!SUPPORTED_CHAINS.has(chainId)) return void 0;
|
|
20232
|
-
const hit =
|
|
20482
|
+
const hit = cache2[chainId];
|
|
20233
20483
|
if (hit && Date.now() - hit.at < TTL_MS2) return hit.data;
|
|
20234
20484
|
const pending = inflight.get(chainId);
|
|
20235
20485
|
if (pending) return pending;
|
|
@@ -20240,11 +20490,11 @@ var fetchFluidApiData = async (chainId) => {
|
|
|
20240
20490
|
const json = await res.json();
|
|
20241
20491
|
if (!Array.isArray(json)) throw new Error("unexpected payload");
|
|
20242
20492
|
const data = parseChainPayload(json);
|
|
20243
|
-
|
|
20493
|
+
cache2[chainId] = { at: Date.now(), data };
|
|
20244
20494
|
return data;
|
|
20245
20495
|
} catch {
|
|
20246
|
-
const prev =
|
|
20247
|
-
|
|
20496
|
+
const prev = cache2[chainId]?.data;
|
|
20497
|
+
cache2[chainId] = { at: Date.now(), data: prev };
|
|
20248
20498
|
return prev;
|
|
20249
20499
|
} finally {
|
|
20250
20500
|
inflight.delete(chainId);
|
|
@@ -20253,7 +20503,7 @@ var fetchFluidApiData = async (chainId) => {
|
|
|
20253
20503
|
inflight.set(chainId, run);
|
|
20254
20504
|
return run;
|
|
20255
20505
|
};
|
|
20256
|
-
var getCachedFluidApiData = (chainId) =>
|
|
20506
|
+
var getCachedFluidApiData = (chainId) => cache2[chainId]?.data;
|
|
20257
20507
|
var DEX_RESOLVER_FALLBACK = {
|
|
20258
20508
|
"1": "0x11D80CfF056Cef4F9E6d23da8672fE9873e5cC07",
|
|
20259
20509
|
"137": "0x11D80CfF056Cef4F9E6d23da8672fE9873e5cC07",
|
|
@@ -20265,12 +20515,12 @@ var DEX_RESOLVER_FALLBACK = {
|
|
|
20265
20515
|
var dexResolverFor = (chainId) => fluidResolvers()?.[chainId]?.dexResolver ?? DEX_RESOLVER_FALLBACK[chainId];
|
|
20266
20516
|
var ZERO_ADDRESS5 = "0x0000000000000000000000000000000000000000";
|
|
20267
20517
|
var TTL_MS3 = 6e4;
|
|
20268
|
-
var
|
|
20518
|
+
var cache3 = {};
|
|
20269
20519
|
var inflight2 = /* @__PURE__ */ new Map();
|
|
20270
20520
|
var fetchFluidDexState = async (chainId, multicallRetry, extraDexAddresses = []) => {
|
|
20271
20521
|
const resolver = dexResolverFor(chainId);
|
|
20272
20522
|
if (!resolver) return void 0;
|
|
20273
|
-
const hit =
|
|
20523
|
+
const hit = cache3[chainId];
|
|
20274
20524
|
if (hit && Date.now() - hit.at < TTL_MS3) return hit.data;
|
|
20275
20525
|
const pending = inflight2.get(chainId);
|
|
20276
20526
|
if (pending) return pending;
|
|
@@ -20310,11 +20560,11 @@ var fetchFluidDexState = async (chainId, multicallRetry, extraDexAddresses = [])
|
|
|
20310
20560
|
totalBorrowShares: BigInt(s.totalBorrowShares ?? 0)
|
|
20311
20561
|
};
|
|
20312
20562
|
}
|
|
20313
|
-
|
|
20563
|
+
cache3[chainId] = { at: Date.now(), data };
|
|
20314
20564
|
return data;
|
|
20315
20565
|
} catch {
|
|
20316
|
-
const prev =
|
|
20317
|
-
|
|
20566
|
+
const prev = cache3[chainId]?.data;
|
|
20567
|
+
cache3[chainId] = { at: Date.now(), data: prev };
|
|
20318
20568
|
return prev;
|
|
20319
20569
|
} finally {
|
|
20320
20570
|
inflight2.delete(chainId);
|
|
@@ -20323,7 +20573,7 @@ var fetchFluidDexState = async (chainId, multicallRetry, extraDexAddresses = [])
|
|
|
20323
20573
|
inflight2.set(chainId, run);
|
|
20324
20574
|
return run;
|
|
20325
20575
|
};
|
|
20326
|
-
var getCachedFluidDexState = (chainId) =>
|
|
20576
|
+
var getCachedFluidDexState = (chainId) => cache3[chainId]?.data;
|
|
20327
20577
|
|
|
20328
20578
|
// src/lending/public-data/fluid/publicCallParse.ts
|
|
20329
20579
|
var FLUID_EEE_LOWER = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
@@ -25520,7 +25770,7 @@ var LLAMALEND_READ_ABI = [
|
|
|
25520
25770
|
...LlamaLendAmmAbi,
|
|
25521
25771
|
...Erc20Abi
|
|
25522
25772
|
];
|
|
25523
|
-
var
|
|
25773
|
+
var ZERO2 = "0x0000000000000000000000000000000000000000";
|
|
25524
25774
|
var WAD8 = 10n ** 18n;
|
|
25525
25775
|
var CALLS_PER_MARKET = 6;
|
|
25526
25776
|
var fetchJson2 = async (url, timeoutMs = 8e3) => {
|
|
@@ -25569,7 +25819,7 @@ async function fetchChainExtras(chainId, markets) {
|
|
|
25569
25819
|
{ address: m.amm, name: "price_oracle", params: [] },
|
|
25570
25820
|
{ address: m.amm, name: "active_band", params: [] },
|
|
25571
25821
|
{ address: m.controller, name: "n_loans", params: [] },
|
|
25572
|
-
{ address: m.vault, name: "maxDeposit", params: [
|
|
25822
|
+
{ address: m.vault, name: "maxDeposit", params: [ZERO2] },
|
|
25573
25823
|
// v1 controllers have no `borrow_cap`; allowFailure turns that into a
|
|
25574
25824
|
// null rather than sinking the whole batch.
|
|
25575
25825
|
{ address: m.controller, name: "borrow_cap", params: [] },
|
|
@@ -29342,7 +29592,7 @@ function convertFrankencoinMarketsToResponse(raw, chainId, prices = {}, _additio
|
|
|
29342
29592
|
}
|
|
29343
29593
|
|
|
29344
29594
|
// src/lending/public-data/silo-v2/fetchPublic.ts
|
|
29345
|
-
var
|
|
29595
|
+
var BASE_URL3 = "https://api-v3.silo.finance";
|
|
29346
29596
|
var SILO_API_SUPPORTED_CHAIN_IDS = /* @__PURE__ */ new Set([
|
|
29347
29597
|
"1",
|
|
29348
29598
|
// Ethereum
|
|
@@ -29485,7 +29735,7 @@ query GetSilosLite {
|
|
|
29485
29735
|
async function fetchSiloMarketsLite(chainId, options) {
|
|
29486
29736
|
if (!SILO_API_SUPPORTED_CHAIN_IDS.has(chainId)) return [];
|
|
29487
29737
|
const limit = options?.limit ?? 500;
|
|
29488
|
-
const response = await fetch(
|
|
29738
|
+
const response = await fetch(BASE_URL3, {
|
|
29489
29739
|
method: "POST",
|
|
29490
29740
|
headers: { "Content-Type": "application/json" },
|
|
29491
29741
|
body: JSON.stringify({ query: liteQuery(chainId, limit) })
|
|
@@ -29510,7 +29760,7 @@ async function fetchSiloMarketsLite(chainId, options) {
|
|
|
29510
29760
|
async function fetchSiloMarkets(chainId, options) {
|
|
29511
29761
|
if (!SILO_API_SUPPORTED_CHAIN_IDS.has(chainId)) return [];
|
|
29512
29762
|
const limit = options?.limit ?? 500;
|
|
29513
|
-
const response = await fetch(
|
|
29763
|
+
const response = await fetch(BASE_URL3, {
|
|
29514
29764
|
method: "POST",
|
|
29515
29765
|
headers: { "Content-Type": "application/json" },
|
|
29516
29766
|
body: JSON.stringify({ query: query2(chainId, limit) })
|
|
@@ -30291,39 +30541,6 @@ var getLenderPublicDataViaApi = async (chainId, lenders, prices, additionalYield
|
|
|
30291
30541
|
}
|
|
30292
30542
|
return lenderData;
|
|
30293
30543
|
};
|
|
30294
|
-
|
|
30295
|
-
// src/lending/public-data/morpho/unlisted.ts
|
|
30296
|
-
var MORPHO_UNLISTED_CHAINS = /* @__PURE__ */ new Set([
|
|
30297
|
-
// Robinhood Chain. 189 of its 194 markets are unlisted and essentially all of
|
|
30298
|
-
// them are Longbow — a curated Morpho Blue deployment (tokenized equities and
|
|
30299
|
-
// RWAs against USDG) that Morpho's own frontend does not carry, so `listed`
|
|
30300
|
-
// here says nothing about the market's quality. Enabled 2026-09-08 together
|
|
30301
|
-
// with the three things a chain needs before it can be:
|
|
30302
|
-
// 1. its collateral tokens in `token-lists` (wsNET was the last gap — the
|
|
30303
|
-
// collateral of the chain's LARGEST market), or the rows price at $0,
|
|
30304
|
-
// 2. `lender-metadata`'s `SERVES_UNLISTED_CHAINS` carrying the same chain
|
|
30305
|
-
// id, so the markets get a NAME and an oracle roster (5 -> 188 rows),
|
|
30306
|
-
// 3. a look at what the unlisted book actually holds — here 56 real
|
|
30307
|
-
// markets, $524k supplied / $351k borrowed, no runaway rates (the
|
|
30308
|
-
// highest borrow APR on the chain is 21.9 %).
|
|
30309
|
-
// See LONGBOW.md.
|
|
30310
|
-
"4663",
|
|
30311
|
-
// World Chain. blue-api indexes it, but 0 of its 30 markets are listed —
|
|
30312
|
-
// Morpho's frontend simply does not carry the chain, so `listed` says
|
|
30313
|
-
// nothing about the book (the Longbow shape again). Looked at 2026-09-16:
|
|
30314
|
-
// $59.5M supplied / $45.0M borrowed, of which the real two-sided markets are
|
|
30315
|
-
// USDC/WBTC $3.9M, USDC/WETH $3.6M, WETH/WBTC $2.1M, USDC/WLD $1.6M and
|
|
30316
|
-
// WETH/ezETH $1.1M at 0.1–4.6 % borrow APY; the $35.8M USDC/sdeUSD market is
|
|
30317
|
-
// pinned at 100 % utilization (297,994 % APY, $0 liquid) and is exactly what
|
|
30318
|
-
// `earn/rateSanity.ts` exists to drop. Token-list gaps on 480 at enablement:
|
|
30319
|
-
// sdeUSD and ezETH (collateral of two markets) — those rows price at $0 with
|
|
30320
|
-
// a blank LTV until token-lists carries them. `lender-metadata`'s
|
|
30321
|
-
// `SERVES_UNLISTED_CHAINS` was updated in the same change.
|
|
30322
|
-
"480"
|
|
30323
|
-
]);
|
|
30324
|
-
function morphoIncludesUnlisted(chainId) {
|
|
30325
|
-
return MORPHO_UNLISTED_CHAINS.has(chainId);
|
|
30326
|
-
}
|
|
30327
30544
|
var ERC20_BALANCE_OF_ABI2 = [
|
|
30328
30545
|
{
|
|
30329
30546
|
inputs: [{ name: "account", type: "address" }],
|
|
@@ -30946,7 +31163,7 @@ function decodeVariableLensRows(blob, fixedWords, headerBytes = 0) {
|
|
|
30946
31163
|
}
|
|
30947
31164
|
|
|
30948
31165
|
// src/lending/user-data/aave-v3-type/lens.ts
|
|
30949
|
-
var
|
|
31166
|
+
var ZERO3 = "0x0000000000000000000000000000000000000000";
|
|
30950
31167
|
var AAVE_LENS_HEADER_BYTES = 3;
|
|
30951
31168
|
var HEADER_EMODE_OK = 1;
|
|
30952
31169
|
var HEADER_CONFIG_OK = 2;
|
|
@@ -30954,7 +31171,7 @@ var AAVE_LENS_WORDS = 7;
|
|
|
30954
31171
|
var reserveTuple = (tokens, asset) => {
|
|
30955
31172
|
const t = tokens?.[asset.toLowerCase()];
|
|
30956
31173
|
if (!t?.aToken || !t?.vToken) return void 0;
|
|
30957
|
-
return [asset, t.aToken, t.vToken, t.sToken ??
|
|
31174
|
+
return [asset, t.aToken, t.vToken, t.sToken ?? ZERO3];
|
|
30958
31175
|
};
|
|
30959
31176
|
var usesAaveLens = (chainId, lender) => {
|
|
30960
31177
|
if (getPositionLensFor(chainId, LENS_FAMILY.AAVE) === void 0) return false;
|
|
@@ -30984,7 +31201,7 @@ var buildAaveLensCall = (chainId, lender, account, assetsToQuery, withEMode) =>
|
|
|
30984
31201
|
getAaveTypePoolDataProviderAddress(chainId, lender),
|
|
30985
31202
|
// A zero pool disables the e-mode read, which is exactly what YLDR wants:
|
|
30986
31203
|
// it has no `getUserEMode` and the walk omits that call for it too.
|
|
30987
|
-
withEMode ? getAaveTypePoolAddress(chainId, lender) :
|
|
31204
|
+
withEMode ? getAaveTypePoolAddress(chainId, lender) : ZERO3
|
|
30988
31205
|
]
|
|
30989
31206
|
);
|
|
30990
31207
|
return [
|
|
@@ -32064,7 +32281,7 @@ var buildExactlyUserCall = (chainId, _lender, account) => {
|
|
|
32064
32281
|
return [{ address: cfg.previewer, name: "exactly", params: [account] }];
|
|
32065
32282
|
};
|
|
32066
32283
|
var OWNER_INDEX_PROBE_COUNT = 8;
|
|
32067
|
-
var
|
|
32284
|
+
var CACHE_TTL_MS2 = 5 * 6e4;
|
|
32068
32285
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
32069
32286
|
async function discoverViaLens(chainId, branches, zappers, account, opts) {
|
|
32070
32287
|
const lens = getPositionLensFor(chainId, LENS_FAMILY.LIQUITY);
|
|
@@ -32133,7 +32350,7 @@ var getCachedLiquityTroves = (chainId, lender, account, opts) => {
|
|
|
32133
32350
|
const hit = discoveryCache.get(
|
|
32134
32351
|
cacheKey(chainId, lender, account, blockKey(opts))
|
|
32135
32352
|
);
|
|
32136
|
-
if (!hit || Date.now() - hit.at >
|
|
32353
|
+
if (!hit || Date.now() - hit.at > CACHE_TTL_MS2) return void 0;
|
|
32137
32354
|
return hit;
|
|
32138
32355
|
};
|
|
32139
32356
|
var ADDRESS_ADDRESS_UINT = [
|
|
@@ -32353,7 +32570,7 @@ var buildRiverUserCall = (chainId, lender, account) => {
|
|
|
32353
32570
|
});
|
|
32354
32571
|
return calls;
|
|
32355
32572
|
};
|
|
32356
|
-
var
|
|
32573
|
+
var ZERO4 = "0x0000000000000000000000000000000000000000";
|
|
32357
32574
|
var LLAMALEND_LENS_WORDS = 12;
|
|
32358
32575
|
var LLAMALEND_CALLS_PER_MARKET = 8;
|
|
32359
32576
|
var usesLlamaLendLens = (chainId) => getPositionLensFor(chainId, LENS_FAMILY.LLAMALEND) !== void 0;
|
|
@@ -32367,7 +32584,7 @@ var buildLlamaLendLensCall = (chainId, markets, account, delegate) => {
|
|
|
32367
32584
|
m.controller,
|
|
32368
32585
|
m.amm,
|
|
32369
32586
|
m.vault,
|
|
32370
|
-
m.gauge ??
|
|
32587
|
+
m.gauge ?? ZERO4
|
|
32371
32588
|
]),
|
|
32372
32589
|
delegate
|
|
32373
32590
|
]
|
|
@@ -32916,7 +33133,7 @@ function getCachedTwyneDiscovery(chainId, lender, account, opts) {
|
|
|
32916
33133
|
}
|
|
32917
33134
|
var lower2 = (a) => String(a).toLowerCase();
|
|
32918
33135
|
var isAddress4 = (v) => typeof v === "string" && /^0x[0-9a-fA-F]{40}$/.test(v);
|
|
32919
|
-
async function
|
|
33136
|
+
async function discover2(chainId, lender, account, opts) {
|
|
32920
33137
|
const key3 = discoveryKey3(chainId, lender, account, blockKey(opts));
|
|
32921
33138
|
const cached = discoveryCache4.get(key3);
|
|
32922
33139
|
if (cached && Date.now() - cached.at < DISCOVERY_TTL_MS3) return cached;
|
|
@@ -33018,7 +33235,7 @@ async function discover(chainId, lender, account, opts) {
|
|
|
33018
33235
|
return result;
|
|
33019
33236
|
}
|
|
33020
33237
|
async function buildTwyneUserCall(chainId, lender, account, opts) {
|
|
33021
|
-
const { vaults } = await
|
|
33238
|
+
const { vaults } = await discover2(chainId, lender, account, opts);
|
|
33022
33239
|
if (vaults.length === 0) return [];
|
|
33023
33240
|
return vaults.flatMap(({ vault }) => [
|
|
33024
33241
|
{ address: vault, name: "totalAssetsDepositedOrReserved", args: [] },
|
|
@@ -33032,14 +33249,14 @@ async function buildTwyneUserCall(chainId, lender, account, opts) {
|
|
|
33032
33249
|
}
|
|
33033
33250
|
var DSS_CALLS_PER_CDP = 1;
|
|
33034
33251
|
var MAX_CDP_WALK = 64;
|
|
33035
|
-
var
|
|
33252
|
+
var CACHE_TTL_MS3 = 5 * 6e4;
|
|
33036
33253
|
var discoveryCache5 = /* @__PURE__ */ new Map();
|
|
33037
33254
|
var cacheKey2 = (lender, chainId, account, block = "head") => `${lender}:${chainId}:${account.toLowerCase()}:${block}`;
|
|
33038
33255
|
var getCachedDssCdps = (lender, chainId, account, opts) => {
|
|
33039
33256
|
const hit = discoveryCache5.get(
|
|
33040
33257
|
cacheKey2(lender, chainId, account, blockKey(opts))
|
|
33041
33258
|
);
|
|
33042
|
-
if (!hit || Date.now() - hit.at >
|
|
33259
|
+
if (!hit || Date.now() - hit.at > CACHE_TTL_MS3) return void 0;
|
|
33043
33260
|
return hit;
|
|
33044
33261
|
};
|
|
33045
33262
|
var big7 = (v) => {
|
|
@@ -33282,12 +33499,12 @@ async function discoverTellerBidsViaLens(chainId, tellerV2, account, opts) {
|
|
|
33282
33499
|
|
|
33283
33500
|
// src/lending/user-data/teller/userCallBuild.ts
|
|
33284
33501
|
var TELLER_CALLS_PER_BID = 4;
|
|
33285
|
-
var
|
|
33502
|
+
var CACHE_TTL_MS4 = 5 * 6e4;
|
|
33286
33503
|
var discoveryCache7 = /* @__PURE__ */ new Map();
|
|
33287
33504
|
var cacheKey4 = (chainId, account, block = "head") => `${chainId}:${account.toLowerCase()}:${block}`;
|
|
33288
33505
|
var getCachedTellerBids = (chainId, account, opts) => {
|
|
33289
33506
|
const hit = discoveryCache7.get(cacheKey4(chainId, account, blockKey(opts)));
|
|
33290
|
-
if (!hit || Date.now() - hit.at >
|
|
33507
|
+
if (!hit || Date.now() - hit.at > CACHE_TTL_MS4) return void 0;
|
|
33291
33508
|
return hit;
|
|
33292
33509
|
};
|
|
33293
33510
|
var nowSec5 = () => Math.floor(Date.now() / 1e3);
|
|
@@ -33424,12 +33641,12 @@ var buildFlyingTulipUserCall = (chainId, lender, account) => {
|
|
|
33424
33641
|
];
|
|
33425
33642
|
};
|
|
33426
33643
|
var TERMMAX_MARKETS_PER_CALL = 180;
|
|
33427
|
-
var
|
|
33644
|
+
var CACHE_TTL_MS5 = 5 * 6e4;
|
|
33428
33645
|
var discoveryCache8 = /* @__PURE__ */ new Map();
|
|
33429
33646
|
var cacheKey5 = (chainId, account) => `${chainId}:${account.toLowerCase()}`;
|
|
33430
33647
|
var getCachedTermMaxDiscovery = (chainId, account) => {
|
|
33431
33648
|
const hit = discoveryCache8.get(cacheKey5(chainId, account));
|
|
33432
|
-
if (!hit || Date.now() - hit.at >
|
|
33649
|
+
if (!hit || Date.now() - hit.at > CACHE_TTL_MS5) return void 0;
|
|
33433
33650
|
return hit;
|
|
33434
33651
|
};
|
|
33435
33652
|
var buildTermMaxUserCall = async (chainId, _lender, account) => {
|
|
@@ -43709,7 +43926,7 @@ var MORPHO_API_CHAIN_IDS = {
|
|
|
43709
43926
|
[Chain.UNICHAIN]: 130
|
|
43710
43927
|
};
|
|
43711
43928
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
43712
|
-
var
|
|
43929
|
+
var CACHE_TTL_MS6 = 2e3;
|
|
43713
43930
|
var buildSubgraphQuery = (account) => `
|
|
43714
43931
|
{
|
|
43715
43932
|
account(id: "${account.toLowerCase()}") {
|
|
@@ -43777,7 +43994,7 @@ async function dedupedFetch(chainId, account, loader) {
|
|
|
43777
43994
|
const existing = inflight3.get(key3);
|
|
43778
43995
|
if (existing) return existing;
|
|
43779
43996
|
const promise = loader().then((value) => {
|
|
43780
|
-
resolved.set(key3, { value, expiresAt: Date.now() +
|
|
43997
|
+
resolved.set(key3, { value, expiresAt: Date.now() + CACHE_TTL_MS6 });
|
|
43781
43998
|
return value;
|
|
43782
43999
|
}).finally(() => {
|
|
43783
44000
|
inflight3.delete(key3);
|
|
@@ -56754,7 +56971,7 @@ var dtrinityRebateRewardFetcher = {
|
|
|
56754
56971
|
};
|
|
56755
56972
|
var SECONDS_PER_YEAR15 = 31536e3;
|
|
56756
56973
|
var WAD16 = 10n ** 18n;
|
|
56757
|
-
var
|
|
56974
|
+
var ZERO5 = "0x0000000000000000000000000000000000000000";
|
|
56758
56975
|
var UNBOOSTED_FACTOR = 0.4;
|
|
56759
56976
|
var MAX_BOOST = 2.5;
|
|
56760
56977
|
var GAUGE_CONTROLLER = "0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB";
|
|
@@ -56950,7 +57167,7 @@ async function fetchPrices(keys) {
|
|
|
56950
57167
|
var priceOf = (prices, chainId, address) => prices[`${LLAMA_CHAIN_SLUG[chainId]}:${address.toLowerCase()}`] ?? 0;
|
|
56951
57168
|
function rosterFor(chainId) {
|
|
56952
57169
|
const markets = llamaLendChainData(Lender.LLAMALEND, chainId)?.markets ?? [];
|
|
56953
|
-
return markets.filter((m) => m.gauge && m.gauge !==
|
|
57170
|
+
return markets.filter((m) => m.gauge && m.gauge !== ZERO5).map((m) => ({
|
|
56954
57171
|
controller: m.controller,
|
|
56955
57172
|
vault: m.vault,
|
|
56956
57173
|
gauge: m.gauge,
|
|
@@ -57027,7 +57244,7 @@ async function fetchForChain(chainId, nowSeconds) {
|
|
|
57027
57244
|
}) : [];
|
|
57028
57245
|
let cursor = 0;
|
|
57029
57246
|
const withTokens = state.map((s) => {
|
|
57030
|
-
const tokens = r2.slice(cursor, cursor + s.rewardCount).filter((t) => typeof t === "string" && t !==
|
|
57247
|
+
const tokens = r2.slice(cursor, cursor + s.rewardCount).filter((t) => typeof t === "string" && t !== ZERO5);
|
|
57031
57248
|
cursor += s.rewardCount;
|
|
57032
57249
|
return { ...s, tokens };
|
|
57033
57250
|
});
|
|
@@ -57622,26 +57839,32 @@ function getMorphoAbi() {
|
|
|
57622
57839
|
var MORPHO_GRAPHQL_URL = "https://blue-api.morpho.org/graphql";
|
|
57623
57840
|
var MAX_UNLISTED_PRICE_PAGES = 10;
|
|
57624
57841
|
var PRICE_PAGE_SIZE = 200;
|
|
57625
|
-
var PRICE_QUERY = (first, skip, chainId, includeUnlisted) => `
|
|
57842
|
+
var PRICE_QUERY = (first, skip, chainId, includeUnlisted, uniqueKeys) => `
|
|
57626
57843
|
query GetMarketPrices {
|
|
57627
57844
|
markets(first: ${first}, skip: ${skip}, where: {
|
|
57628
|
-
chainId_in: [${chainId}]${!includeUnlisted && chainId != Chain.ETHEREUM_MAINNET ? `,listed: true` : ""}
|
|
57845
|
+
chainId_in: [${chainId}]${uniqueKeys ? `,${uniqueKeyInFilter(uniqueKeys)}` : !includeUnlisted && chainId != Chain.ETHEREUM_MAINNET ? `,listed: true` : ""}
|
|
57629
57846
|
},
|
|
57630
|
-
orderBy: SupplyAssetsUsd,
|
|
57847
|
+
orderBy: ${uniqueKeys ? "UniqueKey" : "SupplyAssetsUsd"},
|
|
57631
57848
|
orderDirection: Desc
|
|
57632
57849
|
) {
|
|
57633
57850
|
items {
|
|
57634
57851
|
uniqueKey: marketId
|
|
57635
|
-
|
|
57852
|
+
oracle {
|
|
57853
|
+
address
|
|
57854
|
+
}
|
|
57636
57855
|
loanAsset {
|
|
57637
57856
|
address
|
|
57638
57857
|
decimals
|
|
57639
|
-
|
|
57858
|
+
price {
|
|
57859
|
+
usd
|
|
57860
|
+
}
|
|
57640
57861
|
}
|
|
57641
57862
|
collateralAsset {
|
|
57642
57863
|
address
|
|
57643
57864
|
decimals
|
|
57644
|
-
|
|
57865
|
+
price {
|
|
57866
|
+
usd
|
|
57867
|
+
}
|
|
57645
57868
|
}
|
|
57646
57869
|
state {
|
|
57647
57870
|
price
|
|
@@ -57652,7 +57875,7 @@ query GetMarketPrices {
|
|
|
57652
57875
|
`;
|
|
57653
57876
|
async function fetchMorphoGraphQLPrices(chainId, includeUnlisted = false) {
|
|
57654
57877
|
if (!morphoApiAvailable(chainId)) return null;
|
|
57655
|
-
const
|
|
57878
|
+
const post2 = (skip) => fetch(MORPHO_GRAPHQL_URL, {
|
|
57656
57879
|
method: "POST",
|
|
57657
57880
|
headers: { "Content-Type": "application/json" },
|
|
57658
57881
|
body: JSON.stringify({
|
|
@@ -57673,7 +57896,7 @@ async function fetchMorphoGraphQLPrices(chainId, includeUnlisted = false) {
|
|
|
57673
57896
|
const allMarkets = [];
|
|
57674
57897
|
if (includeUnlisted) {
|
|
57675
57898
|
for (let page = 0; page < MAX_UNLISTED_PRICE_PAGES; page++) {
|
|
57676
|
-
const items = readItems(await
|
|
57899
|
+
const items = readItems(await post2(page * PRICE_PAGE_SIZE));
|
|
57677
57900
|
if (!items) return null;
|
|
57678
57901
|
allMarkets.push(...items);
|
|
57679
57902
|
if (items.length < PRICE_PAGE_SIZE) break;
|
|
@@ -57685,14 +57908,23 @@ async function fetchMorphoGraphQLPrices(chainId, includeUnlisted = false) {
|
|
|
57685
57908
|
}
|
|
57686
57909
|
} else {
|
|
57687
57910
|
const skips = chainId === Chain.ETHEREUM_MAINNET ? [0, PRICE_PAGE_SIZE] : [0];
|
|
57688
|
-
const results = await Promise.all(skips.map(
|
|
57911
|
+
const results = await Promise.all(skips.map(post2));
|
|
57689
57912
|
for (const result of results) {
|
|
57690
57913
|
const items = readItems(result);
|
|
57691
57914
|
if (!items) return null;
|
|
57692
57915
|
allMarkets.push(...items);
|
|
57693
57916
|
}
|
|
57694
57917
|
}
|
|
57695
|
-
|
|
57918
|
+
const priced = includeUnlisted ? allMarkets : await appendVaultFundedMarkets(
|
|
57919
|
+
chainId,
|
|
57920
|
+
allMarkets,
|
|
57921
|
+
(keys) => PRICE_QUERY(keys.length, 0, chainId, false, keys)
|
|
57922
|
+
);
|
|
57923
|
+
return processMarketsToEntries(
|
|
57924
|
+
chainId,
|
|
57925
|
+
normalizeMorphoApiMarkets(priced),
|
|
57926
|
+
"morpho-gql"
|
|
57927
|
+
);
|
|
57696
57928
|
} catch (err) {
|
|
57697
57929
|
console.warn(
|
|
57698
57930
|
`[morpho-gql] chain ${chainId}: API error, falling back to on-chain`,
|
|
@@ -64297,7 +64529,7 @@ var fetchSiloVaults = async (chainId, prices = {}, tokenList = {}, options) => {
|
|
|
64297
64529
|
// src/vaults/euler-earn/entityLabels.ts
|
|
64298
64530
|
var LABELS_BASE = "https://raw.githubusercontent.com/euler-xyz/euler-labels/master";
|
|
64299
64531
|
var TTL_MS4 = 30 * 60 * 1e3;
|
|
64300
|
-
var
|
|
64532
|
+
var cache4 = /* @__PURE__ */ new Map();
|
|
64301
64533
|
var inflight4 = /* @__PURE__ */ new Map();
|
|
64302
64534
|
async function fetchChainEntities(chainId) {
|
|
64303
64535
|
const res = await fetch(`${LABELS_BASE}/${chainId}/entities.json`);
|
|
@@ -64321,12 +64553,12 @@ async function fetchChainEntities(chainId) {
|
|
|
64321
64553
|
return map;
|
|
64322
64554
|
}
|
|
64323
64555
|
async function fetchEulerEntityNames(chainId) {
|
|
64324
|
-
const hit =
|
|
64556
|
+
const hit = cache4.get(chainId);
|
|
64325
64557
|
if (hit && Date.now() - hit.at <= TTL_MS4) return hit.map;
|
|
64326
64558
|
const running = inflight4.get(chainId);
|
|
64327
64559
|
if (running) return running;
|
|
64328
64560
|
const p = fetchChainEntities(chainId).then((map) => {
|
|
64329
|
-
|
|
64561
|
+
cache4.set(chainId, { at: Date.now(), map });
|
|
64330
64562
|
return map;
|
|
64331
64563
|
}).catch(() => {
|
|
64332
64564
|
return hit?.map ?? /* @__PURE__ */ new Map();
|
|
@@ -64423,7 +64655,7 @@ query EvkByAssets($assets: [Bytes!]!) {
|
|
|
64423
64655
|
}
|
|
64424
64656
|
}
|
|
64425
64657
|
`;
|
|
64426
|
-
var
|
|
64658
|
+
var ZERO6 = 0n;
|
|
64427
64659
|
var RAY_TO_PERCENT3 = 1e25;
|
|
64428
64660
|
function readAddress2(field13) {
|
|
64429
64661
|
if (!field13) return void 0;
|
|
@@ -64438,28 +64670,28 @@ function parseVaultFee(v) {
|
|
|
64438
64670
|
return n;
|
|
64439
64671
|
}
|
|
64440
64672
|
function safeBigInt(v) {
|
|
64441
|
-
if (v == null || v === "") return
|
|
64673
|
+
if (v == null || v === "") return ZERO6;
|
|
64442
64674
|
try {
|
|
64443
64675
|
return BigInt(v);
|
|
64444
64676
|
} catch {
|
|
64445
|
-
return
|
|
64677
|
+
return ZERO6;
|
|
64446
64678
|
}
|
|
64447
64679
|
}
|
|
64448
64680
|
function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent2, evkIndex) {
|
|
64449
64681
|
if (!strategies?.length) return 0;
|
|
64450
64682
|
const totalAssets = safeBigInt(totalAssetsRaw);
|
|
64451
|
-
if (totalAssets ===
|
|
64452
|
-
let weightedRay =
|
|
64683
|
+
if (totalAssets === ZERO6) return 0;
|
|
64684
|
+
let weightedRay = ZERO6;
|
|
64453
64685
|
for (const s of strategies) {
|
|
64454
64686
|
const evk = s.strategy?.toLowerCase();
|
|
64455
64687
|
if (!evk) continue;
|
|
64456
64688
|
const apyRay = evkIndex.bySupplyApyRay.get(evk);
|
|
64457
64689
|
if (apyRay == null) continue;
|
|
64458
64690
|
const allocated = safeBigInt(s.allocatedAssets);
|
|
64459
|
-
if (allocated ===
|
|
64691
|
+
if (allocated === ZERO6) continue;
|
|
64460
64692
|
weightedRay += allocated * apyRay;
|
|
64461
64693
|
}
|
|
64462
|
-
if (weightedRay ===
|
|
64694
|
+
if (weightedRay === ZERO6) return 0;
|
|
64463
64695
|
const apyRayPerAsset = weightedRay / totalAssets;
|
|
64464
64696
|
const grossPercent = apyToAprPercent(Number(apyRayPerAsset) / RAY_TO_PERCENT3);
|
|
64465
64697
|
const netPercent = grossPercent * (1 - feePercent2 / 100);
|
|
@@ -64467,24 +64699,24 @@ function computeWeightedSupplyApy(strategies, totalAssetsRaw, feePercent2, evkIn
|
|
|
64467
64699
|
}
|
|
64468
64700
|
function computeRealLiquidity(strategies, totalAssetsRaw, evkIndex) {
|
|
64469
64701
|
const totalAssets = safeBigInt(totalAssetsRaw);
|
|
64470
|
-
if (totalAssets ===
|
|
64702
|
+
if (totalAssets === ZERO6) return ZERO6;
|
|
64471
64703
|
if (evkIndex.byCash.size === 0 && evkIndex.bySupplyApyRay.size === 0) {
|
|
64472
64704
|
return totalAssets;
|
|
64473
64705
|
}
|
|
64474
64706
|
if (!strategies?.length) {
|
|
64475
64707
|
return totalAssets;
|
|
64476
64708
|
}
|
|
64477
|
-
let allocSum =
|
|
64478
|
-
let withdrawable =
|
|
64709
|
+
let allocSum = ZERO6;
|
|
64710
|
+
let withdrawable = ZERO6;
|
|
64479
64711
|
for (const s of strategies) {
|
|
64480
64712
|
const alloc = safeBigInt(s.allocatedAssets);
|
|
64481
|
-
if (alloc ===
|
|
64713
|
+
if (alloc === ZERO6) continue;
|
|
64482
64714
|
allocSum += alloc;
|
|
64483
64715
|
const evk = s.strategy?.toLowerCase();
|
|
64484
64716
|
const cash = evk ? evkIndex.byCash.get(evk) : void 0;
|
|
64485
64717
|
withdrawable += cash == null ? alloc : alloc < cash ? alloc : cash;
|
|
64486
64718
|
}
|
|
64487
|
-
const idle = totalAssets > allocSum ? totalAssets - allocSum :
|
|
64719
|
+
const idle = totalAssets > allocSum ? totalAssets - allocSum : ZERO6;
|
|
64488
64720
|
const result = idle + withdrawable;
|
|
64489
64721
|
return result > totalAssets ? totalAssets : result;
|
|
64490
64722
|
}
|
|
@@ -75061,7 +75293,7 @@ function isLiveMarket(market, nowSecs = Math.floor(Date.now() / 1e3)) {
|
|
|
75061
75293
|
if (expiry === void 0) return false;
|
|
75062
75294
|
return expiry > nowSecs;
|
|
75063
75295
|
}
|
|
75064
|
-
var
|
|
75296
|
+
var CACHE_TTL_MS7 = 6e4;
|
|
75065
75297
|
var marketsCache;
|
|
75066
75298
|
var assetsCache;
|
|
75067
75299
|
function clearPendleMarketsCache() {
|
|
@@ -75077,9 +75309,9 @@ async function getJson4(url, label) {
|
|
|
75077
75309
|
}
|
|
75078
75310
|
return response.json();
|
|
75079
75311
|
}
|
|
75080
|
-
function
|
|
75312
|
+
function cache5(slot, build6, store) {
|
|
75081
75313
|
const now = Date.now();
|
|
75082
|
-
if (slot && now - slot.at <
|
|
75314
|
+
if (slot && now - slot.at < CACHE_TTL_MS7) return slot.promise;
|
|
75083
75315
|
const promise = build6();
|
|
75084
75316
|
const entry = { at: now, promise };
|
|
75085
75317
|
store(entry);
|
|
@@ -75087,7 +75319,7 @@ function cache4(slot, build6, store) {
|
|
|
75087
75319
|
return promise;
|
|
75088
75320
|
}
|
|
75089
75321
|
function fetchPendleApiMarkets() {
|
|
75090
|
-
return
|
|
75322
|
+
return cache5(
|
|
75091
75323
|
marketsCache,
|
|
75092
75324
|
async () => (await getJson4(PENDLE_MARKETS_URL, "markets"))?.markets ?? [],
|
|
75093
75325
|
(c) => {
|
|
@@ -75097,7 +75329,7 @@ function fetchPendleApiMarkets() {
|
|
|
75097
75329
|
}
|
|
75098
75330
|
var assetKey = (chainId, address) => `${chainId}-${address.toLowerCase()}`;
|
|
75099
75331
|
function fetchPendleApiAssets() {
|
|
75100
|
-
return
|
|
75332
|
+
return cache5(
|
|
75101
75333
|
assetsCache,
|
|
75102
75334
|
async () => {
|
|
75103
75335
|
const json = await getJson4(PENDLE_ASSETS_URL, "assets");
|
|
@@ -75348,17 +75580,17 @@ function parsePtRate(raw) {
|
|
|
75348
75580
|
if (!Number.isFinite(n) || n < 0 || n > 1.000001) return void 0;
|
|
75349
75581
|
return n;
|
|
75350
75582
|
}
|
|
75351
|
-
var
|
|
75352
|
-
var
|
|
75583
|
+
var CACHE_TTL_MS8 = 6e4;
|
|
75584
|
+
var cache6 = /* @__PURE__ */ new Map();
|
|
75353
75585
|
function clearSpectraMarketsCache() {
|
|
75354
|
-
|
|
75586
|
+
cache6.clear();
|
|
75355
75587
|
}
|
|
75356
75588
|
function fetchSpectraApiMarkets(chainId) {
|
|
75357
75589
|
const network = spectraNetwork(chainId);
|
|
75358
75590
|
if (!network) return Promise.resolve([]);
|
|
75359
75591
|
const now = Date.now();
|
|
75360
|
-
const hit =
|
|
75361
|
-
if (hit && now - hit.at <
|
|
75592
|
+
const hit = cache6.get(network);
|
|
75593
|
+
if (hit && now - hit.at < CACHE_TTL_MS8) return hit.promise;
|
|
75362
75594
|
const promise = (async () => {
|
|
75363
75595
|
const response = await fetch(spectraPoolsUrl(network), {
|
|
75364
75596
|
headers: { Accept: "application/json" }
|
|
@@ -75371,9 +75603,9 @@ function fetchSpectraApiMarkets(chainId) {
|
|
|
75371
75603
|
const json = await response.json();
|
|
75372
75604
|
return Array.isArray(json) ? json : [];
|
|
75373
75605
|
})();
|
|
75374
|
-
|
|
75606
|
+
cache6.set(network, { at: now, promise });
|
|
75375
75607
|
promise.catch(() => {
|
|
75376
|
-
if (
|
|
75608
|
+
if (cache6.get(network)?.promise === promise) cache6.delete(network);
|
|
75377
75609
|
});
|
|
75378
75610
|
return promise;
|
|
75379
75611
|
}
|