@1delta/margin-fetcher 0.0.230 → 0.0.232

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.
Files changed (28) hide show
  1. package/dist/index.js +374 -48
  2. package/dist/index.js.map +1 -1
  3. package/dist/lending/margin/e-mode/index.d.ts +10 -1
  4. package/dist/lending/margin/e-mode/index.d.ts.map +1 -1
  5. package/dist/lending/user-data/abis.d.ts.map +1 -1
  6. package/dist/lending/user-data/fetch-balances/parse.d.ts.map +1 -1
  7. package/dist/lending/user-data/fetch-balances/prepare.d.ts.map +1 -1
  8. package/dist/lending/user-data/silo-v2/userCallParse.d.ts.map +1 -1
  9. package/dist/lending/user-data/silo-v3/userCallBuild.d.ts +5 -0
  10. package/dist/lending/user-data/silo-v3/userCallBuild.d.ts.map +1 -0
  11. package/dist/lending/user-data/silo-v3/userCallParse.d.ts +30 -0
  12. package/dist/lending/user-data/silo-v3/userCallParse.d.ts.map +1 -0
  13. package/dist/lending/user-data/with-permissions/evaluate.d.ts +2 -0
  14. package/dist/lending/user-data/with-permissions/evaluate.d.ts.map +1 -1
  15. package/dist/lending/user-data/with-permissions/types.d.ts +2 -0
  16. package/dist/lending/user-data/with-permissions/types.d.ts.map +1 -1
  17. package/dist/prices/oracle-prices/fetchOraclePrices.d.ts.map +1 -1
  18. package/dist/prices/oracle-prices/fetchers/siloV2.d.ts.map +1 -1
  19. package/dist/prices/oracle-prices/fetchers/siloV2Graphql.d.ts +19 -1
  20. package/dist/prices/oracle-prices/fetchers/siloV2Graphql.d.ts.map +1 -1
  21. package/dist/prices/oracle-prices/fetchers/siloV3.d.ts.map +1 -1
  22. package/dist/prices/oracle-prices/fetchers/siloV3Graphql.d.ts +12 -1
  23. package/dist/prices/oracle-prices/fetchers/siloV3Graphql.d.ts.map +1 -1
  24. package/dist/types/lenderTypes.d.ts +6 -0
  25. package/dist/types/lenderTypes.d.ts.map +1 -1
  26. package/dist/utils/index.d.ts +1 -1
  27. package/dist/utils/index.d.ts.map +1 -1
  28. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import lodash from 'lodash';
7
7
  import { getEvmChain, getEvmClient, getEvmClientUniversal, multicallRetryUniversal } from '@1delta/providers';
8
8
  import { MorphoLensAbi, AaveV4SpokeAbi, AaveV4OracleAbi, AaveV4HubAbi, MorphoBlueAbi } from '@1delta/abis';
9
9
  export { MorphoLensAbi } from '@1delta/abis';
10
- import { prepareDebitDataMulticall, prepareLenderDebitMulticall, parseDebitDataResult, parseLenderDebitResult, getPermit2ContractAddress, getCompoundV3CometAddress as getCompoundV3CometAddress$1, getMorphoAddress, getAaveCollateralTokenAddress, InitMarginAddresses } from '@1delta/calldata-sdk';
10
+ import { prepareDebitDataMulticall, prepareLenderDebitMulticall, parseDebitDataResult, parseLenderDebitResult, getPermit2ContractAddress, getCompoundV3CometAddress as getCompoundV3CometAddress$1, getMorphoAddress, getAaveCollateralTokenAddress, getSiloHalfForUnderlying, InitMarginAddresses } from '@1delta/calldata-sdk';
11
11
  import { BALANCER_V2_FORKS, BALANCER_V3_FORKS, UNISWAP_V4_FORKS, FLASH_LOAN_IDS } from '@1delta/dex-registry';
12
12
 
13
13
  // src/abis/aave-v2/ProtocolDataProvider.ts
@@ -13449,7 +13449,7 @@ function getCompoundV2Lens(chainId, lender) {
13449
13449
  return COMPOUND_V2_LENS[lender]?.[chainId];
13450
13450
  }
13451
13451
  function getCompoundV2Tokens(chainId, lender = Lender.VENUS) {
13452
- return compoundV2TokenArray()?.[lender]?.[chainId];
13452
+ return compoundV2TokenArray()?.[lender]?.[chainId] ?? [];
13453
13453
  }
13454
13454
 
13455
13455
  // src/abis/compound-v2/VenusLensLegacy.ts
@@ -18747,7 +18747,7 @@ var getSiloV2ReservesDataConverter = (lender, chainId, prices, additionalYields,
18747
18747
  { self: market.silo0, other: market.silo1 },
18748
18748
  { self: market.silo1, other: market.silo0 }
18749
18749
  ];
