@1delta/margin-fetcher 0.0.268 → 0.0.270

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 CHANGED
@@ -5,7 +5,7 @@ import { Lender, isAaveType, isCompoundV3, isMultiMarket, isSiloV2Type, isSiloV3
5
5
  export { isAaveType, isAaveV2Type, isAaveV32Type, isAaveV3Type, isCompoundV3, isCompoundV3Type, isInit, isMorphoType, isMultiMarket, isYLDR } from '@1delta/lender-registry';
6
6
  import lodash from 'lodash';
7
7
  import { getEvmChain, getEvmClient, getEvmClientUniversal, multicallRetryUniversal, getEvmClientWithCustomRpcsUniversal } from '@1delta/providers';
8
- import { FluidLendingResolverAbi, MetaMorphoAbi, MoolahVaultAbi, MorphoLensAbi, AaveV4SpokeAbi, AaveV4OracleAbi, AaveV4HubAbi, FluidVaultResolverAbi, DolomiteMarginAbi, GearboxMarketCompressorV310Abi, MorphoBlueAbi, GearboxCreditAccountCompressorV310Abi } from '@1delta/abis';
8
+ import { FluidLendingResolverAbi, FluidVaultResolverAbi, MetaMorphoAbi, MoolahVaultAbi, MorphoBlueAbi, MorphoLensAbi, AaveV4SpokeAbi, AaveV4OracleAbi, AaveV4HubAbi, DolomiteMarginAbi, GearboxMarketCompressorV310Abi, GearboxCreditAccountCompressorV310Abi } from '@1delta/abis';
9
9
  export { MorphoLensAbi } from '@1delta/abis';
10
10
  import { prepareDebitDataMulticall, prepareLenderDebitMulticall, parseDebitDataResult, parseLenderDebitResult, getPermit2ContractAddress, getCompoundV3CometAddress as getCompoundV3CometAddress$1, getMorphoAddress, getAaveCollateralTokenAddress, getSiloHalfForUnderlying, InitMarginAddresses, getLstAcceptedInputs } from '@1delta/calldata-sdk';
11
11
  import { proxyNativeFetch } from '@1delta/proxy-fetch';
@@ -12487,17 +12487,17 @@ function convertMarketsToMorphoResponse(response, chainId, additionalYields = {
12487
12487
  var query = (first, skip, chainId, includeUnlisted = false) => `
12488
12488
  query GetMarkets {
12489
12489
  markets(first: ${first}, skip: ${skip}, where: {
12490
- chainId_in: [${chainId}]${includeUnlisted ? "" : ",\n whitelisted: true"}
12490
+ chainId_in: [${chainId}]${includeUnlisted ? "" : ",\n listed: true"}
12491
12491
  },
12492
12492
  orderBy: SupplyAssetsUsd,
12493
12493
  orderDirection: Desc
12494
12494
  ) {
12495
12495
  items {
12496
- uniqueKey
12496
+ uniqueKey: marketId
12497
12497
  irmAddress
12498
12498
  oracleAddress
12499
12499
  lltv
12500
- whitelisted
12500
+ whitelisted: listed
12501
12501
  loanAsset {
12502
12502
  address
12503
12503
  name
@@ -12537,6 +12537,13 @@ query GetMarkets {
12537
12537
  }
12538
12538
  `;
12539
12539
  var BASE_URL = "https://blue-api.morpho.org/graphql";
12540
+ function assertNoGraphQLErrors(json) {
12541
+ if (json?.errors?.length) {
12542
+ throw new Error(
12543
+ `Morpho markets API GraphQL error: ${json.errors.map((e) => e?.message).join("; ")}`
12544
+ );
12545
+ }
12546
+ }
12540
12547
  async function fetchMorphoMarkets(chainId, includeUnlisted = false) {
12541
12548
  if (chainId !== Chain.ETHEREUM_MAINNET) {
12542
12549
  const requestBody = {
@@ -12556,6 +12563,7 @@ async function fetchMorphoMarkets(chainId, includeUnlisted = false) {
12556
12563
  );
12557
12564
  }
12558
12565
  const data = await response.json();
12566
+ assertNoGraphQLErrors(data);
12559
12567
  return data.data;
12560
12568
  }
12561
12569
  const requestBody0 = {
@@ -12582,6 +12590,8 @@ async function fetchMorphoMarkets(chainId, includeUnlisted = false) {
12582
12590
  body: JSON.stringify(requestBody1)
12583
12591
  }).then((x) => x.json())
12584
12592
  ]);
12593
+ assertNoGraphQLErrors(data0);
12594
+ assertNoGraphQLErrors(data1);
12585
12595
  return {
12586
12596
  markets: {
12587
12597
  items: [...data0.data.markets.items, ...data1.data.markets.items]
@@ -19873,8 +19883,8 @@ var getDolomitePublicDataConverter = (lender, chainId, _prices, additionalYields
19873
19883
  const isClosing = Boolean(data[base + 1 /* isClosing */]);
19874
19884
  const config = buildDolomiteConfigs(marketId, p, R, isClosing, emode);
19875
19885
  const liquidity = Number(totalDeposits) - Number(totalDebt);
19876
- const marketUid = createMarketUid(chainId, lender, underlying);
19877
- result[underlying] = {
19886
+ const marketUid = createMarketUid(chainId, lender, String(marketId));
19887
+ result[marketUid] = {
19878
19888
  marketUid,
19879
19889
  name: lenderShortName(lender) + " " + (meta?.symbol ?? ""),
19880
19890
  poolId: underlying,
@@ -20932,8 +20942,8 @@ function convertDolomiteSubgraphMarkets(raw, chainId, prices, additionalYields,
20932
20942
  isClosing,
20933
20943
  emode
20934
20944
  );
20935
- const marketUid = createMarketUid(chainId, LENDER, underlying);
20936
- result[underlying] = {
20945
+ const marketUid = createMarketUid(chainId, LENDER, String(info.token.marketId));
20946
+ result[marketUid] = {
20937
20947
  marketUid,
20938
20948
  name: lenderShortName(LENDER) + " " + (meta?.symbol ?? info.token.symbol ?? ""),
20939
20949
  poolId: underlying,
@@ -23935,6 +23945,7 @@ var getDolomiteUserDataConverter = (lender, chainId, account, metaMap) => {
23935
23945
  const marketIds = res?.[0 /* markets */] ?? [];
23936
23946
  const tokens = res?.[1 /* tokens */] ?? [];
23937
23947
  const weis = res?.[3 /* weis */] ?? [];
23948
+ const pars = res?.[2 /* pars */] ?? [];
23938
23949
  modes[id] = resolveDolomiteMode(
23939
23950
  marketIds.map((m) => String(m)),
23940
23951
  emode
@@ -23943,7 +23954,7 @@ var getDolomiteUserDataConverter = (lender, chainId, account, metaMap) => {
23943
23954
  const wei = weis[k];
23944
23955
  if (!wei) return;
23945
23956
  const underlying = normalizeUnderlying3(token);
23946
- const key = createMarketUid(chainId, lender, underlying);
23957
+ const key = createMarketUid(chainId, lender, String(marketIds[k]));
23947
23958
  const meta = metaMap?.[key];
23948
23959
  if (!meta) return;
23949
23960
  const decimals = meta.asset?.decimals ?? 18;
@@ -23951,6 +23962,7 @@ var getDolomiteUserDataConverter = (lender, chainId, account, metaMap) => {
23951
23962
  const isSupply = wei.sign;
23952
23963
  const deposits = isSupply ? amount : "0";
23953
23964
  const debt = isSupply ? "0" : amount;
23965
+ const debtPar = isSupply ? "0" : pars[k]?.value?.toString() ?? "0";
23954
23966
  const price2 = getDisplayPrice(meta);
23955
23967
  const oPrice = getOraclePrice(meta);
23956
23968
  const priceHist = meta?.price?.priceUsd24h ?? price2;
@@ -23961,6 +23973,7 @@ var getDolomiteUserDataConverter = (lender, chainId, account, metaMap) => {
23961
23973
  underlying,
23962
23974
  deposits,
23963
23975
  debt,
23976
+ debtPar,
23964
23977
  debtStable: "0",
23965
23978
  debtStableUSD: 0,
23966
23979
  depositsUSD: price2 * Number(deposits),
@@ -29277,10 +29290,12 @@ var buildApiQuery = (account, chainId) => `
29277
29290
  {
29278
29291
  userByAddress(address: "${account}", chainId: ${chainId}) {
29279
29292
  marketPositions {
29280
- market { uniqueKey }
29281
- supplyShares
29282
- borrowShares
29283
- collateral
29293
+ market { uniqueKey: marketId }
29294
+ state {
29295
+ supplyShares
29296
+ borrowShares
29297
+ collateral
29298
+ }
29284
29299
  }
29285
29300
  }
29286
29301
  }`;
@@ -29413,14 +29428,17 @@ async function fetchBalancesFromApi(chainId, account, proxyConfig) {
29413
29428
  const positions = json.data?.userByAddress?.marketPositions ?? [];
29414
29429
  const result = [];
29415
29430
  for (const pos of positions) {
29416
- if (!isNonZero(pos.supplyShares) && !isNonZero(pos.borrowShares) && !isNonZero(pos.collateral)) {
29431
+ const supplyShares = pos.state?.supplyShares ?? 0;
29432
+ const borrowShares = pos.state?.borrowShares ?? 0;
29433
+ const collateral = pos.state?.collateral ?? 0;
29434
+ if (!isNonZero(supplyShares) && !isNonZero(borrowShares) && !isNonZero(collateral)) {
29417
29435
  continue;
29418
29436
  }
29419
29437
  result.push({
29420
29438
  marketId: pos.market.uniqueKey.toLowerCase(),
29421
- supplyShares: String(pos.supplyShares),
29422
- borrowShares: String(pos.borrowShares),
29423
- collateral: String(pos.collateral)
29439
+ supplyShares: String(supplyShares),
29440
+ borrowShares: String(borrowShares),
29441
+ collateral: String(collateral)
29424
29442
  });
29425
29443
  }
29426
29444
  return result;
@@ -32928,13 +32946,13 @@ var MORPHO_GRAPHQL_URL = "https://blue-api.morpho.org/graphql";
32928
32946
  var PRICE_QUERY = (first, skip, chainId) => `
32929
32947
  query GetMarketPrices {
32930
32948
  markets(first: ${first}, skip: ${skip}, where: {
32931
- chainId_in: [${chainId}]${chainId != Chain.ETHEREUM_MAINNET ? `,whitelisted: true` : ""}
32949
+ chainId_in: [${chainId}]${chainId != Chain.ETHEREUM_MAINNET ? `,listed: true` : ""}
32932
32950
  },
32933
32951
  orderBy: SupplyAssetsUsd,
32934
32952
  orderDirection: Desc
32935
32953
  ) {
32936
32954
  items {
32937
- uniqueKey
32955
+ uniqueKey: marketId
32938
32956
  oracleAddress
32939
32957
  loanAsset {
32940
32958
  address
@@ -34145,7 +34163,7 @@ function parseDolomiteResults(data, meta, context) {
34145
34163
  asset,
34146
34164
  price: priceUSD,
34147
34165
  priceUSD,
34148
- marketUid: createMarketUid(chainId, LENDER2, asset),
34166
+ marketUid: createMarketUid(chainId, LENDER2, String(mkt.marketId)),
34149
34167
  targetLender: LENDER2
34150
34168
  });
34151
34169
  } catch {
@@ -35602,6 +35620,30 @@ function attachPricesToFlashLiquidity(chainId, liq, prices, list = {}) {
35602
35620
  return liqCopy;
35603
35621
  }
35604
35622
 
35623
+ // src/vaults/exposure.ts
35624
+ var IDLE_MARKET_ID = "idle";
35625
+ function withIdleExposure(exposures, totalAssetsFormatted, pricePerUnit) {
35626
+ if (!(totalAssetsFormatted > 0)) return exposures;
35627
+ const deployed = exposures.reduce((sum, e) => sum + e.assets, 0);
35628
+ const idleAssets = totalAssetsFormatted - deployed;
35629
+ if (idleAssets <= totalAssetsFormatted * 1e-9) return exposures;
35630
+ const out = [
35631
+ ...exposures,
35632
+ {
35633
+ marketId: IDLE_MARKET_ID,
35634
+ collateralAddress: "",
35635
+ collateral: void 0,
35636
+ assets: idleAssets,
35637
+ assetsUsd: idleAssets * pricePerUnit,
35638
+ weightPct: idleAssets / totalAssetsFormatted * 100,
35639
+ supplyApr: 0,
35640
+ idle: true
35641
+ }
35642
+ ];
35643
+ out.sort((a, b) => b.weightPct - a.weightPct);
35644
+ return out;
35645
+ }
35646
+
35605
35647
  // src/vaults/fluid/publicCallBuild.ts
35606
35648
  var buildFluidFTokensCall = (chainId) => {
35607
35649
  const resolvers = fluidResolvers()?.[chainId];
@@ -35706,8 +35748,80 @@ var fetchFluidFTokens = async (chainId, multicallRetry, prices = {}, tokenList =
35706
35748
  abi: calls.map(() => FluidLendingResolverAbi)
35707
35749
  });
35708
35750
  const [converter] = getFluidFTokensConverter(chainId, prices, tokenList);
35709
- return converter(raw) ?? {};
35751
+ const fTokens = converter(raw) ?? {};
35752
+ try {
35753
+ const exposuresByUnderlying = await fetchFluidExposures(
35754
+ chainId,
35755
+ multicallRetry,
35756
+ prices,
35757
+ tokenList
35758
+ );
35759
+ for (const underlying of Object.keys(fTokens)) {
35760
+ const exposures = exposuresByUnderlying.get(underlying);
35761
+ if (exposures?.length) fTokens[underlying].exposures = exposures;
35762
+ }
35763
+ } catch {
35764
+ }
35765
+ return fTokens;
35710
35766
  };
35767
+ async function fetchFluidExposures(chainId, multicallRetry, prices, tokenList) {
35768
+ const out = /* @__PURE__ */ new Map();
35769
+ const vaultCalls = buildFluidCall(chainId);
35770
+ if (vaultCalls.length === 0) return out;
35771
+ const rawVaults = await multicallRetry({
35772
+ chain: chainId,
35773
+ calls: vaultCalls,
35774
+ abi: vaultCalls.map(() => FluidVaultResolverAbi)
35775
+ });
35776
+ const [convert] = getFluidPublicDataConverter(
35777
+ "FLUID",
35778
+ chainId,
35779
+ prices,
35780
+ { intrinsicYields: {}},
35781
+ tokenList
35782
+ );
35783
+ const lenderMap = convert(rawVaults) ?? {};
35784
+ const rowsByLoan = /* @__PURE__ */ new Map();
35785
+ for (const lender of Object.keys(lenderMap)) {
35786
+ const entry = lenderMap[lender];
35787
+ const vault = entry?.params?.vault;
35788
+ if (!vault) continue;
35789
+ const loanAddress = (vault.loanAddress ?? "").toLowerCase();
35790
+ const collateralAddress = (vault.collateralAddress ?? "").toLowerCase();
35791
+ if (!loanAddress) continue;
35792
+ const loanEntry = Object.values(entry.data ?? {}).find(
35793
+ (d) => d?.borrowingEnabled && d?.underlying === loanAddress
35794
+ );
35795
+ if (!loanEntry) continue;
35796
+ const assets = Number(loanEntry.totalDebt ?? 0);
35797
+ if (!(assets > 0)) continue;
35798
+ const assetsUsd = Number(loanEntry.totalDebtUSD ?? 0) || 0;
35799
+ const row = {
35800
+ marketId: (vault.vaultAddress ?? "").toLowerCase(),
35801
+ collateralAddress,
35802
+ collateral: collateralAddress ? tokenList[collateralAddress] : void 0,
35803
+ assets,
35804
+ assetsUsd,
35805
+ supplyApr: Number(loanEntry.variableBorrowRate ?? 0) || 0
35806
+ };
35807
+ const list = rowsByLoan.get(loanAddress);
35808
+ if (list) list.push(row);
35809
+ else rowsByLoan.set(loanAddress, [row]);
35810
+ }
35811
+ for (const [loanAddress, rows] of rowsByLoan) {
35812
+ const totalUsd = rows.reduce((s, r) => s + r.assetsUsd, 0);
35813
+ const totalAssets = rows.reduce((s, r) => s + r.assets, 0);
35814
+ const useUsd = totalUsd > 0;
35815
+ const denom = useUsd ? totalUsd : totalAssets;
35816
+ if (denom <= 0) continue;
35817
+ const exposures = rows.map((r) => ({
35818
+ ...r,
35819
+ weightPct: (useUsd ? r.assetsUsd : r.assets) / denom * 100
35820
+ })).sort((a, b) => b.weightPct - a.weightPct);
35821
+ out.set(loanAddress, exposures);
35822
+ }
35823
+ return out;
35824
+ }
35711
35825
 
35712
35826
  // src/vaults/gearbox/publicCallBuild.ts
35713
35827
  var buildGearboxV3PoolsCall = (chainId) => {
@@ -35832,7 +35946,7 @@ query GetVaults {
35832
35946
  vaults(
35833
35947
  first: ${first},
35834
35948
  skip: ${skip},
35835
- where: { chainId_in: [${chainId}], whitelisted: true },
35949
+ where: { chainId_in: [${chainId}], listed: true },
35836
35950
  orderBy: TotalAssetsUsd,
35837
35951
  orderDirection: Desc
35838
35952
  ) {
@@ -35840,7 +35954,7 @@ query GetVaults {
35840
35954
  address
35841
35955
  symbol
35842
35956
  name
35843
- whitelisted
35957
+ whitelisted: listed
35844
35958
  asset {
35845
35959
  address
35846
35960
  name
@@ -35892,6 +36006,11 @@ async function fetchPage(chainId, first, skip) {
35892
36006
  );
35893
36007
  }
35894
36008
  const json = await response.json();
36009
+ if (json?.errors?.length) {
36010
+ throw new Error(
36011
+ `Morpho vaults API GraphQL error: ${json.errors.map((e) => e?.message).join("; ")}`
36012
+ );
36013
+ }
35895
36014
  return json?.data?.vaults?.items ?? [];
35896
36015
  }
35897
36016
  var parseCurators = (curators) => {
@@ -36238,7 +36357,12 @@ function parseVault4(entry, results, chainId, prices, tokenList) {
36238
36357
  liquidityUsd: totalAssetsFormatted * priceUsd
36239
36358
  };
36240
36359
  }
36360
+ var { chunk: chunk5 } = lodash;
36241
36361
  var LISTA_PROTOCOL = "LISTA_DAO";
36362
+ var LISTA_LENS_ABI = parseAbi([
36363
+ "function getListaMarketDataCompact(address morpho, bytes32[] calldata marketsIds) external view returns (bytes memory data)"
36364
+ ]);
36365
+ var LISTA_MARKET_CHUNK = 100;
36242
36366
  var PHASE1_CALLS = [
36243
36367
  "name",
36244
36368
  "symbol",
@@ -36247,9 +36371,11 @@ var PHASE1_CALLS = [
36247
36371
  "totalSupply",
36248
36372
  "fee",
36249
36373
  "feeRecipient",
36250
- "CURATOR"
36374
+ "CURATOR",
36375
+ "withdrawQueueLength"
36251
36376
  ];
36252
36377
  var PHASE1_PER_VAULT = PHASE1_CALLS.length;
36378
+ var WITHDRAW_QUEUE_LENGTH_INDEX = 8;
36253
36379
  var FEE_SCALE2 = 1e18;
36254
36380
  var isHex402 = (addr) => typeof addr === "string" && /^0x[0-9a-f]{40}$/i.test(addr);
36255
36381
  var lcOrUndefined2 = (addr) => {
@@ -36296,42 +36422,209 @@ var fetchListaVaultsFromChain = async (chainId, multicallRetry, prices = {}, tok
36296
36422
  allowFailure: true
36297
36423
  });
36298
36424
  const curatorRoleByVault = [];
36425
+ const queueLenByVault = [];
36299
36426
  for (let i = 0; i < entries.length; i++) {
36300
36427
  const role = phase1[i * PHASE1_PER_VAULT + 7];
36301
36428
  curatorRoleByVault.push(isHex64(role) ? role : void 0);
36429
+ queueLenByVault.push(
36430
+ toNumberSafe2(phase1[i * PHASE1_PER_VAULT + WITHDRAW_QUEUE_LENGTH_INDEX])
36431
+ );
36302
36432
  }
36303
- const phase2Calls = entries.map((entry, i) => ({
36304
- address: entry.vault,
36305
- name: "getRoleMember",
36306
- params: [curatorRoleByVault[i] ?? zeroHash, 0n]
36307
- }));
36433
+ const phase2Calls = [];
36434
+ const phase2Meta = [];
36435
+ entries.forEach((entry, i) => {
36436
+ phase2Calls.push({
36437
+ address: entry.vault,
36438
+ name: "getRoleMember",
36439
+ params: [curatorRoleByVault[i] ?? zeroHash, 0n]
36440
+ });
36441
+ phase2Meta.push({ kind: "curator", vault: i });
36442
+ for (let q = 0; q < queueLenByVault[i]; q++) {
36443
+ phase2Calls.push({
36444
+ address: entry.vault,
36445
+ name: "withdrawQueue",
36446
+ params: [BigInt(q)]
36447
+ });
36448
+ phase2Meta.push({ kind: "queue", vault: i });
36449
+ }
36450
+ });
36308
36451
  const phase2 = await multicallRetry({
36309
36452
  chain: chainId,
36310
36453
  calls: phase2Calls,
36311
36454
  abi: phase2Calls.map(() => MoolahVaultAbi),
36312
36455
  allowFailure: true
36313
36456
  });
36457
+ const curatorAddrByVault = entries.map(() => void 0);
36458
+ const marketIdsByVault = entries.map(() => []);
36459
+ phase2.forEach((res, k) => {
36460
+ const meta = phase2Meta[k];
36461
+ if (meta.kind === "curator") {
36462
+ if (curatorRoleByVault[meta.vault]) curatorAddrByVault[meta.vault] = res;
36463
+ } else if (isHex64(res)) {
36464
+ marketIdsByVault[meta.vault].push(res.toLowerCase());
36465
+ }
36466
+ });
36467
+ const moolah = morphoPools()?.[LISTA_PROTOCOL]?.[chainId];
36468
+ const allMarketIds = [...new Set(marketIdsByVault.flat())];
36469
+ const [rateMap, positionMap] = await Promise.all([
36470
+ fetchListaMarketRates(chainId, moolah, allMarketIds, multicallRetry),
36471
+ fetchVaultSupplyShares(
36472
+ chainId,
36473
+ moolah,
36474
+ entries,
36475
+ marketIdsByVault,
36476
+ multicallRetry
36477
+ )
36478
+ ]);
36314
36479
  const out = {};
36315
36480
  for (let i = 0; i < entries.length; i++) {
36316
36481
  const entry = entries[i];
36317
- const slice = phase1.slice(
36318
- i * PHASE1_PER_VAULT,
36319
- (i + 1) * PHASE1_PER_VAULT
36320
- );
36321
- const curatorAddrRaw = curatorRoleByVault[i] ? phase2[i] : void 0;
36482
+ const slice = phase1.slice(i * PHASE1_PER_VAULT, (i + 1) * PHASE1_PER_VAULT);
36322
36483
  const parsed = parseVault5(
36323
36484
  entry,
36324
36485
  slice,
36325
- curatorAddrRaw,
36486
+ curatorAddrByVault[i],
36326
36487
  chainId,
36327
36488
  prices,
36328
- tokenList
36489
+ tokenList,
36490
+ marketIdsByVault[i],
36491
+ rateMap,
36492
+ positionMap
36329
36493
  );
36330
36494
  if (parsed) out[parsed.address] = parsed;
36331
36495
  }
36332
36496
  return out;
36333
36497
  };
36334
- function parseVault5(entry, results, curatorAddrRaw, chainId, prices, tokenList) {
36498
+ async function fetchListaMarketRates(chainId, moolah, marketIds, multicallRetry) {
36499
+ const map = /* @__PURE__ */ new Map();
36500
+ const lens = MORPHO_LENS[chainId];
36501
+ if (!moolah || !lens || marketIds.length === 0) return map;
36502
+ const groups = chunk5(marketIds, LISTA_MARKET_CHUNK);
36503
+ const calls = groups.map((group) => ({
36504
+ address: lens,
36505
+ name: "getListaMarketDataCompact",
36506
+ params: [moolah, group]
36507
+ }));
36508
+ const raw = await multicallRetry({
36509
+ chain: chainId,
36510
+ calls,
36511
+ abi: calls.map(() => LISTA_LENS_ABI),
36512
+ allowFailure: true
36513
+ });
36514
+ groups.forEach((group, c) => {
36515
+ const bytes = raw[c];
36516
+ if (!bytes || bytes === "0x") return;
36517
+ let decoded;
36518
+ try {
36519
+ decoded = decodeMarkets(bytes);
36520
+ } catch {
36521
+ return;
36522
+ }
36523
+ decoded.forEach((mkt, j) => {
36524
+ const id = group[j]?.toLowerCase();
36525
+ if (!id) return;
36526
+ const utilization = MathLib.getUtilization({
36527
+ totalSupplyAssets: mkt.totalSupplyAssets,
36528
+ totalBorrowAssets: mkt.totalBorrowAssets
36529
+ });
36530
+ let supplyApy = 0n;
36531
+ try {
36532
+ const borrowApy = MathLib.getListaBorrowApy(
36533
+ mkt.rateAtTarget,
36534
+ utilization,
36535
+ void 0,
36536
+ Number(mkt.lastUpdate),
36537
+ mkt.rateCap,
36538
+ mkt.rateFloor
36539
+ );
36540
+ supplyApy = MathLib.getSupplyApy(borrowApy, utilization, mkt.fee);
36541
+ } catch {
36542
+ }
36543
+ map.set(id, {
36544
+ supplyApr: apyToApr(Number(formatEther(supplyApy))) * 100,
36545
+ totalSupplyAssets: mkt.totalSupplyAssets,
36546
+ totalSupplyShares: mkt.totalSupplyShares,
36547
+ collateralAddress: (mkt.collateralToken ?? "").toLowerCase()
36548
+ });
36549
+ });
36550
+ });
36551
+ return map;
36552
+ }
36553
+ async function fetchVaultSupplyShares(chainId, moolah, entries, marketIdsByVault, multicallRetry) {
36554
+ const map = /* @__PURE__ */ new Map();
36555
+ if (!moolah) return map;
36556
+ const calls = [];
36557
+ const keys = [];
36558
+ entries.forEach((entry, i) => {
36559
+ const vault = entry.vault.toLowerCase();
36560
+ for (const id of marketIdsByVault[i]) {
36561
+ calls.push({
36562
+ address: moolah,
36563
+ name: "position",
36564
+ params: [id, entry.vault]
36565
+ });
36566
+ keys.push(`${vault}:${id}`);
36567
+ }
36568
+ });
36569
+ if (calls.length === 0) return map;
36570
+ const res = await multicallRetry({
36571
+ chain: chainId,
36572
+ calls,
36573
+ abi: calls.map(() => MorphoBlueAbi),
36574
+ allowFailure: true
36575
+ });
36576
+ res.forEach((r, k) => {
36577
+ const supplyShares = Array.isArray(r) ? r[0] : r?.supplyShares;
36578
+ if (supplyShares == null) return;
36579
+ try {
36580
+ map.set(keys[k], BigInt(supplyShares));
36581
+ } catch {
36582
+ }
36583
+ });
36584
+ return map;
36585
+ }
36586
+ function computeVaultAllocation(vaultAddress, decimals, totalAssetsFormatted, feePercent, priceUsd, marketIds, rateMap, positionMap, tokenList) {
36587
+ if (totalAssetsFormatted <= 0) {
36588
+ return { depositRate: 0, exposures: [] };
36589
+ }
36590
+ if (marketIds.length === 0) {
36591
+ return {
36592
+ depositRate: 0,
36593
+ exposures: withIdleExposure([], totalAssetsFormatted, priceUsd)
36594
+ };
36595
+ }
36596
+ let weighted = 0;
36597
+ const exposures = [];
36598
+ for (const id of marketIds) {
36599
+ const rate = rateMap.get(id);
36600
+ if (!rate || rate.totalSupplyShares === 0n) continue;
36601
+ const shares = positionMap.get(`${vaultAddress}:${id}`);
36602
+ if (!shares || shares === 0n) continue;
36603
+ const allocAssetsRaw = shares * rate.totalSupplyAssets / rate.totalSupplyShares;
36604
+ const allocAssets = Number(
36605
+ parseRawAmount(allocAssetsRaw.toString(), decimals)
36606
+ );
36607
+ if (allocAssets <= 0) continue;
36608
+ weighted += allocAssets * rate.supplyApr;
36609
+ exposures.push({
36610
+ marketId: id,
36611
+ collateralAddress: rate.collateralAddress,
36612
+ collateral: tokenList[rate.collateralAddress],
36613
+ assets: allocAssets,
36614
+ assetsUsd: allocAssets * priceUsd,
36615
+ weightPct: allocAssets / totalAssetsFormatted * 100,
36616
+ supplyApr: rate.supplyApr
36617
+ });
36618
+ }
36619
+ exposures.sort((a, b) => b.weightPct - a.weightPct);
36620
+ const grossApr = weighted / totalAssetsFormatted;
36621
+ return {
36622
+ depositRate: grossApr * (1 - feePercent / 100),
36623
+ // Tag uninvested deposits as an idle entry so the breakdown sums to ~100%.
36624
+ exposures: withIdleExposure(exposures, totalAssetsFormatted, priceUsd)
36625
+ };
36626
+ }
36627
+ function parseVault5(entry, results, curatorAddrRaw, chainId, prices, tokenList, marketIds, rateMap, positionMap) {
36335
36628
  const address = entry?.vault?.toLowerCase();
36336
36629
  const underlying = entry?.underlying?.toLowerCase();
36337
36630
  if (!address || !underlying) return null;
@@ -36343,9 +36636,9 @@ function parseVault5(entry, results, curatorAddrRaw, chainId, prices, tokenList)
36343
36636
  totalSupplyRaw,
36344
36637
  feeRaw,
36345
36638
  /* feeRecipientRaw */
36346
- ,
36347
36639
  /* curatorRoleRaw */
36348
36640
  ,
36641
+ ,
36349
36642
  ] = results;
36350
36643
  const assetMeta = tokenList[underlying];
36351
36644
  const decimals = Number(decimalsRaw ?? assetMeta?.decimals ?? 18);
@@ -36358,6 +36651,17 @@ function parseVault5(entry, results, curatorAddrRaw, chainId, prices, tokenList)
36358
36651
  const fallbackName = onchainName || (entry.name ?? "").trim();
36359
36652
  const symbol = toStringSafe2(symbolRaw);
36360
36653
  const fee = toNumberSafe2(feeRaw) / FEE_SCALE2 * 100;
36654
+ const { depositRate, exposures } = computeVaultAllocation(
36655
+ address,
36656
+ decimals,
36657
+ totalAssetsFormatted,
36658
+ fee,
36659
+ priceUsd,
36660
+ marketIds,
36661
+ rateMap,
36662
+ positionMap,
36663
+ tokenList
36664
+ );
36361
36665
  return {
36362
36666
  address,
36363
36667
  underlying,
@@ -36372,9 +36676,9 @@ function parseVault5(entry, results, curatorAddrRaw, chainId, prices, tokenList)
36372
36676
  decimals,
36373
36677
  totalAssets,
36374
36678
  totalSupply,
36375
- supplyRate: 0,
36679
+ supplyRate: depositRate,
36376
36680
  rewardsRate: 0,
36377
- depositRate: 0,
36681
+ depositRate,
36378
36682
  fee,
36379
36683
  timelock: 0,
36380
36684
  whitelisted: true,
@@ -36387,7 +36691,8 @@ function parseVault5(entry, results, curatorAddrRaw, chainId, prices, tokenList)
36387
36691
  totalAssetsUsd: totalAssetsFormatted * priceUsd,
36388
36692
  liquidity: totalAssets,
36389
36693
  liquidityFormatted: totalAssetsFormatted,
36390
- liquidityUsd: totalAssetsFormatted * priceUsd
36694
+ liquidityUsd: totalAssetsFormatted * priceUsd,
36695
+ exposures: exposures.length > 0 ? exposures : void 0
36391
36696
  };
36392
36697
  }
36393
36698
 
@@ -36418,8 +36723,55 @@ query GetSiloVaults {
36418
36723
  userApr
36419
36724
  }
36420
36725
  }
36726
+ positions(where: {chainId_in: [${chainId}], isVaultAllocation: true, isOpen: true}, limit: ${limit}) {
36727
+ items {
36728
+ accountId
36729
+ marketId
36730
+ sTokenBalance
36731
+ }
36732
+ }
36733
+ markets(where: {chainId_in: [${chainId}]}, limit: ${limit}) {
36734
+ items {
36735
+ id
36736
+ depositRate
36737
+ collateralSharesSupply
36738
+ collateralAssetsSupply
36739
+ otherMarket { inputToken { id } }
36740
+ }
36741
+ }
36421
36742
  }
36422
36743
  `;
36744
+ function buildExposures(vaultId, totalAssetsFormatted, pricePerUnit, positionsByVault, marketMeta, tokenList) {
36745
+ if (totalAssetsFormatted <= 0) return void 0;
36746
+ const rows = positionsByVault.get(vaultId) ?? [];
36747
+ const exposures = [];
36748
+ for (const row of rows) {
36749
+ const marketId = (row.marketId ?? "").toLowerCase();
36750
+ if (!marketId) continue;
36751
+ const meta = marketMeta.get(marketId);
36752
+ if (!meta || meta.collateralShares <= 0) continue;
36753
+ const shares = Number(row.sTokenBalance ?? 0);
36754
+ if (!Number.isFinite(shares) || shares <= 0) continue;
36755
+ const assets = shares * meta.collateralAssets / meta.collateralShares;
36756
+ if (!(assets > 0) || assets > totalAssetsFormatted * 1.01) continue;
36757
+ exposures.push({
36758
+ marketId,
36759
+ collateralAddress: meta.collateralAddress,
36760
+ collateral: meta.collateralAddress ? tokenList[meta.collateralAddress] : void 0,
36761
+ assets,
36762
+ assetsUsd: assets * pricePerUnit,
36763
+ weightPct: assets / totalAssetsFormatted * 100,
36764
+ supplyApr: meta.supplyApr
36765
+ });
36766
+ }
36767
+ exposures.sort((a, b) => b.weightPct - a.weightPct);
36768
+ const withIdle = withIdleExposure(
36769
+ exposures,
36770
+ totalAssetsFormatted,
36771
+ pricePerUnit
36772
+ );
36773
+ return withIdle.length > 0 ? withIdle : void 0;
36774
+ }
36423
36775
  var PERFORMANCE_FEE_SCALE = 1e16;
36424
36776
  var toRawAmount = (decimalString, decimals) => {
36425
36777
  if (!decimalString) return "0";
@@ -36429,7 +36781,7 @@ var toRawAmount = (decimalString, decimals) => {
36429
36781
  return "0";
36430
36782
  }
36431
36783
  };
36432
- function parseVault6(v, chainId, prices, tokenList) {
36784
+ function parseVault6(v, chainId, prices, tokenList, exposures) {
36433
36785
  const address = (v?.id ?? "").toLowerCase();
36434
36786
  const assetAddr = (v?.asset?.id ?? "").toLowerCase();
36435
36787
  if (!address || !assetAddr) return null;
@@ -36485,7 +36837,8 @@ function parseVault6(v, chainId, prices, tokenList) {
36485
36837
  // Morpho / Fluid / Gearbox. Not suitable for hard withdraw validation.
36486
36838
  liquidity: totalAssetsRaw,
36487
36839
  liquidityFormatted: totalAssetsFormatted,
36488
- liquidityUsd: totalAssetsUsd
36840
+ liquidityUsd: totalAssetsUsd,
36841
+ exposures
36489
36842
  };
36490
36843
  }
36491
36844
  var fetchSiloVaults = async (chainId, prices = {}, tokenList = {}, options) => {
@@ -36508,12 +36861,46 @@ var fetchSiloVaults = async (chainId, prices = {}, tokenList = {}, options) => {
36508
36861
  );
36509
36862
  }
36510
36863
  const items = payload?.data?.vaults?.items ?? [];
36864
+ const positions = payload?.data?.positions?.items ?? [];
36865
+ const positionsByVault = /* @__PURE__ */ new Map();
36866
+ for (const row of positions) {
36867
+ const accountId = (row.accountId ?? "").toLowerCase();
36868
+ if (!accountId) continue;
36869
+ const list = positionsByVault.get(accountId);
36870
+ if (list) list.push(row);
36871
+ else positionsByVault.set(accountId, [row]);
36872
+ }
36873
+ const markets = payload?.data?.markets?.items ?? [];
36874
+ const marketMeta = /* @__PURE__ */ new Map();
36875
+ for (const m of markets) {
36876
+ const id = (m.id ?? "").toLowerCase();
36877
+ if (!id) continue;
36878
+ const apr = Number(m.depositRate ?? 0);
36879
+ marketMeta.set(id, {
36880
+ collateralAddress: (m.otherMarket?.inputToken?.id ?? "").toLowerCase(),
36881
+ supplyApr: Number.isFinite(apr) ? apr : 0,
36882
+ collateralShares: Number(m.collateralSharesSupply ?? 0) || 0,
36883
+ collateralAssets: Number(m.collateralAssetsSupply ?? 0) || 0
36884
+ });
36885
+ }
36511
36886
  const out = {};
36512
36887
  for (const v of items) {
36513
36888
  if (options?.protocolVersion && v.protocol?.protocolVersion !== options.protocolVersion) {
36514
36889
  continue;
36515
36890
  }
36516
- const parsed = parseVault6(v, chainId, prices, tokenList);
36891
+ const vaultId = (v.id ?? "").toLowerCase();
36892
+ const totalAssetsFormatted = Number(v.totalAssets ?? 0) || 0;
36893
+ const apiTotalAssetsUsd = Number(v.totalAssetsUsd ?? 0) || 0;
36894
+ const pricePerUnit = totalAssetsFormatted > 0 && apiTotalAssetsUsd > 0 ? apiTotalAssetsUsd / totalAssetsFormatted : prices[(v.asset?.id ?? "").toLowerCase()] ?? 0;
36895
+ const exposures = buildExposures(
36896
+ vaultId,
36897
+ totalAssetsFormatted,
36898
+ pricePerUnit,
36899
+ positionsByVault,
36900
+ marketMeta,
36901
+ tokenList
36902
+ );
36903
+ const parsed = parseVault6(v, chainId, prices, tokenList, exposures);
36517
36904
  if (parsed) out[parsed.address] = parsed;
36518
36905
  }
36519
36906
  return out;
@@ -45115,6 +45502,6 @@ async function fetchTokenBalances(chainId, account, tokens, options = {}) {
45115
45502
  return parseTokenBalanceResult(rawResult, prepared.query);
45116
45503
  }
45117
45504
 
45118
- export { EMPTY_BALANCE, GMX_API_HOSTS, GMX_READ_CONTRACTS, GMX_SUPPORTED_CHAINS, HYPERCORE_VAULT_REGISTRY, INTERFACE_IDS, LAGOON_API_URL, LAGOON_CHAIN_IDS, MORPHO_LENS, MaxParamThresholds, STABLECOIN_SYMBOLS, VAULT_SHARE_PRICE_PROBE, VOLATILE_VAULT_OVERRIDES, accountDepositListKey, accountWithdrawalListKey, appendSnapshot, applyPositionDelta, attachPricesToFlashLiquidity, buildFluidFTokensCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildSumerAccumulators, buildSummaries, buildVaultLookup, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyVault, computeBorrowDelta2 as computeBorrowDelta, computeCloseTradeDeltas, computeCollateralSwapDeltas, computeDebtSwapDeltas, computeDepositDelta2 as computeDepositDelta, computeEModeAnalysis, computeOpenTradeDeltas, computePostTradeMetrics, computeRepayDelta2 as computeRepayDelta, computeSumerBorrowDelta, computeSumerDepositDelta, computeSumerRepayDelta, computeSumerWaterfall, computeSumerWithdrawDelta, computeVaultApr, computeWithdrawDelta2 as computeWithdrawDelta, computeZapTradeDeltas, convertLenderUserDataResult, createMarketUid, createMulticallRpcCall, createRawRpcCalls, decodeListaMarkets, decodeMarkets, decodePackedListaUserDataset, decodePackedMorphoUserDataset, detectInterfaceKinds, encodeBalanceFetcherCalldata, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchFlashLiquidityForChain, fetchFluidFTokens, fetchGeneralYields, fetchGeneralYieldsByMarketUid, fetchGmxExecutionFees, fetchGmxTickerPrices, fetchGmxVaults, fetchHypercoreVaults, fetchLagoonApiVaults, fetchLagoonVaults, fetchListaVaultsFromChain, fetchMorphoUserBalances, fetchMorphoUserPositionMarkets, fetchMorphoVaults, fetchMorphoVaultsFromApi, fetchMorphoVaultsFromChain, fetchMorphoVaultsFromSubgraph, fetchOraclePrices, fetchPendlePrices, fetchSiloVaults, fetchTokenBalances, fetchTokenMetadata, filterActiveLenders, filterLendersByProtocol, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, getFluidFTokensConverter, getGmxApiHost, getGmxReadContracts, getGmxUserPositions, getHealthFactor, getHypercoreUserPositions, getHypercoreVaultRegistry, getLenderAssets, getLenderPublicData, getLenderPublicDataAll, getLenderPublicDataViaApi, getLenderUserDataMulti, getLenderUserDataResult, getLendersForChain, getLstWithdrawalRegistry, getLstWithdrawalRequests, getMaxAmountClose, getMaxAmountCollateralSwap, getMaxAmountDebtSwap, getMaxAmountOpen, getMergedUserData, getMorphoTypeMarketConverter, getSubAccountAddress, getSubAccountIndex, getVaultPublicDataAll, getVaultWithdrawalRequests, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasMorphoVaultSubgraph, isStablecoinSymbol, keysFromMaps, multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, parseBalanceFetcherResult, parseMergedResult, parseMulticallRpcResponses, parseRawRpcBatchResponses, parseRawRpcResponses, parseTokenBalanceResult, positivePart2 as positivePart, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, readVaultSharePrices, selectAssetGroupPrices, stampVaultClassification, unflattenLenderData };
45505
+ export { EMPTY_BALANCE, GMX_API_HOSTS, GMX_READ_CONTRACTS, GMX_SUPPORTED_CHAINS, HYPERCORE_VAULT_REGISTRY, IDLE_MARKET_ID, INTERFACE_IDS, LAGOON_API_URL, LAGOON_CHAIN_IDS, MORPHO_LENS, MaxParamThresholds, STABLECOIN_SYMBOLS, VAULT_SHARE_PRICE_PROBE, VOLATILE_VAULT_OVERRIDES, accountDepositListKey, accountWithdrawalListKey, appendSnapshot, applyPositionDelta, attachPricesToFlashLiquidity, buildFluidFTokensCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildSumerAccumulators, buildSummaries, buildVaultLookup, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyVault, computeBorrowDelta2 as computeBorrowDelta, computeCloseTradeDeltas, computeCollateralSwapDeltas, computeDebtSwapDeltas, computeDepositDelta2 as computeDepositDelta, computeEModeAnalysis, computeOpenTradeDeltas, computePostTradeMetrics, computeRepayDelta2 as computeRepayDelta, computeSumerBorrowDelta, computeSumerDepositDelta, computeSumerRepayDelta, computeSumerWaterfall, computeSumerWithdrawDelta, computeVaultApr, computeWithdrawDelta2 as computeWithdrawDelta, computeZapTradeDeltas, convertLenderUserDataResult, createMarketUid, createMulticallRpcCall, createRawRpcCalls, decodeListaMarkets, decodeMarkets, decodePackedListaUserDataset, decodePackedMorphoUserDataset, detectInterfaceKinds, encodeBalanceFetcherCalldata, fetchDolomiteAccountNumbers, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchFlashLiquidityForChain, fetchFluidFTokens, fetchGeneralYields, fetchGeneralYieldsByMarketUid, fetchGmxExecutionFees, fetchGmxTickerPrices, fetchGmxVaults, fetchHypercoreVaults, fetchLagoonApiVaults, fetchLagoonVaults, fetchListaVaultsFromChain, fetchMorphoUserBalances, fetchMorphoUserPositionMarkets, fetchMorphoVaults, fetchMorphoVaultsFromApi, fetchMorphoVaultsFromChain, fetchMorphoVaultsFromSubgraph, fetchOraclePrices, fetchPendlePrices, fetchSiloVaults, fetchTokenBalances, fetchTokenMetadata, filterActiveLenders, filterLendersByProtocol, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, getFluidFTokensConverter, getGmxApiHost, getGmxReadContracts, getGmxUserPositions, getHealthFactor, getHypercoreUserPositions, getHypercoreVaultRegistry, getLenderAssets, getLenderPublicData, getLenderPublicDataAll, getLenderPublicDataViaApi, getLenderUserDataMulti, getLenderUserDataResult, getLendersForChain, getLstWithdrawalRegistry, getLstWithdrawalRequests, getMaxAmountClose, getMaxAmountCollateralSwap, getMaxAmountDebtSwap, getMaxAmountOpen, getMergedUserData, getMorphoTypeMarketConverter, getResolvedDolomiteAccountNumbers, getSubAccountAddress, getSubAccountIndex, getVaultPublicDataAll, getVaultWithdrawalRequests, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasMorphoVaultSubgraph, isStablecoinSymbol, keysFromMaps, multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, parseBalanceFetcherResult, parseMergedResult, parseMulticallRpcResponses, parseRawRpcBatchResponses, parseRawRpcResponses, parseTokenBalanceResult, positivePart2 as positivePart, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, readVaultSharePrices, selectAssetGroupPrices, stampVaultClassification, unflattenLenderData };
45119
45506
  //# sourceMappingURL=index.js.map
45120
45507
  //# sourceMappingURL=index.js.map