@1delta/margin-fetcher 0.0.231 → 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.
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
  }
@@ -32158,16 +32366,48 @@ function getSupportedAssets(lenderMeta, targetMode) {
32158
32366
  }
32159
32367
  return { collateral, borrow };
32160
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
+ }
32161
32375
  function canSwitchToEMode(positions, lenderMeta, targetMode, healthFactor) {
32162
- 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 = [];
32163
32381
  for (let i = 0; i < positions.length; i++) {
32164
32382
  const pos = positions[i];
32165
- const totalDebt = pos.debtUSD + pos.debtStableUSD;
32166
- if (totalDebt <= 0) continue;
32167
32383
  const config = lenderMeta[pos.marketUid]?.configs?.[targetMode];
32168
- 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
+ }
32169
32395
  }
32170
- 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 };
32171
32411
  }
32172
32412
  function computeEModeAnalysis(subAccount, lenderMeta, eModes) {
32173
32413
  const { positions, balanceData: balanceData2, userConfig } = subAccount;
@@ -32183,18 +32423,22 @@ function computeEModeAnalysis(subAccount, lenderMeta, eModes) {
32183
32423
  targetMode
32184
32424
  );
32185
32425
  const supportedAssets = getSupportedAssets(lenderMeta, targetMode);
32186
- const canSwitch = canSwitchToEMode(
32426
+ const { canSwitch, blockReason, blockingAssets } = canSwitchToEMode(
32187
32427
  positions,
32188
32428
  lenderMeta,
32189
32429
  targetMode,
32190
32430
  healthFactor
32191
32431
  );
32192
32432
  return {
32433
+ modeId: eMode.category,
32193
32434
  category: eMode.category,
32435
+ // backward-compat alias
32194
32436
  label: eMode.label,
32195
32437
  healthFactor,
32196
32438
  supportedAssets,
32197
- canSwitch
32439
+ canSwitch,
32440
+ ...blockReason ? { blockReason } : {},
32441
+ ...blockingAssets ? { blockingAssets } : {}
32198
32442
  };
32199
32443
  });
32200
32444
  }