@1delta/margin-fetcher 5.0.60 → 5.0.62

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
@@ -1,9 +1,9 @@
1
1
  import { parseAbi, keccak256, encodeAbiParameters, formatEther, BaseError, erc20Abi, stringToHex, isAddress, pad, encodeFunctionData, formatUnits, getAddress, decodeFunctionResult, decodeAbiParameters, concat, parseAbiParameters, AbiEncodingLengthMismatchError, concatHex, toBytes, slice, hexToString, InvalidAddressError, boolToHex, integerRegex, numberToHex, bytesRegex, BytesSizeMismatchError, arrayRegex, UnsupportedPackedAbiType } from './chunk-JUYF2XLF.js';
2
2
  import './chunk-BYTNVMX7.js';
3
3
  import './chunk-PR4QN5HX.js';
4
- import { Lender, isExactly, isMidnight, isTerm, isTermMax, isTeller, isListaDao, isLiquityFamily, isRiver, isInverse, isCooler, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, isTwyne, isFraxlend, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, isMorphoType, isUsdd, isSky, hasCrossMarginRisk, isEulerType, isAaveV4Type, isInit, isCompoundV2Type, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isMorphoBlue, isAaveV2Type, isAaveV32Type, isAaveV3Type, isYLDR, isLista, hasSubAccounts, isTectonicType, isKineticType, isBenqiType } from '@1delta/lender-registry';
4
+ import { Lender, isExactly, isMidnight, isTerm, isTermMax, isTeller, isListaDao, isLiquityFamily, isRiver, isInverse, isCooler, isDssType, isCompoundV3Type, isFluid, isGearboxV3, isLlamaLend, isFrankencoin, isResupply, isCurvance, isTwyne, isFraxlend, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isCompoundV2Type, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, isMorphoType, isUsdd, isSky, hasCrossMarginRisk, isEulerType, isAaveV4Type, isInit, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isMorphoBlue, isAaveV2Type, isAaveV32Type, isAaveV3Type, isYLDR, isLista, hasSubAccounts, isTectonicType, isKineticType, isBenqiType } from '@1delta/lender-registry';
5
5
  export { hasCrossMarginRisk, isAaveType, isAaveV2Type, isAaveV32Type, isAaveV3Type, isCompoundV3, isCompoundV3Type, isInit, isMorphoType, isMultiMarket, isYLDR } from '@1delta/lender-registry';
6
- import { fetchTokenLists, fetchTokenList, aavePools, compoundV3Pools, initConfig, morphoPools, compoundV2Pools, eulerVaults, siloMarkets, siloV2LenderKey, siloMarketsV3, siloV3LenderKey, aaveV4Spokes, aaveV4SpokeLenderKey, fluidResolvers, gearboxResolvers, dolomiteConfigs, midnightConfig, termConfig, termMarketsByChain, exactlyConfig, liquityLendersByChain, riverLendersByChain, inverseLendersByChain, coolerLendersByChain, llamaLendLendersByChain, usddLendersByChain, skyLendersByChain, frankencoinLendersByChain, resupplyLendersByChain, curvanceLendersByChain, fraxlendLendersByChain, twyneLendersByChain, tellerConfigByChain, tellerPoolsByChain, termMaxConfigByChain, aaveReserves, compoundV3Reserves, resolveTermApiBase, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, termMaxApiBaseUrl, termMaxLenderKey, inverseConfigFor, inverseChainData, coolerConfigFor, llamaLendConfigFor, llamaLendChainData, llamaLendApiBaseUrl, resupplyConfigFor, fraxlendConfigFor, dssConfigFor, dssChainData, dssDebtToken, dssDebtJoin, frankencoinConfigFor, frankencoinChainData, aaveOracles, morphoTypeMarkets, resolveMidnightApiBase, llamaLendMarketByVault, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, curvanceConfigFor, aaveTokens, morphoTypeVaults, listaCollateralProvider, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxV3LenderKey, midnightMarketsByChain, twyneConfigFor, twyneChainData, parseAaveV4SpokeLenderKey, fraxlendPairsFor, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2TokenArray, compoundV2OraclesConfig, compoundV3OraclesData, compoundV3BaseData, compoundV2Reserves, aaveV4Oracles, morphoTypeOracles } from '@1delta/data-sdk';
6
+ import { fetchTokenLists, fetchTokenList, aavePools, compoundV3Pools, initConfig, morphoPools, compoundV2Pools, eulerVaults, siloMarkets, siloV2LenderKey, siloMarketsV3, siloV3LenderKey, aaveV4Spokes, aaveV4SpokeLenderKey, fluidResolvers, gearboxResolvers, dolomiteConfigs, midnightConfig, termConfig, termMarketsByChain, exactlyConfig, liquityLendersByChain, riverLendersByChain, inverseLendersByChain, coolerLendersByChain, llamaLendLendersByChain, usddLendersByChain, skyLendersByChain, frankencoinLendersByChain, resupplyLendersByChain, curvanceLendersByChain, fraxlendLendersByChain, twyneLendersByChain, tellerConfigByChain, tellerPoolsByChain, termMaxConfigByChain, aaveReserves, compoundV3Reserves, resolveTermApiBase, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, termMaxApiBaseUrl, termMaxLenderKey, inverseConfigFor, inverseChainData, coolerConfigFor, llamaLendConfigFor, llamaLendChainData, llamaLendApiBaseUrl, resupplyConfigFor, fraxlendConfigFor, dssConfigFor, dssChainData, dssDebtToken, dssDebtJoin, frankencoinConfigFor, frankencoinChainData, aaveOracles, morphoTypeMarkets, resolveMidnightApiBase, llamaLendMarketByVault, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, curvanceConfigFor, aaveTokens, morphoTypeVaults, listaCollateralProvider, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, compoundV2TokenArray, gearboxV3LenderKey, midnightMarketsByChain, twyneConfigFor, twyneChainData, parseAaveV4SpokeLenderKey, fraxlendPairsFor, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2OraclesConfig, compoundV3OraclesData, compoundV3BaseData, compoundV2Reserves, aaveV4Oracles, morphoTypeOracles } from '@1delta/data-sdk';
7
7
  import lodash from 'lodash';
8
8
  import { Chain } from '@1delta/chain-registry';
9
9
  import { multicallRetryUniversal, getEvmClient, getEvmChain, getEvmClientUniversal } from '@1delta/providers';
@@ -6325,10 +6325,45 @@ var ENABLED_COMPOUNDS = [
6325
6325
  Lender.SEGMENT,
6326
6326
  Lender.COMPOUND_V2,
6327
6327
  Lender.FLUX_FINANCE,
6328
- Lender.CAPY_FI
6328
+ Lender.CAPY_FI,
6329
+ // Long-tail forks read through a shared CompoundLens on their chain
6330
+ // (addresses/compoundV2.ts). Enabled only where a lens exists AND the
6331
+ // markets are open; the rest of the `lender-metadata` long tail stays off
6332
+ // this list — see the table in
6333
+ // `lending/public-data/compound-v2/README.md`.
6334
+ Lender.DEMETER,
6335
+ Lender.LANDER,
6336
+ Lender.FILDA,
6337
+ Lender.SOLIDLIZARD,
6338
+ // Reachable since the CompoundV2MarketLens deployment on Optimism, Linea and
6339
+ // Base (2026-08-24). Xpert is deliberately NOT here: 4 of its 6 Base markets
6340
+ // revert their own `exchangeRateStored`, so the lens reads them as zero and
6341
+ // serving them would publish a market with no exchange rate.
6342
+ Lender.IRON_BANK,
6343
+ Lender.MENDI,
6344
+ Lender.PAXO,
6345
+ Lender.SONNE,
6346
+ Lender.ASO_FINANCE,
6347
+ Lender.BLUME,
6348
+ Lender.KAWA,
6349
+ Lender.XPERT,
6350
+ // Manta and zkSync Era joined the lens rollout. KEOM_STONE is deliberately
6351
+ // absent: 1 of its 2 markets (kSTONE) exposes no exchange-rate getter at all,
6352
+ // so half the pool would publish with `exchangeRate = 0`.
6353
+ Lender.KEOM,
6354
+ Lender.REACTOR_FUSION
6329
6355
  ];
6330
6356
  var DISABLED_COMPOUNDS = {
6331
- [Chain.ETHEREUM_MAINNET]: [Lender.CREAM_FINANCE]
6357
+ [Chain.ETHEREUM_MAINNET]: [Lender.CREAM_FINANCE],
6358
+ // FilDA's IoTeX deployment: no lens on that chain, and all 9 markets are
6359
+ // mint+borrow paused with `seizeGuardianPaused` set globally. Its BNB
6360
+ // deployment is open and stays enabled.
6361
+ [Chain.IOTEX_NETWORK_MAINNET]: [Lender.FILDA],
6362
+ // Xpert on Base: 4 of its 6 markets revert their OWN `exchangeRateStored`
6363
+ // (checked against two independent RPCs), so any lens reads them as zero and
6364
+ // serving them would publish markets with no exchange rate. Its Ink
6365
+ // deployment reads 5/5 clean and stays enabled.
6366
+ [Chain.BASE]: [Lender.XPERT]
6332
6367
  };
