@1delta/margin-fetcher 0.0.195 → 0.0.197

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
@@ -4,7 +4,7 @@ import './chunk-PR4QN5HX.js';
4
4
  import { Lender, isAaveType, isCompoundV3, isMultiMarket, isInit, isMorphoType, isCompoundV2Type, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isAaveV2Type, isAaveV32Type, isAaveV3Type, isEulerType, isYLDR, isCompoundV3Type, isTectonicType, isBenqiType, isLista } from '@1delta/lender-registry';
5
5
  export { isAaveType, isAaveV2Type, isAaveV32Type, isAaveV3Type, isCompoundV3, isCompoundV3Type, isInit, isMorphoType, isMultiMarket, isYLDR } from '@1delta/lender-registry';
6
6
  import lodash from 'lodash';
7
- import { getEvmChain, multicallRetry, getEvmClient, getEvmClientUniversal } from '@1delta/providers';
7
+ import { getEvmChain, multicallRetryUniversal, getEvmClient, getEvmClientUniversal } from '@1delta/providers';
8
8
  import { MorphoLensAbi, MorphoBlueAbi } from '@1delta/abis';
9
9
  export { MorphoLensAbi } from '@1delta/abis';
10
10
  import { prepareDebitDataMulticall, prepareLenderDebitMulticall, parseDebitDataResult, parseLenderDebitResult, getPermit2ContractAddress, InitMarginAddresses } from '@1delta/calldata-sdk';
@@ -7485,16 +7485,21 @@ var DISABLED_COMPOUNDS = {
7485
7485
  [Chain.ETHEREUM_MAINNET]: [Lender.CREAM_FINANCE]
7486
7486
  };
7487
7487
  var ENABLED_EULER_V2_CHAINS = [
7488
+ Chain.ETHEREUM_MAINNET,
7488
7489
  Chain.BNB_SMART_CHAIN_MAINNET,
7489
- Chain.PLASMA_MAINNET,
7490
- Chain.BERACHAIN,
7491
- Chain.HYPEREVM,
7492
7490
  Chain.UNICHAIN,
7493
- Chain.SONIC_MAINNET,
7494
7491
  Chain.MONAD_MAINNET,
7495
- Chain.AVALANCHE_C_CHAIN
7496
- // Chain.BASE,
7497
- // Chain.ARBITRUM_ONE,
7492
+ Chain.SONIC_MAINNET,
7493
+ Chain.TAC_MAINNET,
7494
+ Chain.SWELLCHAIN,
7495
+ Chain.BASE,
7496
+ Chain.PLASMA_MAINNET,
7497
+ Chain.ARBITRUM_ONE,
7498
+ Chain.AVALANCHE_C_CHAIN,
7499
+ Chain.LINEA,
7500
+ Chain.BOB,
7501
+ Chain.BERACHAIN,
7502
+ Chain.HYPEREVM
7498
7503
  ];
