@1delta/margin-fetcher 0.0.339 → 0.0.341
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/abis/oracle/AaveOracle.d.ts +14 -0
- package/dist/abis/oracle/AaveOracle.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +625 -91
- package/dist/index.js.map +1 -1
- package/dist/prices/oracle-prices/derivation.d.ts +25 -0
- package/dist/prices/oracle-prices/derivation.d.ts.map +1 -0
- package/dist/prices/oracle-prices/feedStaleness.d.ts +44 -0
- package/dist/prices/oracle-prices/feedStaleness.d.ts.map +1 -0
- package/dist/prices/oracle-prices/feedStats.d.ts +145 -0
- package/dist/prices/oracle-prices/feedStats.d.ts.map +1 -0
- package/dist/prices/oracle-prices/fetchOraclePrices.d.ts +14 -2
- package/dist/prices/oracle-prices/fetchOraclePrices.d.ts.map +1 -1
- package/dist/prices/oracle-prices/fetchers/aave.d.ts +14 -0
- package/dist/prices/oracle-prices/fetchers/aave.d.ts.map +1 -1
- package/dist/prices/oracle-prices/fetchers/compoundV3.d.ts.map +1 -1
- package/dist/prices/oracle-prices/fetchers/euler.d.ts.map +1 -1
- package/dist/prices/oracle-prices/fetchers/morpho.d.ts.map +1 -1
- package/dist/prices/oracle-prices/index.d.ts +7 -2
- package/dist/prices/oracle-prices/index.d.ts.map +1 -1
- package/dist/prices/oracle-prices/lenderKeys.d.ts +18 -0
- package/dist/prices/oracle-prices/lenderKeys.d.ts.map +1 -0
- package/dist/prices/oracle-prices/outlierGuard.d.ts +43 -0
- package/dist/prices/oracle-prices/outlierGuard.d.ts.map +1 -0
- package/dist/prices/oracle-prices/selectAssetGroupPrices.d.ts +45 -4
- package/dist/prices/oracle-prices/selectAssetGroupPrices.d.ts.map +1 -1
- package/dist/prices/oracle-prices/types.d.ts +114 -1
- package/dist/prices/oracle-prices/types.d.ts.map +1 -1
- package/dist/prices/pendle/fetchPendlePrices.d.ts.map +1 -1
- package/dist/yields/intrinsic/fetcherRegistry.d.ts.map +1 -1
- package/dist/yields/intrinsic/fetchers/angle.d.ts.map +1 -1
- package/dist/yields/intrinsic/fetchers/anzen.d.ts +3 -0
- package/dist/yields/intrinsic/fetchers/anzen.d.ts.map +1 -0
- package/dist/yields/intrinsic/fetchers/liquidCollective.d.ts +3 -0
- package/dist/yields/intrinsic/fetchers/liquidCollective.d.ts.map +1 -0
- package/dist/yields/intrinsic/fetchers/reserve.d.ts.map +1 -1
- package/dist/yields/intrinsic/fetchers/stakewise.d.ts.map +1 -1
- package/dist/yields/intrinsic/fetchers/strata.d.ts +3 -0
- package/dist/yields/intrinsic/fetchers/strata.d.ts.map +1 -0
- package/dist/yields/intrinsic/fetchers/treehouse.d.ts +3 -0
- package/dist/yields/intrinsic/fetchers/treehouse.d.ts.map +1 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import './chunk-BYTNVMX7.js';
|
|
|
3
3
|
import './chunk-PR4QN5HX.js';
|
|
4
4
|
import { Lender, LIQUITY_FAMILY_LENDERS, isAaveType, isCompoundV3, isMultiMarket, isSiloV2Type, isSiloV3Type, isDolomite, isEulerType, isAaveV4Type, isInit, isMorphoType, isCompoundV2Type, isVenusType, isSumerType, AAVE_V3_LENDERS, AAVE_V2_LENDERS, isAaveV2Type, isAaveV32Type, isAaveV3Type, isFluid, isGearboxV3, isMidnight, isTerm, isExactly, isLiquityFamily, isRiver, isTeller, isYLDR, isCompoundV3Type, isLista, isTectonicType, isKineticType, isBenqiType } from '@1delta/lender-registry';
|
|
5
5
|
export { 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, tellerConfigByChain, tellerPoolsByChain, aaveReserves, compoundV3Reserves, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, morphoTypeMarkets, resolveMidnightApiBase, resolveTermApiBase, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, aaveTokens, morphoTypeVaults, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxV3LenderKey, midnightMarketsByChain, parseAaveV4SpokeLenderKey, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain,
|
|
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, tellerConfigByChain, tellerPoolsByChain, aaveReserves, compoundV3Reserves, liquityConfigFor, liquityBranchesByChain, riverConfigFor, riverChainData, aaveOracles, morphoTypeMarkets, resolveMidnightApiBase, resolveTermApiBase, getSiloV2MarketEntry, getSiloV3MarketEntry, dolomiteEmode, aaveTokens, morphoTypeVaults, eulerConfigs, gearboxMarketCompressor, gearboxMarketConfigurators, gearboxV3LenderKey, midnightMarketsByChain, parseAaveV4SpokeLenderKey, gearboxAccountCompressor, compoundV2Tokens, exactlyMarketsByChain, aaveOraclesConfig, compoundV2Oracles, compoundV2TokenArray, compoundV2OraclesConfig, compoundV3OraclesData, compoundV3BaseData, compoundV2Reserves, aaveV4Oracles } from '@1delta/data-sdk';
|
|
7
7
|
import lodash from 'lodash';
|
|
8
8
|
import { getEvmClient, multicallRetryUniversal, getEvmChain, getEvmClientUniversal } from '@1delta/providers';
|
|
9
9
|
import { LiquityTroveManagerAbi, LiquityActivePoolAbi, LiquityStabilityPoolAbi, LiquityPriceFeedAbi, LiquitySortedTrovesAbi, RiverTroveManagerAbi, RiverStabilityPoolAbi, TellerMarketRegistryAbi, TellerV2Abi, MetaMorphoAbi, ExactlyPreviewerAbi, ExactlyAuditorAbi, LenderCommitmentGroupAbi, FluidLendingResolverAbi, FluidVaultResolverAbi, FluidLiquidityResolverAbi, MoolahVaultAbi, MorphoLensAbi, AaveV4SpokeAbi, AaveV4OracleAbi, AaveV4HubAbi, DolomiteMarginAbi, GearboxMarketCompressorV310Abi, MorphoBlueAbi, MidnightAbi, TermRepoTokenAbi, TermRepoServicerAbi, TermRepoCollateralManagerAbi, LiquityTroveNFTAbi, LiquityCollSurplusPoolAbi, TellerCollateralManagerAbi, GearboxCreditAccountCompressorV310Abi, TermPriceConsumerAbi } from '@1delta/abis';
|
|
@@ -35208,7 +35208,12 @@ var osethFetcher = {
|
|
|
35208
35208
|
operationName: "osTokenApy"
|
|
35209
35209
|
})
|
|
35210
35210
|
}).then((r) => r.json());
|
|
35211
|
-
|
|
35211
|
+
const apr = apyToAprPercent(res.data?.osTokens?.[0]?.apy);
|
|
35212
|
+
return {
|
|
35213
|
+
[osETH]: apr,
|
|
35214
|
+
// token-lists unifies every osETH deployment (incl. bridged) to the bare `OSETH` group — emit there too.
|
|
35215
|
+
OSETH: apr
|
|
35216
|
+
};
|
|
35212
35217
|
}
|
|
35213
35218
|
};
|
|
35214
35219
|
|
|
@@ -37550,6 +37555,8 @@ var angleFetcher = {
|
|
|
37550
37555
|
label: "ANGLE",
|
|
37551
37556
|
fetch: async () => ({
|
|
37552
37557
|
[stEur]: 0,
|
|
37558
|
+
// token-lists unifies every stEUR deployment to the bare `STEUR` group — emit there too.
|
|
37559
|
+
STEUR: 0,
|
|
37553
37560
|
[stUSD]: 0
|
|
37554
37561
|
})
|
|
37555
37562
|
};
|
|
@@ -38298,10 +38305,13 @@ var rtokensFetcher = {
|
|
|
38298
38305
|
const data = res?.rtokens?.["8453"];
|
|
38299
38306
|
const dataMainnet = res?.rtokens?.["1"];
|
|
38300
38307
|
const dataMainnetColalterals = res?.collaterals?.["1"];
|
|
38308
|
+
const sfrxethApr = apyToAprPercent((dataMainnetColalterals?.sfrxeth ?? 0) / 100) * 100;
|
|
38301
38309
|
return {
|
|
38302
38310
|
[bsdETH]: apyToAprPercent((data?.bsdETH ?? 0) / 100) * 100,
|
|
38303
38311
|
[hyUSD]: apyToAprPercent((data?.hyUSD ?? 0) / 100) * 100,
|
|
38304
|
-
[sfrxeth]:
|
|
38312
|
+
[sfrxeth]: sfrxethApr,
|
|
38313
|
+
// token-lists unifies every sfrxETH deployment to the bare `SFRXETH` group — emit there too.
|
|
38314
|
+
SFRXETH: sfrxethApr,
|
|
38305
38315
|
[sfrax]: apyToAprPercent((dataMainnetColalterals?.sfrax ?? 0) / 100) * 100,
|
|
38306
38316
|
[ceth]: apyToAprPercent((dataMainnetColalterals?.ceth ?? 0) / 100) * 100,
|
|
38307
38317
|
[ethPlus]: apyToAprPercent((dataMainnet?.["ETH+"] ?? 0) / 100) * 100,
|
|
@@ -38462,7 +38472,8 @@ async function fetchPendleYields(lists = {}) {
|
|
|
38462
38472
|
const ptPrice = prices[market.pt];
|
|
38463
38473
|
const ytPrice = prices[market.yt];
|
|
38464
38474
|
const [chainId, address] = market.pt.split("-");
|
|
38465
|
-
const assetKey = lists[chainId]?.list?.[address.toLowerCase()]?.assetGroup
|
|
38475
|
+
const assetKey = lists[chainId]?.list?.[address.toLowerCase()]?.assetGroup;
|
|
38476
|
+
if (!assetKey) return;
|
|
38466
38477
|
const expiry = new Date(market.expiry);
|
|
38467
38478
|
if (expiry <= now) {
|
|
38468
38479
|
yields[assetKey] = 0;
|
|
@@ -38817,6 +38828,50 @@ var yearnKatanaFetcher = {
|
|
|
38817
38828
|
}
|
|
38818
38829
|
};
|
|
38819
38830
|
|
|
38831
|
+
// src/yields/intrinsic/fetchers/liquidCollective.ts
|
|
38832
|
+
var LSETH_POOL_ID = "465d177e-3d0d-42c0-b5f5-31c857567135";
|
|
38833
|
+
var KEYS = ["Liquid Staked ETH::LSETH", "LSETH"];
|
|
38834
|
+
var lsethFetcher = {
|
|
38835
|
+
label: "LSETH",
|
|
38836
|
+
fetch: async () => {
|
|
38837
|
+
const apr = apyToAprPercent(await fetchDefiLlamaApy(LSETH_POOL_ID));
|
|
38838
|
+
return Object.fromEntries(KEYS.map((k) => [k, apr]));
|
|
38839
|
+
}
|
|
38840
|
+
};
|
|
38841
|
+
|
|
38842
|
+
// src/yields/intrinsic/fetchers/treehouse.ts
|
|
38843
|
+
var TETH_POOL_ID = "5762f4a8-bb48-45d6-90ed-2d93d1777169";
|
|
38844
|
+
var KEYS2 = ["Treehouse ETH::tETH"];
|
|
38845
|
+
var tethFetcher = {
|
|
38846
|
+
label: "TETH",
|
|
38847
|
+
fetch: async () => {
|
|
38848
|
+
const apr = apyToAprPercent(await fetchDefiLlamaApy(TETH_POOL_ID));
|
|
38849
|
+
return Object.fromEntries(KEYS2.map((k) => [k, apr]));
|
|
38850
|
+
}
|
|
38851
|
+
};
|
|
38852
|
+
|
|
38853
|
+
// src/yields/intrinsic/fetchers/strata.ts
|
|
38854
|
+
var SRNUSD_POOL_ID = "979711ce-d0c0-4aae-a5fc-d7b76e868649";
|
|
38855
|
+
var KEYS3 = ["Strata Senior NUSD::srNUSD"];
|
|
38856
|
+
var srnusdFetcher = {
|
|
38857
|
+
label: "SRNUSD",
|
|
38858
|
+
fetch: async () => {
|
|
38859
|
+
const apr = apyToAprPercent(await fetchDefiLlamaApy(SRNUSD_POOL_ID));
|
|
38860
|
+
return Object.fromEntries(KEYS3.map((k) => [k, apr]));
|
|
38861
|
+
}
|
|
38862
|
+
};
|
|
38863
|
+
|
|
38864
|
+
// src/yields/intrinsic/fetchers/anzen.ts
|
|
38865
|
+
var SUSDZ_POOL_ID = "46518e93-8197-4539-9861-2340c2ac965a";
|
|
38866
|
+
var KEYS4 = ["Anzen Staked USDz::SUSDZ", "Anzen Staked USDz::sUSDz", "Staked USDz::sUSDz"];
|
|
38867
|
+
var susdzFetcher = {
|
|
38868
|
+
label: "SUSDZ",
|
|
38869
|
+
fetch: async () => {
|
|
38870
|
+
const apr = apyToAprPercent(await fetchDefiLlamaApy(SUSDZ_POOL_ID));
|
|
38871
|
+
return Object.fromEntries(KEYS4.map((k) => [k, apr]));
|
|
38872
|
+
}
|
|
38873
|
+
};
|
|
38874
|
+
|
|
38820
38875
|
// src/yields/intrinsic/fetcherRegistry.ts
|
|
38821
38876
|
var LENDING_ONLY_FETCHERS = [
|
|
38822
38877
|
stmaticFetcher,
|
|
@@ -38842,7 +38897,12 @@ var LENDING_ONLY_FETCHERS = [
|
|
|
38842
38897
|
nestFetcher,
|
|
38843
38898
|
accountableFetcher,
|
|
38844
38899
|
upshiftFetcher,
|
|
38845
|
-
yearnKatanaFetcher
|
|
38900
|
+
yearnKatanaFetcher,
|
|
38901
|
+
// DefiLlama-mapped intrinsic yields for classifier assets lacking a bespoke source
|
|
38902
|
+
lsethFetcher,
|
|
38903
|
+
tethFetcher,
|
|
38904
|
+
srnusdFetcher,
|
|
38905
|
+
susdzFetcher
|
|
38846
38906
|
];
|
|
38847
38907
|
var collectVaultFetchers = () => {
|
|
38848
38908
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -39215,6 +39275,25 @@ var AaveOracleAbi = [
|
|
|
39215
39275
|
],
|
|
39216
39276
|
stateMutability: "view",
|
|
39217
39277
|
type: "function"
|
|
39278
|
+
},
|
|
39279
|
+
{
|
|
39280
|
+
inputs: [
|
|
39281
|
+
{
|
|
39282
|
+
internalType: "address",
|
|
39283
|
+
name: "asset",
|
|
39284
|
+
type: "address"
|
|
39285
|
+
}
|
|
39286
|
+
],
|
|
39287
|
+
name: "getSourceOfAsset",
|
|
39288
|
+
outputs: [
|
|
39289
|
+
{
|
|
39290
|
+
internalType: "address",
|
|
39291
|
+
name: "",
|
|
39292
|
+
type: "address"
|
|
39293
|
+
}
|
|
39294
|
+
],
|
|
39295
|
+
stateMutability: "view",
|
|
39296
|
+
type: "function"
|
|
39218
39297
|
}
|
|
39219
39298
|
];
|
|
39220
39299
|
|
|
@@ -39571,6 +39650,8 @@ function processMarketsToEntries(chainId, allMarkets, source) {
|
|
|
39571
39650
|
) : 0;
|
|
39572
39651
|
const resolvedLoanUSD = loanPriceUSD != null && loanPriceUSD > 0 ? loanPriceUSD : collateralPriceUSD != null && collateralPriceUSD > 0 && oracleRatio > 0 ? collateralPriceUSD / oracleRatio : 0;
|
|
39573
39652
|
const resolvedCollateralUSD = collateralPriceUSD != null && collateralPriceUSD > 0 ? collateralPriceUSD : loanPriceUSD != null && loanPriceUSD > 0 && oracleRatio > 0 ? oracleRatio * loanPriceUSD : 0;
|
|
39653
|
+
const collateralFromApi = collateralPriceUSD != null && collateralPriceUSD > 0;
|
|
39654
|
+
const loanFromApi = loanPriceUSD != null && loanPriceUSD > 0;
|
|
39574
39655
|
if (resolvedCollateralUSD > 0) {
|
|
39575
39656
|
entries.push({
|
|
39576
39657
|
asset: collateralAsset,
|
|
@@ -39579,7 +39660,8 @@ function processMarketsToEntries(chainId, allMarkets, source) {
|
|
|
39579
39660
|
priceUSD: resolvedCollateralUSD,
|
|
39580
39661
|
marketUid: createMarketUid(chainId, lenderKey, collateralAsset),
|
|
39581
39662
|
targetLender: lenderKey,
|
|
39582
|
-
baseAsset: loanAsset
|
|
39663
|
+
baseAsset: loanAsset,
|
|
39664
|
+
derivation: collateralFromApi ? "direct" : "derived"
|
|
39583
39665
|
});
|
|
39584
39666
|
}
|
|
39585
39667
|
if (resolvedLoanUSD > 0) {
|
|
@@ -39591,7 +39673,8 @@ function processMarketsToEntries(chainId, allMarkets, source) {
|
|
|
39591
39673
|
targetLender: lenderKey,
|
|
39592
39674
|
description: "Morpho loan asset",
|
|
39593
39675
|
staticBase: true,
|
|
39594
|
-
baseAsset: loanAsset
|
|
39676
|
+
baseAsset: loanAsset,
|
|
39677
|
+
derivation: loanFromApi ? "direct" : "derived"
|
|
39595
39678
|
});
|
|
39596
39679
|
}
|
|
39597
39680
|
}
|
|
@@ -40140,6 +40223,7 @@ var ChainlinkAggregatorAbi = [
|
|
|
40140
40223
|
}
|
|
40141
40224
|
];
|
|
40142
40225
|
var ANSWER_INDEX = 1;
|
|
40226
|
+
var UPDATED_AT_INDEX = 3;
|
|
40143
40227
|
var CHAINLINK_DECIMALS = 8;
|
|
40144
40228
|
var USD_PRICED_OVERRIDES = {
|
|
40145
40229
|
[Lender.COMPOUND_V3_AERO]: /* @__PURE__ */ new Set(["8453"]),
|
|
@@ -40211,6 +40295,7 @@ function parseCompoundV3Results(data, meta, context) {
|
|
|
40211
40295
|
priceUSD = rawPrice * baseAssetUSD;
|
|
40212
40296
|
}
|
|
40213
40297
|
}
|
|
40298
|
+
const updatedAtRaw = Array.isArray(rawResult) ? Number(rawResult[UPDATED_AT_INDEX]) : 0;
|
|
40214
40299
|
entries.push({
|
|
40215
40300
|
asset: assetLc,
|
|
40216
40301
|
price: rawPrice,
|
|
@@ -40219,7 +40304,9 @@ function parseCompoundV3Results(data, meta, context) {
|
|
|
40219
40304
|
marketUid: createMarketUid(chainId, queryMeta.lender, queryMeta.asset),
|
|
40220
40305
|
description: queryMeta.description,
|
|
40221
40306
|
staticBase: queryMeta.staticBase || void 0,
|
|
40222
|
-
baseAsset: queryMeta.baseAsset
|
|
40307
|
+
baseAsset: queryMeta.baseAsset,
|
|
40308
|
+
updatedAt: updatedAtRaw > 0 ? updatedAtRaw : void 0,
|
|
40309
|
+
feedSource: updatedAtRaw > 0 ? queryMeta.oracle : void 0
|
|
40223
40310
|
});
|
|
40224
40311
|
} catch {
|
|
40225
40312
|
}
|
|
@@ -40467,12 +40554,15 @@ function parseEulerV2Results(data, meta, context) {
|
|
|
40467
40554
|
const priceInUoA = Number(amountOutMid) / Number(10n ** unitOfAccountDecimals);
|
|
40468
40555
|
if (isNaN(priceInUoA) || priceInUoA === 0) return;
|
|
40469
40556
|
let priceUSD;
|
|
40557
|
+
let derivation;
|
|
40470
40558
|
if (isUsdUnitOfAccount(unitOfAccount)) {
|
|
40471
40559
|
priceUSD = priceInUoA;
|
|
40560
|
+
derivation = "direct";
|
|
40472
40561
|
} else {
|
|
40473
40562
|
const uoaUSD = context.usdPrices[unitOfAccount] ?? 0;
|
|
40474
40563
|
if (uoaUSD === 0) return;
|
|
40475
40564
|
priceUSD = priceInUoA * uoaUSD;
|
|
40565
|
+
derivation = "quoted";
|
|
40476
40566
|
}
|
|
40477
40567
|
if (isNaN(priceUSD) || priceUSD === 0) return;
|
|
40478
40568
|
if (priceUSD > MAX_SANE_PRICE_USD) return;
|
|
@@ -40484,7 +40574,8 @@ function parseEulerV2Results(data, meta, context) {
|
|
|
40484
40574
|
context.chainId,
|
|
40485
40575
|
queryMeta.lender,
|
|
40486
40576
|
queryMeta.vault
|
|
40487
|
-
)
|
|
40577
|
+
),
|
|
40578
|
+
derivation
|
|
40488
40579
|
});
|
|
40489
40580
|
} catch {
|
|
40490
40581
|
}
|
|
@@ -41197,7 +41288,7 @@ function lookupUSD3(context, asset) {
|
|
|
41197
41288
|
return context.usdPrices[groupKey] ?? context.usdPrices[lc] ?? 0;
|
|
41198
41289
|
}
|
|
41199
41290
|
function parseSiloV2GraphQLResults(items, context) {
|
|
41200
|
-
const
|
|
41291
|
+
const ZERO_ADDRESS8 = "0x0000000000000000000000000000000000000000";
|
|
41201
41292
|
const out = [];
|
|
41202
41293
|
const seen = /* @__PURE__ */ new Set();
|
|
41203
41294
|
for (const item of items) {
|
|
@@ -41220,8 +41311,8 @@ function parseSiloV2GraphQLResults(items, context) {
|
|
|
41220
41311
|
const partnerTokenLc = other.token.toLowerCase();
|
|
41221
41312
|
const dedupKey = `${lenderKey}:${tokenLc}`;
|
|
41222
41313
|
if (seen.has(dedupKey)) continue;
|
|
41223
|
-
const oracleAddr = (side.solvencyOracleAddress ?? side.solvencyOracle?.id ?? self.solvencyOracle ??
|
|
41224
|
-
const isStatic = !oracleAddr || oracleAddr ===
|
|
41314
|
+
const oracleAddr = (side.solvencyOracleAddress ?? side.solvencyOracle?.id ?? self.solvencyOracle ?? ZERO_ADDRESS8).toLowerCase();
|
|
41315
|
+
const isStatic = !oracleAddr || oracleAddr === ZERO_ADDRESS8;
|
|
41225
41316
|
const siloAddrLc = self.silo.toLowerCase();
|
|
41226
41317
|
try {
|
|
41227
41318
|
let priceUSD = 0;
|
|
@@ -41339,7 +41430,7 @@ function lookupUSD4(context, asset) {
|
|
|
41339
41430
|
return context.usdPrices[groupKey] ?? context.usdPrices[lc] ?? 0;
|
|
41340
41431
|
}
|
|
41341
41432
|
function parseSiloV3GraphQLResults(items, context) {
|
|
41342
|
-
const
|
|
41433
|
+
const ZERO_ADDRESS8 = "0x0000000000000000000000000000000000000000";
|
|
41343
41434
|
const out = [];
|
|
41344
41435
|
const seen = /* @__PURE__ */ new Set();
|
|
41345
41436
|
for (const item of items) {
|
|
@@ -41362,8 +41453,8 @@ function parseSiloV3GraphQLResults(items, context) {
|
|
|
41362
41453
|
const partnerTokenLc = other.token.toLowerCase();
|
|
41363
41454
|
const dedupKey = `${lenderKey}:${tokenLc}`;
|
|
41364
41455
|
if (seen.has(dedupKey)) continue;
|
|
41365
|
-
const oracleAddr = (side.solvencyOracleAddress ?? side.solvencyOracle?.id ?? self.solvencyOracle ??
|
|
41366
|
-
const isStatic = !oracleAddr || oracleAddr ===
|
|
41456
|
+
const oracleAddr = (side.solvencyOracleAddress ?? side.solvencyOracle?.id ?? self.solvencyOracle ?? ZERO_ADDRESS8).toLowerCase();
|
|
41457
|
+
const isStatic = !oracleAddr || oracleAddr === ZERO_ADDRESS8;
|
|
41367
41458
|
const siloAddrLc = self.silo.toLowerCase();
|
|
41368
41459
|
try {
|
|
41369
41460
|
let priceUSD = 0;
|
|
@@ -41472,6 +41563,116 @@ async function fetchMorphoMysticPrices(chainId) {
|
|
|
41472
41563
|
return null;
|
|
41473
41564
|
}
|
|
41474
41565
|
}
|
|
41566
|
+
var DESCRIPTION_ABI = [
|
|
41567
|
+
{
|
|
41568
|
+
inputs: [],
|
|
41569
|
+
name: "description",
|
|
41570
|
+
outputs: [{ internalType: "string", name: "", type: "string" }],
|
|
41571
|
+
stateMutability: "view",
|
|
41572
|
+
type: "function"
|
|
41573
|
+
}
|
|
41574
|
+
];
|
|
41575
|
+
var AGGREGATOR_ABI = [...ChainlinkAggregatorAbi, ...DESCRIPTION_ABI];
|
|
41576
|
+
function isFailed(r) {
|
|
41577
|
+
return r === "0x" || r === void 0 || r === null;
|
|
41578
|
+
}
|
|
41579
|
+
var ZERO_ADDRESS7 = "0x0000000000000000000000000000000000000000";
|
|
41580
|
+
async function probeAaveFeedTimestamps(chainId, options = {}) {
|
|
41581
|
+
const { rpcOverrides, batchSize, retries = 2 } = options;
|
|
41582
|
+
const result = {};
|
|
41583
|
+
const oracles = aaveOracles() ?? {};
|
|
41584
|
+
const reserves = aaveReserves() ?? {};
|
|
41585
|
+
const jobs = [];
|
|
41586
|
+
for (const [lender, chains] of Object.entries(oracles)) {
|
|
41587
|
+
const oracle = chains?.[chainId];
|
|
41588
|
+
const assets = reserves[lender]?.[chainId] ?? [];
|
|
41589
|
+
if (!oracle || assets.length === 0) continue;
|
|
41590
|
+
for (const asset of assets) jobs.push({ lender, oracle, asset });
|
|
41591
|
+
}
|
|
41592
|
+
if (jobs.length === 0) return result;
|
|
41593
|
+
try {
|
|
41594
|
+
const sourceResults = await multicallRetryUniversal({
|
|
41595
|
+
chain: chainId,
|
|
41596
|
+
calls: jobs.map((j) => ({
|
|
41597
|
+
address: j.oracle,
|
|
41598
|
+
name: "getSourceOfAsset",
|
|
41599
|
+
params: [j.asset]
|
|
41600
|
+
})),
|
|
41601
|
+
abi: AaveOracleAbi,
|
|
41602
|
+
batchSize,
|
|
41603
|
+
maxRetries: retries,
|
|
41604
|
+
providerId: void 0,
|
|
41605
|
+
allowFailure: true,
|
|
41606
|
+
overrdies: rpcOverrides,
|
|
41607
|
+
logErrors: false
|
|
41608
|
+
});
|
|
41609
|
+
const sourceOf = /* @__PURE__ */ new Map();
|
|
41610
|
+
const uniqueSources = [];
|
|
41611
|
+
const sourceIndex = /* @__PURE__ */ new Map();
|
|
41612
|
+
jobs.forEach((_3, i) => {
|
|
41613
|
+
const raw = sourceResults[i];
|
|
41614
|
+
if (isFailed(raw)) return;
|
|
41615
|
+
const source = String(raw).toLowerCase();
|
|
41616
|
+
if (source === ZERO_ADDRESS7) return;
|
|
41617
|
+
sourceOf.set(i, source);
|
|
41618
|
+
if (!sourceIndex.has(source)) {
|
|
41619
|
+
sourceIndex.set(source, uniqueSources.length);
|
|
41620
|
+
uniqueSources.push(source);
|
|
41621
|
+
}
|
|
41622
|
+
});
|
|
41623
|
+
if (uniqueSources.length === 0) return result;
|
|
41624
|
+
const roundResults = await multicallRetryUniversal({
|
|
41625
|
+
chain: chainId,
|
|
41626
|
+
calls: uniqueSources.flatMap((source) => [
|
|
41627
|
+
{ address: source, name: "latestRoundData", params: [] },
|
|
41628
|
+
{ address: source, name: "description", params: [] }
|
|
41629
|
+
]),
|
|
41630
|
+
abi: AGGREGATOR_ABI,
|
|
41631
|
+
batchSize,
|
|
41632
|
+
maxRetries: retries,
|
|
41633
|
+
providerId: void 0,
|
|
41634
|
+
allowFailure: true,
|
|
41635
|
+
overrdies: rpcOverrides,
|
|
41636
|
+
logErrors: false
|
|
41637
|
+
});
|
|
41638
|
+
const infoOfSource = /* @__PURE__ */ new Map();
|
|
41639
|
+
uniqueSources.forEach((source, i) => {
|
|
41640
|
+
const round = roundResults[i * 2];
|
|
41641
|
+
const description = roundResults[i * 2 + 1];
|
|
41642
|
+
if (isFailed(round) || !Array.isArray(round)) return;
|
|
41643
|
+
const updatedAt = Number(round[3]);
|
|
41644
|
+
if (!(updatedAt > 0)) return;
|
|
41645
|
+
infoOfSource.set(source, {
|
|
41646
|
+
source,
|
|
41647
|
+
updatedAt,
|
|
41648
|
+
description: isFailed(description) ? void 0 : String(description)
|
|
41649
|
+
});
|
|
41650
|
+
});
|
|
41651
|
+
for (const [i, source] of sourceOf) {
|
|
41652
|
+
const info = infoOfSource.get(source);
|
|
41653
|
+
if (!info) continue;
|
|
41654
|
+
const { lender, asset } = jobs[i];
|
|
41655
|
+
if (!result[lender]) result[lender] = {};
|
|
41656
|
+
result[lender][asset.toLowerCase()] = info;
|
|
41657
|
+
}
|
|
41658
|
+
} catch {
|
|
41659
|
+
return result;
|
|
41660
|
+
}
|
|
41661
|
+
return result;
|
|
41662
|
+
}
|
|
41663
|
+
|
|
41664
|
+
// src/prices/oracle-prices/derivation.ts
|
|
41665
|
+
var DERIVATION_RANK = {
|
|
41666
|
+
direct: 0,
|
|
41667
|
+
quoted: 1,
|
|
41668
|
+
derived: 2
|
|
41669
|
+
};
|
|
41670
|
+
function resolveDerivation(entry, groupDefault) {
|
|
41671
|
+
if (entry.derivation) return entry.derivation;
|
|
41672
|
+
if (groupDefault === "derived") return "derived";
|
|
41673
|
+
if (entry.baseAsset && !entry.staticBase) return "quoted";
|
|
41674
|
+
return groupDefault ?? "direct";
|
|
41675
|
+
}
|
|
41475
41676
|
|
|
41476
41677
|
// src/prices/oracle-prices/fetchOraclePrices.ts
|
|
41477
41678
|
function countFailures(data, offset, count) {
|
|
@@ -41489,11 +41690,12 @@ function safeGetCalls(fetcherName, fn, errors) {
|
|
|
41489
41690
|
return [];
|
|
41490
41691
|
}
|
|
41491
41692
|
}
|
|
41492
|
-
function buildGroup(fetcherName, results, parse, abi) {
|
|
41693
|
+
function buildGroup(fetcherName, results, parse, abi, derivation) {
|
|
41493
41694
|
const group = {
|
|
41494
41695
|
fetcherName,
|
|
41495
41696
|
calls: [],
|
|
41496
41697
|
abi,
|
|
41698
|
+
derivation,
|
|
41497
41699
|
trackers: []
|
|
41498
41700
|
};
|
|
41499
41701
|
for (const fr of results) {
|
|
@@ -41508,7 +41710,7 @@ function buildGroup(fetcherName, results, parse, abi) {
|
|
|
41508
41710
|
}
|
|
41509
41711
|
return group;
|
|
41510
41712
|
}
|
|
41511
|
-
function
|
|
41713
|
+
function isFailed2(r) {
|
|
41512
41714
|
return r === "0x" || r === void 0;
|
|
41513
41715
|
}
|
|
41514
41716
|
async function executeGroup(group, chainId, chainBatchSize, retries, allowFailure, rpcOverrides, failRetries = 2) {
|
|
@@ -41527,7 +41729,7 @@ async function executeGroup(group, chainId, chainBatchSize, retries, allowFailur
|
|
|
41527
41729
|
overrdies: rpcOverrides,
|
|
41528
41730
|
logErrors: true
|
|
41529
41731
|
});
|
|
41530
|
-
let failedIndices = results.map((r, i) =>
|
|
41732
|
+
let failedIndices = results.map((r, i) => isFailed2(r) ? i : -1).filter((i) => i >= 0);
|
|
41531
41733
|
for (let round = 0; round < failRetries && failedIndices.length > 0; round++) {
|
|
41532
41734
|
const retryCalls = failedIndices.map((i) => group.calls[i]);
|
|
41533
41735
|
try {
|
|
@@ -41545,7 +41747,7 @@ async function executeGroup(group, chainId, chainBatchSize, retries, allowFailur
|
|
|
41545
41747
|
});
|
|
41546
41748
|
const stillFailed = [];
|
|
41547
41749
|
for (let j = 0; j < failedIndices.length; j++) {
|
|
41548
|
-
if (!
|
|
41750
|
+
if (!isFailed2(retryResults[j])) {
|
|
41549
41751
|
results[failedIndices[j]] = retryResults[j];
|
|
41550
41752
|
} else {
|
|
41551
41753
|
stillFailed.push(failedIndices[j]);
|
|
@@ -41556,7 +41758,7 @@ async function executeGroup(group, chainId, chainBatchSize, retries, allowFailur
|
|
|
41556
41758
|
break;
|
|
41557
41759
|
}
|
|
41558
41760
|
}
|
|
41559
|
-
const failCount = results.filter((r) =>
|
|
41761
|
+
const failCount = results.filter((r) => isFailed2(r)).length;
|
|
41560
41762
|
const allFailed = failCount === results.length && results.length > 0;
|
|
41561
41763
|
return {
|
|
41562
41764
|
results,
|
|
@@ -41570,7 +41772,7 @@ async function executeGroup(group, chainId, chainBatchSize, retries, allowFailur
|
|
|
41570
41772
|
};
|
|
41571
41773
|
}
|
|
41572
41774
|
}
|
|
41573
|
-
async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3, batchSize = void 0, allowFailure = true, basePrices = {}, morphoMarketOverrides, listaMarketOverrides, stalenessThresholdSeconds = 3600, onlyFetchers) {
|
|
41775
|
+
async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3, batchSize = void 0, allowFailure = true, basePrices = {}, morphoMarketOverrides, listaMarketOverrides, stalenessThresholdSeconds = 3600, onlyFetchers, probeFeedStaleness = true) {
|
|
41574
41776
|
const totalStart = Date.now();
|
|
41575
41777
|
const result = {};
|
|
41576
41778
|
const chainPromises = chainIds.map(async (chainId) => {
|
|
@@ -41638,7 +41840,11 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
41638
41840
|
() => exactlyFetcher.getCalls(chainId),
|
|
41639
41841
|
getCallsErrors
|
|
41640
41842
|
) : [];
|
|
41641
|
-
const termResults = isActive("term") ? safeGetCalls(
|
|
41843
|
+
const termResults = isActive("term") ? safeGetCalls(
|
|
41844
|
+
"term",
|
|
41845
|
+
() => termFetcher.getCalls(chainId),
|
|
41846
|
+
getCallsErrors
|
|
41847
|
+
) : [];
|
|
41642
41848
|
const liquityResults = isActive("liquity") ? safeGetCalls(
|
|
41643
41849
|
"liquity",
|
|
41644
41850
|
() => liquityFetcher.getCalls(chainId),
|
|
@@ -41683,109 +41889,127 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
41683
41889
|
"aave",
|
|
41684
41890
|
aaveResults,
|
|
41685
41891
|
aaveFetcher.parse,
|
|
41686
|
-
AaveOracleAbi
|
|
41892
|
+
AaveOracleAbi,
|
|
41893
|
+
"direct"
|
|
41687
41894
|
);
|
|
41688
41895
|
const compoundV2Group = buildGroup(
|
|
41689
41896
|
"compoundV2",
|
|
41690
41897
|
compoundV2Results,
|
|
41691
41898
|
compoundV2Fetcher.parse,
|
|
41692
|
-
CompoundV2OracleAbi
|
|
41899
|
+
CompoundV2OracleAbi,
|
|
41900
|
+
"direct"
|
|
41693
41901
|
);
|
|
41694
41902
|
const compoundV3Group = buildGroup(
|
|
41695
41903
|
"compoundV3",
|
|
41696
41904
|
compoundV3Results,
|
|
41697
41905
|
compoundV3Fetcher.parse,
|
|
41698
|
-
ChainlinkAggregatorAbi
|
|
41906
|
+
ChainlinkAggregatorAbi,
|
|
41907
|
+
"direct"
|
|
41699
41908
|
);
|
|
41700
41909
|
const listaGroup = buildGroup(
|
|
41701
41910
|
"lista",
|
|
41702
41911
|
listaResults,
|
|
41703
41912
|
listaFetcher.parse,
|
|
41704
|
-
ProxyOracleAbi
|
|
41913
|
+
ProxyOracleAbi,
|
|
41914
|
+
"direct"
|
|
41705
41915
|
);
|
|
41706
41916
|
const eulerGroup = buildGroup(
|
|
41707
41917
|
"eulerV2",
|
|
41708
41918
|
eulerResults,
|
|
41709
41919
|
eulerV2Fetcher.parse,
|
|
41710
|
-
getEulerV2Abi()
|
|
41920
|
+
getEulerV2Abi(),
|
|
41921
|
+
"direct"
|
|
41711
41922
|
);
|
|
41712
41923
|
const aaveV4Group = buildGroup(
|
|
41713
41924
|
"aaveV4",
|
|
41714
41925
|
aaveV4Results,
|
|
41715
41926
|
aaveV4Fetcher.parse,
|
|
41716
|
-
getAaveV4Abi()
|
|
41927
|
+
getAaveV4Abi(),
|
|
41928
|
+
"direct"
|
|
41717
41929
|
);
|
|
41718
41930
|
const morphoGroup = buildGroup(
|
|
41719
41931
|
"morpho",
|
|
41720
41932
|
morphoResults,
|
|
41721
41933
|
morphoFetcher.parse,
|
|
41722
|
-
ProxyOracleAbi
|
|
41934
|
+
ProxyOracleAbi,
|
|
41935
|
+
"derived"
|
|
41723
41936
|
);
|
|
41724
41937
|
const midnightGroup = buildGroup(
|
|
41725
41938
|
"midnight",
|
|
41726
41939
|
midnightResults,
|
|
41727
41940
|
midnightFetcher.parse,
|
|
41728
|
-
ProxyOracleAbi
|
|
41941
|
+
ProxyOracleAbi,
|
|
41942
|
+
"derived"
|
|
41729
41943
|
);
|
|
41730
41944
|
const exactlyGroup = buildGroup(
|
|
41731
41945
|
"exactly",
|
|
41732
41946
|
exactlyResults,
|
|
41733
41947
|
exactlyFetcher.parse,
|
|
41734
|
-
getExactlyAbi()
|
|
41948
|
+
getExactlyAbi(),
|
|
41949
|
+
"direct"
|
|
41735
41950
|
);
|
|
41736
41951
|
const termGroup = buildGroup(
|
|
41737
41952
|
"term",
|
|
41738
41953
|
termResults,
|
|
41739
41954
|
termFetcher.parse,
|
|
41740
|
-
getTermAbi()
|
|
41955
|
+
getTermAbi(),
|
|
41956
|
+
"direct"
|
|
41741
41957
|
);
|
|
41742
41958
|
const liquityGroup = buildGroup(
|
|
41743
41959
|
"liquity",
|
|
41744
41960
|
liquityResults,
|
|
41745
41961
|
liquityFetcher.parse,
|
|
41746
|
-
getLiquityAbi()
|
|
41962
|
+
getLiquityAbi(),
|
|
41963
|
+
"direct"
|
|
41747
41964
|
);
|
|
41748
41965
|
const riverGroup = buildGroup(
|
|
41749
41966
|
"river",
|
|
41750
41967
|
riverResults,
|
|
41751
41968
|
riverFetcher.parse,
|
|
41752
|
-
getRiverAbi()
|
|
41969
|
+
getRiverAbi(),
|
|
41970
|
+
"direct"
|
|
41753
41971
|
);
|
|
41754
41972
|
const tellerGroup = buildGroup(
|
|
41755
41973
|
"teller",
|
|
41756
41974
|
tellerResults,
|
|
41757
41975
|
tellerFetcher.parse,
|
|
41758
|
-
getTellerAbi()
|
|
41976
|
+
getTellerAbi(),
|
|
41977
|
+
"derived"
|
|
41759
41978
|
);
|
|
41760
41979
|
const siloV2Group = buildGroup(
|
|
41761
41980
|
"siloV2",
|
|
41762
41981
|
siloV2Results,
|
|
41763
41982
|
siloV2Fetcher.parse,
|
|
41764
|
-
getSiloV2Abi()
|
|
41983
|
+
getSiloV2Abi(),
|
|
41984
|
+
"derived"
|
|
41765
41985
|
);
|
|
41766
41986
|
const siloV3Group = buildGroup(
|
|
41767
41987
|
"siloV3",
|
|
41768
41988
|
siloV3Results,
|
|
41769
41989
|
siloV3Fetcher.parse,
|
|
41770
|
-
getSiloV3Abi()
|
|
41990
|
+
getSiloV3Abi(),
|
|
41991
|
+
"derived"
|
|
41771
41992
|
);
|
|
41772
41993
|
const fluidGroup = buildGroup(
|
|
41773
41994
|
"fluid",
|
|
41774
41995
|
fluidResults,
|
|
41775
41996
|
fluidFetcher.parse,
|
|
41776
|
-
getFluidAbi()
|
|
41997
|
+
getFluidAbi(),
|
|
41998
|
+
"derived"
|
|
41777
41999
|
);
|
|
41778
42000
|
const gearboxV3Group = buildGroup(
|
|
41779
42001
|
"gearboxV3",
|
|
41780
42002
|
gearboxV3Results,
|
|
41781
42003
|
gearboxV3Fetcher.parse,
|
|
41782
|
-
getGearboxV3Abi()
|
|
42004
|
+
getGearboxV3Abi(),
|
|
42005
|
+
"derived"
|
|
41783
42006
|
);
|
|
41784
42007
|
const dolomiteGroup = buildGroup(
|
|
41785
42008
|
"dolomite",
|
|
41786
42009
|
dolomiteResults,
|
|
41787
42010
|
dolomiteFetcher.parse,
|
|
41788
|
-
getDolomiteAbi()
|
|
42011
|
+
getDolomiteAbi(),
|
|
42012
|
+
"direct"
|
|
41789
42013
|
);
|
|
41790
42014
|
const allGroups = [
|
|
41791
42015
|
aaveGroup,
|
|
@@ -41826,6 +42050,11 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
41826
42050
|
const morphoGqlPromise = morphoUseMystic ? fetchMorphoMysticPrices(chainId) : morphoUseApi ? fetchMorphoGraphQLPrices(chainId) : Promise.resolve(null);
|
|
41827
42051
|
const siloV2GqlPromise = isActive("silov2") ? fetchSiloV2GraphQLPrices(chainId, basePrices, tokenList) : Promise.resolve(null);
|
|
41828
42052
|
const siloV3GqlPromise = isActive("silov3") ? fetchSiloV3GraphQLPrices(chainId, basePrices, tokenList) : Promise.resolve(null);
|
|
42053
|
+
const feedTimestampsPromise = stalenessThresholdSeconds > 0 && probeFeedStaleness ? probeAaveFeedTimestamps(chainId, {
|
|
42054
|
+
rpcOverrides,
|
|
42055
|
+
batchSize: chainBatchSize,
|
|
42056
|
+
retries
|
|
42057
|
+
}) : Promise.resolve({});
|
|
41829
42058
|
const [
|
|
41830
42059
|
aaveData,
|
|
41831
42060
|
compoundV2Data,
|
|
@@ -42052,6 +42281,7 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42052
42281
|
if (!chainResult[lender]) {
|
|
42053
42282
|
chainResult[lender] = [];
|
|
42054
42283
|
}
|
|
42284
|
+
entry.derivation = resolveDerivation(entry, group.derivation);
|
|
42055
42285
|
chainResult[lender].push(entry);
|
|
42056
42286
|
if (updatePrices) {
|
|
42057
42287
|
const oracleKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset}`;
|
|
@@ -42076,29 +42306,6 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42076
42306
|
parseTrackers(listaGroup, listaData.results);
|
|
42077
42307
|
parseTrackers(eulerGroup, eulerData.results);
|
|
42078
42308
|
parseTrackers(aaveV4Group, aaveV4Data.results);
|
|
42079
|
-
if (stalenessThresholdSeconds > 0) {
|
|
42080
|
-
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
42081
|
-
for (const tracker of compoundV3Group.trackers) {
|
|
42082
|
-
const meta = tracker.meta;
|
|
42083
|
-
for (let i = 0; i < tracker.count; i++) {
|
|
42084
|
-
const raw = compoundV3Data.results[tracker.offset + i];
|
|
42085
|
-
if (!raw || raw === "0x" || !Array.isArray(raw)) continue;
|
|
42086
|
-
const updatedAt = Number(raw[3]);
|
|
42087
|
-
if (updatedAt > 0) {
|
|
42088
|
-
const staleSeconds = nowSeconds - updatedAt;
|
|
42089
|
-
if (staleSeconds > stalenessThresholdSeconds) {
|
|
42090
|
-
const queryMeta = meta[i];
|
|
42091
|
-
staleFeeds.push({
|
|
42092
|
-
asset: queryMeta?.asset?.toLowerCase() ?? "unknown",
|
|
42093
|
-
lender: queryMeta?.lender ?? tracker.lender,
|
|
42094
|
-
oracle: queryMeta?.oracle ?? "unknown",
|
|
42095
|
-
staleSeconds
|
|
42096
|
-
});
|
|
42097
|
-
}
|
|
42098
|
-
}
|
|
42099
|
-
}
|
|
42100
|
-
}
|
|
42101
|
-
}
|
|
42102
42309
|
parseTrackers(
|
|
42103
42310
|
aaveGroup,
|
|
42104
42311
|
aaveData.results,
|
|
@@ -42122,6 +42329,7 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42122
42329
|
for (const entry of siloV2GqlEntries) {
|
|
42123
42330
|
const lender = entry.targetLender ?? "SILO_V2";
|
|
42124
42331
|
if (!chainResult[lender]) chainResult[lender] = [];
|
|
42332
|
+
entry.derivation = resolveDerivation(entry, "derived");
|
|
42125
42333
|
chainResult[lender].push(entry);
|
|
42126
42334
|
const oracleKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset}`;
|
|
42127
42335
|
usdPrices[oracleKey] = entry.priceUSD;
|
|
@@ -42141,6 +42349,7 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42141
42349
|
for (const entry of siloV3GqlEntries) {
|
|
42142
42350
|
const lender = entry.targetLender ?? "SILO_V3";
|
|
42143
42351
|
if (!chainResult[lender]) chainResult[lender] = [];
|
|
42352
|
+
entry.derivation = resolveDerivation(entry, "derived");
|
|
42144
42353
|
chainResult[lender].push(entry);
|
|
42145
42354
|
const oracleKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset}`;
|
|
42146
42355
|
usdPrices[oracleKey] = entry.priceUSD;
|
|
@@ -42172,6 +42381,7 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42172
42381
|
const key = `${lender}|${entry.marketUid}|${entry.asset}`;
|
|
42173
42382
|
if (onChainKeys.has(key)) continue;
|
|
42174
42383
|
if (!chainResult[lender]) chainResult[lender] = [];
|
|
42384
|
+
entry.derivation = resolveDerivation(entry, "derived");
|
|
42175
42385
|
chainResult[lender].push(entry);
|
|
42176
42386
|
gqlPushed++;
|
|
42177
42387
|
}
|
|
@@ -42191,6 +42401,7 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42191
42401
|
for (const entry of morphoGqlEntries) {
|
|
42192
42402
|
const lender = entry.targetLender ?? "MORPHO_BLUE";
|
|
42193
42403
|
if (!chainResult[lender]) chainResult[lender] = [];
|
|
42404
|
+
entry.derivation = resolveDerivation(entry, "derived");
|
|
42194
42405
|
chainResult[lender].push(entry);
|
|
42195
42406
|
}
|
|
42196
42407
|
trackerDiags.push(morphoGqlDiag);
|
|
@@ -42217,6 +42428,39 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42217
42428
|
}
|
|
42218
42429
|
parseTrackers(midnightGroup, midnightData.results, false);
|
|
42219
42430
|
parseTrackers(tellerGroup, tellerData.results, false);
|
|
42431
|
+
if (stalenessThresholdSeconds > 0) {
|
|
42432
|
+
const feedTimestamps = await feedTimestampsPromise;
|
|
42433
|
+
for (const [lender, assetMap] of Object.entries(feedTimestamps)) {
|
|
42434
|
+
for (const entry of chainResult[lender] ?? []) {
|
|
42435
|
+
const info = assetMap[entry.asset];
|
|
42436
|
+
if (!info) continue;
|
|
42437
|
+
entry.updatedAt = info.updatedAt;
|
|
42438
|
+
entry.feedSource = info.source;
|
|
42439
|
+
if (!entry.description && info.description) {
|
|
42440
|
+
entry.description = info.description;
|
|
42441
|
+
}
|
|
42442
|
+
}
|
|
42443
|
+
}
|
|
42444
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
42445
|
+
const reported = /* @__PURE__ */ new Set();
|
|
42446
|
+
for (const [lender, entries] of Object.entries(chainResult)) {
|
|
42447
|
+
for (const entry of entries) {
|
|
42448
|
+
if (!entry.updatedAt || entry.updatedAt <= 0) continue;
|
|
42449
|
+
const staleSeconds = nowSeconds - entry.updatedAt;
|
|
42450
|
+
if (staleSeconds <= stalenessThresholdSeconds) continue;
|
|
42451
|
+
const key = `${lender}|${entry.asset}|${entry.feedSource ?? ""}`;
|
|
42452
|
+
if (reported.has(key)) continue;
|
|
42453
|
+
reported.add(key);
|
|
42454
|
+
staleFeeds.push({
|
|
42455
|
+
asset: entry.asset,
|
|
42456
|
+
lender,
|
|
42457
|
+
oracle: entry.feedSource ?? "unknown",
|
|
42458
|
+
staleSeconds,
|
|
42459
|
+
description: entry.description
|
|
42460
|
+
});
|
|
42461
|
+
}
|
|
42462
|
+
}
|
|
42463
|
+
}
|
|
42220
42464
|
const totalFailedCalls = trackerDiags.reduce(
|
|
42221
42465
|
(sum, d) => sum + d.failedCalls,
|
|
42222
42466
|
0
|
|
@@ -42272,6 +42516,217 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
|
|
|
42272
42516
|
};
|
|
42273
42517
|
return { prices: result, diagnostics };
|
|
42274
42518
|
}
|
|
42519
|
+
|
|
42520
|
+
// src/prices/oracle-prices/lenderKeys.ts
|
|
42521
|
+
function lenderFamily(lender) {
|
|
42522
|
+
return lender.replace(/_(0X)?[0-9A-F]{6,}$/i, "");
|
|
42523
|
+
}
|
|
42524
|
+
|
|
42525
|
+
// src/prices/oracle-prices/outlierGuard.ts
|
|
42526
|
+
var DEFAULT_OUTLIER_GUARD = {
|
|
42527
|
+
minAgreeingFamilies: 3,
|
|
42528
|
+
agreementTolerance: 0.05,
|
|
42529
|
+
rejectFactor: 2
|
|
42530
|
+
};
|
|
42531
|
+
function median(values) {
|
|
42532
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
42533
|
+
const mid = Math.floor(sorted.length / 2);
|
|
42534
|
+
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
42535
|
+
}
|
|
42536
|
+
function consensusReference(candidates, guard = DEFAULT_OUTLIER_GUARD) {
|
|
42537
|
+
if (candidates.length < guard.minAgreeingFamilies) return void 0;
|
|
42538
|
+
const perFeed = /* @__PURE__ */ new Map();
|
|
42539
|
+
for (const c of candidates) {
|
|
42540
|
+
const bucket = perFeed.get(c.feedKey);
|
|
42541
|
+
if (bucket) bucket.push(c.priceUSD);
|
|
42542
|
+
else perFeed.set(c.feedKey, [c.priceUSD]);
|
|
42543
|
+
}
|
|
42544
|
+
if (perFeed.size < guard.minAgreeingFamilies) return void 0;
|
|
42545
|
+
const feedPrices = [...perFeed.values()].map(median);
|
|
42546
|
+
const reference = median(feedPrices);
|
|
42547
|
+
if (!(reference > 0)) return void 0;
|
|
42548
|
+
const agreeing = feedPrices.filter(
|
|
42549
|
+
(p) => Math.abs(p / reference - 1) <= guard.agreementTolerance
|
|
42550
|
+
).length;
|
|
42551
|
+
if (agreeing < guard.minAgreeingFamilies) return void 0;
|
|
42552
|
+
return reference;
|
|
42553
|
+
}
|
|
42554
|
+
function rejectOutliers(candidates, guard = DEFAULT_OUTLIER_GUARD) {
|
|
42555
|
+
const reference = consensusReference(candidates, guard);
|
|
42556
|
+
if (reference === void 0) return candidates;
|
|
42557
|
+
const upper = reference * guard.rejectFactor;
|
|
42558
|
+
const lower = reference / guard.rejectFactor;
|
|
42559
|
+
const kept = candidates.filter(
|
|
42560
|
+
(c) => c.priceUSD <= upper && c.priceUSD >= lower
|
|
42561
|
+
);
|
|
42562
|
+
return kept.length > 0 ? kept : candidates;
|
|
42563
|
+
}
|
|
42564
|
+
|
|
42565
|
+
// src/prices/oracle-prices/feedStats.ts
|
|
42566
|
+
var EWMA_ALPHA = 0.1;
|
|
42567
|
+
var MIN_DEVIATION_SAMPLES = 5;
|
|
42568
|
+
var BAD_DEVIATION = 0.25;
|
|
42569
|
+
var DEGRADED_DEVIATION = 0.05;
|
|
42570
|
+
var STALE_INTERVAL_MULTIPLE = 4;
|
|
42571
|
+
var MIN_LEARNED_STALE_SECONDS = 6 * 3600;
|
|
42572
|
+
var MIN_UPDATES_FOR_INTERVAL = 4;
|
|
42573
|
+
var FRESHNESS_RANK = {
|
|
42574
|
+
fresh: 0,
|
|
42575
|
+
unknown: 0,
|
|
42576
|
+
// absence of evidence must not demote
|
|
42577
|
+
stale: 1
|
|
42578
|
+
};
|
|
42579
|
+
var RELIABILITY_RANK = {
|
|
42580
|
+
good: 0,
|
|
42581
|
+
unknown: 0,
|
|
42582
|
+
// absence of evidence must not demote
|
|
42583
|
+
degraded: 1,
|
|
42584
|
+
bad: 2
|
|
42585
|
+
};
|
|
42586
|
+
function feedKeyOf(entry, lender) {
|
|
42587
|
+
if (entry.feedSource) return entry.feedSource.toLowerCase();
|
|
42588
|
+
return `${lenderFamily(lender)}|${entry.asset.toLowerCase()}`;
|
|
42589
|
+
}
|
|
42590
|
+
function feedStatKey(chainId, feedKey) {
|
|
42591
|
+
return `${chainId}|${feedKey}`;
|
|
42592
|
+
}
|
|
42593
|
+
function ewma(prev, sample) {
|
|
42594
|
+
if (prev === void 0 || !(prev > 0)) return sample;
|
|
42595
|
+
return prev * (1 - EWMA_ALPHA) + sample * EWMA_ALPHA;
|
|
42596
|
+
}
|
|
42597
|
+
function updateFeedStats(prev, observations, nowSeconds = Math.floor(Date.now() / 1e3)) {
|
|
42598
|
+
const next = { ...prev };
|
|
42599
|
+
for (const obs of observations) {
|
|
42600
|
+
const key = feedStatKey(obs.chainId, obs.feedKey);
|
|
42601
|
+
const existing = next[key];
|
|
42602
|
+
const stat = existing ? { ...existing } : {
|
|
42603
|
+
chainId: obs.chainId,
|
|
42604
|
+
feedKey: obs.feedKey,
|
|
42605
|
+
lastUpdatedAt: 0,
|
|
42606
|
+
lastObservedAt: nowSeconds,
|
|
42607
|
+
updates: 0,
|
|
42608
|
+
intervalEwmaSeconds: 0,
|
|
42609
|
+
intervalMaxSeconds: 0,
|
|
42610
|
+
deviationSamples: 0
|
|
42611
|
+
};
|
|
42612
|
+
if (obs.updatedAt && obs.updatedAt > 0) {
|
|
42613
|
+
if (obs.updatedAt > stat.lastUpdatedAt) {
|
|
42614
|
+
if (stat.lastUpdatedAt > 0) {
|
|
42615
|
+
const interval = obs.updatedAt - stat.lastUpdatedAt;
|
|
42616
|
+
stat.intervalEwmaSeconds = ewma(stat.intervalEwmaSeconds, interval);
|
|
42617
|
+
stat.intervalMaxSeconds = Math.max(stat.intervalMaxSeconds, interval);
|
|
42618
|
+
}
|
|
42619
|
+
stat.lastUpdatedAt = obs.updatedAt;
|
|
42620
|
+
stat.updates += 1;
|
|
42621
|
+
}
|
|
42622
|
+
}
|
|
42623
|
+
if (obs.consensusDeviation !== void 0) {
|
|
42624
|
+
stat.deviationEwma = ewma(stat.deviationEwma, obs.consensusDeviation);
|
|
42625
|
+
stat.deviationSamples += 1;
|
|
42626
|
+
}
|
|
42627
|
+
stat.lastObservedAt = nowSeconds;
|
|
42628
|
+
next[key] = stat;
|
|
42629
|
+
}
|
|
42630
|
+
return next;
|
|
42631
|
+
}
|
|
42632
|
+
function classifyFreshness(updatedAt, stat, defaultStaleSeconds, nowSeconds = Math.floor(Date.now() / 1e3)) {
|
|
42633
|
+
if (!updatedAt || updatedAt <= 0) return "unknown";
|
|
42634
|
+
const age = nowSeconds - updatedAt;
|
|
42635
|
+
if (age < 0) return "fresh";
|
|
42636
|
+
const learned = stat && stat.updates >= MIN_UPDATES_FOR_INTERVAL ? Math.max(
|
|
42637
|
+
stat.intervalEwmaSeconds * STALE_INTERVAL_MULTIPLE,
|
|
42638
|
+
stat.intervalMaxSeconds * 1.5,
|
|
42639
|
+
MIN_LEARNED_STALE_SECONDS
|
|
42640
|
+
) : void 0;
|
|
42641
|
+
const threshold = learned === void 0 ? defaultStaleSeconds : Math.min(learned, defaultStaleSeconds * 2);
|
|
42642
|
+
return age > threshold ? "stale" : "fresh";
|
|
42643
|
+
}
|
|
42644
|
+
function classifyReliability(stat) {
|
|
42645
|
+
if (!stat) return "unknown";
|
|
42646
|
+
if (stat.deviationEwma === void 0 || stat.deviationSamples < MIN_DEVIATION_SAMPLES) {
|
|
42647
|
+
return "unknown";
|
|
42648
|
+
}
|
|
42649
|
+
if (stat.deviationEwma > BAD_DEVIATION) return "bad";
|
|
42650
|
+
if (stat.deviationEwma > DEGRADED_DEVIATION) return "degraded";
|
|
42651
|
+
return "good";
|
|
42652
|
+
}
|
|
42653
|
+
function collectFeedObservations(structuredPrices, lists = {}, guard = DEFAULT_OUTLIER_GUARD) {
|
|
42654
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
42655
|
+
const samples = [];
|
|
42656
|
+
for (const [chainId, lenders] of Object.entries(structuredPrices)) {
|
|
42657
|
+
const tokenList = lists[chainId] ?? {};
|
|
42658
|
+
for (const [lender, entries] of Object.entries(lenders)) {
|
|
42659
|
+
if (!Array.isArray(entries)) continue;
|
|
42660
|
+
for (const entry of entries) {
|
|
42661
|
+
if (!entry?.asset || !(entry.priceUSD > 0)) continue;
|
|
42662
|
+
const sample = {
|
|
42663
|
+
chainId,
|
|
42664
|
+
feedKey: feedKeyOf(entry, lender),
|
|
42665
|
+
priceUSD: entry.priceUSD,
|
|
42666
|
+
updatedAt: entry.updatedAt
|
|
42667
|
+
};
|
|
42668
|
+
samples.push(sample);
|
|
42669
|
+
const groupKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset.toLowerCase()}`;
|
|
42670
|
+
const bucket = byGroup.get(groupKey);
|
|
42671
|
+
if (bucket) bucket.push(sample);
|
|
42672
|
+
else byGroup.set(groupKey, [sample]);
|
|
42673
|
+
}
|
|
42674
|
+
}
|
|
42675
|
+
}
|
|
42676
|
+
const observations = [];
|
|
42677
|
+
const seen = /* @__PURE__ */ new Set();
|
|
42678
|
+
for (const [, group] of byGroup) {
|
|
42679
|
+
const perFeed = /* @__PURE__ */ new Map();
|
|
42680
|
+
for (const s of group) {
|
|
42681
|
+
const bucket = perFeed.get(s.feedKey);
|
|
42682
|
+
if (bucket) bucket.push(s.priceUSD);
|
|
42683
|
+
else perFeed.set(s.feedKey, [s.priceUSD]);
|
|
42684
|
+
}
|
|
42685
|
+
if (perFeed.size < 2) continue;
|
|
42686
|
+
const feedPrices = [...perFeed.entries()].map(([feedKey, prices]) => ({
|
|
42687
|
+
feedKey,
|
|
42688
|
+
price: median(prices)
|
|
42689
|
+
}));
|
|
42690
|
+
for (const { feedKey, price: price2 } of feedPrices) {
|
|
42691
|
+
const others = feedPrices.filter((f) => f.feedKey !== feedKey).map((f) => ({ feedKey: f.feedKey, priceUSD: f.price }));
|
|
42692
|
+
const reference = consensusReference(others, guard);
|
|
42693
|
+
const sample = group.find((s) => s.feedKey === feedKey);
|
|
42694
|
+
const dedupKey = `${sample.chainId}|${feedKey}`;
|
|
42695
|
+
if (seen.has(dedupKey)) continue;
|
|
42696
|
+
seen.add(dedupKey);
|
|
42697
|
+
observations.push({
|
|
42698
|
+
chainId: sample.chainId,
|
|
42699
|
+
feedKey,
|
|
42700
|
+
updatedAt: sample.updatedAt,
|
|
42701
|
+
// Undefined when the rest of the group does not agree on anything —
|
|
42702
|
+
// no verdict is recorded rather than a meaningless one.
|
|
42703
|
+
consensusDeviation: reference === void 0 ? void 0 : Math.abs(price2 / reference - 1)
|
|
42704
|
+
});
|
|
42705
|
+
}
|
|
42706
|
+
}
|
|
42707
|
+
for (const s of samples) {
|
|
42708
|
+
const dedupKey = `${s.chainId}|${s.feedKey}`;
|
|
42709
|
+
if (seen.has(dedupKey)) continue;
|
|
42710
|
+
seen.add(dedupKey);
|
|
42711
|
+
observations.push({
|
|
42712
|
+
chainId: s.chainId,
|
|
42713
|
+
feedKey: s.feedKey,
|
|
42714
|
+
updatedAt: s.updatedAt
|
|
42715
|
+
});
|
|
42716
|
+
}
|
|
42717
|
+
return observations;
|
|
42718
|
+
}
|
|
42719
|
+
function pruneFeedStats(stats, maxAgeSeconds = 30 * 24 * 3600, nowSeconds = Math.floor(Date.now() / 1e3)) {
|
|
42720
|
+
const out = {};
|
|
42721
|
+
for (const [key, stat] of Object.entries(stats)) {
|
|
42722
|
+
if (nowSeconds - stat.lastObservedAt <= maxAgeSeconds) out[key] = stat;
|
|
42723
|
+
}
|
|
42724
|
+
return out;
|
|
42725
|
+
}
|
|
42726
|
+
|
|
42727
|
+
// src/prices/oracle-prices/selectAssetGroupPrices.ts
|
|
42728
|
+
var DEFAULT_STALE_REJECT_SECONDS = 172800;
|
|
42729
|
+
var AAVE_V4_PREFIX = "AAVE_V4";
|
|
42275
42730
|
var DEFAULT_PRIORITY = {
|
|
42276
42731
|
chainPriority: [
|
|
42277
42732
|
Chain.ETHEREUM_MAINNET,
|
|
@@ -42280,7 +42735,10 @@ var DEFAULT_PRIORITY = {
|
|
|
42280
42735
|
Chain.BASE,
|
|
42281
42736
|
Chain.AVALANCHE_C_CHAIN
|
|
42282
42737
|
],
|
|
42283
|
-
|
|
42738
|
+
// Aave V4 has no enum member — every key is the runtime-synthesized
|
|
42739
|
+
// `AAVE_V4_<SPOKE_HEX>` — so it is matched by the literal prefix, the same
|
|
42740
|
+
// way `isAaveV4Type()` does.
|
|
42741
|
+
lenderPriority: [Lender.AAVE_V3, AAVE_V4_PREFIX, "COMPOUND_V3"],
|
|
42284
42742
|
lowPriorityLenders: [Lender.ZEROLEND, Lender.AVALON, Lender.MORPHO_BLUE],
|
|
42285
42743
|
excludedLenders: {
|
|
42286
42744
|
// paused
|
|
@@ -42291,64 +42749,140 @@ var DEFAULT_PRIORITY = {
|
|
|
42291
42749
|
"1": [Lender.ZEROLEND_STABLECOINS_RWA, Lender.ZEROLEND_ETH_LRTS],
|
|
42292
42750
|
"534352": ["LORE"],
|
|
42293
42751
|
"167000": [Lender.TAKOTAKO, Lender.TAKOTAKO_ETH],
|
|
42294
|
-
|
|
42752
|
+
// GAMMA (Planet Finance) is abandoned and its oracle is frozen at ~2022
|
|
42753
|
+
// prices across the board — AVAX $23.78 vs $6.44, BTCB $23k vs $64k, and
|
|
42754
|
+
// it still quotes LUNA/UST. Kept as a hard veto because it prices several
|
|
42755
|
+
// dead assets NOTHING else prices, so no consensus can form to catch it.
|
|
42756
|
+
"56": [Lender.AVALON_USDX, Lender.GAMMA],
|
|
42295
42757
|
// broken
|
|
42296
42758
|
"169": [Lender.ZEROLEND]
|
|
42297
42759
|
},
|
|
42298
42760
|
lenderPriorityPerChain: {
|
|
42299
|
-
|
|
42761
|
+
// NOTE: a per-chain list REPLACES the global one, so it has to repeat
|
|
42762
|
+
// every prefix that should still rank on that chain.
|
|
42763
|
+
[Chain.BNB_SMART_CHAIN_MAINNET]: [
|
|
42764
|
+
Lender.AAVE_V3,
|
|
42765
|
+
AAVE_V4_PREFIX,
|
|
42766
|
+
Lender.VENUS
|
|
42767
|
+
],
|
|
42300
42768
|
[Chain.XDC_NETWORK]: [Lender.PRIME_FI, Lender.FATHOM],
|
|
42301
42769
|
[Chain.HYPEREVM]: [Lender.HYPERLEND, Lender.HYPURRFI]
|
|
42302
42770
|
},
|
|
42303
42771
|
lowPriorityLendersPerChain: {},
|
|
42304
|
-
excludedLendersPerChain: {}
|
|
42305
|
-
|
|
42306
|
-
|
|
42307
|
-
|
|
42772
|
+
excludedLendersPerChain: {},
|
|
42773
|
+
staleRejectSeconds: DEFAULT_STALE_REJECT_SECONDS,
|
|
42774
|
+
outlierGuard: DEFAULT_OUTLIER_GUARD
|
|
42775
|
+
};
|
|
42776
|
+
var LENDER_RANK_UNLISTED = 1e3;
|
|
42777
|
+
var LENDER_RANK_LOW = 2e3;
|
|
42778
|
+
var CHAIN_RANK_UNLISTED = 1e3;
|
|
42779
|
+
function lenderRankOf(lender, chainId, cfg) {
|
|
42308
42780
|
const excluded = cfg.excludedLenders[chainId];
|
|
42309
42781
|
if (excluded?.some((p) => lender.startsWith(p))) return -1;
|
|
42310
42782
|
const excludedPerChain = cfg.excludedLendersPerChain[chainId];
|
|
42311
42783
|
if (excludedPerChain?.some((p) => lender.startsWith(p))) return -1;
|
|
42312
42784
|
const lowPerChain = cfg.lowPriorityLendersPerChain[chainId];
|
|
42313
42785
|
const isLow = lowPerChain ? lowPerChain.some((p) => lender.startsWith(p)) : cfg.lowPriorityLenders.some((p) => lender.startsWith(p));
|
|
42314
|
-
if (isLow) return
|
|
42786
|
+
if (isLow) return LENDER_RANK_LOW;
|
|
42315
42787
|
const lenderPriority = cfg.lenderPriorityPerChain[chainId] ?? cfg.lenderPriority;
|
|
42316
|
-
const
|
|
42317
|
-
|
|
42318
|
-
|
|
42319
|
-
|
|
42320
|
-
|
|
42321
|
-
|
|
42322
|
-
|
|
42323
|
-
|
|
42788
|
+
const idx = lenderPriority.findIndex((p) => lender.startsWith(p));
|
|
42789
|
+
return idx >= 0 ? idx : LENDER_RANK_UNLISTED;
|
|
42790
|
+
}
|
|
42791
|
+
function depthOf(entryMarketUid, lender, depth) {
|
|
42792
|
+
if (!depth) return 0;
|
|
42793
|
+
if (entryMarketUid) {
|
|
42794
|
+
const perMarket = depth[entryMarketUid];
|
|
42795
|
+
if (typeof perMarket === "number") return perMarket;
|
|
42796
|
+
}
|
|
42797
|
+
const perLender = depth[lender];
|
|
42798
|
+
return typeof perLender === "number" ? perLender : 0;
|
|
42799
|
+
}
|
|
42800
|
+
function compareCandidates(a, b) {
|
|
42801
|
+
return a.freshnessRank - b.freshnessRank || a.reliabilityRank - b.reliabilityRank || a.derivationRank - b.derivationRank || a.lenderRank - b.lenderRank || b.depth - a.depth || a.chainRank - b.chainRank || cmpStr(a.lender, b.lender) || cmpStr(a.chainId, b.chainId) || // One lender can emit many entries for the same asset (Euler prices a
|
|
42802
|
+
// token in every vault that lists it), so lender+chain is NOT a unique
|
|
42803
|
+
// identity. Without these last two the winner among them fell out of
|
|
42804
|
+
// enumeration order and the flat price moved between runs.
|
|
42805
|
+
cmpStr(a.marketUid, b.marketUid) || a.priceUSD - b.priceUSD;
|
|
42806
|
+
}
|
|
42807
|
+
function cmpStr(a, b) {
|
|
42808
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
42809
|
+
}
|
|
42810
|
+
function selectAssetGroupPrices(structuredPrices, lists = {}, depthOrTvl = {}, priorityCfg = DEFAULT_PRIORITY, options = {}) {
|
|
42811
|
+
const staleRejectSeconds = priorityCfg.staleRejectSeconds ?? DEFAULT_STALE_REJECT_SECONDS;
|
|
42812
|
+
const guard = priorityCfg.outlierGuard === void 0 ? DEFAULT_OUTLIER_GUARD : priorityCfg.outlierGuard;
|
|
42813
|
+
const depth = options.depth ?? depthOrTvl;
|
|
42814
|
+
const feedStats = options.feedStats;
|
|
42815
|
+
const nowSeconds = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
42816
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
42324
42817
|
for (const [chainId, lenders] of Object.entries(structuredPrices)) {
|
|
42325
42818
|
const tokenList = lists[chainId] ?? {};
|
|
42326
42819
|
for (const [lender, entries] of Object.entries(lenders)) {
|
|
42327
42820
|
if (!Array.isArray(entries)) continue;
|
|
42328
|
-
const
|
|
42329
|
-
if (
|
|
42330
|
-
const
|
|
42821
|
+
const lenderRank = lenderRankOf(lender, chainId, priorityCfg);
|
|
42822
|
+
if (lenderRank < 0) continue;
|
|
42823
|
+
const family = lenderFamily(lender);
|
|
42824
|
+
const chainIdx = priorityCfg.chainPriority.indexOf(chainId);
|
|
42825
|
+
const chainRank = chainIdx >= 0 ? chainIdx : CHAIN_RANK_UNLISTED;
|
|
42331
42826
|
for (const entry of entries) {
|
|
42332
42827
|
if (!entry?.asset || entry.priceUSD <= 0) continue;
|
|
42828
|
+
const feedKey = feedKeyOf(entry, lender);
|
|
42829
|
+
const stat = feedStats?.[feedStatKey(chainId, feedKey)];
|
|
42830
|
+
const freshness = staleRejectSeconds > 0 ? classifyFreshness(
|
|
42831
|
+
entry.updatedAt,
|
|
42832
|
+
stat,
|
|
42833
|
+
staleRejectSeconds,
|
|
42834
|
+
nowSeconds
|
|
42835
|
+
) : "unknown";
|
|
42333
42836
|
const oracleKey = tokenList[entry.asset]?.assetGroup ?? `${chainId}-${entry.asset.toLowerCase()}`;
|
|
42334
|
-
|
|
42837
|
+
const candidate = {
|
|
42335
42838
|
oracleKey,
|
|
42336
42839
|
priceUSD: entry.priceUSD,
|
|
42337
|
-
|
|
42338
|
-
|
|
42339
|
-
|
|
42840
|
+
chainId,
|
|
42841
|
+
lender,
|
|
42842
|
+
family,
|
|
42843
|
+
feedKey,
|
|
42844
|
+
marketUid: entry.marketUid ?? "",
|
|
42845
|
+
derivationRank: DERIVATION_RANK[resolveDerivation(entry)],
|
|
42846
|
+
freshnessRank: FRESHNESS_RANK[freshness],
|
|
42847
|
+
reliabilityRank: RELIABILITY_RANK[classifyReliability(stat)],
|
|
42848
|
+
lenderRank,
|
|
42849
|
+
depth: depthOf(entry.marketUid, lender, depth),
|
|
42850
|
+
chainRank
|
|
42851
|
+
};
|
|
42852
|
+
const bucket = byKey.get(oracleKey);
|
|
42853
|
+
if (bucket) bucket.push(candidate);
|
|
42854
|
+
else byKey.set(oracleKey, [candidate]);
|
|
42340
42855
|
}
|
|
42341
42856
|
}
|
|
42342
42857
|
}
|
|
42343
|
-
candidates.sort((a, b) => a.priority - b.priority || b.tvl - a.tvl);
|
|
42344
42858
|
const flatPrices = {};
|
|
42345
|
-
for (const
|
|
42346
|
-
|
|
42347
|
-
|
|
42859
|
+
for (const [oracleKey, candidates] of byKey) {
|
|
42860
|
+
const viable = guard ? rejectOutliers(candidates, guard) : candidates;
|
|
42861
|
+
let best = viable[0];
|
|
42862
|
+
for (const c of viable) {
|
|
42863
|
+
if (compareCandidates(c, best) < 0) best = c;
|
|
42864
|
+
}
|
|
42865
|
+
if (!best) continue;
|
|
42866
|
+
flatPrices[oracleKey] = best.priceUSD;
|
|
42867
|
+
if (options.onSelection) {
|
|
42868
|
+
options.onSelection({
|
|
42869
|
+
assetGroup: oracleKey,
|
|
42870
|
+
priceUSD: best.priceUSD,
|
|
42871
|
+
chainId: best.chainId,
|
|
42872
|
+
lender: best.lender,
|
|
42873
|
+
feedKey: best.feedKey,
|
|
42874
|
+
derivation: derivationOfRank(best.derivationRank),
|
|
42875
|
+
candidates: candidates.length,
|
|
42876
|
+
rejected: candidates.length - viable.length
|
|
42877
|
+
});
|
|
42348
42878
|
}
|
|
42349
42879
|
}
|
|
42350
42880
|
return flatPrices;
|
|
42351
42881
|
}
|
|
42882
|
+
var RANK_TO_DERIVATION = ["direct", "quoted", "derived"];
|
|
42883
|
+
function derivationOfRank(rank) {
|
|
42884
|
+
return RANK_TO_DERIVATION[rank] ?? "derived";
|
|
42885
|
+
}
|
|
42352
42886
|
var { uniq: uniq2 } = lodash;
|
|
42353
42887
|
function createAssetArrayPerChain() {
|
|
42354
42888
|
let assetsPerChain = {};
|
|
@@ -53051,6 +53585,6 @@ async function fetchTokenBalances(chainId, account, tokens, options = {}) {
|
|
|
53051
53585
|
return parseTokenBalanceResult(rawResult, prepared.query);
|
|
53052
53586
|
}
|
|
53053
53587
|
|
|
53054
|
-
export { ApiBookSource, DEFAULT_MIDNIGHT_API, EMPTY_BALANCE, GMX_API_HOSTS, GMX_READ_CONTRACTS, GMX_SUPPORTED_CHAINS, HYPERCORE_VAULT_REGISTRY, IDLE_MARKET_ID, INTERFACE_IDS, LAGOON_API_URL, LAGOON_CHAIN_IDS, MORPHO_LENS, MaxParamThresholds, STABLECOIN_SYMBOLS, STCELO_MANAGER_ADDRESS, TELLER_CALLS_PER_BID, TermSubgraphSource, UPSHIFT_CHAIN_IDS, UPSHIFT_VAULTS_URL, VAULT_SHARE_PRICE_PROBE, VOLATILE_VAULT_OVERRIDES, YEARN_CHAIN_IDS, YEARN_YDAEMON_BASE, accountDepositListKey, accountWithdrawalListKey, appendSnapshot, applyPositionDelta, attachPricesToFlashLiquidity, buildFluidFTokensCall, buildLiquityUserCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildSumerAccumulators, buildSummaries, buildTellerUserCall, buildVaultLookup, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyVault, computeBorrowDelta2 as computeBorrowDelta, computeCloseTradeDeltas, computeCollateralSwapDeltas, computeDebtSwapDeltas, computeDepositDelta2 as computeDepositDelta, computeEModeAnalysis, computeOpenTradeDeltas, computePostTradeMetrics, computeRepayDelta2 as computeRepayDelta, computeSumerBorrowDelta, computeSumerDepositDelta, computeSumerRepayDelta, computeSumerWaterfall, computeSumerWithdrawDelta, computeVaultApr, computeWithdrawDelta2 as computeWithdrawDelta, computeZapTradeDeltas, convertExactlyMarketsToResponse, convertLenderUserDataResult, convertLiquityMarketsToResponse, convertRiverMarketsToResponse, convertTellerMarketsToResponse, convertTermMarketsToResponse, createMarketUid, createMidnightBookSource, createMulticallRpcCall, createRawRpcCalls, createTermBookSource, decodeListaMarkets, decodeMarkets, decodePackedListaUserDataset, decodePackedMorphoUserDataset, detectInterfaceKinds, encodeBalanceFetcherCalldata, exactlyLenderKey, exactlyMarketFromLenderKey, exactlyPairLtv, exactlyPenaltyRateToAprPercent, exactlyWadRateToPercent, fetchDolomiteAccountNumbers, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchExactlyMarkets, fetchFlashLiquidityForChain, fetchFluidFTokens, fetchGeneralYields, fetchGeneralYieldsByMarketUid, fetchGmxExecutionFees, fetchGmxTickerPrices, fetchGmxVaults, fetchHypercoreVaults, fetchLagoonApiVaults, fetchLagoonVaults, fetchLiquityMarkets, fetchListaVaultsFromChain, fetchMorphoUserBalances, fetchMorphoUserPositionMarkets, fetchMorphoVaults, fetchMorphoVaultsFromApi, fetchMorphoVaultsFromChain, fetchOraclePrices, fetchPendlePrices, fetchRiverMarkets, fetchSiloVaults, fetchTellerMarkets, fetchTermMarkets, fetchTokenBalances, fetchTokenMetadata, fetchUpshiftApiVaults, fetchUpshiftVaults, fetchYearnApiVaults, fetchYearnVaults, filterActiveLenders, filterLendersByProtocol, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, getCachedLiquityTroves, getCachedTellerBids, getCoreValidators, getFluidFTokensConverter, getGmxApiHost, getGmxReadContracts, getGmxUserPositions, getHealthFactor, getHypercoreUserPositions, getHypercoreVaultRegistry, getLenderAssets, getLenderPublicData, getLenderPublicDataAll, getLenderPublicDataViaApi, getLenderUserDataMulti, getLenderUserDataResult, getLendersForChain, getLstDelegation, getLstValidators, getLstWithdrawalRegistry, getLstWithdrawalRequests, getMaxAmountClose, getMaxAmountCollateralSwap, getMaxAmountDebtSwap, getMaxAmountOpen, getMergedUserData, getMorphoTypeMarketConverter, getResolvedDolomiteAccountNumbers, getStCeloValidatorGroups, getSubAccountAddress, getSubAccountIndex, getVaultPublicDataAll, getVaultWithdrawalRequests, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasUpshiftVaults, hasYearnVaults, isStablecoinSymbol, isYearnV3, keysFromMaps, liquityCandidateTroveIds, liquityKeyParts, liquityLenderKey, multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, parseBalanceFetcherResult, parseMergedResult, parseMulticallRpcResponses, parseRawRpcBatchResponses, parseRawRpcResponses, parseTokenBalanceResult, positivePart2 as positivePart, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, readVaultSharePrices, resolveStCeloDepositGroup, riverKeyParts, riverLenderKey, selectAssetGroupPrices, stampVaultClassification, tellerBpsToPercent, tellerImpliedLtv, tellerLenderKey, tellerPoolFromLenderKey, termLenderKey, tickToAprNumber, tickToPrice, unflattenLenderData };
|
|
53588
|
+
export { ApiBookSource, DEFAULT_MIDNIGHT_API, DEFAULT_OUTLIER_GUARD, DEFAULT_STALE_REJECT_SECONDS, EMPTY_BALANCE, GMX_API_HOSTS, GMX_READ_CONTRACTS, GMX_SUPPORTED_CHAINS, HYPERCORE_VAULT_REGISTRY, IDLE_MARKET_ID, INTERFACE_IDS, LAGOON_API_URL, LAGOON_CHAIN_IDS, MORPHO_LENS, MaxParamThresholds, STABLECOIN_SYMBOLS, STCELO_MANAGER_ADDRESS, TELLER_CALLS_PER_BID, TermSubgraphSource, UPSHIFT_CHAIN_IDS, UPSHIFT_VAULTS_URL, VAULT_SHARE_PRICE_PROBE, VOLATILE_VAULT_OVERRIDES, YEARN_CHAIN_IDS, YEARN_YDAEMON_BASE, accountDepositListKey, accountWithdrawalListKey, appendSnapshot, applyPositionDelta, attachPricesToFlashLiquidity, buildFluidFTokensCall, buildLiquityUserCall, buildLoopResult, buildMorphoTypeCall, buildMorphoTypeUserCallWithLens, buildPortfolioTotals, buildSumerAccumulators, buildSummaries, buildTellerUserCall, buildVaultLookup, calculateLeverage, calculateNetApr, calculateOverallNetApr, calculateWeightedAverage, classifyFreshness, classifyReliability, classifyVault, collectFeedObservations, computeBorrowDelta2 as computeBorrowDelta, computeCloseTradeDeltas, computeCollateralSwapDeltas, computeDebtSwapDeltas, computeDepositDelta2 as computeDepositDelta, computeEModeAnalysis, computeOpenTradeDeltas, computePostTradeMetrics, computeRepayDelta2 as computeRepayDelta, computeSumerBorrowDelta, computeSumerDepositDelta, computeSumerRepayDelta, computeSumerWaterfall, computeSumerWithdrawDelta, computeVaultApr, computeWithdrawDelta2 as computeWithdrawDelta, computeZapTradeDeltas, consensusReference, convertExactlyMarketsToResponse, convertLenderUserDataResult, convertLiquityMarketsToResponse, convertRiverMarketsToResponse, convertTellerMarketsToResponse, convertTermMarketsToResponse, createMarketUid, createMidnightBookSource, createMulticallRpcCall, createRawRpcCalls, createTermBookSource, decodeListaMarkets, decodeMarkets, decodePackedListaUserDataset, decodePackedMorphoUserDataset, detectInterfaceKinds, encodeBalanceFetcherCalldata, exactlyLenderKey, exactlyMarketFromLenderKey, exactlyPairLtv, exactlyPenaltyRateToAprPercent, exactlyWadRateToPercent, feedKeyOf, feedStatKey, fetchDolomiteAccountNumbers, fetchEulerEarnVaults, fetchEulerEarnVaultsFromSubgraph, fetchEulerSubAccountIndexes, fetchExactlyMarkets, fetchFlashLiquidityForChain, fetchFluidFTokens, fetchGeneralYields, fetchGeneralYieldsByMarketUid, fetchGmxExecutionFees, fetchGmxTickerPrices, fetchGmxVaults, fetchHypercoreVaults, fetchLagoonApiVaults, fetchLagoonVaults, fetchLiquityMarkets, fetchListaVaultsFromChain, fetchMorphoUserBalances, fetchMorphoUserPositionMarkets, fetchMorphoVaults, fetchMorphoVaultsFromApi, fetchMorphoVaultsFromChain, fetchOraclePrices, fetchPendlePrices, fetchRiverMarkets, fetchSiloVaults, fetchTellerMarkets, fetchTermMarkets, fetchTokenBalances, fetchTokenMetadata, fetchUpshiftApiVaults, fetchUpshiftVaults, fetchYearnApiVaults, fetchYearnVaults, filterActiveLenders, filterLendersByProtocol, fuseLenderData, generateLendingPools, getAavesForChain, getAssetConfig, getBalanceForMarketUid, getBorrowCapacity, getCachedLiquityTroves, getCachedTellerBids, getCoreValidators, getFluidFTokensConverter, getGmxApiHost, getGmxReadContracts, getGmxUserPositions, getHealthFactor, getHypercoreUserPositions, getHypercoreVaultRegistry, getLenderAssets, getLenderPublicData, getLenderPublicDataAll, getLenderPublicDataViaApi, getLenderUserDataMulti, getLenderUserDataResult, getLendersForChain, getLstDelegation, getLstValidators, getLstWithdrawalRegistry, getLstWithdrawalRequests, getMaxAmountClose, getMaxAmountCollateralSwap, getMaxAmountDebtSwap, getMaxAmountOpen, getMergedUserData, getMorphoTypeMarketConverter, getResolvedDolomiteAccountNumbers, getStCeloValidatorGroups, getSubAccountAddress, getSubAccountIndex, getVaultPublicDataAll, getVaultWithdrawalRequests, hasEulerEarnVaultSubgraph, hasLagoonVaults, hasMorphoPositionIndex, hasMorphoUserApi, hasMorphoUserSubgraph, hasUpshiftVaults, hasYearnVaults, isStablecoinSymbol, isYearnV3, keysFromMaps, lenderFamily, liquityCandidateTroveIds, liquityKeyParts, liquityLenderKey, multicall3Abi, nanTo, needsLenderApproval, needsTokenApproval, noOpResult, normalizeToBytes, parseBalanceFetcherResult, parseMergedResult, parseMulticallRpcResponses, parseRawRpcBatchResponses, parseRawRpcResponses, parseTokenBalanceResult, positivePart2 as positivePart, prepareLenderUserDataRpcCalls, prepareMergedMulticallParams, prepareMergedRpcCalls, prepareMulticallInputs, prepareTokenBalanceRpcCalls, priceGlvVaults, priceGmMarkets, probeAaveFeedTimestamps, pruneFeedStats, readVaultSharePrices, rejectOutliers as rejectPriceOutliers, resolveDerivation, resolveStCeloDepositGroup, riverKeyParts, riverLenderKey, selectAssetGroupPrices, stampVaultClassification, tellerBpsToPercent, tellerImpliedLtv, tellerLenderKey, tellerPoolFromLenderKey, termLenderKey, tickToAprNumber, tickToPrice, unflattenLenderData, updateFeedStats };
|
|
53055
53589
|
//# sourceMappingURL=index.js.map
|
|
53056
53590
|
//# sourceMappingURL=index.js.map
|