18750
- const toBigInt6 = (v) => {
18750
+ const toBigInt7 = (v) => {
18751
18751
  if (v === void 0 || v === null || v === "0x") return 0n;
18752
18752
  if (typeof v === "bigint") return v;
18753
18753
  try {
@@ -18759,8 +18759,8 @@ var getSiloV2ReservesDataConverter = (lender, chainId, prices, additionalYields,
18759
18759
  for (let s = 0; s < 2; s++) {
18760
18760
  const { self, other } = sides[s];
18761
18761
  const slot = s * SILO_V2_CALLS_PER_SIDE;
18762
- const totalAssetsRaw = toBigInt6(data[slot]);
18763
- const debtAssetsRaw = toBigInt6(data[slot + 1]);
18762
+ const totalAssetsRaw = toBigInt7(data[slot]);
18763
+ const debtAssetsRaw = toBigInt7(data[slot + 1]);
18764
18764
  const decimals = self.decimals;
18765
18765
  const totalDeposits = Number(formatUnits(totalAssetsRaw, decimals));
18766
18766
  const totalDebt = Number(formatUnits(debtAssetsRaw, decimals));
@@ -18899,7 +18899,7 @@ var getSiloV3ReservesDataConverter = (lender, chainId, prices, additionalYields,
18899
18899
  { self: market.silo0, other: market.silo1 },
18900
18900
  { self: market.silo1, other: market.silo0 }
18901
18901
  ];
18902
- const toBigInt6 = (v) => {
18902
+ const toBigInt7 = (v) => {
18903
18903
  if (v === void 0 || v === null || v === "0x") return 0n;
18904
18904
  if (typeof v === "bigint") return v;
18905
18905
  try {
@@ -18911,8 +18911,8 @@ var getSiloV3ReservesDataConverter = (lender, chainId, prices, additionalYields,
18911
18911
  for (let s = 0; s < 2; s++) {
18912
18912
  const { self, other } = sides[s];
18913
18913
  const slot = s * SILO_V3_CALLS_PER_SIDE;
18914
- const totalAssetsRaw = toBigInt6(data[slot]);
18915
- const debtAssetsRaw = toBigInt6(data[slot + 1]);
18914
+ const totalAssetsRaw = toBigInt7(data[slot]);
18915
+ const debtAssetsRaw = toBigInt7(data[slot + 1]);
18916
18916
  const decimals = self.decimals;
18917
18917
  const totalDeposits = Number(formatUnits(totalAssetsRaw, decimals));
18918
18918
  const totalDebt = Number(formatUnits(debtAssetsRaw, decimals));
@@ -20310,6 +20310,55 @@ var buildSiloV2UserCall = (chainId, lender, account) => {
20310
20310
  return calls;
20311
20311
  };
20312
20312
 
20313
+ // src/lending/user-data/silo-v3/userCallBuild.ts
20314
+ var ASSET_TYPE_PROTECTED2 = 0;
20315
+ var ASSET_TYPE_COLLATERAL2 = 1;
20316
+ var SILO_V3_USER_CALLS_PER_SIDE = 5;
20317
+ var SILO_V3_USER_CALLS_PER_PAIR = SILO_V3_USER_CALLS_PER_SIDE * 2;
20318
+ var buildSiloV3UserCall = (chainId, lender, account) => {
20319
+ const market = getSiloV3MarketEntry(chainId, lender);
20320
+ if (!market) return [];
20321
+ const calls = [];
20322
+ for (const half of [market.silo0, market.silo1]) {
20323
+ const oneUnit = BigInt(10) ** BigInt(half.decimals);
20324
+ calls.push(
20325
+ // [0] collateral shares (silo IS the collateral share token)
20326
+ {
20327
+ address: half.silo,
20328
+ name: "balanceOf",
20329
+ params: [account]
20330
+ },
20331
+ // [1] protected shares (separate ERC-20)
20332
+ {
20333
+ address: half.protectedShareToken,
20334
+ name: "balanceOf",
20335
+ params: [account]
20336
+ },
20337
+ // [2] collateral rate: assets per unit of collateral shares
20338
+ {
20339
+ address: half.silo,
20340
+ name: "convertToAssets",
20341
+ params: [oneUnit, ASSET_TYPE_COLLATERAL2],
20342
+ abi: SiloConvertToAssetsTypedAbi
20343
+ },
20344
+ // [3] protected rate: assets per unit of protected shares
20345
+ {
20346
+ address: half.silo,
20347
+ name: "convertToAssets",
20348
+ params: [oneUnit, ASSET_TYPE_PROTECTED2],
20349
+ abi: SiloConvertToAssetsTypedAbi
20350
+ },
20351
+ // [4] debt position (already in assets, includes accrued interest)
20352
+ {
20353
+ address: half.silo,
20354
+ name: "maxRepay",
20355
+ params: [account]
20356
+ }
20357
+ );
20358
+ }
20359
+ return calls;
20360
+ };
20361
+
20313
20362
  // src/lending/user-data/fetch-balances/prepare.ts
20314
20363
  async function buildUserCall(chainId, lender, account, params) {
20315
20364
  if (isAaveV4Type(lender)) return buildAaveV4UserCall(chainId, lender, account);
@@ -20324,7 +20373,11 @@ async function buildUserCall(chainId, lender, account, params) {
20324
20373
  return buildEulerUserCall(chainId, lender, account, params?.subAccountIndexes);
20325
20374
  if (isSiloV2Type(lender))
20326
20375
  return buildSiloV2UserCall(chainId, lender, account);
20327
- return buildCompoundV2UserCall(chainId, lender, account);
20376
+ if (isSiloV3Type(lender))
20377
+ return buildSiloV3UserCall(chainId, lender, account);
20378
+ if (isCompoundV2Type(lender))
20379
+ return buildCompoundV2UserCall(chainId, lender, account);
20380
+ return [];
20328
20381
  }
20329
20382
  function organizeUserQueries(queries) {
20330
20383
  const morphos = queries.filter((q) => isMorphoType(q.lender));
@@ -21864,6 +21917,14 @@ var getSiloV2UserDataConverter = (lender, chainId, account, metaMap) => {
21864
21917
  depositAssetsRaw.toString(),
21865
21918
  metaDecimals
21866
21919
  );
21920
+ const depositsStandardStr = parseRawAmount(
21921
+ collateralAssets.toString(),
21922
+ metaDecimals
21923
+ );
21924
+ const depositsProtectedStr = parseRawAmount(
21925
+ protectedAssets.toString(),
21926
+ metaDecimals
21927
+ );
21867
21928
  const debtStr = parseRawAmount(repayRaw.toString(), metaDecimals);
21868
21929
  const depositsNum = Number(depositsStr);
21869
21930
  const debtNum = Number(debtStr);
@@ -21882,8 +21943,15 @@ var getSiloV2UserDataConverter = (lender, chainId, account, metaMap) => {
21882
21943
  marketUid,
21883
21944
  underlying: self.token.toLowerCase(),
21884
21945
  deposits: depositsStr,
21946
+ depositsStandard: depositsStandardStr,
21947
+ depositsProtected: depositsProtectedStr,
21885
21948
  debt: debtStr,
21886
21949
  debtStable: "0",
21950
+ // Raw share balances (stringified bigints, not decimal-formatted).
21951
+ // Used by the leverage close flow to approve the exact share count
21952
+ // and avoid rounding errors on "withdraw all".
21953
+ depositShares: collateralShares.toString(),
21954
+ protectedDepositShares: protectedShares.toString(),
21887
21955
  depositsUSD,
21888
21956
  debtUSD,
21889
21957
  debtStableUSD: 0,
@@ -21892,6 +21960,7 @@ var getSiloV2UserDataConverter = (lender, chainId, account, metaMap) => {
21892
21960
  debtStableUSDOracle: 0,
21893
21961
  stableBorrowRate: "0",
21894
21962
  collateralEnabled,
21963
+ collateralRate: collateralRate.toString(),
21895
21964
  claimableRewards: 0
21896
21965
  };
21897
21966
  }
@@ -21924,6 +21993,118 @@ function toBigInt5(v) {
21924
21993
  }
21925
21994
  }
21926
21995
 
21996
+ // src/lending/user-data/silo-v3/userCallParse.ts
21997
+ var getSiloV3UserDataConverter = (lender, chainId, account, metaMap) => {
21998
+ const market = getSiloV3MarketEntry(chainId, lender);
21999
+ if (!market) return [() => void 0, 0];
22000
+ return [
22001
+ (data) => {
22002
+ if (!data || data.length !== SILO_V3_USER_CALLS_PER_PAIR)
22003
+ return void 0;
22004
+ const sides = [
22005
+ { self: market.silo0, other: market.silo1 },
22006
+ { self: market.silo1, other: market.silo0 }
22007
+ ];
22008
+ const lendingPositions = {};
22009
+ let addedDeposits = 0;
22010
+ let addedDebt = 0;
22011
+ let hasAnyPosition = false;
22012
+ for (let s = 0; s < 2; s++) {
22013
+ const { self } = sides[s];
22014
+ const slot = s * SILO_V3_USER_CALLS_PER_SIDE;
22015
+ const collateralShares = toBigInt6(data[slot]);
22016
+ const protectedShares = toBigInt6(data[slot + 1]);
22017
+ const collateralRate = toBigInt6(data[slot + 2]);
22018
+ const protectedRate = toBigInt6(data[slot + 3]);
22019
+ const repayRaw = toBigInt6(data[slot + 4]);
22020
+ const decimals = self.decimals;
22021
+ const oneUnit = BigInt(10) ** BigInt(decimals);
22022
+ const collateralAssets = oneUnit > 0n ? collateralShares * collateralRate / oneUnit : 0n;
22023
+ const protectedAssets = oneUnit > 0n ? protectedShares * protectedRate / oneUnit : 0n;
22024
+ const depositAssetsRaw = collateralAssets + protectedAssets;
22025
+ if (depositAssetsRaw === 0n && repayRaw === 0n) continue;
22026
+ hasAnyPosition = true;
22027
+ const marketUid = createMarketUid(chainId, lender, self.silo);
22028
+ const meta = metaMap?.[marketUid];
22029
+ const metaDecimals = meta?.asset?.decimals ?? decimals;
22030
+ const depositsStr = parseRawAmount(
22031
+ depositAssetsRaw.toString(),
22032
+ metaDecimals
22033
+ );
22034
+ const depositsStandardStr = parseRawAmount(
22035
+ collateralAssets.toString(),
22036
+ metaDecimals
22037
+ );
22038
+ const depositsProtectedStr = parseRawAmount(
22039
+ protectedAssets.toString(),
22040
+ metaDecimals
22041
+ );
22042
+ const debtStr = parseRawAmount(repayRaw.toString(), metaDecimals);
22043
+ const depositsNum = Number(depositsStr);
22044
+ const debtNum = Number(debtStr);
22045
+ const displayPrice = meta ? getDisplayPrice(meta) : 0;
22046
+ const oraclePrice = meta ? getOraclePrice(meta) : 0;
22047
+ const priceHist = meta?.price?.priceUsd24h ?? displayPrice;
22048
+ const depositsUSD = depositsNum * displayPrice;
22049
+ const debtUSD = debtNum * displayPrice;
22050
+ const depositsUSDOracle = depositsNum * oraclePrice;
22051
+ const debtUSDOracle = debtNum * oraclePrice;
22052
+ addedDeposits += depositsNum * priceHist;
22053
+ addedDebt += debtNum * priceHist;
22054
+ const selfLt = Number(self.lt) / 1e18;
22055
+ const collateralEnabled = selfLt > 0 && depositAssetsRaw > 0n;
22056
+ lendingPositions[marketUid] = {
22057
+ marketUid,
22058
+ underlying: self.token.toLowerCase(),
22059
+ deposits: depositsStr,
22060
+ depositsStandard: depositsStandardStr,
22061
+ depositsProtected: depositsProtectedStr,
22062
+ debt: debtStr,
22063
+ debtStable: "0",
22064
+ // Raw share balances (stringified bigints, not decimal-formatted).
22065
+ depositShares: collateralShares.toString(),
22066
+ protectedDepositShares: protectedShares.toString(),
22067
+ depositsUSD,
22068
+ debtUSD,
22069
+ debtStableUSD: 0,
22070
+ depositsUSDOracle,
22071
+ debtUSDOracle,
22072
+ debtStableUSDOracle: 0,
22073
+ stableBorrowRate: "0",
22074
+ collateralEnabled,
22075
+ collateralRate: collateralRate.toString(),
22076
+ claimableRewards: 0
22077
+ };
22078
+ }
22079
+ if (!hasAnyPosition) return void 0;
22080
+ const payload = {
22081
+ chainId,
22082
+ account,
22083
+ lendingPositions,
22084
+ rewards: [],
22085
+ userEMode: 0
22086
+ };
22087
+ return createBaseTypeUserState(
22088
+ payload,
22089
+ metaMap,
22090
+ addedDeposits,
22091
+ addedDebt,
22092
+ lender
22093
+ );
22094
+ },
22095
+ SILO_V3_USER_CALLS_PER_PAIR
22096
+ ];
22097
+ };
22098
+ function toBigInt6(v) {
22099
+ if (v === void 0 || v === null || v === "0x") return 0n;
22100
+ if (typeof v === "bigint") return v;
22101
+ try {
22102
+ return BigInt(v);
22103
+ } catch {
22104
+ return 0n;
22105
+ }
22106
+ }
22107
+
21927
22108
  // src/lending/user-data/fetch-balances/parse.ts
21928
22109
  function getUserDataConverter(lender, chainId, account, params, meta) {
21929
22110
  if (isAaveV4Type(lender))
@@ -21960,6 +22141,8 @@ function getUserDataConverter(lender, chainId, account, params, meta) {
21960
22141
  return getEulerUserDataConverter(lender, chainId, account, meta?.[lender], params?.subAccountIndexes);
21961
22142
  if (isSiloV2Type(lender))
21962
22143
  return getSiloV2UserDataConverter(lender, chainId, account, meta?.[lender]);
22144
+ if (isSiloV3Type(lender))
22145
+ return getSiloV3UserDataConverter(lender, chainId, account, meta?.[lender]);
21963
22146
  return getCompoundV2UserDataConverter(
21964
22147
  lender,
21965
22148
  chainId,
@@ -26639,7 +26822,8 @@ var getAbi2 = (lender) => {
26639
26822
  if (isEulerType(lender)) return accountLensAbi;
26640
26823
  if (isCompoundV2Type(lender))
26641
26824
  return [...ComptrollerAbi, ...CompoundV2CollateralToken];
26642
- if (isSiloV2Type(lender)) return [...SiloAbi];
26825
+ if (isSiloV2Type(lender) || isSiloV3Type(lender))
26826
+ return [...SiloAbi];
26643
26827
  return [];
26644
26828
  };
26645
26829
 
@@ -27047,7 +27231,21 @@ function toCompoundV2Shares(entry, amount) {
27047
27231
  return amount;
27048
27232
  }
27049
27233
  }
27050
- function resolveDebitDataKey(chainId, lender, tokenAddress, cToken) {
27234
+ function toSiloShares(entry, amount, chainId, lender, tokenAddress) {
27235
+ const raw = entry.params?.collateralRate;
27236
+ if (!raw || raw === "0x") return amount;
27237
+ try {
27238
+ const rate = BigInt(raw);
27239
+ if (rate === 0n) return amount;
27240
+ const half = getSiloHalfForUnderlying(chainId, lender, tokenAddress);
27241
+ if (!half) return amount;
27242
+ const oneUnit = BigInt(10) ** BigInt(half.decimals);
27243
+ return amount * oneUnit / rate * 1001n / 1000n;
27244
+ } catch {
27245
+ return amount;
27246
+ }
27247
+ }
27248
+ function resolveDebitDataKey(chainId, lender, tokenAddress, cToken, isProtected) {
27051
27249
  if (isCompoundV2Type(lender) || isVenusType(lender)) {
27052
27250
  if (cToken) return cToken.toLowerCase();
27053
27251
  const tokenMap = getCompoundV2CollateralTokens(chainId, lender);
@@ -27071,10 +27269,16 @@ function resolveDebitDataKey(chainId, lender, tokenAddress, cToken) {
27071
27269
  const aToken = getAaveCollateralTokenAddress(chainId, lender, tokenAddress);
27072
27270
  if (aToken) return aToken;
27073
27271
  }
27272
+ if (isSiloV2Type(lender) || isSiloV3Type(lender)) {
27273
+ const half = getSiloHalfForUnderlying(chainId, lender, tokenAddress);
27274
+ if (half) {
27275
+ return isProtected ? half.protectedShareToken.toLowerCase() : half.collateralShareToken.toLowerCase();
27276
+ }
27277
+ }
27074
27278
  return tokenAddress.toLowerCase();
27075
27279
  }
27076
27280
  function needsLenderApproval(params) {
27077
- const { lender, lenderDebitData, tokenAddress, amount, chainId, cToken } = params;
27281
+ const { lender, lenderDebitData, tokenAddress, amount, chainId, cToken, isProtected } = params;
27078
27282
  if (!lenderDebitData) return true;
27079
27283
  if (isAaveV4Type(lender)) {
27080
27284
  const key2 = (params.aaveV4Spoke ?? tokenAddress).toLowerCase();
@@ -27087,13 +27291,17 @@ function needsLenderApproval(params) {
27087
27291
  if (!entry2 || entry2.amount === void 0) return true;
27088
27292
  return entry2.amount === 0n;
27089
27293
  }
27090
- const key = resolveDebitDataKey(chainId, lender, tokenAddress, cToken);
27294
+ const key = resolveDebitDataKey(chainId, lender, tokenAddress, cToken, isProtected);
27091
27295
  const entry = lenderDebitData[key];
27092
27296
  if (!entry || entry.amount === void 0) return true;
27093
27297
  if (isCompoundV2Type(lender) || isVenusType(lender)) {
27094
27298
  const requiredShares = toCompoundV2Shares(entry, amount);
27095
27299
  return entry.amount < requiredShares;
27096
27300
  }
27301
+ if (isSiloV2Type(lender) || isSiloV3Type(lender)) {
27302
+ const requiredShares = toSiloShares(entry, amount, chainId, lender, tokenAddress);
27303
+ return entry.amount < requiredShares;
27304
+ }
27097
27305
  if (isCompoundV3(lender)) {
27098
27306
  return entry.amount === 0n;
27099
27307
  }
@@ -30637,9 +30845,7 @@ function parseSiloV2Results(data, meta, context) {
30637
30845
  const rawQt = data[qtIdx];
30638
30846
  if (!rawQt || rawQt === "0x") continue;
30639
30847
  const quoteTokenAddr = rawQt.toLowerCase();
30640
- const qtMeta = context.tokenList?.[quoteTokenAddr];
30641
- const qtDecimals = qtMeta?.decimals ?? 18;
30642
- const priceInQt = Number(quoteAmount) / Number(10n ** BigInt(qtDecimals));
30848
+ const priceInQt = Number(quoteAmount) / 1e18;
30643
30849
  if (isNaN(priceInQt) || priceInQt === 0) continue;
30644
30850
  const qtUSD = lookupUSD(context, quoteTokenAddr);
30645
30851
  if (!qtUSD) continue;
@@ -30810,9 +31016,7 @@ function parseSiloV3Results(data, meta, context) {
30810
31016
  const rawQt = data[qtIdx];
30811
31017
  if (!rawQt || rawQt === "0x") continue;
30812
31018
  const quoteTokenAddr = rawQt.toLowerCase();
30813
- const qtMeta = context.tokenList?.[quoteTokenAddr];
30814
- const qtDecimals = qtMeta?.decimals ?? 18;
30815
- const priceInQt = Number(quoteAmount) / Number(10n ** BigInt(qtDecimals));
31019
+ const priceInQt = Number(quoteAmount) / 1e18;
30816
31020
  if (isNaN(priceInQt) || priceInQt === 0) continue;
30817
31021
  const qtUSD = lookupUSD2(context, quoteTokenAddr);
30818
31022
  if (!qtUSD) continue;
@@ -30861,6 +31065,51 @@ async function fetchSiloV2GraphQLMarkets(chainId) {
30861
31065
  return null;
30862
31066
  }
30863
31067
  }
31068
+ async function fetchSiloV2GraphQLPrices(chainId, basePrices = {}, tokenList = {}) {
31069
+ const items = await fetchSiloV2GraphQLMarkets(chainId);
31070
+ if (items == null) return null;
31071
+ const usdPrices = buildSelfDerivedUsdMap(chainId, items, basePrices, tokenList);
31072
+ const context = { chainId, usdPrices, tokenList };
31073
+ const entries = parseSiloV2GraphQLResults(items, context);
31074
+ if (entries.length === 0) {
31075
+ console.warn(
31076
+ `[silo-v2-gql] chain ${chainId}: ${items.length} markets fetched but 0 price entries produced`
31077
+ );
31078
+ return null;
31079
+ }
31080
+ return entries;
31081
+ }
31082
+ function buildSelfDerivedUsdMap(chainId, items, basePrices, tokenList) {
31083
+ const map = {};
31084
+ const set = (tokenLc, priceUSD) => {
31085
+ if (!Number.isFinite(priceUSD) || priceUSD === 0) return;
31086
+ const groupKey = tokenList[tokenLc]?.assetGroup ?? `${chainId}-${tokenLc}`;
31087
+ if (map[groupKey] == null) map[groupKey] = priceUSD;
31088
+ if (map[tokenLc] == null) map[tokenLc] = priceUSD;
31089
+ };
31090
+ for (const item of items) {
31091
+ for (const market of [item.market1, item.market2]) {
31092
+ if (!market) continue;
31093
+ const tokenLc = (market.inputTokenId ?? market.inputToken?.id ?? "").toLowerCase();
31094
+ if (!tokenLc) continue;
31095
+ const supply = safeNumber3(market.supply);
31096
+ const supplyUsd = market.supplyUsd != null ? Number(market.supplyUsd) : 0;
31097
+ if (supply > 0 && supplyUsd > 0) {
31098
+ set(tokenLc, supplyUsd / supply);
31099
+ continue;
31100
+ }
31101
+ const borrowed = safeNumber3(market.borrowed);
31102
+ const borrowedUsd = market.borrowedUsd != null ? Number(market.borrowedUsd) : 0;
31103
+ if (borrowed > 0 && borrowedUsd > 0) {
31104
+ set(tokenLc, borrowedUsd / borrowed);
31105
+ }
31106
+ }
31107
+ }
31108
+ for (const [k, v] of Object.entries(basePrices)) {
31109
+ if (Number.isFinite(v) && v > 0) map[k] = v;
31110
+ }
31111
+ return map;
31112
+ }
30864
31113
  function safeNumber3(v) {
30865
31114
  if (v == null) return 0;
30866
31115
  const n = typeof v === "number" ? v : Number(v);
@@ -30960,6 +31209,51 @@ async function fetchSiloV3GraphQLMarkets(chainId) {
30960
31209
  return null;
30961
31210
  }
30962
31211
  }
31212
+ async function fetchSiloV3GraphQLPrices(chainId, basePrices = {}, tokenList = {}) {
31213
+ const items = await fetchSiloV3GraphQLMarkets(chainId);
31214
+ if (items == null) return null;
31215
+ const usdPrices = buildSelfDerivedUsdMap2(chainId, items, basePrices, tokenList);
31216
+ const context = { chainId, usdPrices, tokenList };
31217
+ const entries = parseSiloV3GraphQLResults(items, context);
31218
+ if (entries.length === 0) {
31219
+ console.warn(
31220
+ `[silo-v3-gql] chain ${chainId}: ${items.length} markets fetched but 0 price entries produced`
31221
+ );
31222
+ return null;
31223
+ }
31224
+ return entries;
31225
+ }
31226
+ function buildSelfDerivedUsdMap2(chainId, items, basePrices, tokenList) {
31227
+ const map = {};
31228
+ const set = (tokenLc, priceUSD) => {
31229
+ if (!Number.isFinite(priceUSD) || priceUSD === 0) return;
31230
+ const groupKey = tokenList[tokenLc]?.assetGroup ?? `${chainId}-${tokenLc}`;
31231
+ if (map[groupKey] == null) map[groupKey] = priceUSD;
31232
+ if (map[tokenLc] == null) map[tokenLc] = priceUSD;
31233
+ };
31234
+ for (const item of items) {
31235
+ for (const market of [item.market1, item.market2]) {
31236
+ if (!market) continue;
31237
+ const tokenLc = (market.inputTokenId ?? market.inputToken?.id ?? "").toLowerCase();
31238
+ if (!tokenLc) continue;
31239
+ const supply = safeNumber4(market.supply);
31240
+ const supplyUsd = market.supplyUsd != null ? Number(market.supplyUsd) : 0;
31241
+ if (supply > 0 && supplyUsd > 0) {
31242
+ set(tokenLc, supplyUsd / supply);
31243
+ continue;
31244
+ }
31245
+ const borrowed = safeNumber4(market.borrowed);
31246
+ const borrowedUsd = market.borrowedUsd != null ? Number(market.borrowedUsd) : 0;
31247
+ if (borrowed > 0 && borrowedUsd > 0) {
31248
+ set(tokenLc, borrowedUsd / borrowed);
31249
+ }
31250
+ }
31251
+ }
31252
+ for (const [k, v] of Object.entries(basePrices)) {
31253
+ if (Number.isFinite(v) && v > 0) map[k] = v;
31254
+ }
31255
+ return map;
31256
+ }
30963
31257
  function safeNumber4(v) {
30964
31258
  if (v == null) return 0;
30965
31259
  const n = typeof v === "number" ? v : Number(v);
@@ -31287,8 +31581,8 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31287
31581
  }
31288
31582
  const chainBatchSize = batchSize?.[chainId];
31289
31583
  const morphoGqlPromise = isActive("morpho") ? fetchMorphoGraphQLPrices(chainId) : Promise.resolve(null);
31290
- const siloV2GqlPromise = fetchSiloV2GraphQLMarkets(chainId);
31291
- const siloV3GqlPromise = fetchSiloV3GraphQLMarkets(chainId);
31584
+ const siloV2GqlPromise = isActive("silov2") ? fetchSiloV2GraphQLPrices(chainId, basePrices, tokenList) : Promise.resolve(null);
31585
+ const siloV3GqlPromise = isActive("silov3") ? fetchSiloV3GraphQLPrices(chainId, basePrices, tokenList) : Promise.resolve(null);
31292
31586
  const [
31293
31587
  aaveData,
31294
31588
  compoundV2Data,
@@ -31297,8 +31591,8 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31297
31591
  eulerData,
31298
31592
  aaveV4Data,
31299
31593
  morphoGqlEntries,
31300
- siloV2GqlItems,
31301
- siloV3GqlItems
31594
+ siloV2GqlEntries,
31595
+ siloV3GqlEntries
31302
31596
  ] = await Promise.all([
31303
31597
  executeGroup(
31304
31598
  aaveGroup,
@@ -31352,12 +31646,12 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31352
31646
  siloV2GqlPromise,
31353
31647
  siloV3GqlPromise
31354
31648
  ]);
31355
- if (siloV2GqlItems == null && siloV2Group.calls.length > 0) {
31649
+ if (siloV2GqlEntries == null && siloV2Group.calls.length > 0) {
31356
31650
  console.warn(
31357
- `[prices] chain ${chainId}: Silo v2 GraphQL unavailable, falling back to on-chain (${siloV2Group.trackers.length} trackers)`
31651
+ `[prices] chain ${chainId}: Silo v2 GraphQL returned null, falling back to on-chain (${siloV2Group.trackers.length} trackers)`
31358
31652
  );
31359
31653
  }
31360
- const siloV2Data = siloV2GqlItems != null ? { results: [], error: void 0 } : await executeGroup(
31654
+ const siloV2Data = siloV2GqlEntries != null ? { results: [], error: void 0 } : await executeGroup(
31361
31655
  siloV2Group,
31362
31656
  chainId,
31363
31657
  chainBatchSize,
@@ -31365,12 +31659,12 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31365
31659
  allowFailure,
31366
31660
  rpcOverrides
31367
31661
  );
31368
- if (siloV3GqlItems == null && siloV3Group.calls.length > 0) {
31662
+ if (siloV3GqlEntries == null && siloV3Group.calls.length > 0) {
31369
31663
  console.warn(
31370
- `[prices] chain ${chainId}: Silo v3 GraphQL unavailable, falling back to on-chain (${siloV3Group.trackers.length} trackers)`
31664
+ `[prices] chain ${chainId}: Silo v3 GraphQL returned null, falling back to on-chain (${siloV3Group.trackers.length} trackers)`
31371
31665
  );
31372
31666
  }
31373
- const siloV3Data = siloV3GqlItems != null ? { results: [], error: void 0 } : await executeGroup(
31667
+ const siloV3Data = siloV3GqlEntries != null ? { results: [], error: void 0 } : await executeGroup(
31374
31668
  siloV3Group,
31375
31669
  chainId,
31376
31670
  chainBatchSize,
@@ -31399,8 +31693,8 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31399
31693
  { group: listaGroup, data: listaData },
31400
31694
  { group: eulerGroup, data: eulerData },
31401
31695
  { group: aaveV4Group, data: aaveV4Data },
31402
- ...siloV2GqlItems != null ? [] : [{ group: siloV2Group, data: siloV2Data }],
31403
- ...siloV3GqlItems != null ? [] : [{ group: siloV3Group, data: siloV3Data }],
31696
+ ...siloV2GqlEntries != null ? [] : [{ group: siloV2Group, data: siloV2Data }],
31697
+ ...siloV3GqlEntries != null ? [] : [{ group: siloV3Group, data: siloV3Data }],
31404
31698
  ...useMorphoGql ? [] : [{ group: morphoGroup, data: morphoData }]
31405
31699
  ];
31406
31700
  for (const { group, data } of groupResults) {
@@ -31485,16 +31779,14 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31485
31779
  true,
31486
31780
  (t) => !!t.meta.baseAssetSource
31487
31781
  );
31488
- if (siloV2GqlItems != null) {
31489
- const context = { chainId, usdPrices, tokenList };
31490
- const entries = parseSiloV2GraphQLResults(siloV2GqlItems, context);
31782
+ if (siloV2GqlEntries != null) {
31491
31783
  const diag2 = {
31492
31784
  lender: "SILO_V2 (GraphQL)",
31493
31785
  callCount: 0,
31494
31786
  failedCalls: 0,
31495
- parsedEntries: entries.length
31787
+ parsedEntries: siloV2GqlEntries.length
31496
31788
  };
31497
- for (const entry of entries) {
31789
+ for (const entry of siloV2GqlEntries) {
31498
31790
  const lender = entry.targetLender ?? "SILO_V2";
31499
31791
  if (!chainResult[lender]) chainResult[lender] = [];
31500
31792
  chainResult[lender].push(entry);
@@ -31506,16 +31798,14 @@ async function fetchOraclePrices(chainIds, rpcOverrides, lists = {}, retries = 3
31506
31798
  } else {
31507
31799
  parseTrackers(siloV2Group, siloV2Data.results);
31508
31800
  }
31509
- if (siloV3GqlItems != null) {
31510
- const context = { chainId, usdPrices, tokenList };
31511
- const entries = parseSiloV3GraphQLResults(siloV3GqlItems, context);
31801
+ if (siloV3GqlEntries != null) {
31512
31802
  const diag2 = {
31513
31803
  lender: "SILO_V3 (GraphQL)",
31514
31804
  callCount: 0,
31515
31805
  failedCalls: 0,
31516
- parsedEntries: entries.length
31806
+ parsedEntries: siloV3GqlEntries.length
31517
31807
  };
31518
- for (const entry of entries) {
31808
+ for (const entry of siloV3GqlEntries) {
31519
31809
  const lender = entry.targetLender ?? "SILO_V3";
31520
31810
  if (!chainResult[lender]) chainResult[lender] = [];
31521
31811
  chainResult[lender].push(entry);
@@ -32076,16 +32366,48 @@ function getSupportedAssets(lenderMeta, targetMode) {
32076
32366
  }
32077
32367
  return { collateral, borrow };
32078
32368
  }
32369
+ function isCollateralBlockedInMode(config) {
32370
+ if (!config) return true;
32371
+ if (config.collateralDisabled) return true;
32372
+ if ((config.borrowCollateralFactor ?? 0) === 0) return true;
32373
+ return false;
32374
+ }
32079
32375
  function canSwitchToEMode(positions, lenderMeta, targetMode, healthFactor) {
32080
- if (healthFactor !== null && healthFactor <= 1) return false;
32376
+ if (healthFactor !== null && healthFactor <= 1) {
32377
+ return { canSwitch: false, blockReason: "health_factor", blockingAssets: [] };
32378
+ }
32379
+ const collateralBlocking = [];
32380
+ const debtBlocking = [];
32081
32381
  for (let i = 0; i < positions.length; i++) {
32082
32382
  const pos = positions[i];
32083
- const totalDebt = pos.debtUSD + pos.debtStableUSD;
32084
- if (totalDebt <= 0) continue;
32085
32383
  const config = lenderMeta[pos.marketUid]?.configs?.[targetMode];
32086
- if (!config || config.debtDisabled) return false;
32384
+ if (pos.collateralEnabled && pos.depositsUSD > 0) {
32385
+ if (isCollateralBlockedInMode(config)) {
32386
+ collateralBlocking.push(pos.marketUid);
32387
+ }
32388
+ }
32389
+ const totalDebt = pos.debtUSD + pos.debtStableUSD;
32390
+ if (totalDebt > 0) {
32391
+ if (!config || config.debtDisabled) {
32392
+ debtBlocking.push(pos.marketUid);
32393
+ }
32394
+ }
32087
32395
  }
32088
- return true;
32396
+ if (collateralBlocking.length > 0) {
32397
+ return {
32398
+ canSwitch: false,
32399
+ blockReason: "collateral_not_supported",
32400
+ blockingAssets: [...collateralBlocking, ...debtBlocking]
32401
+ };
32402
+ }
32403
+ if (debtBlocking.length > 0) {
32404
+ return {
32405
+ canSwitch: false,
32406
+ blockReason: "debt_not_supported",
32407
+ blockingAssets: debtBlocking
32408
+ };
32409
+ }
32410
+ return { canSwitch: true };
32089
32411
  }
32090
32412
  function computeEModeAnalysis(subAccount, lenderMeta, eModes) {
32091
32413
  const { positions, balanceData: balanceData2, userConfig } = subAccount;
@@ -32101,18 +32423,22 @@ function computeEModeAnalysis(subAccount, lenderMeta, eModes) {
32101
32423
  targetMode
32102
32424
  );
32103
32425
  const supportedAssets = getSupportedAssets(lenderMeta, targetMode);
32104
- const canSwitch = canSwitchToEMode(
32426
+ const { canSwitch, blockReason, blockingAssets } = canSwitchToEMode(
32105
32427
  positions,
32106
32428
  lenderMeta,
32107
32429
  targetMode,
32108
32430
  healthFactor
32109
32431
  );
32110
32432
  return {
32433
+ modeId: eMode.category,
32111
32434
  category: eMode.category,
32435
+ // backward-compat alias
32112
32436
  label: eMode.label,
32113
32437
  healthFactor,
32114
32438
  supportedAssets,
32115
- canSwitch
32439
+ canSwitch,
32440
+ ...blockReason ? { blockReason } : {},
32441
+ ...blockingAssets ? { blockingAssets } : {}
32116
32442
  };
32117
32443
  });
32118
32444
  }