6333
6368
  var isExcludedLender = (lender) => {
6334
6369
  if (lender === Lender.PLOUTOS) return true;
@@ -7068,18 +7103,15 @@ var formatAaveYieldToNumber = (n) => {
7068
7103
  if (!n) return 0;
7069
7104
  return Number(formatEther(BigInt(n) / BigInt(1e7)));
7070
7105
  };
7071
- var calculateRateForCompoundType2 = (n) => {
7106
+ var calculateRateForCompoundType2 = (n, unitSeconds) => {
7072
7107
  const rate = Number(formatEther(BigInt(n)));
7073
- return (Math.pow(rate * 60 * 60 * 24 / 12 + 1, 365) - 1) * 100;
7108
+ const perUnit = unitSeconds && unitSeconds > 0 ? unitSeconds : 12;
7109
+ return (Math.pow(rate * 60 * 60 * 24 / perUnit + 1, 365) - 1) * 100;
7074
7110
  };
7075
- var calculateRateForCompoundType = (n, chainId, scale3 = 1 /* SECOND */) => {
7111
+ var calculateRateForCompoundType = (n, chainId, scale3 = 1 /* SECOND */, unitSeconds) => {
7076
7112
  const rate = Number(formatEther(BigInt(n)));
7077
- if (scale3 === 0 /* BLOCK */)
7078
- return (Math.pow(
7079
- rate * 60 * 60 * 24 / (BLOCK_TIMES[chainId] ?? "1") + 1,
7080
- 365
7081
- ) - 1) * 100;
7082
- return (Math.pow(rate * 60 * 60 * 24 + 1, 365) - 1) * 100;
7113
+ const perUnit = unitSeconds && unitSeconds > 0 ? unitSeconds : scale3 === 0 /* BLOCK */ ? Number(BLOCK_TIMES[chainId] ?? 1) : 1;
7114
+ return (Math.pow(rate * 60 * 60 * 24 / perUnit + 1, 365) - 1) * 100;
7083
7115
  };
7084
7116
  var formatAaveRawApyToApr = (raw) => {
7085
7117
  const apy = formatAaveYieldToNumber(raw);
@@ -12821,7 +12853,8 @@ var SUMER_LENS = {
12821
12853
  };
12822
12854
  var MOONWELL_LENS = {
12823
12855
  [Chain.OP_MAINNET]: "0xD6C66868f937f00604d0FB860241970D6CC2CBfE",
12824
- [Chain.BASE]: "0x6834770aba6c2028f448e3259ddee4bcb879d459"
12856
+ [Chain.BASE]: "0x6834770aba6c2028f448e3259ddee4bcb879d459",
12857
+ [Chain.ETHEREUM_MAINNET]: "0x2d85b9c48a8c582f0AA244e134e9C6f30Cf7786e"
12825
12858
  };
12826
12859
  var ENCLABS_LENS = {
12827
12860
  [Chain.SONIC_MAINNET]: "0x3567B16050cB90236997eF47B1941502e85d65f3",
@@ -12868,15 +12901,45 @@ var SEGMENT_LENS = {
12868
12901
  var ROBUST_LENS = {
12869
12902
  [Chain.ETHEREUM_MAINNET]: "0x92ee472A52A79AB407aED9FE0deB512d230baF87"
12870
12903
  };
12904
+ var COMPOUND_V2_MARKET_LENS = "0xD16EC79B110f27AA2EEEc913087823Df032121E4";
12905
+ var MARKET_LENS = {
12906
+ [Chain.OP_MAINNET]: COMPOUND_V2_MARKET_LENS,
12907
+ [Chain.XDC_NETWORK]: COMPOUND_V2_MARKET_LENS,
12908
+ [Chain.SEI_NETWORK]: COMPOUND_V2_MARKET_LENS,
12909
+ [Chain.MORPH]: COMPOUND_V2_MARKET_LENS,
12910
+ [Chain.BASE]: COMPOUND_V2_MARKET_LENS,
12911
+ [Chain.AVALANCHE_C_CHAIN]: COMPOUND_V2_MARKET_LENS,
12912
+ [Chain.INK]: COMPOUND_V2_MARKET_LENS,
12913
+ [Chain.LINEA]: COMPOUND_V2_MARKET_LENS,
12914
+ [Chain.BLAST]: COMPOUND_V2_MARKET_LENS,
12915
+ [Chain.MANTA_PACIFIC_MAINNET]: COMPOUND_V2_MARKET_LENS,
12916
+ /**
12917
+ * zkSync Era is the one chain where the address differs. zk-stack chains
12918
+ * derive contract addresses from a registered bytecode hash rather than
12919
+ * `keccak(0xff ‖ factory ‖ salt ‖ initCodeHash)`, so the CREATE2 factory path
12920
+ * is skipped there (see the deploy script) and this is the nonce-derived
12921
+ * address of the same runtime — byte-identical to the other nine, verified
12922
+ * against the compiled artifact.
12923
+ */
12924
+ [Chain.ZKSYNC_MAINNET]: "0x6Bc6aCB905c1216B0119C87Bf9E178ce298310FA"
12925
+ };
12871
12926
  var CREAM_LENS = {
12872
12927
  [Chain.ETHEREUM_MAINNET]: "0x92ee472A52A79AB407aED9FE0deB512d230baF87",
12873
12928
  [Chain.BNB_SMART_CHAIN_MAINNET]: "0x1A014Ffe0cd187A298a7E79BA5ab05538686ea4a",
12874
12929
  [Chain.POLYGON_MAINNET]: "0x139Dd8Bb6355d20342e08ff013150b1aE5040a42",
12875
- [Chain.ARBITRUM_ONE]: "0x139Dd8Bb6355d20342e08ff013150b1aE5040a42"
12930
+ [Chain.ARBITRUM_ONE]: "0x139Dd8Bb6355d20342e08ff013150b1aE5040a42",
12931
+ // Cream's Base deployment has no lens of its own; ours serves it.
12932
+ [Chain.BASE]: COMPOUND_V2_MARKET_LENS
12876
12933
  };
12877
12934
  var GAMMA_LENS = {
12878
12935
  [Chain.BNB_SMART_CHAIN_MAINNET]: "0xcaf6856f6Ec1B66EE89dD296D2020dfA431D8f6B"
12879
12936
  };
12937
+ var SHARED_LENS_BNB = {
12938
+ [Chain.BNB_SMART_CHAIN_MAINNET]: "0x560dD9b47d40E0cd0aEDA326e46BeD25249d936A"
12939
+ };
12940
+ var SHARED_LENS_ARBITRUM = {
12941
+ [Chain.ARBITRUM_ONE]: "0x14Ec7324753340Bd8685496da14c4B173ac05b18"
12942
+ };
12880
12943
  var COMPOUND_V2_LENS = {
12881
12944
  [Lender.VENUS]: VENUS_LENS,
12882
12945
  [Lender.VENUS_ETH]: VENUS_LENS,
@@ -12901,7 +12964,25 @@ var COMPOUND_V2_LENS = {
12901
12964
  [Lender.SEGMENT]: SEGMENT_LENS,
12902
12965
  [Lender.CREAM_FINANCE]: CREAM_LENS,
12903
12966
  [Lender.GAMMA]: GAMMA_LENS,
12904
- [Lender.CAPY_FI]: ROBUST_LENS
12967
+ [Lender.CAPY_FI]: ROBUST_LENS,
12968
+ [Lender.DEMETER]: SHARED_LENS_BNB,
12969
+ [Lender.LANDER]: SHARED_LENS_BNB,
12970
+ // FilDA also has an IoTeX deployment; it is NOT wired here (no lens on that
12971
+ // chain, and all 9 of its IoTeX markets are mint+borrow paused) and is held
12972
+ // back by `DISABLED_COMPOUNDS` in `utils/index.ts`.
12973
+ [Lender.FILDA]: SHARED_LENS_BNB,
12974
+ [Lender.SOLIDLIZARD]: SHARED_LENS_ARBITRUM,
12975
+ // Served by our own CompoundV2MarketLens deployment.
12976
+ [Lender.IRON_BANK]: MARKET_LENS,
12977
+ [Lender.MENDI]: MARKET_LENS,
12978
+ [Lender.PAXO]: MARKET_LENS,
12979
+ [Lender.SONNE]: MARKET_LENS,
12980
+ [Lender.ASO_FINANCE]: MARKET_LENS,
12981
+ [Lender.BLUME]: MARKET_LENS,
12982
+ [Lender.KAWA]: MARKET_LENS,
12983
+ [Lender.XPERT]: MARKET_LENS,
12984
+ [Lender.KEOM]: MARKET_LENS,
12985
+ [Lender.REACTOR_FUSION]: MARKET_LENS
12905
12986
  };
12906
12987
  function getCompoundV2Comptroller(chainId, lender = Lender.VENUS) {
12907
12988
  return compoundV2Pools()?.[lender]?.[chainId];
@@ -15028,7 +15109,24 @@ var COMPTROLLER_PAUSE_READ_LENDERS = [
15028
15109
  Lender.GAMMA,
15029
15110
  Lender.CAPY_FI,
15030
15111
  Lender.LODESTAR,
15031
- Lender.TENDER
15112
+ Lender.TENDER,
15113
+ // Long-tail forks on the shared lenses — same plain `cTokenMetadata`, same
15114
+ // missing pause field. Their Comptrollers DO answer both guardian getters
15115
+ // (verified 2026-08-24), so the live read resolves every market.
15116
+ Lender.DEMETER,
15117
+ Lender.LANDER,
15118
+ Lender.FILDA,
15119
+ Lender.SOLIDLIZARD,
15120
+ Lender.IRON_BANK,
15121
+ Lender.MENDI,
15122
+ Lender.PAXO,
15123
+ Lender.SONNE,
15124
+ Lender.ASO_FINANCE,
15125
+ Lender.BLUME,
15126
+ Lender.KAWA,
15127
+ Lender.XPERT,
15128
+ Lender.KEOM,
15129
+ Lender.REACTOR_FUSION
15032
15130
  ];
15033
15131
  var usesComptrollerPauseReads = (lender) => COMPTROLLER_PAUSE_READ_LENDERS.includes(lender);
15034
15132
  var parsePausedFlag = (raw) => typeof raw === "boolean" ? raw : void 0;
@@ -15041,6 +15139,7 @@ var resolveMarketPause = (token, live) => {
15041
15139
 
15042
15140
  // src/lending/public-data/compound-v2/publicCallBuild.ts
15043
15141
  var buildCompoundV2StyleLenderReserveCall = (chainId, lender) => {
15142
+ if (!getCompoundV2Lens(chainId, lender)) return [];
15044
15143
  if (lender === Lender.TAKARA) {
15045
15144
  const lens = getCompoundV2Lens(chainId, lender);
15046
15145
  return [
@@ -15178,7 +15277,10 @@ function getCall(lender, chainId) {
15178
15277
  params: [tk]
15179
15278
  });
15180
15279
  }
15181
- if (lender === Lender.CREAM_FINANCE || lender === Lender.GAMMA || lender === Lender.TENDER || lender === Lender.COMPOUND_V2 || lender === Lender.CAPY_FI || lender === Lender.FLUX_FINANCE || lender === Lender.WE_PIGGY) {
15280
+ if (lender === Lender.CREAM_FINANCE || lender === Lender.GAMMA || lender === Lender.TENDER || lender === Lender.COMPOUND_V2 || lender === Lender.CAPY_FI || lender === Lender.FLUX_FINANCE || lender === Lender.WE_PIGGY || // long-tail forks served by a shared lens on their chain — see
15281
+ // SHARED_LENS_BNB / SHARED_LENS_ARBITRUM in addresses/compoundV2.ts
15282
+ lender === Lender.DEMETER || lender === Lender.LANDER || lender === Lender.FILDA || lender === Lender.SOLIDLIZARD || // served by our own CompoundV2MarketLens deployment (same 14-field struct)
15283
+ lender === Lender.IRON_BANK || lender === Lender.MENDI || lender === Lender.PAXO || lender === Lender.SONNE || lender === Lender.ASO_FINANCE || lender === Lender.BLUME || lender === Lender.KAWA || lender === Lender.XPERT || lender === Lender.KEOM || lender === Lender.REACTOR_FUSION) {
15182
15284
  return (tk) => ({
15183
15285
  abi: CreamLensAbi,
15184
15286
  address: lens,
@@ -15200,9 +15302,102 @@ function getCall(lender, chainId) {
15200
15302
  params: [tk]
15201
15303
  });
15202
15304
  }
15305
+ var L1_BLOCK_SECONDS = 12;
15306
+ var L1_MERGE_BLOCK = 15537394;
15307
+ var L1_MERGE_TIMESTAMP = 1663224162;
15308
+ var estimateL1Height = (nowSeconds) => L1_MERGE_BLOCK + (nowSeconds - L1_MERGE_TIMESTAMP) / L1_BLOCK_SECONDS;
15309
+ var CADENCE_SPAN = 20000n;
15310
+ var TTL_MS = 24 * 60 * 60 * 1e3;
15311
+ var clockCache = /* @__PURE__ */ new Map();
15312
+ var cadenceCache = /* @__PURE__ */ new Map();
15313
+ var fresh = (e) => !!e && Date.now() - e.at < TTL_MS;
15314
+ function classifyRateClock(accrualBlockNumber, headBlockNumber, headTimestamp) {
15315
+ const v = Number(accrualBlockNumber);
15316
+ if (!Number.isFinite(v) || v <= 0) return void 0;
15317
+ const candidates = [
15318
+ ["timestamp", Number(headTimestamp)],
15319
+ ["block", Number(headBlockNumber)],
15320
+ // The L1 height is not readable from this chain; derive it from the L2
15321
+ // head's timestamp, which is the same wall clock Ethereum runs on.
15322
+ ["l1-block", estimateL1Height(Number(headTimestamp))]
15323
+ ];
15324
+ let best;
15325
+ let bestRatio = Infinity;
15326
+ for (const [kind, expected] of candidates) {
15327
+ if (!Number.isFinite(expected) || expected <= 0) continue;
15328
+ const ratio = v > expected ? v / expected : expected / v;
15329
+ if (ratio < bestRatio) {
15330
+ bestRatio = ratio;
15331
+ best = kind;
15332
+ }
15333
+ }
15334
+ return bestRatio <= 2 ? best : void 0;
15335
+ }
15336
+ async function chainBlockSeconds(chainId) {
15337
+ const hit = cadenceCache.get(chainId);
15338
+ if (fresh(hit)) return hit.value;
15339
+ let value;
15340
+ try {
15341
+ const client = await getEvmClient(chainId);
15342
+ const head = await client.getBlockNumber();
15343
+ const span = head > CADENCE_SPAN ? CADENCE_SPAN : head / 2n;
15344
+ const [b1, b0] = await Promise.all([
15345
+ client.getBlock({ blockNumber: head }),
15346
+ client.getBlock({ blockNumber: head - span })
15347
+ ]);
15348
+ const secs = Number(b1.timestamp - b0.timestamp) / Number(span);
15349
+ if (secs >= 0.05 && secs <= 60) value = secs;
15350
+ } catch {
15351
+ value = void 0;
15352
+ }
15353
+ cadenceCache.set(chainId, { at: Date.now(), value });
15354
+ return value;
15355
+ }
15356
+ async function resolveRateUnitSeconds(chainId, lender) {
15357
+ const key3 = `${chainId}:${lender}`;
15358
+ let clock = clockCache.get(key3);
15359
+ if (!fresh(clock)) {
15360
+ let value;
15361
+ try {
15362
+ const sample = getCompoundV2Tokens(chainId, lender)[0]?.cToken;
15363
+ if (sample) {
15364
+ const client = await getEvmClient(chainId);
15365
+ const head = await client.getBlock();
15366
+ const accrual = await client.readContract({
15367
+ address: sample,
15368
+ abi: [
15369
+ {
15370
+ inputs: [],
15371
+ name: "accrualBlockNumber",
15372
+ outputs: [{ name: "", type: "uint256" }],
15373
+ stateMutability: "view",
15374
+ type: "function"
15375
+ }
15376
+ ],
15377
+ functionName: "accrualBlockNumber"
15378
+ });
15379
+ value = classifyRateClock(accrual, head.number, head.timestamp);
15380
+ }
15381
+ } catch {
15382
+ value = void 0;
15383
+ }
15384
+ clock = { at: Date.now(), value };
15385
+ clockCache.set(key3, clock);
15386
+ }
15387
+ switch (clock.value) {
15388
+ case "timestamp":
15389
+ return 1;
15390
+ case "l1-block":
15391
+ return L1_BLOCK_SECONDS;
15392
+ case "block":
15393
+ return await chainBlockSeconds(chainId);
15394
+ default:
15395
+ return void 0;
15396
+ }
15397
+ }
15203
15398
 
15204
15399
  // src/lending/public-data/compound-v2/getters/venus.ts
15205
- function readVTokenMetadata(meta, token) {
15400
+ function readVTokenMetadata(meta, token, unitSeconds) {
15206
15401
  const pick3 = (...values) => values.find((v) => v !== void 0);
15207
15402
  return {
15208
15403
  vToken: meta.vToken ?? "",
@@ -15238,7 +15433,8 @@ function readVTokenMetadata(meta, token) {
15238
15433
  meta.supplyRatePerBlockOrTimestamp
15239
15434
  )?.toString() ?? "0",
15240
15435
  token.chainId,
15241
- 0 /* BLOCK */
15436
+ 0 /* BLOCK */,
15437
+ unitSeconds
15242
15438
  ) / 100
15243
15439
  ) * 100,
15244
15440
  variableBorrowRate: apyToApr(
@@ -15248,7 +15444,8 @@ function readVTokenMetadata(meta, token) {
15248
15444
  meta.borrowRatePerBlockOrTimestamp
15249
15445
  )?.toString() ?? "0",
15250
15446
  token.chainId,
15251
- 0 /* BLOCK */
15447
+ 0 /* BLOCK */,
15448
+ unitSeconds
15252
15449
  ) / 100
15253
15450
  ) * 100,
15254
15451
  supplyCap: 0,
@@ -15467,20 +15664,24 @@ function parseTectonicMarketData(input) {
15467
15664
  isBoosted: toBool3(field3(input, "isBoosted", 22)),
15468
15665
  baseRatePerBlock: toBigInt3(field3(input, "baseRatePerBlock", 23)),
15469
15666
  multiplierPerBlock: toBigInt3(field3(input, "multiplierPerBlock", 24)),
15470
- jumpMultiplierPerBlock: toBigInt3(field3(input, "jumpMultiplierPerBlock", 25)),
15667
+ jumpMultiplierPerBlock: toBigInt3(
15668
+ field3(input, "jumpMultiplierPerBlock", 25)
15669
+ ),
15471
15670
  kink: toBigInt3(field3(input, "kink", 26))
15472
15671
  };
15473
15672
  }
15474
- function getTectonicRates(info, chainId) {
15673
+ function getTectonicRates(info, chainId, unitSeconds) {
15475
15674
  const supplyApy = calculateRateForCompoundType(
15476
15675
  info.supplyRatePerBlock.toString(),
15477
15676
  chainId,
15478
- 0 /* BLOCK */
15677
+ 0 /* BLOCK */,
15678
+ unitSeconds
15479
15679
  );
15480
15680
  const borrowApy = calculateRateForCompoundType(
15481
15681
  info.borrowRatePerBlock.toString(),
15482
15682
  chainId,
15483
- 0 /* BLOCK */
15683
+ 0 /* BLOCK */,
15684
+ unitSeconds
15484
15685
  );
15485
15686
  return {
15486
15687
  depositRate: apyToApr(supplyApy / 100) * 100,
@@ -15526,7 +15727,9 @@ function parseKineticMarketMetadata(input) {
15526
15727
  totalBorrows: toBigInt4(field4(input, "totalBorrows", 9)),
15527
15728
  collateralFactor: toBigInt4(field4(input, "collateralFactor", 10)),
15528
15729
  underlyingToken: String(field4(input, "underlyingToken", 11)),
15529
- underlyingTokenDecimals: Number(field4(input, "underlyingTokenDecimals", 12)),
15730
+ underlyingTokenDecimals: Number(
15731
+ field4(input, "underlyingTokenDecimals", 12)
15732
+ ),
15530
15733
  cTokenDecimals: Number(field4(input, "cTokenDecimals", 13)),
15531
15734
  totalReserves: toBigInt4(field4(input, "totalReserves", 16)),
15532
15735
  cash: toBigInt4(field4(input, "cash", 17)),
@@ -15559,9 +15762,20 @@ var RESERVE_MANTISSA_DECIMALS = 18;
15559
15762
  var DEFAULT_CLOSE_FACTOR = 0.5;
15560
15763
  var DEFAULT_LIQUIDATION_PENALTY = 0.08;
15561
15764
 
15765
+ // src/lending/public-data/compound-v2/convert/liquidity.ts
15766
+ var cashLiquidity = (raw, decimals) => raw === void 0 || raw === null ? void 0 : Number(parseRawAmount(raw.toString(), decimals));
15767
+
15562
15768
  // src/lending/public-data/compound-v2/convert/standard.ts
15563
15769
  var COMPOUND_V2_NAME_OVERRIDES = {
15564
- "0xccf4429db6322d5c611ee964527d42e5d685dd6a": "Compound"
15770
+ "1:0xccf4429db6322d5c611ee964527d42e5d685dd6a": "Compound",
15771
+ // PAXO (WeFi) on XDC runs three assets twice, split by purpose. Verified
15772
+ // on-chain 2026-08-24 against each cToken's `name()` / `symbol()`.
15773
+ // vBuyFXD, against vFXD "WEFI FXD"
15774
+ "50:0xfc839b46019606b425f8b4c65b4479c3315de5c6": "Paxo FXD Buy",
15775
+ // vBuyEURS, against vEURS "EURS Vault"
15776
+ "50:0xb7c3b74f897adce04db33d9438d60a8fcf70cbc1": "Paxo EURS Buy",
15777
+ // vBorrowWXDC, against vWXDC "WEFI WXDC"
15778
+ "50:0xcc402f9573132b006d6b63b5d5b5a986767959a5": "Paxo WXDC Borrow"
15565
15779
  };
15566
15780
  function convertSingleEntry(opts) {
15567
15781
  const {
@@ -15607,7 +15821,7 @@ function convertSingleEntry(opts) {
15607
15821
  const totalDebt = Number(
15608
15822
  parseRawAmount(currentEntry?.totalBorrows?.toString(), decs)
15609
15823
  );
15610
- const liquidity = totalSupplyUnderlying - totalDebt;
15824
+ const liquidity = cashLiquidity(currentEntry?.totalCash ?? currentEntry?.cash, decs) ?? totalSupplyUnderlying - totalDebt;
15611
15825
  const price2 = prices[asset.assetGroup] ?? 0;
15612
15826
  const pausedActions = { ...currentEntry.pausedActions };
15613
15827
  if (opts.pause?.mintPaused !== void 0)
@@ -15619,7 +15833,7 @@ function convertSingleEntry(opts) {
15619
15833
  const collateralActive = Boolean(currentEntry?.isListed);
15620
15834
  const borrowingEnabled = Boolean(currentEntry?.isBorrowAllowed) && !pausedActions[2 /* BORROW */];
15621
15835
  const marketUid = createMarketUid(chainId, lender, cToken);
15622
- const name = COMPOUND_V2_NAME_OVERRIDES[cToken.toLowerCase()] ?? lenderShortName(lender) + " " + (asset?.symbol ?? "");
15836
+ const name = COMPOUND_V2_NAME_OVERRIDES[`${chainId}:${cToken.toLowerCase()}`] ?? lenderShortName(lender) + " " + (asset?.symbol ?? "");
15623
15837
  return {
15624
15838
  marketUid,
15625
15839
  name,
@@ -15696,7 +15910,7 @@ function convertSumerEntry(opts) {
15696
15910
  const totalDebt = Number(
15697
15911
  parseRawAmount(currentEntry.totalBorrows?.toString(), decs)
15698
15912
  );
15699
- const liquidity = totalSupplyUnderlying - totalDebt;
15913
+ const liquidity = cashLiquidity(currentEntry?.totalCash, decs) ?? totalSupplyUnderlying - totalDebt;
15700
15914
  const price2 = prices[asset.assetGroup] ?? 0;
15701
15915
  const poolId = asset.address;
15702
15916
  const collateralActive = Boolean(currentEntry.isListed);
@@ -15872,19 +16086,15 @@ function convertTectonicEntry(opts) {
15872
16086
  parseRawAmount(info.collateralFactor.toString(), RESERVE_MANTISSA_DECIMALS)
15873
16087
  );
15874
16088
  const liquidationPenalty = Math.max(
15875
- Number(
15876
- parseRawAmount(info.liquidationPenalty.toString(), PRICE_DECIMALS)
15877
- ) - 1,
16089
+ Number(parseRawAmount(info.liquidationPenalty.toString(), PRICE_DECIMALS)) - 1,
15878
16090
  0
15879
16091
  );
15880
16092
  const exchangeRateCurrent = Number(
15881
16093
  parseRawAmount(info.exchangeRate.toString(), PRICE_DECIMALS)
15882
16094
  );
15883
16095
  const totalSupplyUnderlying = Number(parseRawAmount(info.totalSupply.toString(), decs)) * exchangeRateCurrent;
15884
- const totalDebt = Number(
15885
- parseRawAmount(info.totalBorrow.toString(), decs)
15886
- );
15887
- const liquidity = totalSupplyUnderlying - totalDebt;
16096
+ const totalDebt = Number(parseRawAmount(info.totalBorrow.toString(), decs));
16097
+ const liquidity = cashLiquidity(info.availableLiquidity, decs) ?? totalSupplyUnderlying - totalDebt;
15888
16098
  const poolId = asset.address;
15889
16099
  const marketUid = createMarketUid(chainId, lender, cToken);
15890
16100
  return {
@@ -16004,9 +16214,7 @@ function parseBenqiEcoMarketMetadata(input) {
16004
16214
  borrowCap: toBigInt5(field5(input, "borrowCap", 6)),
16005
16215
  supplyCap: toBigInt5(field5(input, "supplyCap", 7)),
16006
16216
  totalSupply: toBigInt5(field5(input, "totalSupply", 8)),
16007
- totalUnderlyingSupply: toBigInt5(
16008
- field5(input, "totalUnderlyingSupply", 9)
16009
- ),
16217
+ totalUnderlyingSupply: toBigInt5(field5(input, "totalUnderlyingSupply", 9)),
16010
16218
  totalBorrows: toBigInt5(field5(input, "totalBorrows", 10)),
16011
16219
  collateralFactor: toBigInt5(field5(input, "collateralFactor", 11)),
16012
16220
  underlying: parseToken(field5(input, "underlying", 12)),
@@ -16017,16 +16225,18 @@ function parseBenqiEcoMarketMetadata(input) {
16017
16225
  borrowPaused: toBool5(field5(input, "borrowPaused", 17))
16018
16226
  };
16019
16227
  }
16020
- function getBenqiRates(info, chainId) {
16228
+ function getBenqiRates(info, chainId, unitSeconds) {
16021
16229
  const supplyApy = calculateRateForCompoundType(
16022
16230
  info.supplyRate.toString(),
16023
16231
  chainId,
16024
- 0 /* BLOCK */
16232
+ 0 /* BLOCK */,
16233
+ unitSeconds
16025
16234
  );
16026
16235
  const borrowApy = calculateRateForCompoundType(
16027
16236
  info.borrowRate.toString(),
16028
16237
  chainId,
16029
- 0 /* BLOCK */
16238
+ 0 /* BLOCK */,
16239
+ unitSeconds
16030
16240
  );
16031
16241
  return {
16032
16242
  depositRate: apyToApr(supplyApy / 100) * 100,
@@ -16049,10 +16259,8 @@ function convertBenqiEntry(opts) {
16049
16259
  const totalDeposits = Number(
16050
16260
  parseRawAmount(parsed.totalUnderlyingSupply.toString(), decs)
16051
16261
  );
16052
- const totalDebt = Number(
16053
- parseRawAmount(parsed.totalBorrows.toString(), decs)
16054
- );
16055
- const liquidity = totalDeposits - totalDebt;
16262
+ const totalDebt = Number(parseRawAmount(parsed.totalBorrows.toString(), decs));
16263
+ const liquidity = cashLiquidity(parsed.cash, decs) ?? totalDeposits - totalDebt;
16056
16264
  const poolId = asset.address;
16057
16265
  const marketUid = createMarketUid(chainId, lender, cToken);
16058
16266
  const collateralActive = !parsed.mintPaused;
@@ -16123,10 +16331,8 @@ function convertKineticEntry(opts) {
16123
16331
  const totalDeposits = Number(
16124
16332
  parseRawAmount(parsed.totalUnderlyingSupply.toString(), decs)
16125
16333
  );
16126
- const totalDebt = Number(
16127
- parseRawAmount(parsed.totalBorrows.toString(), decs)
16128
- );
16129
- const liquidity = totalDeposits - totalDebt;
16334
+ const totalDebt = Number(parseRawAmount(parsed.totalBorrows.toString(), decs));
16335
+ const liquidity = cashLiquidity(parsed.cash, decs) ?? totalDeposits - totalDebt;
16130
16336
  const poolId = asset.address;
16131
16337
  const marketUid = createMarketUid(chainId, lender, cToken);
16132
16338
  const collateralActive = !parsed.mintPaused;
@@ -16215,7 +16421,10 @@ function parseBaseFields(meta) {
16215
16421
  totalBorrows: pick(meta, "totalBorrows", 5) ?? 0n,
16216
16422
  totalReserves: pick(meta, "totalReserves", 6) ?? 0n,
16217
16423
  totalSupply: pick(meta, "totalSupply", 7) ?? 0n,
16218
- totalCash: pick(meta, "totalCash", 8) ?? 0n,
16424
+ // deliberately NOT `?? 0n`: an absent cash field must stay `undefined`
16425
+ // so the converter falls back to the derived figure instead of
16426
+ // reporting a live market as empty. See `convert/liquidity.ts`.
16427
+ totalCash: pick(meta, "totalCash", 8),
16219
16428
  isListed: pick(meta, "isListed", 9) ?? true,
16220
16429
  collateralFactorMantissa: pick(meta, "collateralFactorMantissa", 10) ?? 0n,
16221
16430
  underlyingAssetAddress: pick(meta, "underlyingAssetAddress", 11) ?? "",
@@ -16228,27 +16437,29 @@ function parseBaseFields(meta) {
16228
16437
  pausedActions: DEFAULT_PAUSED_ACTIONS
16229
16438
  };
16230
16439
  }
16231
- function readLodestarCTokenMetadata(meta, token) {
16440
+ function readLodestarCTokenMetadata(meta, token, unitSeconds) {
16232
16441
  const base = parseBaseFields(meta);
16233
16442
  return {
16234
16443
  ...base,
16235
16444
  depositRate: capRate(
16236
16445
  apyToApr(
16237
16446
  calculateRateForCompoundType2(
16238
- base.supplyRatePerBlock?.toString() ?? "0"
16447
+ base.supplyRatePerBlock?.toString() ?? "0",
16448
+ unitSeconds
16239
16449
  ) / 100
16240
16450
  ) * 100
16241
16451
  ),
16242
16452
  variableBorrowRate: capRate(
16243
16453
  apyToApr(
16244
16454
  calculateRateForCompoundType2(
16245
- base.borrowRatePerBlock?.toString() ?? "0"
16455
+ base.borrowRatePerBlock?.toString() ?? "0",
16456
+ unitSeconds
16246
16457
  ) / 100
16247
16458
  ) * 100
16248
16459
  )
16249
16460
  };
16250
16461
  }
16251
- function readCompoundV2CTokenMetadata(meta, token) {
16462
+ function readCompoundV2CTokenMetadata(meta, token, unitSeconds) {
16252
16463
  const base = parseBaseFields(meta);
16253
16464
  return {
16254
16465
  ...base,
@@ -16257,7 +16468,8 @@ function readCompoundV2CTokenMetadata(meta, token) {
16257
16468
  calculateRateForCompoundType(
16258
16469
  base.supplyRatePerBlock?.toString() ?? "0",
16259
16470
  token.chainId,
16260
- 0 /* BLOCK */
16471
+ 0 /* BLOCK */,
16472
+ unitSeconds
16261
16473
  ) / 100
16262
16474
  ) * 100
16263
16475
  ),
@@ -16266,7 +16478,8 @@ function readCompoundV2CTokenMetadata(meta, token) {
16266
16478
  calculateRateForCompoundType(
16267
16479
  base.borrowRatePerBlock?.toString() ?? "0",
16268
16480
  token.chainId,
16269
- 0 /* BLOCK */
16481
+ 0 /* BLOCK */,
16482
+ unitSeconds
16270
16483
  ) / 100
16271
16484
  ) * 100
16272
16485
  )
@@ -16282,7 +16495,10 @@ function parseCreamV2BaseFields(meta) {
16282
16495
  totalBorrows: pick(meta, "totalBorrows", 5) ?? 0n,
16283
16496
  totalReserves: pick(meta, "totalReserves", 6) ?? 0n,
16284
16497
  totalSupply: pick(meta, "totalSupply", 7) ?? 0n,
16285
- totalCash: pick(meta, "totalCash", 8) ?? 0n,
16498
+ // deliberately NOT `?? 0n`: an absent cash field must stay `undefined`
16499
+ // so the converter falls back to the derived figure instead of
16500
+ // reporting a live market as empty. See `convert/liquidity.ts`.
16501
+ totalCash: pick(meta, "totalCash", 8),
16286
16502
  isListed: pick(meta, "isListed", 10) ?? true,
16287
16503
  collateralFactorMantissa: pick(meta, "collateralFactorMantissa", 11) ?? 0n,
16288
16504
  underlyingAssetAddress: pick(meta, "underlyingAssetAddress", 12) ?? "",
@@ -16292,7 +16508,7 @@ function parseCreamV2BaseFields(meta) {
16292
16508
  pausedActions: DEFAULT_PAUSED_ACTIONS
16293
16509
  };
16294
16510
  }
16295
- function readCreamV2CTokenMetadata(meta, token) {
16511
+ function readCreamV2CTokenMetadata(meta, token, unitSeconds) {
16296
16512
  const base = parseCreamV2BaseFields(meta);
16297
16513
  return {
16298
16514
  ...base,
@@ -16301,7 +16517,8 @@ function readCreamV2CTokenMetadata(meta, token) {
16301
16517
  calculateRateForCompoundType(
16302
16518
  base.supplyRatePerBlock?.toString() ?? "0",
16303
16519
  token.chainId,
16304
- 0 /* BLOCK */
16520
+ 0 /* BLOCK */,
16521
+ unitSeconds
16305
16522
  ) / 100
16306
16523
  ) * 100
16307
16524
  ),
@@ -16310,12 +16527,446 @@ function readCreamV2CTokenMetadata(meta, token) {
16310
16527
  calculateRateForCompoundType(
16311
16528
  base.borrowRatePerBlock?.toString() ?? "0",
16312
16529
  token.chainId,
16313
- 0 /* BLOCK */
16530
+ 0 /* BLOCK */,
16531
+ unitSeconds
16314
16532
  ) / 100
16315
16533
  ) * 100
16316
16534
  )
16317
16535
  };
16318
16536
  }
16537
+ var MULTICALL_DEFAULT_BATCH_SIZE = 4096;
16538
+ var CELO_MULTICALL_ADDRESS = "0x633987602DE5C4F337e3DbF265303A1080324204";
16539
+ var BNB_MULTICALL_ADDRESS = "0x963Df249eD09c358A4819E39d9Cd5736c3087184";
16540
+ var MANTLE_MULTICALL_ADDRESS = "0x2A51f2F647E1883F88C992244dEd171238693107";
16541
+ var ARBITRUM_ONE_MULTICALL_ADDRESS = "0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB";
16542
+ var LINEA_MULTICALL_ADDRESS = "0xac1cE734566f390A94b00eb9bf561c2625BF44ea";
16543
+ var AVALANCHE_MULTICALL_ADDRESS = "0x0139141Cd4Ee88dF3Cdb65881D411bAE271Ef0C2";
16544
+ var BASE_MULTICALL_ADDRESS = "0x091e99cb1C49331a94dD62755D168E941AbD0693";
16545
+ var BLAST_MULTICALL_ADDRESS = "0xdC7f370de7631cE9e2c2e1DCDA6B3B5744Cf4705";
16546
+ var TAIKO_MULTICALL_ADDRESS = "0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201";
16547
+ var HEMI_MULTICALL_ADDRESS = "0x352A86168e6988A1aDF9A15Cb00017AAd3B67155";
16548
+ var GNOSIS_MULTICALL_ADDRESS = "0x4dfa9a980efE4802E969AC33968E3d6E59B8a19e";
16549
+ var MODE_MULTICALL_ADDRESS = "0xAB39cE30D98a59DFDa40A630b074170800bfF179";
16550
+ var FANTOM_MULTICALL_ADDRESS = "0xDb51CffFf3B989d0cB6b58AbF173371b6F2d0D24";
16551
+ var SCROLL_MULTICALL_ADDRESS = "0x3b615B1AC55bc34e51a81D3dea67467F32bcb8C2";
16552
+ var SHAPE_MULTICALL_ADDRESS = "0x356A450B32f5030ae7083702b86FaFbBe7490411";
16553
+ var SONIC_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
16554
+ var INK_MULTICALL_ADDRESS = "0xA0fCec583AeE6176527C07B198e5561722332014";
16555
+ var METIS_MULTICALL_ADDRESS = "0x7a59ddbB76521E8982Fa3A08598C9a83b14A6C07";
16556
+ var IOTA_MULTICALL_ADDRESS = "0x9683D433621A83aA7dd290106e1da85251317F55";
16557
+ var KAVA_MULTICALL_ADDRESS = "0x8B741B0D79BE80E135C880F7583d427B4D41F015";
16558
+ var SAGA_MULTICALL_ADDRESS = "0x743E03cceB4af2efA3CC76838f6E8B50B63F184c";
16559
+ var CYBER_MULTICALL_ADDRESS = "0x906d6eB9CF8f64e100e44f8f491b833a8d40B530";
16560
+ var METAL_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
16561
+ var ZERO_MULTICALL_ADDRESS = "0x9CA4dcb2505fbf536F6c54AA0a77C79f4fBC35C0";
16562
+ var BOB_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
16563
+ var WORLDCHAIN_MULTICALL_ADDRESS = "0x0a22c04215c97E3F532F4eF30e0aD9458792dAB9";
16564
+ var LISK_MULTICALL_ADDRESS = "0xE3dbcD53f4Ce1b06Ab200f4912BD35672e68f1FA";
16565
+ var REDSTONE_MULTICALL_ADDRESS = "0xd57B52452a0FDfE3ff8e0A40Bd10D00D0bfe0723";
16566
+ var MANTA_MULTICALL_ADDRESS = "0x52dFC0D9960F11A9Ca9FF616e791B91188446a60";
16567
+ var ZORA_MULTICALL_ADDRESS = "0xA51c76bEE6746cB487a7e9312E43e2b8f4A37C15";
16568
+ var CORE_MULTICALL_ADDRESS = "0xFe9F82D820757787895Da00B1dBD35c3B8b04894";
16569
+ var MORPH_MULTICALL_ADDRESS = "0xAcD82113982479B25E7c1D09858F0130921Dbbca";
16570
+ var TELOS_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
16571
+ var MULTICALL_ADDRESS = {
16572
+ [Chain.OP_MAINNET]: "0x1F98415757620B543A52E61c46B32eB19261F984",
16573
+ [Chain.POLYGON_MAINNET]: "0x1F98415757620B543A52E61c46B32eB19261F984",
16574
+ [Chain.ETHEREUM_MAINNET]: "0x1F98415757620B543A52E61c46B32eB19261F984",
16575
+ [Chain.ARBITRUM_ONE]: ARBITRUM_ONE_MULTICALL_ADDRESS,
16576
+ [Chain.BASE]: BASE_MULTICALL_ADDRESS,
16577
+ [Chain.CELO_MAINNET]: CELO_MULTICALL_ADDRESS,
16578
+ [Chain.BNB_SMART_CHAIN_MAINNET]: BNB_MULTICALL_ADDRESS,
16579
+ [Chain.MANTLE]: MANTLE_MULTICALL_ADDRESS,
16580
+ [Chain.BLAST]: BLAST_MULTICALL_ADDRESS,
16581
+ [Chain.LINEA]: LINEA_MULTICALL_ADDRESS,
16582
+ [Chain.AVALANCHE_C_CHAIN]: AVALANCHE_MULTICALL_ADDRESS,
16583
+ [Chain.TAIKO_ALETHIA]: TAIKO_MULTICALL_ADDRESS,
16584
+ [Chain.HEMI_NETWORK]: HEMI_MULTICALL_ADDRESS,
16585
+ [Chain.GNOSIS]: GNOSIS_MULTICALL_ADDRESS,
16586
+ [Chain.CORE_BLOCKCHAIN_MAINNET]: CORE_MULTICALL_ADDRESS,
16587
+ [Chain.METIS_ANDROMEDA_MAINNET]: METIS_MULTICALL_ADDRESS,
16588
+ [Chain.MODE]: MODE_MULTICALL_ADDRESS,
16589
+ [Chain.INK]: INK_MULTICALL_ADDRESS,
16590
+ [Chain.IOTA_EVM]: IOTA_MULTICALL_ADDRESS,
16591
+ [Chain.SONIC_MAINNET]: SONIC_MULTICALL_ADDRESS,
16592
+ [Chain.FANTOM_OPERA]: FANTOM_MULTICALL_ADDRESS,
16593
+ [Chain.SCROLL]: SCROLL_MULTICALL_ADDRESS,
16594
+ [Chain.SHAPE]: SHAPE_MULTICALL_ADDRESS,
16595
+ [Chain.CYBER_MAINNET]: CYBER_MULTICALL_ADDRESS,
16596
+ [Chain.ZORA]: ZORA_MULTICALL_ADDRESS,
16597
+ [Chain.MANTA_PACIFIC_MAINNET]: MANTA_MULTICALL_ADDRESS,
16598
+ [Chain.REDSTONE]: REDSTONE_MULTICALL_ADDRESS,
16599
+ [Chain.KAVA]: KAVA_MULTICALL_ADDRESS,
16600
+ [Chain.METAL_L2]: METAL_MULTICALL_ADDRESS,
16601
+ [Chain.LISK]: LISK_MULTICALL_ADDRESS,
16602
+ [Chain.BOB]: BOB_MULTICALL_ADDRESS,
16603
+ [Chain.ZERO_NETWORK]: ZERO_MULTICALL_ADDRESS,
16604
+ [Chain.SAGA]: SAGA_MULTICALL_ADDRESS,
16605
+ [Chain.MORPH]: MORPH_MULTICALL_ADDRESS,
16606
+ [Chain.TELOS_EVM_MAINNET]: TELOS_MULTICALL_ADDRESS,
16607
+ [Chain.WORLD_CHAIN]: WORLDCHAIN_MULTICALL_ADDRESS
16608
+ };
16609
+
16610
+ // src/utils/multicall.ts
16611
+ var { isArray } = lodash;
16612
+ var maxRetries = 3;
16613
+ var MULTICALL_FAILURE = "0x";
16614
+ var isFailedCall = (value) => value === void 0 || value === null || value === MULTICALL_FAILURE;
16615
+ var MULTICALL_REPAIR_ROUNDS = 3;
16616
+ var MAX_CALLS_PER_SHARD = 300;
16617
+ var ONE_REQUEST_BATCH_BYTES = 1e6;
16618
+ var MAX_INFLIGHT_REQUESTS = 6;
16619
+ var HEDGE_DELAY_MS = 1200;
16620
+ var SHARD_TIMEOUT_MS = 4e3;
16621
+ var MIN_ADAPTIVE_SHARD = 25;
16622
+ var ADAPTIVE_CAP_TTL_MS = 6e4;
16623
+ var endpointCallCap = /* @__PURE__ */ new Map();
16624
+ var capFor = (url, requested) => {
16625
+ const hit = endpointCallCap.get(url);
16626
+ if (!hit) return requested;
16627
+ if (Date.now() - hit.at > ADAPTIVE_CAP_TTL_MS) {
16628
+ endpointCallCap.delete(url);
16629
+ return requested;
16630
+ }
16631
+ return Math.min(requested, hit.calls);
16632
+ };
16633
+ var noteEndpointRefusal = (url, calls) => {
16634
+ if (calls <= MIN_ADAPTIVE_SHARD) return;
16635
+ const next = Math.max(MIN_ADAPTIVE_SHARD, Math.floor(calls / 2));
16636
+ const current = endpointCallCap.get(url);
16637
+ if (current && Date.now() - current.at <= ADAPTIVE_CAP_TTL_MS && current.calls <= next)
16638
+ return;
16639
+ endpointCallCap.set(url, { calls: next, at: Date.now() });
16640
+ };
16641
+ var DETERMINISTIC_ERROR_NAMES = /* @__PURE__ */ new Set([
16642
+ "ContractFunctionRevertedError",
16643
+ "RawContractError",
16644
+ "AbiDecodingZeroDataError",
16645
+ "AbiDecodingDataSizeTooSmallError",
16646
+ "AbiFunctionNotFoundError"
16647
+ ]);
16648
+ var isDeterministicCallError = (error) => {
16649
+ let err = error;
16650
+ for (let depth = 0; err && depth < 8; depth++) {
16651
+ if (DETERMINISTIC_ERROR_NAMES.has(err.name)) return true;
16652
+ const message = String(err.shortMessage ?? err.message ?? "").toLowerCase();
16653
+ if (message.includes("execution reverted") || message.includes("returned no data"))
16654
+ return true;
16655
+ err = err.cause;
16656
+ }
16657
+ return false;
16658
+ };
16659
+ var REPAIR_BACKOFF_BASE_MS = 100;
16660
+ var REPAIR_BACKOFF_JITTER_MS = 60;
16661
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
16662
+ var backoffForRound = (round) => REPAIR_BACKOFF_BASE_MS * 2 ** round + Math.random() * REPAIR_BACKOFF_JITTER_MS;
16663
+ var endpointUrl = (client, rpcId) => client?.transport?.url ?? `rpc#${rpcId}`;
16664
+ var resolveEndpoint = (chainId, getEvmClient18, startRpcId, tried, maxProbe = 12, timeoutMs) => {
16665
+ let fallback = null;
16666
+ for (let probe = 0; probe < maxProbe; probe++) {
16667
+ const rpcId = startRpcId + probe;
16668
+ let client;
16669
+ try {
16670
+ client = getEvmClient18(chainId, rpcId, { timeoutMs });
16671
+ } catch {
16672
+ break;
16673
+ }
16674
+ const url = endpointUrl(client, rpcId);
16675
+ if (!tried?.has(url)) {
16676
+ tried?.add(url);
16677
+ return { client, rpcId, url, reused: false };
16678
+ }
16679
+ fallback ??= { client, rpcId, url, reused: true };
16680
+ }
16681
+ return fallback;
16682
+ };
16683
+ var toSlots = (returnData, allowFailure) => {
16684
+ if (!allowFailure)
16685
+ return returnData.map((value) => ({ value, permanent: false }));
16686
+ return returnData.map(
16687
+ ({ result, status, error }) => status === "success" ? { value: result, permanent: false } : {
16688
+ value: MULTICALL_FAILURE,
16689
+ permanent: isDeterministicCallError(error)
16690
+ }
16691
+ );
16692
+ };
16693
+ var recordPermanentFailures = (slots, offset, collector) => {
16694
+ if (!collector) return;
16695
+ for (let i = 0; i < slots.length; i++) {
16696
+ if (slots[i].permanent) collector.add(offset + i);
16697
+ }
16698
+ };
16699
+ var repairFailedSlots = async (chainId, contracts, slots, getEvmClient18, nextRpcId, batchSize, logs, rounds = MULTICALL_REPAIR_ROUNDS, options) => {
16700
+ let searchFrom = nextRpcId;
16701
+ for (let round = 0; round < rounds; round++) {
16702
+ const failedIdx = [];
16703
+ for (let i = 0; i < slots.length; i++) {
16704
+ if (isFailedCall(slots[i].value) && !slots[i].permanent) failedIdx.push(i);
16705
+ }
16706
+ if (failedIdx.length === 0) return slots;
16707
+ const endpoint = resolveEndpoint(
16708
+ chainId,
16709
+ getEvmClient18,
16710
+ searchFrom,
16711
+ options?.tried
16712
+ );
16713
+ if (!endpoint) {
16714
+ if (logs)
16715
+ console.log(
16716
+ `multicall repair: no usable endpoint for chain ${chainId}, giving up with ${failedIdx.length} failed slots`
16717
+ );
16718
+ return slots;
16719
+ }
16720
+ searchFrom = endpoint.rpcId + 1;
16721
+ await sleep(backoffForRound(round));
16722
+ try {
16723
+ const returnData = await endpoint.client.multicall({
16724
+ allowFailure: true,
16725
+ batchSize,
16726
+ contracts: failedIdx.map((i) => contracts[i])
16727
+ });
16728
+ let repaired = 0;
16729
+ returnData.forEach((entry, k) => {
16730
+ const idx = failedIdx[k];
16731
+ if (entry?.status === "success") {
16732
+ slots[idx] = { value: entry.result, permanent: false };
16733
+ repaired++;
16734
+ } else if (isDeterministicCallError(entry?.error)) {
16735
+ slots[idx].permanent = true;
16736
+ }
16737
+ });
16738
+ if (repaired === 0)
16739
+ options?.onEndpointFailure?.({
16740
+ chainId,
16741
+ url: endpoint.url,
16742
+ rpcId: endpoint.rpcId,
16743
+ kind: "slots"
16744
+ });
16745
+ } catch (error) {
16746
+ options?.onEndpointFailure?.({
16747
+ chainId,
16748
+ url: endpoint.url,
16749
+ rpcId: endpoint.rpcId,
16750
+ kind: "transport"
16751
+ });
16752
+ if (logs)
16753
+ console.log(
16754
+ `error in multicall failure-repair round ${round} chain ${chainId}`,
16755
+ error
16756
+ );
16757
+ }
16758
+ }
16759
+ return slots;
16760
+ };
16761
+ var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient18, poolSize, retries = maxRetries, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, logs = false, retryFailed = false, permanentFailures, options) => {
16762
+ const abiIsArray = isArray(abi[0]);
16763
+ const contracts = calls.map(({ address, name, params }, i) => ({
16764
+ abi: abiIsArray ? abi?.[i] : abi,
16765
+ address,
16766
+ functionName: name,
16767
+ args: params
16768
+ }));
16769
+ const requestBytes = batchSize < MULTICALL_DEFAULT_BATCH_SIZE ? batchSize : ONE_REQUEST_BATCH_BYTES;
16770
+ const workerBudget = Math.max(1, Math.floor(MAX_INFLIGHT_REQUESTS / 2));
16771
+ const workers = Math.max(1, Math.min(poolSize, workerBudget));
16772
+ const shardSize = Math.max(
16773
+ 1,
16774
+ Math.min(MAX_CALLS_PER_SHARD, Math.ceil(contracts.length / workers))
16775
+ );
16776
+ const batches = [];
16777
+ for (let i = 0; i < contracts.length; i += shardSize) {
16778
+ batches.push({ start: i, items: contracts.slice(i, i + shardSize) });
16779
+ }
16780
+ const results = new Array(contracts.length);
16781
+ const request = async (endpoint, items) => {
16782
+ try {
16783
+ const returnData = await endpoint.client.multicall({
16784
+ allowFailure,
16785
+ batchSize: requestBytes,
16786
+ contracts: items
16787
+ });
16788
+ const slots = toSlots(returnData, allowFailure);
16789
+ if (allowFailure && slots.length > 0 && slots.every((s) => isFailedCall(s.value) && !s.permanent)) {
16790
+ if (logs)
16791
+ console.log(
16792
+ `sharded multicall: rpc ${endpoint.rpcId} answered ${items.length} calls with nothing`
16793
+ );
16794
+ options?.onEndpointFailure?.({
16795
+ chainId,
16796
+ url: endpoint.url,
16797
+ rpcId: endpoint.rpcId,
16798
+ kind: "slots"
16799
+ });
16800
+ noteEndpointRefusal(endpoint.url, items.length);
16801
+ return null;
16802
+ }
16803
+ return slots;
16804
+ } catch (error) {
16805
+ if (logs) console.log("error in sharded multicall request", error);
16806
+ options?.onEndpointFailure?.({
16807
+ chainId,
16808
+ url: endpoint.url,
16809
+ rpcId: endpoint.rpcId,
16810
+ kind: "transport"
16811
+ });
16812
+ noteEndpointRefusal(endpoint.url, items.length);
16813
+ return null;
16814
+ }
16815
+ };
16816
+ const firstUsable = (attempts) => new Promise((resolve) => {
16817
+ let pending = attempts.length;
16818
+ let settled = false;
16819
+ const lose = () => {
16820
+ if (!settled && --pending === 0) resolve(null);
16821
+ };
16822
+ for (const attempt of attempts) {
16823
+ attempt.then((won) => {
16824
+ if (settled) return;
16825
+ if (won) {
16826
+ settled = true;
16827
+ resolve(won);
16828
+ } else lose();
16829
+ }, lose);
16830
+ }
16831
+ });
16832
+ const attemptHedged = async (items, startRpcId, tried) => {
16833
+ const primary = resolveEndpoint(
16834
+ chainId,
16835
+ getEvmClient18,
16836
+ startRpcId,
16837
+ tried,
16838
+ 12,
16839
+ SHARD_TIMEOUT_MS
16840
+ );
16841
+ if (!primary) {
16842
+ if (logs)
16843
+ console.log(
16844
+ `sharded multicall: no untried endpoint left for chain ${chainId}`
16845
+ );
16846
+ return null;
16847
+ }
16848
+ let timer;
16849
+ let hedgeStarted = false;
16850
+ let beginHedge = () => {
16851
+ };
16852
+ const hedged = new Promise((resolve) => {
16853
+ beginHedge = () => {
16854
+ if (hedgeStarted) return;
16855
+ hedgeStarted = true;
16856
+ clearTimeout(timer);
16857
+ const alt = resolveEndpoint(
16858
+ chainId,
16859
+ getEvmClient18,
16860
+ primary.rpcId + 1,
16861
+ tried,
16862
+ 12,
16863
+ SHARD_TIMEOUT_MS
16864
+ );
16865
+ if (!alt) return resolve(null);
16866
+ const altItems = items.slice(0, capFor(alt.url, items.length));
16867
+ if (altItems.length < items.length) return resolve(null);
16868
+ request(alt, items).then(
16869
+ (slots) => resolve(slots ? { slots, rpcId: alt.rpcId } : null)
16870
+ );
16871
+ };
16872
+ });
16873
+ timer = setTimeout(() => beginHedge(), HEDGE_DELAY_MS);
16874
+ const direct = request(primary, items).then((slots) => {
16875
+ if (slots) return { slots, rpcId: primary.rpcId };
16876
+ beginHedge();
16877
+ return null;
16878
+ });
16879
+ const won = await firstUsable([direct, hedged]);
16880
+ clearTimeout(timer);
16881
+ return won;
16882
+ };
16883
+ const runBatch = async (batch, rpcId, attemptsLeft, tried) => {
16884
+ if (!batch.items.length) return;
16885
+ const won = await attemptHedged(batch.items, rpcId, tried);
16886
+ if (!won) {
16887
+ if (attemptsLeft > 0 && batch.items.length > 1) {
16888
+ const half = Math.ceil(batch.items.length / 2);
16889
+ await sleep(backoffForRound(0));
16890
+ await runBatch(
16891
+ { start: batch.start, items: batch.items.slice(0, half) },
16892
+ rpcId,
16893
+ attemptsLeft - 1,
16894
+ tried
16895
+ );
16896
+ await runBatch(
16897
+ { start: batch.start + half, items: batch.items.slice(half) },
16898
+ rpcId + 1,
16899
+ attemptsLeft - 1,
16900
+ tried
16901
+ );
16902
+ }
16903
+ return;
16904
+ }
16905
+ let slots = won.slots;
16906
+ if (allowFailure && retryFailed) {
16907
+ slots = await repairFailedSlots(
16908
+ chainId,
16909
+ batch.items,
16910
+ slots,
16911
+ getEvmClient18,
16912
+ won.rpcId + 1,
16913
+ requestBytes,
16914
+ logs,
16915
+ MULTICALL_REPAIR_ROUNDS,
16916
+ { tried, onEndpointFailure: options?.onEndpointFailure }
16917
+ );
16918
+ }
16919
+ recordPermanentFailures(slots, batch.start, permanentFailures);
16920
+ for (let j = 0; j < slots.length; j++) {
16921
+ results[batch.start + j] = slots[j].value;
16922
+ }
16923
+ };
16924
+ let cursor = 0;
16925
+ const worker = async (workerId) => {
16926
+ while (true) {
16927
+ const idx = cursor++;
16928
+ if (idx >= batches.length) break;
16929
+ const batch = batches[idx];
16930
+ const tried = /* @__PURE__ */ new Set();
16931
+ const start = resolveEndpoint(
16932
+ chainId,
16933
+ getEvmClient18,
16934
+ workerId,
16935
+ void 0,
16936
+ 12,
16937
+ SHARD_TIMEOUT_MS
16938
+ );
16939
+ const cap = start ? capFor(start.url, batch.items.length) : batch.items.length;
16940
+ for (let off = 0; off < batch.items.length; off += cap) {
16941
+ await runBatch(
16942
+ {
16943
+ start: batch.start + off,
16944
+ items: batch.items.slice(off, off + cap)
16945
+ },
16946
+ workerId,
16947
+ retries,
16948
+ tried
16949
+ );
16950
+ }
16951
+ }
16952
+ };
16953
+ await Promise.all(
16954
+ Array.from(
16955
+ { length: Math.min(workers, batches.length) },
16956
+ (_3, w) => worker(w)
16957
+ )
16958
+ );
16959
+ return results;
16960
+ };
16961
+ function prepareMulticallInputs(abi, calls) {
16962
+ const abiIsArray = isArray(abi[0]);
16963
+ return calls.map(({ address, name, params }, i) => ({
16964
+ address,
16965
+ functionName: name,
16966
+ params: params || [],
16967
+ abi: abiIsArray ? abi[i] : abi
16968
+ }));
16969
+ }
16319
16970
 
16320
16971
  // src/lending/public-data/compound-v2/publicCallParse.ts
16321
16972
  var parseMantissaWad = (raw) => {
@@ -16326,7 +16977,7 @@ var parseMantissaWad = (raw) => {
16326
16977
  return void 0;
16327
16978
  }
16328
16979
  };
16329
- var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tokenList = {}) => {
16980
+ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tokenList = {}, unitSeconds) => {
16330
16981
  if (lender === Lender.TAKARA) {
16331
16982
  return [
16332
16983
  (data) => {
@@ -16448,7 +17099,7 @@ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tok
16448
17099
  const pauseReads = Boolean(stdComptroller) && usesComptrollerPauseReads(lender);
16449
17100
  const pauseCalls = pauseReads ? tokenCount * 2 : 0;
16450
17101
  const expectedNumberOfCalls = isSumer ? tokenCount + SUMER_GROUP_COUNT : tokenCount + stdComptrollerCalls + pauseCalls;
16451
- const reader = getReader(lender, chainId);
17102
+ const reader = getReader(lender, chainId, unitSeconds);
16452
17103
  return [
16453
17104
  (data) => {
16454
17105
  if (data.length !== expectedNumberOfCalls) return void 0;
@@ -16492,6 +17143,7 @@ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tok
16492
17143
  const asset = tokenList[underlying];
16493
17144
  if (!asset) continue;
16494
17145
  const entryRaw = data[i];
17146
+ if (isFailedCall(entryRaw)) continue;
16495
17147
  const entry = convertSingleEntry({
16496
17148
  entryRaw,
16497
17149
  reader,
@@ -16517,9 +17169,9 @@ var getCompoundV2DataConverter = (lender, chainId, prices, additionalYields, tok
16517
17169
  expectedNumberOfCalls
16518
17170
  ];
16519
17171
  };
16520
- function getReader(lender, chainId) {
17172
+ function getReader(lender, chainId, unitSeconds) {
16521
17173
  if (isVenusType(lender)) {
16522
- return (x, t) => readVTokenMetadata(x, t);
17174
+ return (x, t) => readVTokenMetadata(x, t, unitSeconds);
16523
17175
  }
16524
17176
  if (lender === Lender.MOONWELL) {
16525
17177
  return (x, t) => parseMoonwellMarket(x, t);
@@ -16528,13 +17180,18 @@ function getReader(lender, chainId) {
16528
17180
  return (x, t) => readSumerCTokenMetadata(x, t);
16529
17181
  }
16530
17182
  if (lender === Lender.LODESTAR || lender === Lender.TENDER) {
16531
- return (x, t) => readLodestarCTokenMetadata(x);
17183
+ return (x, t) => readLodestarCTokenMetadata(x, t, unitSeconds);
16532
17184
  }
16533
17185
  if (lender === Lender.CREAM_FINANCE && (chainId === Chain.POLYGON_MAINNET || chainId === Chain.ARBITRUM_ONE)) {
16534
- return (x, t) => readCreamV2CTokenMetadata(x, t);
17186
+ return (x, t) => readCreamV2CTokenMetadata(x, t, unitSeconds);
16535
17187
  }
16536
- if (lender === Lender.COMPOUND_V2 || lender === Lender.FLUX_FINANCE || lender === Lender.WE_PIGGY || lender === Lender.CREAM_FINANCE || lender === Lender.CAPY_FI || lender === Lender.GAMMA) {
16537
- return (x, t) => readCompoundV2CTokenMetadata(x, t);
17188
+ if (lender === Lender.COMPOUND_V2 || lender === Lender.FLUX_FINANCE || lender === Lender.WE_PIGGY || lender === Lender.CREAM_FINANCE || lender === Lender.CAPY_FI || lender === Lender.GAMMA || // long-tail forks read through a shared 14-field lens — MUST mirror the
17189
+ // `CreamLensAbi` branch in publicCallBuild.ts `getCall`. A lender in that
17190
+ // branch and missing here builds fine and then dies in the converter with
17191
+ // `reader is not a function`, which is not a length mismatch and so is not
17192
+ // caught by the parser's own guard.
17193
+ lender === Lender.DEMETER || lender === Lender.LANDER || lender === Lender.FILDA || lender === Lender.SOLIDLIZARD || lender === Lender.IRON_BANK || lender === Lender.MENDI || lender === Lender.PAXO || lender === Lender.SONNE || lender === Lender.ASO_FINANCE || lender === Lender.BLUME || lender === Lender.KAWA || lender === Lender.XPERT || lender === Lender.KEOM || lender === Lender.REACTOR_FUSION) {
17194
+ return (x, t) => readCompoundV2CTokenMetadata(x, t, unitSeconds);
16538
17195
  }
16539
17196
  }
16540
17197
 
@@ -19123,7 +19780,7 @@ var buildFluidCall = (chainId, _lender) => {
19123
19780
  // src/lending/public-data/fluid/apiData.ts
19124
19781
  var FLUID_API_BASE = "https://api.fluid.instadapp.io/v2";
19125
19782
  var SUPPORTED_CHAINS = /* @__PURE__ */ new Set(["1", "56", "137", "8453", "9745", "42161"]);
19126
- var TTL_MS = 6e4;
19783
+ var TTL_MS2 = 6e4;
19127
19784
  var ZERO_ADDRESS4 = "0x0000000000000000000000000000000000000000";
19128
19785
  var cache = {};
19129
19786
  var inflight = /* @__PURE__ */ new Map();
@@ -19171,7 +19828,7 @@ var parseChainPayload = (raw) => {
19171
19828
  var fetchFluidApiData = async (chainId) => {
19172
19829
  if (!SUPPORTED_CHAINS.has(chainId)) return void 0;
19173
19830
  const hit = cache[chainId];
19174
- if (hit && Date.now() - hit.at < TTL_MS) return hit.data;
19831
+ if (hit && Date.now() - hit.at < TTL_MS2) return hit.data;
19175
19832
  const pending = inflight.get(chainId);
19176
19833
  if (pending) return pending;
19177
19834
  const run = (async () => {
@@ -19205,14 +19862,14 @@ var DEX_RESOLVER_FALLBACK = {
19205
19862
  };
19206
19863
  var dexResolverFor = (chainId) => fluidResolvers()?.[chainId]?.dexResolver ?? DEX_RESOLVER_FALLBACK[chainId];
19207
19864
  var ZERO_ADDRESS5 = "0x0000000000000000000000000000000000000000";
19208
- var TTL_MS2 = 6e4;
19865
+ var TTL_MS3 = 6e4;
19209
19866
  var cache2 = {};
19210
19867
  var inflight2 = /* @__PURE__ */ new Map();
19211
19868
  var fetchFluidDexState = async (chainId, multicallRetry, extraDexAddresses = []) => {
19212
19869
  const resolver = dexResolverFor(chainId);
19213
19870
  if (!resolver) return void 0;
19214
19871
  const hit = cache2[chainId];
19215
- if (hit && Date.now() - hit.at < TTL_MS2) return hit.data;
19872
+ if (hit && Date.now() - hit.at < TTL_MS3) return hit.data;
19216
19873
  const pending = inflight2.get(chainId);
19217
19874
  if (pending) return pending;
19218
19875
  const run = (async () => {
@@ -20215,7 +20872,7 @@ function buildLenderCall(chainId, lender) {
20215
20872
  if (isGearboxV3(lender)) return buildGearboxCall(chainId);
20216
20873
  return [];
20217
20874
  }
20218
- function getLenderDataConverter(lender, chainId, prices, additionalYields, tokenList = {}) {
20875
+ function getLenderDataConverter(lender, chainId, prices, additionalYields, tokenList = {}, unitSeconds) {
20219
20876
  if (isAaveV2Type(lender))
20220
20877
  return getAaveV2ReservesDataConverter(
20221
20878
  lender,
@@ -20263,7 +20920,8 @@ function getLenderDataConverter(lender, chainId, prices, additionalYields, token
20263
20920
  chainId,
20264
20921
  prices,
20265
20922
  additionalYields,
20266
- tokenList
20923
+ tokenList,
20924
+ unitSeconds
20267
20925
  );
20268
20926
  if (isEulerType(lender))
20269
20927
  return getEulerV2ReservesDataConverter(
@@ -20404,6 +21062,16 @@ var getLenderPublicData = async (chainId, lenders, prices, additionalYields, mul
20404
21062
  }
20405
21063
  const invalidLenders = [];
20406
21064
  let lenderData = {};
21065
+ const rateUnitSeconds = /* @__PURE__ */ new Map();
21066
+ await Promise.all(
21067
+ validLenders.filter((l) => isCompoundV2Type(l)).map(async (l) => {
21068
+ try {
21069
+ rateUnitSeconds.set(l, await resolveRateUnitSeconds(chainId, l));
21070
+ } catch {
21071
+ rateUnitSeconds.set(l, void 0);
21072
+ }
21073
+ })
21074
+ );
20407
21075
  let currentSlice = 0;
20408
21076
  for (const lender of validLenders) {
20409
21077
  const [converter, sliceLength] = getLenderDataConverter(
@@ -20411,7 +21079,8 @@ var getLenderPublicData = async (chainId, lenders, prices, additionalYields, mul
20411
21079
  chainId,
20412
21080
  prices,
20413
21081
  additionalYields,
20414
- list
21082
+ list,
21083
+ rateUnitSeconds.get(lender)
20415
21084
  );
20416
21085
  if (sliceLength > 0) {
20417
21086
  try {
@@ -20620,16 +21289,16 @@ var LKG_TTL_SEC = 30 * 60;
20620
21289
  var lastGood = /* @__PURE__ */ new Map();
20621
21290
  async function fetchTopAndBookWithFallback(source, chainId, marketId, nowSec9) {
20622
21291
  const key3 = `${chainId}:${marketId}`;
20623
- let fresh = null;
21292
+ let fresh2 = null;
20624
21293
  if (source.getTopAndBook) {
20625
- fresh = await source.getTopAndBook(marketId, MIDNIGHT_BOOK_LEVELS).catch(() => null);
21294
+ fresh2 = await source.getTopAndBook(marketId, MIDNIGHT_BOOK_LEVELS).catch(() => null);
20626
21295
  } else {
20627
21296
  const top = await source.getBookTop(marketId).catch(() => null);
20628
- if (top) fresh = { top, book: { bids: [], asks: [] } };
21297
+ if (top) fresh2 = { top, book: { bids: [], asks: [] } };
20629
21298
  }
20630
- if (fresh) {
20631
- lastGood.set(key3, { top: fresh.top, book: fresh.book, at: nowSec9 });
20632
- return { top: fresh.top, book: fresh.book };
21299
+ if (fresh2) {
21300
+ lastGood.set(key3, { top: fresh2.top, book: fresh2.book, at: nowSec9 });
21301
+ return { top: fresh2.top, book: fresh2.book };
20633
21302
  }
20634
21303
  const cached = lastGood.get(key3);
20635
21304
  if (cached && nowSec9 - cached.at <= LKG_TTL_SEC) {
@@ -21401,21 +22070,21 @@ var LKG_TTL_SEC2 = 30 * 60;
21401
22070
  var lastGood2 = /* @__PURE__ */ new Map();
21402
22071
  async function fetchTopAndBookWithFallback2(source, chainId, config, nowSec9) {
21403
22072
  const key3 = `${chainId}:${config.termRepoId}`;
21404
- let fresh = null;
22073
+ let fresh2 = null;
21405
22074
  if (source.getTopAndBook) {
21406
- fresh = await source.getTopAndBook(config, TERM_BOOK_LEVELS).catch(() => null);
22075
+ fresh2 = await source.getTopAndBook(config, TERM_BOOK_LEVELS).catch(() => null);
21407
22076
  } else {
21408
22077
  const top = await source.getBookTop(config).catch(() => null);
21409
- if (top) fresh = { top, book: { bids: [], asks: [] }, auction: null };
22078
+ if (top) fresh2 = { top, book: { bids: [], asks: [] }, auction: null };
21410
22079
  }
21411
- if (fresh) {
22080
+ if (fresh2) {
21412
22081
  lastGood2.set(key3, {
21413
- top: fresh.top,
21414
- book: fresh.book,
21415
- auction: fresh.auction ?? null,
22082
+ top: fresh2.top,
22083
+ book: fresh2.book,
22084
+ auction: fresh2.auction ?? null,
21416
22085
  at: nowSec9
21417
22086
  });
21418
- return { top: fresh.top, book: fresh.book, auction: fresh.auction ?? null };
22087
+ return { top: fresh2.top, book: fresh2.book, auction: fresh2.auction ?? null };
21419
22088
  }
21420
22089
  const cached = lastGood2.get(key3);
21421
22090
  if (cached && nowSec9 - cached.at <= LKG_TTL_SEC2) {
@@ -23025,10 +23694,10 @@ function refreshLiveMarkets(chainId, source) {
23025
23694
  const running = refreshInFlight.get(chainId);
23026
23695
  if (running) return running;
23027
23696
  lastRefreshAttempt.set(chainId, Date.now());
23028
- const p = source.getChainMarkets(chainId).then((fresh) => {
23029
- if (!fresh) return;
23697
+ const p = source.getChainMarkets(chainId).then((fresh2) => {
23698
+ if (!fresh2) return;
23030
23699
  const nowSec9 = Math.floor(Date.now() / 1e3);
23031
- const live = fresh.filter((m) => m.config.maturity > nowSec9);
23700
+ const live = fresh2.filter((m) => m.config.maturity > nowSec9);
23032
23701
  lastGood3.set(chainId, { markets: live, at: nowSec9 });
23033
23702
  rememberMarkets(chainId, live);
23034
23703
  }).catch(() => void 0).finally(() => refreshInFlight.delete(chainId));
@@ -28930,439 +29599,6 @@ var buildAaveV2UserCall = (chainId, lender, account) => {
28930
29599
  }
28931
29600
  }
28932
29601
  };
28933
- var MULTICALL_DEFAULT_BATCH_SIZE = 4096;
28934
- var CELO_MULTICALL_ADDRESS = "0x633987602DE5C4F337e3DbF265303A1080324204";
28935
- var BNB_MULTICALL_ADDRESS = "0x963Df249eD09c358A4819E39d9Cd5736c3087184";
28936
- var MANTLE_MULTICALL_ADDRESS = "0x2A51f2F647E1883F88C992244dEd171238693107";
28937
- var ARBITRUM_ONE_MULTICALL_ADDRESS = "0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB";
28938
- var LINEA_MULTICALL_ADDRESS = "0xac1cE734566f390A94b00eb9bf561c2625BF44ea";
28939
- var AVALANCHE_MULTICALL_ADDRESS = "0x0139141Cd4Ee88dF3Cdb65881D411bAE271Ef0C2";
28940
- var BASE_MULTICALL_ADDRESS = "0x091e99cb1C49331a94dD62755D168E941AbD0693";
28941
- var BLAST_MULTICALL_ADDRESS = "0xdC7f370de7631cE9e2c2e1DCDA6B3B5744Cf4705";
28942
- var TAIKO_MULTICALL_ADDRESS = "0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201";
28943
- var HEMI_MULTICALL_ADDRESS = "0x352A86168e6988A1aDF9A15Cb00017AAd3B67155";
28944
- var GNOSIS_MULTICALL_ADDRESS = "0x4dfa9a980efE4802E969AC33968E3d6E59B8a19e";
28945
- var MODE_MULTICALL_ADDRESS = "0xAB39cE30D98a59DFDa40A630b074170800bfF179";
28946
- var FANTOM_MULTICALL_ADDRESS = "0xDb51CffFf3B989d0cB6b58AbF173371b6F2d0D24";
28947
- var SCROLL_MULTICALL_ADDRESS = "0x3b615B1AC55bc34e51a81D3dea67467F32bcb8C2";
28948
- var SHAPE_MULTICALL_ADDRESS = "0x356A450B32f5030ae7083702b86FaFbBe7490411";
28949
- var SONIC_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
28950
- var INK_MULTICALL_ADDRESS = "0xA0fCec583AeE6176527C07B198e5561722332014";
28951
- var METIS_MULTICALL_ADDRESS = "0x7a59ddbB76521E8982Fa3A08598C9a83b14A6C07";
28952
- var IOTA_MULTICALL_ADDRESS = "0x9683D433621A83aA7dd290106e1da85251317F55";
28953
- var KAVA_MULTICALL_ADDRESS = "0x8B741B0D79BE80E135C880F7583d427B4D41F015";
28954
- var SAGA_MULTICALL_ADDRESS = "0x743E03cceB4af2efA3CC76838f6E8B50B63F184c";
28955
- var CYBER_MULTICALL_ADDRESS = "0x906d6eB9CF8f64e100e44f8f491b833a8d40B530";
28956
- var METAL_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
28957
- var ZERO_MULTICALL_ADDRESS = "0x9CA4dcb2505fbf536F6c54AA0a77C79f4fBC35C0";
28958
- var BOB_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
28959
- var WORLDCHAIN_MULTICALL_ADDRESS = "0x0a22c04215c97E3F532F4eF30e0aD9458792dAB9";
28960
- var LISK_MULTICALL_ADDRESS = "0xE3dbcD53f4Ce1b06Ab200f4912BD35672e68f1FA";
28961
- var REDSTONE_MULTICALL_ADDRESS = "0xd57B52452a0FDfE3ff8e0A40Bd10D00D0bfe0723";
28962
- var MANTA_MULTICALL_ADDRESS = "0x52dFC0D9960F11A9Ca9FF616e791B91188446a60";
28963
- var ZORA_MULTICALL_ADDRESS = "0xA51c76bEE6746cB487a7e9312E43e2b8f4A37C15";
28964
- var CORE_MULTICALL_ADDRESS = "0xFe9F82D820757787895Da00B1dBD35c3B8b04894";
28965
- var MORPH_MULTICALL_ADDRESS = "0xAcD82113982479B25E7c1D09858F0130921Dbbca";
28966
- var TELOS_MULTICALL_ADDRESS = "0x5d6b0f5335ec95cD2aB7E52f2A0750dd86502435";
28967
- var MULTICALL_ADDRESS = {
28968
- [Chain.OP_MAINNET]: "0x1F98415757620B543A52E61c46B32eB19261F984",
28969
- [Chain.POLYGON_MAINNET]: "0x1F98415757620B543A52E61c46B32eB19261F984",
28970
- [Chain.ETHEREUM_MAINNET]: "0x1F98415757620B543A52E61c46B32eB19261F984",
28971
- [Chain.ARBITRUM_ONE]: ARBITRUM_ONE_MULTICALL_ADDRESS,
28972
- [Chain.BASE]: BASE_MULTICALL_ADDRESS,
28973
- [Chain.CELO_MAINNET]: CELO_MULTICALL_ADDRESS,
28974
- [Chain.BNB_SMART_CHAIN_MAINNET]: BNB_MULTICALL_ADDRESS,
28975
- [Chain.MANTLE]: MANTLE_MULTICALL_ADDRESS,
28976
- [Chain.BLAST]: BLAST_MULTICALL_ADDRESS,
28977
- [Chain.LINEA]: LINEA_MULTICALL_ADDRESS,
28978
- [Chain.AVALANCHE_C_CHAIN]: AVALANCHE_MULTICALL_ADDRESS,
28979
- [Chain.TAIKO_ALETHIA]: TAIKO_MULTICALL_ADDRESS,
28980
- [Chain.HEMI_NETWORK]: HEMI_MULTICALL_ADDRESS,
28981
- [Chain.GNOSIS]: GNOSIS_MULTICALL_ADDRESS,
28982
- [Chain.CORE_BLOCKCHAIN_MAINNET]: CORE_MULTICALL_ADDRESS,
28983
- [Chain.METIS_ANDROMEDA_MAINNET]: METIS_MULTICALL_ADDRESS,
28984
- [Chain.MODE]: MODE_MULTICALL_ADDRESS,
28985
- [Chain.INK]: INK_MULTICALL_ADDRESS,
28986
- [Chain.IOTA_EVM]: IOTA_MULTICALL_ADDRESS,
28987
- [Chain.SONIC_MAINNET]: SONIC_MULTICALL_ADDRESS,
28988
- [Chain.FANTOM_OPERA]: FANTOM_MULTICALL_ADDRESS,
28989
- [Chain.SCROLL]: SCROLL_MULTICALL_ADDRESS,
28990
- [Chain.SHAPE]: SHAPE_MULTICALL_ADDRESS,
28991
- [Chain.CYBER_MAINNET]: CYBER_MULTICALL_ADDRESS,
28992
- [Chain.ZORA]: ZORA_MULTICALL_ADDRESS,
28993
- [Chain.MANTA_PACIFIC_MAINNET]: MANTA_MULTICALL_ADDRESS,
28994
- [Chain.REDSTONE]: REDSTONE_MULTICALL_ADDRESS,
28995
- [Chain.KAVA]: KAVA_MULTICALL_ADDRESS,
28996
- [Chain.METAL_L2]: METAL_MULTICALL_ADDRESS,
28997
- [Chain.LISK]: LISK_MULTICALL_ADDRESS,
28998
- [Chain.BOB]: BOB_MULTICALL_ADDRESS,
28999
- [Chain.ZERO_NETWORK]: ZERO_MULTICALL_ADDRESS,
29000
- [Chain.SAGA]: SAGA_MULTICALL_ADDRESS,
29001
- [Chain.MORPH]: MORPH_MULTICALL_ADDRESS,
29002
- [Chain.TELOS_EVM_MAINNET]: TELOS_MULTICALL_ADDRESS,
29003
- [Chain.WORLD_CHAIN]: WORLDCHAIN_MULTICALL_ADDRESS
29004
- };
29005
-
29006
- // src/utils/multicall.ts
29007
- var { isArray } = lodash;
29008
- var maxRetries = 3;
29009
- var MULTICALL_FAILURE = "0x";
29010
- var isFailedCall = (value) => value === void 0 || value === null || value === MULTICALL_FAILURE;
29011
- var MULTICALL_REPAIR_ROUNDS = 3;
29012
- var MAX_CALLS_PER_SHARD = 300;
29013
- var ONE_REQUEST_BATCH_BYTES = 1e6;
29014
- var MAX_INFLIGHT_REQUESTS = 6;
29015
- var HEDGE_DELAY_MS = 1200;
29016
- var SHARD_TIMEOUT_MS = 4e3;
29017
- var MIN_ADAPTIVE_SHARD = 25;
29018
- var ADAPTIVE_CAP_TTL_MS = 6e4;
29019
- var endpointCallCap = /* @__PURE__ */ new Map();
29020
- var capFor = (url, requested) => {
29021
- const hit = endpointCallCap.get(url);
29022
- if (!hit) return requested;
29023
- if (Date.now() - hit.at > ADAPTIVE_CAP_TTL_MS) {
29024
- endpointCallCap.delete(url);
29025
- return requested;
29026
- }
29027
- return Math.min(requested, hit.calls);
29028
- };
29029
- var noteEndpointRefusal = (url, calls) => {
29030
- if (calls <= MIN_ADAPTIVE_SHARD) return;
29031
- const next = Math.max(MIN_ADAPTIVE_SHARD, Math.floor(calls / 2));
29032
- const current = endpointCallCap.get(url);
29033
- if (current && Date.now() - current.at <= ADAPTIVE_CAP_TTL_MS && current.calls <= next)
29034
- return;
29035
- endpointCallCap.set(url, { calls: next, at: Date.now() });
29036
- };
29037
- var DETERMINISTIC_ERROR_NAMES = /* @__PURE__ */ new Set([
29038
- "ContractFunctionRevertedError",
29039
- "RawContractError",
29040
- "AbiDecodingZeroDataError",
29041
- "AbiDecodingDataSizeTooSmallError",
29042
- "AbiFunctionNotFoundError"
29043
- ]);
29044
- var isDeterministicCallError = (error) => {
29045
- let err = error;
29046
- for (let depth = 0; err && depth < 8; depth++) {
29047
- if (DETERMINISTIC_ERROR_NAMES.has(err.name)) return true;
29048
- const message = String(err.shortMessage ?? err.message ?? "").toLowerCase();
29049
- if (message.includes("execution reverted") || message.includes("returned no data"))
29050
- return true;
29051
- err = err.cause;
29052
- }
29053
- return false;
29054
- };
29055
- var REPAIR_BACKOFF_BASE_MS = 100;
29056
- var REPAIR_BACKOFF_JITTER_MS = 60;
29057
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
29058
- var backoffForRound = (round) => REPAIR_BACKOFF_BASE_MS * 2 ** round + Math.random() * REPAIR_BACKOFF_JITTER_MS;
29059
- var endpointUrl = (client, rpcId) => client?.transport?.url ?? `rpc#${rpcId}`;
29060
- var resolveEndpoint = (chainId, getEvmClient17, startRpcId, tried, maxProbe = 12, timeoutMs) => {
29061
- let fallback = null;
29062
- for (let probe = 0; probe < maxProbe; probe++) {
29063
- const rpcId = startRpcId + probe;
29064
- let client;
29065
- try {
29066
- client = getEvmClient17(chainId, rpcId, { timeoutMs });
29067
- } catch {
29068
- break;
29069
- }
29070
- const url = endpointUrl(client, rpcId);
29071
- if (!tried?.has(url)) {
29072
- tried?.add(url);
29073
- return { client, rpcId, url, reused: false };
29074
- }
29075
- fallback ??= { client, rpcId, url, reused: true };
29076
- }
29077
- return fallback;
29078
- };
29079
- var toSlots = (returnData, allowFailure) => {
29080
- if (!allowFailure)
29081
- return returnData.map((value) => ({ value, permanent: false }));
29082
- return returnData.map(
29083
- ({ result, status, error }) => status === "success" ? { value: result, permanent: false } : {
29084
- value: MULTICALL_FAILURE,
29085
- permanent: isDeterministicCallError(error)
29086
- }
29087
- );
29088
- };
29089
- var recordPermanentFailures = (slots, offset, collector) => {
29090
- if (!collector) return;
29091
- for (let i = 0; i < slots.length; i++) {
29092
- if (slots[i].permanent) collector.add(offset + i);
29093
- }
29094
- };
29095
- var repairFailedSlots = async (chainId, contracts, slots, getEvmClient17, nextRpcId, batchSize, logs, rounds = MULTICALL_REPAIR_ROUNDS, options) => {
29096
- let searchFrom = nextRpcId;
29097
- for (let round = 0; round < rounds; round++) {
29098
- const failedIdx = [];
29099
- for (let i = 0; i < slots.length; i++) {
29100
- if (isFailedCall(slots[i].value) && !slots[i].permanent) failedIdx.push(i);
29101
- }
29102
- if (failedIdx.length === 0) return slots;
29103
- const endpoint = resolveEndpoint(
29104
- chainId,
29105
- getEvmClient17,
29106
- searchFrom,
29107
- options?.tried
29108
- );
29109
- if (!endpoint) {
29110
- if (logs)
29111
- console.log(
29112
- `multicall repair: no usable endpoint for chain ${chainId}, giving up with ${failedIdx.length} failed slots`
29113
- );
29114
- return slots;
29115
- }
29116
- searchFrom = endpoint.rpcId + 1;
29117
- await sleep(backoffForRound(round));
29118
- try {
29119
- const returnData = await endpoint.client.multicall({
29120
- allowFailure: true,
29121
- batchSize,
29122
- contracts: failedIdx.map((i) => contracts[i])
29123
- });
29124
- let repaired = 0;
29125
- returnData.forEach((entry, k) => {
29126
- const idx = failedIdx[k];
29127
- if (entry?.status === "success") {
29128
- slots[idx] = { value: entry.result, permanent: false };
29129
- repaired++;
29130
- } else if (isDeterministicCallError(entry?.error)) {
29131
- slots[idx].permanent = true;
29132
- }
29133
- });
29134
- if (repaired === 0)
29135
- options?.onEndpointFailure?.({
29136
- chainId,
29137
- url: endpoint.url,
29138
- rpcId: endpoint.rpcId,
29139
- kind: "slots"
29140
- });
29141
- } catch (error) {
29142
- options?.onEndpointFailure?.({
29143
- chainId,
29144
- url: endpoint.url,
29145
- rpcId: endpoint.rpcId,
29146
- kind: "transport"
29147
- });
29148
- if (logs)
29149
- console.log(
29150
- `error in multicall failure-repair round ${round} chain ${chainId}`,
29151
- error
29152
- );
29153
- }
29154
- }
29155
- return slots;
29156
- };
29157
- var multicallShardedAbiArray = async (chainId, abi, calls, getEvmClient17, poolSize, retries = maxRetries, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, logs = false, retryFailed = false, permanentFailures, options) => {
29158
- const abiIsArray = isArray(abi[0]);
29159
- const contracts = calls.map(({ address, name, params }, i) => ({
29160
- abi: abiIsArray ? abi?.[i] : abi,
29161
- address,
29162
- functionName: name,
29163
- args: params
29164
- }));
29165
- const requestBytes = batchSize < MULTICALL_DEFAULT_BATCH_SIZE ? batchSize : ONE_REQUEST_BATCH_BYTES;
29166
- const workerBudget = Math.max(1, Math.floor(MAX_INFLIGHT_REQUESTS / 2));
29167
- const workers = Math.max(1, Math.min(poolSize, workerBudget));
29168
- const shardSize = Math.max(
29169
- 1,
29170
- Math.min(MAX_CALLS_PER_SHARD, Math.ceil(contracts.length / workers))
29171
- );
29172
- const batches = [];
29173
- for (let i = 0; i < contracts.length; i += shardSize) {
29174
- batches.push({ start: i, items: contracts.slice(i, i + shardSize) });
29175
- }
29176
- const results = new Array(contracts.length);
29177
- const request = async (endpoint, items) => {
29178
- try {
29179
- const returnData = await endpoint.client.multicall({
29180
- allowFailure,
29181
- batchSize: requestBytes,
29182
- contracts: items
29183
- });
29184
- const slots = toSlots(returnData, allowFailure);
29185
- if (allowFailure && slots.length > 0 && slots.every((s) => isFailedCall(s.value) && !s.permanent)) {
29186
- if (logs)
29187
- console.log(
29188
- `sharded multicall: rpc ${endpoint.rpcId} answered ${items.length} calls with nothing`
29189
- );
29190
- options?.onEndpointFailure?.({
29191
- chainId,
29192
- url: endpoint.url,
29193
- rpcId: endpoint.rpcId,
29194
- kind: "slots"
29195
- });
29196
- noteEndpointRefusal(endpoint.url, items.length);
29197
- return null;
29198
- }
29199
- return slots;
29200
- } catch (error) {
29201
- if (logs) console.log("error in sharded multicall request", error);
29202
- options?.onEndpointFailure?.({
29203
- chainId,
29204
- url: endpoint.url,
29205
- rpcId: endpoint.rpcId,
29206
- kind: "transport"
29207
- });
29208
- noteEndpointRefusal(endpoint.url, items.length);
29209
- return null;
29210
- }
29211
- };
29212
- const firstUsable = (attempts) => new Promise((resolve) => {
29213
- let pending = attempts.length;
29214
- let settled = false;
29215
- const lose = () => {
29216
- if (!settled && --pending === 0) resolve(null);
29217
- };
29218
- for (const attempt of attempts) {
29219
- attempt.then((won) => {
29220
- if (settled) return;
29221
- if (won) {
29222
- settled = true;
29223
- resolve(won);
29224
- } else lose();
29225
- }, lose);
29226
- }
29227
- });
29228
- const attemptHedged = async (items, startRpcId, tried) => {
29229
- const primary = resolveEndpoint(
29230
- chainId,
29231
- getEvmClient17,
29232
- startRpcId,
29233
- tried,
29234
- 12,
29235
- SHARD_TIMEOUT_MS
29236
- );
29237
- if (!primary) {
29238
- if (logs)
29239
- console.log(
29240
- `sharded multicall: no untried endpoint left for chain ${chainId}`
29241
- );
29242
- return null;
29243
- }
29244
- let timer;
29245
- let hedgeStarted = false;
29246
- let beginHedge = () => {
29247
- };
29248
- const hedged = new Promise((resolve) => {
29249
- beginHedge = () => {
29250
- if (hedgeStarted) return;
29251
- hedgeStarted = true;
29252
- clearTimeout(timer);
29253
- const alt = resolveEndpoint(
29254
- chainId,
29255
- getEvmClient17,
29256
- primary.rpcId + 1,
29257
- tried,
29258
- 12,
29259
- SHARD_TIMEOUT_MS
29260
- );
29261
- if (!alt) return resolve(null);
29262
- const altItems = items.slice(0, capFor(alt.url, items.length));
29263
- if (altItems.length < items.length) return resolve(null);
29264
- request(alt, items).then(
29265
- (slots) => resolve(slots ? { slots, rpcId: alt.rpcId } : null)
29266
- );
29267
- };
29268
- });
29269
- timer = setTimeout(() => beginHedge(), HEDGE_DELAY_MS);
29270
- const direct = request(primary, items).then((slots) => {
29271
- if (slots) return { slots, rpcId: primary.rpcId };
29272
- beginHedge();
29273
- return null;
29274
- });
29275
- const won = await firstUsable([direct, hedged]);
29276
- clearTimeout(timer);
29277
- return won;
29278
- };
29279
- const runBatch = async (batch, rpcId, attemptsLeft, tried) => {
29280
- if (!batch.items.length) return;
29281
- const won = await attemptHedged(batch.items, rpcId, tried);
29282
- if (!won) {
29283
- if (attemptsLeft > 0 && batch.items.length > 1) {
29284
- const half = Math.ceil(batch.items.length / 2);
29285
- await sleep(backoffForRound(0));
29286
- await runBatch(
29287
- { start: batch.start, items: batch.items.slice(0, half) },
29288
- rpcId,
29289
- attemptsLeft - 1,
29290
- tried
29291
- );
29292
- await runBatch(
29293
- { start: batch.start + half, items: batch.items.slice(half) },
29294
- rpcId + 1,
29295
- attemptsLeft - 1,
29296
- tried
29297
- );
29298
- }
29299
- return;
29300
- }
29301
- let slots = won.slots;
29302
- if (allowFailure && retryFailed) {
29303
- slots = await repairFailedSlots(
29304
- chainId,
29305
- batch.items,
29306
- slots,
29307
- getEvmClient17,
29308
- won.rpcId + 1,
29309
- requestBytes,
29310
- logs,
29311
- MULTICALL_REPAIR_ROUNDS,
29312
- { tried, onEndpointFailure: options?.onEndpointFailure }
29313
- );
29314
- }
29315
- recordPermanentFailures(slots, batch.start, permanentFailures);
29316
- for (let j = 0; j < slots.length; j++) {
29317
- results[batch.start + j] = slots[j].value;
29318
- }
29319
- };
29320
- let cursor = 0;
29321
- const worker = async (workerId) => {
29322
- while (true) {
29323
- const idx = cursor++;
29324
- if (idx >= batches.length) break;
29325
- const batch = batches[idx];
29326
- const tried = /* @__PURE__ */ new Set();
29327
- const start = resolveEndpoint(
29328
- chainId,
29329
- getEvmClient17,
29330
- workerId,
29331
- void 0,
29332
- 12,
29333
- SHARD_TIMEOUT_MS
29334
- );
29335
- const cap = start ? capFor(start.url, batch.items.length) : batch.items.length;
29336
- for (let off = 0; off < batch.items.length; off += cap) {
29337
- await runBatch(
29338
- {
29339
- start: batch.start + off,
29340
- items: batch.items.slice(off, off + cap)
29341
- },
29342
- workerId,
29343
- retries,
29344
- tried
29345
- );
29346
- }
29347
- }
29348
- };
29349
- await Promise.all(
29350
- Array.from(
29351
- { length: Math.min(workers, batches.length) },
29352
- (_3, w) => worker(w)
29353
- )
29354
- );
29355
- return results;
29356
- };
29357
- function prepareMulticallInputs(abi, calls) {
29358
- const abiIsArray = isArray(abi[0]);
29359
- return calls.map(({ address, name, params }, i) => ({
29360
- address,
29361
- functionName: name,
29362
- params: params || [],
29363
- abi: abiIsArray ? abi[i] : abi
29364
- }));
29365
- }
29366
29602
  var POSITION_LENS_V6 = "0x110ff05D2822DBBe1a5404d2a485267e2Ed962C6";
29367
29603
  var LENS_FAMILY = {
29368
29604
  COMPOUND_V2: 1,
@@ -41649,7 +41885,7 @@ function unflattenLenderData(pools) {
41649
41885
  }
41650
41886
  return result;
41651
41887
  }
41652
- var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient17, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, retries = 3, logs = false, concurrency = 1, permanentFailures, onEndpointFailure) => {
41888
+ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient18, allowFailure = true, batchSize = MULTICALL_DEFAULT_BATCH_SIZE, retries = 3, logs = false, concurrency = 1, permanentFailures, onEndpointFailure) => {
41653
41889
  const queries = organizeUserQueries(queriesRaw);
41654
41890
  const builtCalls = await Promise.all(
41655
41891
  queries.map(async (query3) => {
@@ -41659,7 +41895,7 @@ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient17, allowF
41659
41895
  query3.lender,
41660
41896
  query3.account,
41661
41897
  query3.params,
41662
- getEvmClient17
41898
+ getEvmClient18
41663
41899
  );
41664
41900
  return callData.map((call) => ({ call, abi: call.abi ?? abi }));
41665
41901
  })
@@ -41669,7 +41905,7 @@ var getLenderUserDataResult = async (chainId, queriesRaw, getEvmClient17, allowF
41669
41905
  chainId,
41670
41906
  calls.map((call) => call.abi),
41671
41907
  calls.map((call) => call.call),
41672
- getEvmClient17,
41908
+ getEvmClient18,
41673
41909
  concurrency,
41674
41910
  retries,
41675
41911
  allowFailure,
@@ -59358,7 +59594,7 @@ var fetchSiloVaults = async (chainId, prices = {}, tokenList = {}, options) => {
59358
59594
 
59359
59595
  // src/vaults/euler-earn/entityLabels.ts
59360
59596
  var LABELS_BASE = "https://raw.githubusercontent.com/euler-xyz/euler-labels/master";
59361
- var TTL_MS3 = 30 * 60 * 1e3;
59597
+ var TTL_MS4 = 30 * 60 * 1e3;
59362
59598
  var cache3 = /* @__PURE__ */ new Map();
59363
59599
  var inflight4 = /* @__PURE__ */ new Map();
59364
59600
  async function fetchChainEntities(chainId) {
@@ -59384,7 +59620,7 @@ async function fetchChainEntities(chainId) {
59384
59620
  }
59385
59621
  async function fetchEulerEntityNames(chainId) {
59386
59622
  const hit = cache3.get(chainId);
59387
- if (hit && Date.now() - hit.at <= TTL_MS3) return hit.map;
59623
+ if (hit && Date.now() - hit.at <= TTL_MS4) return hit.map;
59388
59624
  const running = inflight4.get(chainId);
59389
59625
  if (running) return running;
59390
59626
  const p = fetchChainEntities(chainId).then((map) => {