7499
7504
  var getLendersForChain = (c) => {
7500
7505
  let lenders = [];
@@ -17993,7 +17998,7 @@ var getAbi = (lender) => {
17993
17998
  if (isCompoundV2Type(lender)) return VenusLensAbi;
17994
17999
  return [];
17995
18000
  };
17996
- var getLenderPublicData = async (chainId, lenders, prices, additionalYields, multicallRetry3, tokenList = async () => {
18001
+ var getLenderPublicData = async (chainId, lenders, prices, additionalYields, multicallRetry, tokenList = async () => {
17997
18002
  return {};
17998
18003
  }) => {
17999
18004
  let calls = [];
@@ -18004,16 +18009,12 @@ var getLenderPublicData = async (chainId, lenders, prices, additionalYields, mul
18004
18009
  calls = [...calls, ...mappedCalls];
18005
18010
  }
18006
18011
  const [rawResults, list] = await Promise.all([
18007
- multicallRetry3(
18008
- chainId,
18009
- calls.map((call) => call.call),
18010
- calls.map((call) => call.abi),
18011
- chainId === Chain.ETHEREUM_MAINNET ? 500 : void 0
18012
- // default size
18013
- // retries = 3
18014
- // provider = 0
18015
- // allowFailure = false
18016
- ),
18012
+ multicallRetry({
18013
+ chain: chainId,
18014
+ calls: calls.map((call) => call.call),
18015
+ abi: calls.map((call) => call.abi),
18016
+ batchSize: chainId === Chain.ETHEREUM_MAINNET ? 500 : void 0
18017
+ }),
18017
18018
  await tokenList()
18018
18019
  ]);
18019
18020
  const invalidLenders = [];
@@ -18121,7 +18122,7 @@ function lenderCanUseApi(lender, chainId) {
18121
18122
  }
18122
18123
  return false;
18123
18124
  }
18124
- var getLenderPublicDataAll = async (chainId, lenders, prices, additionalYields, multicallRetry3, tokenList, includeUnlistedMorphoMarkets = false) => {
18125
+ var getLenderPublicDataAll = async (chainId, lenders, prices, additionalYields, multicallRetry, tokenList, includeUnlistedMorphoMarkets = false) => {
18125
18126
  const lendersApi = lenders.filter((l) => lenderCanUseApi(l, chainId));
18126
18127
  const lendersOnChain = lenders.filter((l) => !lenderCanUseApi(l, chainId));
18127
18128
  const onChain = getLenderPublicData(
@@ -18129,7 +18130,7 @@ var getLenderPublicDataAll = async (chainId, lenders, prices, additionalYields,
18129
18130
  lendersOnChain,
18130
18131
  prices,
18131
18132
  additionalYields,
18132
- multicallRetry3,
18133
+ multicallRetry,
18133
18134
  tokenList
18134
18135
  );
18135
18136
  const api = getLenderPublicDataViaApi(
@@ -24727,20 +24728,20 @@ function parseMergedResult(chainId, rawResults, prepared, lenderState) {
24727
24728
  }
24728
24729
 
24729
24730
  // src/lending/user-data/with-permissions/e2e.ts
24730
- async function getMergedUserData(chainId, balanceQueries, permissionParams, lenderState, multicallRetry3, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, maxRetries2 = 3, tokenApprovalParams) {
24731
+ async function getMergedUserData(chainId, balanceQueries, permissionParams, lenderState, multicallRetry, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, maxRetries2 = 3, tokenApprovalParams) {
24731
24732
  const prepared = await prepareMergedMulticallParams(
24732
24733
  chainId,
24733
24734
  balanceQueries,
24734
24735
  permissionParams,
24735
24736
  tokenApprovalParams
24736
24737
  );
24737
- const rawResults = await multicallRetry3(
24738
- chainId,
24739
- prepared.calls,
24740
- prepared.abis,
24738
+ const rawResults = await multicallRetry({
24739
+ chain: chainId,
24740
+ calls: prepared.calls,
24741
+ abi: prepared.abis,
24741
24742
  batchSize,
24742
- maxRetries2
24743
- );
24743
+ maxRetries: maxRetries2
24744
+ });
24744
24745
  return parseMergedResult(chainId, rawResults, prepared, lenderState);
24745
24746
  }
24746
24747
  function toCompoundV2Shares(entry, amount) {
@@ -29052,16 +29053,16 @@ var fetchMainPrices = async (chainIds, rpcOverrides, lists = {}, retries = 3, ba
29052
29053
  ...CometAbi,
29053
29054
  ...VenusLensAbi
29054
29055
  ];
29055
- const result = await multicallRetry(
29056
- chainId,
29057
- allCalls,
29058
- abis,
29056
+ const result = await multicallRetryUniversal({
29057
+ chain: chainId,
29058
+ calls: allCalls,
29059
+ abi: abis,
29059
29060
  batchSize,
29060
- retries,
29061
- 0,
29061
+ maxRetries: retries,
29062
+ providerId: 0,
29062
29063
  allowFailure,
29063
- rpcOverrides
29064
- );
29064
+ overrdies: rpcOverrides
29065
+ });
29065
29066
  return {
29066
29067
  chainId,
29067
29068
  result,
@@ -30360,6 +30361,13 @@ var aaveFetcher = {
30360
30361
  parse: parseAaveResults2,
30361
30362
  getAbi: getAaveAbi
30362
30363
  };
30364
+ function morphoApiAvailable(chainId) {
30365
+ if (chainId === Chain.SONEIUM) return false;
30366
+ if (chainId === Chain.HEMI_NETWORK) return false;
30367
+ if (chainId === Chain.BERACHAIN) return false;
30368
+ if (chainId === Chain.SEI_NETWORK) return false;
30369
+ return true;
30370
+ }
30363
30371
  function generateMarketId(oracle, loanAsset, collateralAsset) {
30364
30372
  return `${oracle}${loanAsset}${collateralAsset}`.replace(/0x/gi, "").toUpperCase();
30365
30373
  }
@@ -30451,6 +30459,111 @@ function parseMorphoResults2(data, meta, context) {
30451
30459
  function getMorphoAbi() {
30452
30460
  return ProxyOracleAbi;
30453
30461
  }
30462
+ var MORPHO_GRAPHQL_URL = "https://blue-api.morpho.org/graphql";
30463
+ var PRICE_QUERY = (first, skip, chainId) => `
30464
+ query GetMarketPrices {
30465
+ markets(first: ${first}, skip: ${skip}, where: {
30466
+ chainId_in: [${chainId}],
30467
+ whitelisted: true
30468
+ },
30469
+ orderBy: SupplyAssetsUsd,
30470
+ orderDirection: Desc
30471
+ ) {
30472
+ items {
30473
+ uniqueKey
30474
+ oracleAddress
30475
+ loanAsset {
30476
+ address
30477
+ decimals
30478
+ priceUsd
30479
+ }
30480
+ collateralAsset {
30481
+ address
30482
+ decimals
30483
+ priceUsd
30484
+ }
30485
+ state {
30486
+ price
30487
+ }
30488
+ }
30489
+ }
30490
+ }
30491
+ `;
30492
+ async function fetchMorphoGraphQLPrices(chainId) {
30493
+ if (!morphoApiAvailable(chainId)) return null;
30494
+ try {
30495
+ const pages = chainId === "1" ? [
30496
+ fetch(MORPHO_GRAPHQL_URL, {
30497
+ method: "POST",
30498
+ headers: { "Content-Type": "application/json" },
30499
+ body: JSON.stringify({
30500
+ query: PRICE_QUERY(200, 0, chainId)
30501
+ })
30502
+ }).then((r) => r.json()),
30503
+ fetch(MORPHO_GRAPHQL_URL, {
30504
+ method: "POST",
30505
+ headers: { "Content-Type": "application/json" },
30506
+ body: JSON.stringify({
30507
+ query: PRICE_QUERY(200, 200, chainId)
30508
+ })
30509
+ }).then((r) => r.json())
30510
+ ] : [
30511
+ fetch(MORPHO_GRAPHQL_URL, {
30512
+ method: "POST",
30513
+ headers: { "Content-Type": "application/json" },
30514
+ body: JSON.stringify({
30515
+ query: PRICE_QUERY(200, 0, chainId)
30516
+ })
30517
+ }).then((r) => r.json())
30518
+ ];
30519
+ const results = await Promise.all(pages);
30520
+ const allMarkets = [];
30521
+ for (const result of results) {
30522
+ const items = result?.data?.markets?.items;
30523
+ if (!Array.isArray(items)) return null;
30524
+ allMarkets.push(...items);
30525
+ }
30526
+ if (allMarkets.length === 0) return null;
30527
+ const entries = [];
30528
+ for (const market of allMarkets) {
30529
+ if (!market.collateralAsset) continue;
30530
+ const oracle = market.oracleAddress;
30531
+ const loanAsset = market.loanAsset.address.toLowerCase();
30532
+ const collateralAsset = market.collateralAsset.address.toLowerCase();
30533
+ const marketId = market.uniqueKey?.replace(/^0x/i, "").toUpperCase() ?? generateMarketId(oracle, loanAsset, collateralAsset);
30534
+ const lenderKey = generateMorphoLenderKey(marketId);
30535
+ const loanPriceUSD = market.loanAsset.priceUsd;
30536
+ const collateralPriceUSD = market.collateralAsset.priceUsd;
30537
+ const statePrice = market.state?.price;
30538
+ const oracleRatio = statePrice != null ? formatMorphoPrice(
30539
+ statePrice,
30540
+ market.loanAsset.decimals,
30541
+ market.collateralAsset.decimals
30542
+ ) : 0;
30543
+ if (collateralPriceUSD != null && collateralPriceUSD > 0) {
30544
+ entries.push({
30545
+ asset: collateralAsset,
30546
+ price: oracleRatio || collateralPriceUSD,
30547
+ priceUSD: collateralPriceUSD,
30548
+ marketUid: createMarketUid(chainId, lenderKey, collateralAsset),
30549
+ targetLender: lenderKey
30550
+ });
30551
+ }
30552
+ if (loanPriceUSD != null && loanPriceUSD > 0) {
30553
+ entries.push({
30554
+ asset: loanAsset,
30555
+ price: oracleRatio > 0 ? 1 / oracleRatio : loanPriceUSD,
30556
+ priceUSD: loanPriceUSD,
30557
+ marketUid: createMarketUid(chainId, lenderKey, loanAsset),
30558
+ targetLender: lenderKey
30559
+ });
30560
+ }
30561
+ }
30562
+ return entries.length > 0 ? entries : null;
30563
+ } catch {
30564
+ return null;
30565
+ }
30566
+ }
30454
30567
  var morphoFetcher = {
30455
30568
  getCalls: getMorphoCalls2,
30456
30569
  parse: parseMorphoResults2,
@@ -30801,162 +30914,447 @@ var eulerV2Fetcher = {
30801
30914
  };
30802
30915
 
30803
30916
  // src/prices/oracle-prices/fetchOraclePrices.ts
30804
- async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3, batchSize = void 0, allowFailure = true, basePrices = {}, morphoMarketOverrides, listaMarketOverrides) {
30917
+ function countFailures(data, offset, count) {
30918
+ let failures = 0;
30919
+ for (let i = offset; i < offset + count; i++) {
30920
+ if (data[i] === "0x" || data[i] === void 0) failures++;
30921
+ }
30922
+ return failures;
30923
+ }
30924
+ function safeGetCalls(fetcherName, fn, errors) {
30925
+ try {
30926
+ return fn();
30927
+ } catch (e) {
30928
+ errors[fetcherName] = e instanceof Error ? e.message : String(e);
30929
+ return [];
30930
+ }
30931
+ }
30932
+ function buildGroup(fetcherName, results, parse, abi) {
30933
+ const group = {
30934
+ fetcherName,
30935
+ calls: [],
30936
+ abi,
30937
+ trackers: []
30938
+ };
30939
+ for (const fr of results) {
30940
+ group.trackers.push({
30941
+ lender: fr.lender,
30942
+ meta: fr.meta,
30943
+ offset: group.calls.length,
30944
+ count: fr.calls.length,
30945
+ parse
30946
+ });
30947
+ group.calls.push(...fr.calls);
30948
+ }
30949
+ return group;
30950
+ }
30951
+ function isFailed(r) {
30952
+ return r === "0x" || r === void 0;
30953
+ }
30954
+ async function executeGroup(group, chainId, chainBatchSize, retries, allowFailure, rpcOverrides, failRetries = 2) {
30955
+ if (group.calls.length === 0) {
30956
+ return { results: [] };
30957
+ }
30958
+ try {
30959
+ const results = await multicallRetryUniversal({
30960
+ chain: chainId,
30961
+ calls: group.calls,
30962
+ abi: group.abi,
30963
+ batchSize: chainBatchSize,
30964
+ maxRetries: retries,
30965
+ providerId: void 0,
30966
+ allowFailure,
30967
+ overrdies: rpcOverrides,
30968
+ logErrors: true
30969
+ });
30970
+ let failedIndices = results.map((r, i) => isFailed(r) ? i : -1).filter((i) => i >= 0);
30971
+ for (let round = 0; round < failRetries && failedIndices.length > 0; round++) {
30972
+ const retryCalls = failedIndices.map((i) => group.calls[i]);
30973
+ try {
30974
+ const retryResults = await multicallRetryUniversal({
30975
+ chain: chainId,
30976
+ calls: retryCalls,
30977
+ abi: group.abi,
30978
+ batchSize: chainBatchSize,
30979
+ maxRetries: retries,
30980
+ providerId: round + 1,
30981
+ // rotate to next RPC provider
30982
+ allowFailure,
30983
+ overrdies: rpcOverrides,
30984
+ logErrors: true
30985
+ });
30986
+ const stillFailed = [];
30987
+ for (let j = 0; j < failedIndices.length; j++) {
30988
+ if (!isFailed(retryResults[j])) {
30989
+ results[failedIndices[j]] = retryResults[j];
30990
+ } else {
30991
+ stillFailed.push(failedIndices[j]);
30992
+ }
30993
+ }
30994
+ failedIndices = stillFailed;
30995
+ } catch {
30996
+ break;
30997
+ }
30998
+ }
30999
+ const failCount = results.filter((r) => isFailed(r)).length;
31000
+ const allFailed = failCount === results.length && results.length > 0;
31001
+ return {
31002
+ results,
31003
+ error: allFailed ? `All ${group.calls.length} calls returned 0x (${group.fetcherName})` : void 0
31004
+ };
31005
+ } catch (e) {
31006
+ const msg = e instanceof Error ? e.message : String(e);
31007
+ return {
31008
+ results: Array(group.calls.length).fill("0x"),
31009
+ error: `multicall threw: ${msg.slice(0, 200)}`
31010
+ };
31011
+ }
31012
+ }
31013
+ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3, batchSize = void 0, allowFailure = true, basePrices = {}, morphoMarketOverrides, listaMarketOverrides, stalenessThresholdSeconds = 3600, onlyFetchers) {
31014
+ const totalStart = Date.now();
30805
31015
  const result = {};
30806
- const combinedAbi = [
30807
- ...AaveOracleAbi,
30808
- ...ProxyOracleAbi,
30809
- ...CompoundV2OracleAbi,
30810
- ...ChainlinkAggregatorAbi,
30811
- ...vaultLensAbi
30812
- ];
30813
31016
  const chainPromises = chainIds.map(async (chainId) => {
31017
+ const chainStart = Date.now();
30814
31018
  const chainResult = {};
30815
31019
  const tokenList = lists[chainId] ?? {};
30816
- const aaveResults = aaveFetcher.getCalls(chainId);
30817
- const compoundV2Results = compoundV2Fetcher.getCalls(chainId);
30818
- const compoundV3Results = compoundV3Fetcher.getCalls(chainId);
30819
- const listaResults = listaFetcher.getCalls(chainId, {
30820
- marketOverrides: listaMarketOverrides
30821
- });
30822
- const eulerResults = eulerV2Fetcher.getCalls(chainId);
30823
- const morphoResults = morphoFetcher.getCalls(chainId, {
30824
- marketOverrides: morphoMarketOverrides
30825
- });
30826
- const allCalls = [];
30827
- const fetcherTracker = [];
30828
- for (const fr of aaveResults) {
30829
- fetcherTracker.push({
30830
- lender: fr.lender,
30831
- meta: fr.meta,
30832
- offset: allCalls.length,
30833
- count: fr.calls.length,
30834
- parse: aaveFetcher.parse
30835
- });
30836
- allCalls.push(...fr.calls);
30837
- }
30838
- for (const fr of compoundV2Results) {
30839
- fetcherTracker.push({
30840
- lender: fr.lender,
30841
- meta: fr.meta,
30842
- offset: allCalls.length,
30843
- count: fr.calls.length,
30844
- parse: compoundV2Fetcher.parse
30845
- });
30846
- allCalls.push(...fr.calls);
30847
- }
30848
- for (const fr of compoundV3Results) {
30849
- fetcherTracker.push({
30850
- lender: fr.lender,
30851
- meta: fr.meta,
30852
- offset: allCalls.length,
30853
- count: fr.calls.length,
30854
- parse: compoundV3Fetcher.parse
30855
- });
30856
- allCalls.push(...fr.calls);
30857
- }
30858
- for (const fr of listaResults) {
30859
- fetcherTracker.push({
30860
- lender: fr.lender,
30861
- meta: fr.meta,
30862
- offset: allCalls.length,
30863
- count: fr.calls.length,
30864
- parse: listaFetcher.parse
30865
- });
30866
- allCalls.push(...fr.calls);
30867
- }
30868
- for (const fr of eulerResults) {
30869
- fetcherTracker.push({
30870
- lender: fr.lender,
30871
- meta: fr.meta,
30872
- offset: allCalls.length,
30873
- count: fr.calls.length,
30874
- parse: eulerV2Fetcher.parse
30875
- });
30876
- allCalls.push(...fr.calls);
30877
- }
30878
- for (const fr of morphoResults) {
30879
- fetcherTracker.push({
30880
- lender: fr.lender,
30881
- meta: fr.meta,
30882
- offset: allCalls.length,
30883
- count: fr.calls.length,
30884
- parse: morphoFetcher.parse
30885
- });
30886
- allCalls.push(...fr.calls);
30887
- }
30888
- if (allCalls.length === 0) {
30889
- return { chainId, data: chainResult };
31020
+ const getCallsErrors = {};
31021
+ const trackerDiags = [];
31022
+ const unresolvedMorphoMarkets = [];
31023
+ const staleFeeds = [];
31024
+ const multicallErrors = [];
31025
+ const active = onlyFetchers ? new Set(onlyFetchers.map((f) => f.toLowerCase())) : null;
31026
+ const isActive = (name) => !active || active.has(name);
31027
+ const aaveResults = isActive("aave") ? safeGetCalls(
31028
+ "aave",
31029
+ () => aaveFetcher.getCalls(chainId),
31030
+ getCallsErrors
31031
+ ) : [];
31032
+ const compoundV2Results = isActive("compoundv2") ? safeGetCalls(
31033
+ "compoundV2",
31034
+ () => compoundV2Fetcher.getCalls(chainId),
31035
+ getCallsErrors
31036
+ ) : [];
31037
+ const compoundV3Results = isActive("compoundv3") ? safeGetCalls(
31038
+ "compoundV3",
31039
+ () => compoundV3Fetcher.getCalls(chainId),
31040
+ getCallsErrors
31041
+ ) : [];
31042
+ const listaResults = isActive("lista") ? safeGetCalls(
31043
+ "lista",
31044
+ () => listaFetcher.getCalls(chainId, {
31045
+ marketOverrides: listaMarketOverrides
31046
+ }),
31047
+ getCallsErrors
31048
+ ) : [];
31049
+ const eulerResults = isActive("eulerv2") ? safeGetCalls(
31050
+ "eulerV2",
31051
+ () => eulerV2Fetcher.getCalls(chainId),
31052
+ getCallsErrors
31053
+ ) : [];
31054
+ const morphoResults = isActive("morpho") ? safeGetCalls(
31055
+ "morpho",
31056
+ () => morphoFetcher.getCalls(chainId, {
31057
+ marketOverrides: morphoMarketOverrides
31058
+ }),
31059
+ getCallsErrors
31060
+ ) : [];
31061
+ const aaveGroup = buildGroup(
31062
+ "aave",
31063
+ aaveResults,
31064
+ aaveFetcher.parse,
31065
+ AaveOracleAbi
31066
+ );
31067
+ const compoundV2Group = buildGroup(
31068
+ "compoundV2",
31069
+ compoundV2Results,
31070
+ compoundV2Fetcher.parse,
31071
+ CompoundV2OracleAbi
31072
+ );
31073
+ const compoundV3Group = buildGroup(
31074
+ "compoundV3",
31075
+ compoundV3Results,
31076
+ compoundV3Fetcher.parse,
31077
+ ChainlinkAggregatorAbi
31078
+ );
31079
+ const listaGroup = buildGroup(
31080
+ "lista",
31081
+ listaResults,
31082
+ listaFetcher.parse,
31083
+ ProxyOracleAbi
31084
+ );
31085
+ const eulerGroup = buildGroup(
31086
+ "eulerV2",
31087
+ eulerResults,
31088
+ eulerV2Fetcher.parse,
31089
+ vaultLensAbi
31090
+ );
31091
+ const morphoGroup = buildGroup(
31092
+ "morpho",
31093
+ morphoResults,
31094
+ morphoFetcher.parse,
31095
+ ProxyOracleAbi
31096
+ );
31097
+ const allGroups = [
31098
+ aaveGroup,
31099
+ compoundV2Group,
31100
+ compoundV3Group,
31101
+ listaGroup,
31102
+ eulerGroup,
31103
+ morphoGroup
31104
+ ];
31105
+ const totalCalls = allGroups.reduce((s, g) => s + g.calls.length, 0);
31106
+ if (totalCalls === 0) {
31107
+ const diag2 = {
31108
+ chainId,
31109
+ totalCalls: 0,
31110
+ totalFailedCalls: 0,
31111
+ totalParsedEntries: 0,
31112
+ durationMs: Date.now() - chainStart,
31113
+ trackers: [],
31114
+ getCallsErrors,
31115
+ unresolvedMorphoMarkets: [],
31116
+ staleFeeds: []
31117
+ };
31118
+ return { chainId, data: chainResult, diagnostic: diag2 };
30890
31119
  }
30891
- const multicallResult = await multicallRetry(
31120
+ const chainBatchSize = batchSize?.[chainId];
31121
+ const morphoGqlPromise = isActive("morpho") ? fetchMorphoGraphQLPrices(chainId) : Promise.resolve(null);
31122
+ const [
31123
+ aaveData,
31124
+ compoundV2Data,
31125
+ compoundV3Data,
31126
+ listaData,
31127
+ eulerData,
31128
+ morphoGqlEntries
31129
+ ] = await Promise.all([
31130
+ executeGroup(
31131
+ aaveGroup,
31132
+ chainId,
31133
+ chainBatchSize,
31134
+ retries,
31135
+ allowFailure,
31136
+ rpcOverrides
31137
+ ),
31138
+ executeGroup(
31139
+ compoundV2Group,
31140
+ chainId,
31141
+ chainBatchSize,
31142
+ retries,
31143
+ allowFailure,
31144
+ rpcOverrides
31145
+ ),
31146
+ executeGroup(
31147
+ compoundV3Group,
31148
+ chainId,
31149
+ chainBatchSize,
31150
+ retries,
31151
+ allowFailure,
31152
+ rpcOverrides
31153
+ ),
31154
+ executeGroup(
31155
+ listaGroup,
31156
+ chainId,
31157
+ chainBatchSize,
31158
+ retries,
31159
+ allowFailure,
31160
+ rpcOverrides
31161
+ ),
31162
+ executeGroup(
31163
+ eulerGroup,
31164
+ chainId,
31165
+ chainBatchSize,
31166
+ retries,
31167
+ allowFailure,
31168
+ rpcOverrides
31169
+ ),
31170
+ morphoGqlPromise
31171
+ ]);
31172
+ const morphoData = morphoGqlEntries != null ? { results: [], error: void 0 } : await executeGroup(
31173
+ morphoGroup,
30892
31174
  chainId,
30893
- allCalls,
30894
- combinedAbi,
30895
- batchSize,
31175
+ chainBatchSize,
30896
31176
  retries,
30897
- 0,
30898
31177
  allowFailure,
30899
31178
  rpcOverrides
30900
31179
  );
31180
+ const useMorphoGql = morphoGqlEntries != null;
31181
+ const groupResults = [
31182
+ { group: aaveGroup, data: aaveData },
31183
+ { group: compoundV2Group, data: compoundV2Data },
31184
+ { group: compoundV3Group, data: compoundV3Data },
31185
+ { group: listaGroup, data: listaData },
31186
+ { group: eulerGroup, data: eulerData },
31187
+ ...useMorphoGql ? [] : [{ group: morphoGroup, data: morphoData }]
31188
+ ];
31189
+ for (const { group, data } of groupResults) {
31190
+ if (data.error) {
31191
+ multicallErrors.push(`[${group.fetcherName}] ${data.error}`);
31192
+ }
31193
+ }
30901
31194
  const usdPrices = { ...basePrices };
30902
- const parseTracker = (tracker, updatePrices = true) => {
30903
- const dataSlice = multicallResult.slice(
30904
- tracker.offset,
30905
- tracker.offset + tracker.count
30906
- );
30907
- const context = {
30908
- chainId,
30909
- usdPrices,
30910
- tokenList
30911
- };
30912
- const entries = tracker.parse(dataSlice, tracker.meta, context);
30913
- for (const entry of entries) {
30914
- const lender = entry.targetLender ?? tracker.lender;
30915
- if (!chainResult[lender]) {
30916
- chainResult[lender] = [];
30917
- }
30918
- chainResult[lender].push(entry);
30919
- if (updatePrices) {
30920
- const oracleKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset}`;
30921
- usdPrices[oracleKey] = entry.priceUSD;
30922
- usdPrices[entry.asset] = entry.priceUSD;
31195
+ const parseTrackers = (group, data, updatePrices = true, filter) => {
31196
+ const trackers = filter ? group.trackers.filter(filter) : group.trackers;
31197
+ for (const tracker of trackers) {
31198
+ const failedCalls = countFailures(data, tracker.offset, tracker.count);
31199
+ const diag2 = {
31200
+ lender: tracker.lender,
31201
+ callCount: tracker.count,
31202
+ failedCalls,
31203
+ parsedEntries: 0
31204
+ };
31205
+ try {
31206
+ const dataSlice = data.slice(
31207
+ tracker.offset,
31208
+ tracker.offset + tracker.count
31209
+ );
31210
+ const context = { chainId, usdPrices, tokenList };
31211
+ const entries = tracker.parse(dataSlice, tracker.meta, context);
31212
+ diag2.parsedEntries = entries.length;
31213
+ for (const entry of entries) {
31214
+ const lender = entry.targetLender ?? tracker.lender;
31215
+ if (!chainResult[lender]) {
31216
+ chainResult[lender] = [];
31217
+ }
31218
+ chainResult[lender].push(entry);
31219
+ if (updatePrices) {
31220
+ const oracleKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset}`;
31221
+ usdPrices[oracleKey] = entry.priceUSD;
31222
+ usdPrices[entry.asset] = entry.priceUSD;
31223
+ }
31224
+ }
31225
+ } catch (e) {
31226
+ diag2.parseError = e instanceof Error ? e.message : String(e);
30923
31227
  }
31228
+ trackerDiags.push(diag2);
30924
31229
  }
30925
31230
  };
30926
- const nonMorphoTrackers = fetcherTracker.filter(
30927
- (t) => t.parse !== morphoFetcher.parse
30928
- );
30929
- const aaveSourceTrackers = nonMorphoTrackers.filter(
30930
- (t) => t.parse === aaveFetcher.parse && !t.meta.baseAssetSource
30931
- );
30932
- const aaveDependentTrackers = nonMorphoTrackers.filter(
30933
- (t) => t.parse === aaveFetcher.parse && t.meta.baseAssetSource
31231
+ parseTrackers(
31232
+ aaveGroup,
31233
+ aaveData.results,
31234
+ true,
31235
+ (t) => !t.meta.baseAssetSource
30934
31236
  );
30935
- const otherTrackers = nonMorphoTrackers.filter(
30936
- (t) => t.parse !== aaveFetcher.parse
30937
- );
30938
- for (const tracker of aaveSourceTrackers) {
30939
- parseTracker(tracker);
30940
- }
30941
- for (const tracker of otherTrackers) {
30942
- parseTracker(tracker);
30943
- }
30944
- for (const tracker of aaveDependentTrackers) {
30945
- parseTracker(tracker);
31237
+ parseTrackers(compoundV2Group, compoundV2Data.results);
31238
+ parseTrackers(compoundV3Group, compoundV3Data.results);
31239
+ parseTrackers(listaGroup, listaData.results);
31240
+ parseTrackers(eulerGroup, eulerData.results);
31241
+ if (stalenessThresholdSeconds > 0) {
31242
+ const nowSeconds = Math.floor(Date.now() / 1e3);
31243
+ for (const tracker of compoundV3Group.trackers) {
31244
+ const meta = tracker.meta;
31245
+ for (let i = 0; i < tracker.count; i++) {
31246
+ const raw = compoundV3Data.results[tracker.offset + i];
31247
+ if (!raw || raw === "0x" || !Array.isArray(raw)) continue;
31248
+ const updatedAt = Number(raw[3]);
31249
+ if (updatedAt > 0) {
31250
+ const staleSeconds = nowSeconds - updatedAt;
31251
+ if (staleSeconds > stalenessThresholdSeconds) {
31252
+ const queryMeta = meta[i];
31253
+ staleFeeds.push({
31254
+ asset: queryMeta?.asset?.toLowerCase() ?? "unknown",
31255
+ lender: queryMeta?.lender ?? tracker.lender,
31256
+ oracle: queryMeta?.oracle ?? "unknown",
31257
+ staleSeconds
31258
+ });
31259
+ }
31260
+ }
31261
+ }
31262
+ }
30946
31263
  }
30947
- const morphoTrackers = fetcherTracker.filter(
30948
- (t) => t.parse === morphoFetcher.parse
31264
+ parseTrackers(
31265
+ aaveGroup,
31266
+ aaveData.results,
31267
+ true,
31268
+ (t) => !!t.meta.baseAssetSource
30949
31269
  );
30950
- for (const tracker of morphoTrackers) {
30951
- parseTracker(tracker, false);
31270
+ if (useMorphoGql) {
31271
+ const morphoGqlDiag = {
31272
+ lender: "MORPHO_BLUE (GraphQL)",
31273
+ callCount: 0,
31274
+ failedCalls: 0,
31275
+ parsedEntries: morphoGqlEntries.length
31276
+ };
31277
+ for (const entry of morphoGqlEntries) {
31278
+ const lender = entry.targetLender ?? "MORPHO_BLUE";
31279
+ if (!chainResult[lender]) chainResult[lender] = [];
31280
+ chainResult[lender].push(entry);
31281
+ }
31282
+ trackerDiags.push(morphoGqlDiag);
31283
+ } else {
31284
+ for (const tracker of morphoGroup.trackers) {
31285
+ const meta = tracker.meta;
31286
+ if (meta.markets) {
31287
+ for (const market of meta.markets) {
31288
+ const loanAsset = market.loanAsset?.toLowerCase();
31289
+ const collateralAsset = market.collateralAsset?.toLowerCase();
31290
+ const loanOracleKey = tokenList[loanAsset]?.assetGroup ?? `${chainId}-${loanAsset}`;
31291
+ const collateralOracleKey = tokenList[collateralAsset]?.assetGroup ?? `${chainId}-${collateralAsset}`;
31292
+ const hasLoanPrice = usdPrices[loanOracleKey] !== void 0 || usdPrices[loanAsset] !== void 0;
31293
+ const hasCollateralPrice = usdPrices[collateralOracleKey] !== void 0 || usdPrices[collateralAsset] !== void 0;
31294
+ if (!hasLoanPrice && !hasCollateralPrice) {
31295
+ unresolvedMorphoMarkets.push(
31296
+ `${market.oracle}:${loanAsset}/${collateralAsset}`
31297
+ );
31298
+ }
31299
+ }
31300
+ }
31301
+ }
31302
+ parseTrackers(morphoGroup, morphoData.results, false);
30952
31303
  }
30953
- return { chainId, data: chainResult };
31304
+ const totalFailedCalls = trackerDiags.reduce(
31305
+ (sum, d) => sum + d.failedCalls,
31306
+ 0
31307
+ );
31308
+ const totalParsedEntries = trackerDiags.reduce(
31309
+ (sum, d) => sum + d.parsedEntries,
31310
+ 0
31311
+ );
31312
+ const diag = {
31313
+ chainId,
31314
+ totalCalls,
31315
+ totalFailedCalls,
31316
+ totalParsedEntries,
31317
+ durationMs: Date.now() - chainStart,
31318
+ trackers: trackerDiags,
31319
+ getCallsErrors,
31320
+ chainError: multicallErrors.length > 0 ? multicallErrors.join("; ") : void 0,
31321
+ unresolvedMorphoMarkets,
31322
+ staleFeeds
31323
+ };
31324
+ return { chainId, data: chainResult, diagnostic: diag };
30954
31325
  });
30955
- const chainResults = await Promise.all(chainPromises);
30956
- for (const { chainId, data } of chainResults) {
30957
- result[chainId] = data;
31326
+ const settled = await Promise.allSettled(chainPromises);
31327
+ const chainDiagnostics = [];
31328
+ const failedChains = [];
31329
+ for (let i = 0; i < settled.length; i++) {
31330
+ const settlement = settled[i];
31331
+ const chainId = chainIds[i];
31332
+ if (settlement.status === "fulfilled") {
31333
+ const { data, diagnostic } = settlement.value;
31334
+ result[chainId] = data;
31335
+ chainDiagnostics.push(diagnostic);
31336
+ } else {
31337
+ failedChains.push(chainId);
31338
+ chainDiagnostics.push({
31339
+ chainId,
31340
+ totalCalls: 0,
31341
+ totalFailedCalls: 0,
31342
+ totalParsedEntries: 0,
31343
+ durationMs: 0,
31344
+ trackers: [],
31345
+ getCallsErrors: {},
31346
+ chainError: settlement.reason instanceof Error ? settlement.reason.message : String(settlement.reason),
31347
+ unresolvedMorphoMarkets: [],
31348
+ staleFeeds: []
31349
+ });
31350
+ }
30958
31351
  }
30959
- return result;
31352
+ const diagnostics = {
31353
+ chains: chainDiagnostics,
31354
+ totalDurationMs: Date.now() - totalStart,
31355
+ failedChains
31356
+ };
31357
+ return { prices: result, diagnostics };
30960
31358
  }
30961
31359
  var DEFAULT_PRIORITY = {
30962
31360
  chainPriority: [
@@ -31170,7 +31568,7 @@ var FLASHLOAN_ENABLED_MASK = BigInt(
31170
31568
  function getFlashLoanEnabled(data) {
31171
31569
  return (data & ~FLASHLOAN_ENABLED_MASK) !== BigInt(0);
31172
31570
  }
31173
- async function fetchFlashLiquidityForChain(chain, multicallRetry3, list = {}) {
31571
+ async function fetchFlashLiquidityForChain(chain, multicallRetry, list = {}) {
31174
31572
  let callLengths = {};
31175
31573
  let aaveAssets = {};
31176
31574
  let aaveCalls = [];
@@ -31285,15 +31683,15 @@ async function fetchFlashLiquidityForChain(chain, multicallRetry3, list = {}) {
31285
31683
  ...balancerV3Calls,
31286
31684
  ...uniswapV4Calls
31287
31685
  ];
31288
- const rawResults = await multicallRetry3(
31686
+ const rawResults = await multicallRetry({
31289
31687
  chain,
31290
31688
  calls,
31291
- FlashAbi,
31292
- DEFAULT_BATCH_SIZE,
31293
- 3,
31294
- 0,
31295
- false
31296
- );
31689
+ abi: FlashAbi,
31690
+ batchSize: DEFAULT_BATCH_SIZE,
31691
+ maxRetries: 3,
31692
+ providerId: 0,
31693
+ allowFailure: false
31694
+ });
31297
31695
  let liquidity = {};
31298
31696
  let currentOffset = 0;
31299
31697
  aaveProtocols.forEach((aave) => {