@defisaver/positions-sdk 2.1.166 → 2.1.168-stable-pair-dev

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 (99) hide show
  1. package/cjs/aaveV2/index.js +8 -29
  2. package/cjs/aaveV3/index.js +2 -31
  3. package/cjs/aaveV4/index.d.ts +25 -0
  4. package/cjs/aaveV4/index.js +4 -1
  5. package/cjs/compoundV2/index.d.ts +1 -1
  6. package/cjs/compoundV2/index.js +2 -2
  7. package/cjs/curveUsd/index.d.ts +1 -1
  8. package/cjs/curveUsd/index.js +6 -1
  9. package/cjs/fluid/index.js +13 -12
  10. package/cjs/helpers/aaveBalances.d.ts +5 -0
  11. package/cjs/helpers/aaveBalances.js +51 -0
  12. package/cjs/helpers/aaveV4Helpers/index.js +11 -1
  13. package/cjs/helpers/fluidBalances.d.ts +6 -0
  14. package/cjs/helpers/fluidBalances.js +36 -0
  15. package/cjs/liquityV2/index.d.ts +8 -0
  16. package/cjs/liquityV2/index.js +3 -3
  17. package/cjs/llamaLend/index.d.ts +1 -1
  18. package/cjs/llamaLend/index.js +6 -1
  19. package/cjs/markets/morphoBlue/index.d.ts +0 -2
  20. package/cjs/markets/morphoBlue/index.js +3 -20
  21. package/cjs/moneymarket/moneymarketCommonService.js +12 -2
  22. package/cjs/morphoMidnight/index.d.ts +1 -1
  23. package/cjs/morphoMidnight/index.js +6 -1
  24. package/cjs/portfolio/index.d.ts +1 -0
  25. package/cjs/portfolio/index.js +3 -0
  26. package/cjs/portfolio/lendingSummaries.d.ts +7 -0
  27. package/cjs/portfolio/lendingSummaries.js +262 -0
  28. package/cjs/portfolio/lendingSummaryTransport.d.ts +8 -0
  29. package/cjs/portfolio/lendingSummaryTransport.js +109 -0
  30. package/cjs/spark/index.js +2 -31
  31. package/cjs/types/common.d.ts +1 -0
  32. package/cjs/types/common.js +1 -0
  33. package/cjs/types/index.d.ts +1 -0
  34. package/cjs/types/index.js +1 -0
  35. package/cjs/types/lendingSummary.d.ts +34 -0
  36. package/cjs/types/lendingSummary.js +2 -0
  37. package/cjs/types/morphoBlue.d.ts +0 -1
  38. package/cjs/types/morphoBlue.js +0 -1
  39. package/esm/aaveV2/index.js +11 -32
  40. package/esm/aaveV3/index.js +3 -32
  41. package/esm/aaveV4/index.d.ts +25 -0
  42. package/esm/aaveV4/index.js +3 -1
  43. package/esm/compoundV2/index.d.ts +1 -1
  44. package/esm/compoundV2/index.js +2 -2
  45. package/esm/curveUsd/index.d.ts +1 -1
  46. package/esm/curveUsd/index.js +6 -1
  47. package/esm/fluid/index.js +13 -12
  48. package/esm/helpers/aaveBalances.d.ts +5 -0
  49. package/esm/helpers/aaveBalances.js +45 -0
  50. package/esm/helpers/aaveV4Helpers/index.js +11 -1
  51. package/esm/helpers/fluidBalances.d.ts +6 -0
  52. package/esm/helpers/fluidBalances.js +28 -0
  53. package/esm/liquityV2/index.d.ts +8 -0
  54. package/esm/liquityV2/index.js +1 -1
  55. package/esm/llamaLend/index.d.ts +1 -1
  56. package/esm/llamaLend/index.js +6 -1
  57. package/esm/markets/morphoBlue/index.d.ts +0 -2
  58. package/esm/markets/morphoBlue/index.js +0 -16
  59. package/esm/moneymarket/moneymarketCommonService.js +12 -2
  60. package/esm/morphoMidnight/index.d.ts +1 -1
  61. package/esm/morphoMidnight/index.js +6 -1
  62. package/esm/portfolio/index.d.ts +1 -0
  63. package/esm/portfolio/index.js +1 -0
  64. package/esm/portfolio/lendingSummaries.d.ts +7 -0
  65. package/esm/portfolio/lendingSummaries.js +256 -0
  66. package/esm/portfolio/lendingSummaryTransport.d.ts +8 -0
  67. package/esm/portfolio/lendingSummaryTransport.js +104 -0
  68. package/esm/spark/index.js +4 -33
  69. package/esm/types/common.d.ts +1 -0
  70. package/esm/types/common.js +1 -0
  71. package/esm/types/index.d.ts +1 -0
  72. package/esm/types/index.js +1 -0
  73. package/esm/types/lendingSummary.d.ts +34 -0
  74. package/esm/types/lendingSummary.js +1 -0
  75. package/esm/types/morphoBlue.d.ts +0 -1
  76. package/esm/types/morphoBlue.js +0 -1
  77. package/package.json +1 -1
  78. package/src/aaveV2/index.ts +8 -48
  79. package/src/aaveV3/index.ts +2 -48
  80. package/src/aaveV4/index.ts +6 -1
  81. package/src/compoundV2/index.ts +2 -2
  82. package/src/curveUsd/index.ts +6 -1
  83. package/src/fluid/index.ts +13 -12
  84. package/src/helpers/aaveBalances.ts +41 -0
  85. package/src/helpers/aaveV4Helpers/index.ts +12 -1
  86. package/src/helpers/fluidBalances.ts +34 -0
  87. package/src/liquityV2/index.ts +1 -1
  88. package/src/llamaLend/index.ts +6 -1
  89. package/src/markets/morphoBlue/index.ts +0 -16
  90. package/src/moneymarket/moneymarketCommonService.ts +13 -2
  91. package/src/morphoMidnight/index.ts +6 -1
  92. package/src/portfolio/index.ts +2 -0
  93. package/src/portfolio/lendingSummaries.ts +216 -0
  94. package/src/portfolio/lendingSummaryTransport.ts +84 -0
  95. package/src/spark/index.ts +3 -49
  96. package/src/types/common.ts +1 -0
  97. package/src/types/index.ts +2 -1
  98. package/src/types/lendingSummary.ts +41 -0
  99. package/src/types/morphoBlue.ts +0 -1
@@ -1,6 +1,7 @@
1
1
  import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
2
2
  import { Client } from 'viem';
3
3
  import Dec from 'decimal.js';
4
+ import { getAaveLikeBalances } from '../helpers/aaveBalances';
4
5
  import {
5
6
  AaveIncentiveDataProviderV3ContractViem,
6
7
  AaveIncentivesControllerViem,
@@ -17,7 +18,6 @@ import {
17
18
  isEnabledOnBitmap,
18
19
  isLayer2Network,
19
20
  wethToEth,
20
- wethToEthByAddress,
21
21
  } from '../services/utils';
22
22
  import { getStakingApy, STAKING_ASSETS } from '../staking';
23
23
  import {
@@ -384,53 +384,7 @@ export const EMPTY_AAVE_DATA = {
384
384
  };
385
385
 
386
386
  export const _getAaveV3AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
387
- let balances: PositionBalances = {
388
- collateral: {},
389
- debt: {},
390
- };
391
-
392
- if (!address) {
393
- return balances;
394
- }
395
-
396
- const loanInfoContract = AaveV3ViewContractViem(provider, network, block);
397
-
398
- const market = AAVE_V3(network);
399
- const marketAddress = market.providerAddress;
400
- // @ts-ignore
401
- const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
402
-
403
- // @ts-ignore
404
- const reserveTokens = await protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block)) as { symbol: string, tokenAddress: EthAddress }[];
405
- const symbols = reserveTokens.map(({ symbol }: { symbol: string }) => symbol);
406
- const _addresses = reserveTokens.map(({ tokenAddress }: { tokenAddress: EthAddress }) => tokenAddress);
407
-
408
- // split addresses in half to avoid gas limit by multicall
409
- const middleAddressIndex = Math.floor(_addresses.length / 2);
410
-
411
- const [tokenBalances1, tokenBalances2] = await Promise.all([
412
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
413
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
414
- ]);
415
-
416
- const loanInfo = [...tokenBalances1, ...tokenBalances2];
417
-
418
- loanInfo.forEach((tokenInfo: any, i: number) => {
419
- const asset = wethToEth(symbols[i]);
420
- const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
421
-
422
- balances = {
423
- collateral: {
424
- ...balances.collateral,
425
- [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString(),
426
- },
427
- debt: {
428
- ...balances.debt,
429
- [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString(),
430
- },
431
- };
432
- });
433
-
387
+ const balances = await getAaveLikeBalances(provider, network, block, addressMapping, address, AAVE_V3(network), 'AaveV3View');
434
388
  return balances;
435
389
  };
436
390
 
@@ -1,7 +1,7 @@
1
1
  import { Client } from 'viem';
2
2
  import Dec from 'decimal.js';
3
3
  import { assetAmountInEth, assetAmountInWei, getAssetInfoByAddress } from '@defisaver/tokens';
4
- import { getViemProvider } from '../services/viem';
4
+ import { getViemProvider, setViemBlockNumber } from '../services/viem';
5
5
  import {
6
6
  AaveV4AccountData,
7
7
  AaveV4HubAssetOnChainData,
@@ -275,6 +275,11 @@ export async function _getAaveV4AccountData(provider: Client, network: NetworkNu
275
275
  };
276
276
  }
277
277
 
278
+ /** Shared raw read; no spoke metadata or market enrichment. */
279
+ export const _getAaveV4LoanBalances = (provider: Client, network: NetworkNumber, block: Blockish, address: EthAddress, spoke: EthAddress) => (
280
+ AaveV4ViewContractViem(provider, network, block).read.getLoanData([spoke, address], setViemBlockNumber(block))
281
+ );
282
+
278
283
  /**
279
284
  * Lightweight existence check for Loan Shifter / UI discovery.
280
285
  * Reads only `getLoanData(spoke, user)` and returns whether any reserve has
@@ -116,7 +116,7 @@ const getAllMarketAddresses = async (provider: Client, network: NetworkNumber, b
116
116
  };
117
117
 
118
118
 
119
- export const _getCompoundV2AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
119
+ export const _getCompoundV2AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, tokens?: EthAddress[]): Promise<PositionBalances> => {
120
120
  let balances: PositionBalances = {
121
121
  collateral: {},
122
122
  debt: {},
@@ -126,7 +126,7 @@ export const _getCompoundV2AccountBalances = async (provider: Client, network: N
126
126
  return balances;
127
127
  }
128
128
 
129
- const assets = await getAllMarketAddresses(provider, network, block);
129
+ const assets = tokens || await getAllMarketAddresses(provider, network, block);
130
130
  const assetInfo = assets.map(a => getAssetInfoByAddress(a, network));
131
131
  const loanInfoContract = CompoundLoanInfoContractViem(provider, network, block);
132
132
  const loanInfo = await loanInfoContract.read.getTokenBalances([address, assets], setViemBlockNumber(block));
@@ -128,7 +128,7 @@ const getStatusForUser = (bandRange: string[], activeBand: string, crvUSDSupplie
128
128
  return CrvUSDStatus.Nonexistant;
129
129
  };
130
130
 
131
- export const _getCrvUsdAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress): Promise<PositionBalances> => {
131
+ export const _getCrvUsdAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress, includeDeposited = false): Promise<PositionBalances> => {
132
132
  let balances: PositionBalances = {
133
133
  collateral: {},
134
134
  debt: {},
@@ -152,6 +152,11 @@ export const _getCrvUsdAccountBalances = async (provider: Client, network: Netwo
152
152
  },
153
153
  };
154
154
 
155
+ if (includeDeposited) {
156
+ balances.deposited = {
157
+ [addressMapping ? getAssetInfo(wethToEth(selectedMarket.baseAsset), network).address.toLowerCase() : wethToEth(selectedMarket.baseAsset)]: data.curveUsdCollateralAmount.toString(),
158
+ };
159
+ }
155
160
  return balances;
156
161
  };
157
162
 
@@ -3,6 +3,7 @@ import {
3
3
  assetAmountInEth, AssetData, getAssetInfo, getAssetInfoByAddress,
4
4
  } from '@defisaver/tokens';
5
5
  import { Client, PublicClient } from 'viem';
6
+ import { fluidTokenAmount } from '../helpers/fluidBalances';
6
7
  import {
7
8
  EthAddress, EthereumProvider, IncentiveKind, NetworkNumber,
8
9
  } from '../types/common';
@@ -1178,8 +1179,8 @@ const parseT1UserData = (userPositionData: FluidUserPositionStructOutputStruct,
1178
1179
  const debtAsset = getAssetInfo(marketData.debtAsset0);
1179
1180
 
1180
1181
  // for T2 and T4 - this is the number of shares
1181
- const supplied = getEthAmountForDecimals(userPositionData.supply.toString(), collAsset.decimals);
1182
- const borrowed = getEthAmountForDecimals(userPositionData.borrow.toString(), debtAsset.decimals);
1182
+ const supplied = fluidTokenAmount(userPositionData.supply, collAsset.decimals);
1183
+ const borrowed = fluidTokenAmount(userPositionData.borrow, debtAsset.decimals);
1183
1184
 
1184
1185
  const collUsedAsset: FluidUsedAsset = {
1185
1186
  ...EMPTY_USED_ASSET,
@@ -1234,10 +1235,10 @@ const parseT2UserData = (userPositionData: FluidUserPositionStructOutputStruct,
1234
1235
  const debtAsset = getAssetInfo(marketData.debtAsset0);
1235
1236
 
1236
1237
  const supplyShares = getEthAmountForDecimals(userPositionData.supply.toString(), 18); // this is supplied in coll shares
1237
- const borrowed = getEthAmountForDecimals(userPositionData.borrow.toString(), debtAsset.decimals); // this is actual token borrow
1238
+ const borrowed = fluidTokenAmount(userPositionData.borrow, debtAsset.decimals); // this is actual token borrow
1238
1239
 
1239
- const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare!).toString();
1240
- const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare!).toString();
1240
+ const supplied0 = fluidTokenAmount(userPositionData.supply, collAsset0.decimals, assetsData[collAsset0.symbol].tokenPerSupplyShare!);
1241
+ const supplied1 = fluidTokenAmount(userPositionData.supply, collAsset1.decimals, assetsData[collAsset1.symbol].tokenPerSupplyShare!);
1241
1242
 
1242
1243
  const collUsedAsset0: Partial<FluidUsedAsset> = {
1243
1244
  symbol: collAsset0.symbol,
@@ -1302,11 +1303,11 @@ const parseT3UserData = (userPositionData: FluidUserPositionStructOutputStruct,
1302
1303
  const debtAsset0 = getAssetInfo(marketData.debtAsset0);
1303
1304
  const debtAsset1 = getAssetInfo(marketData.debtAsset1);
1304
1305
 
1305
- const supplied = getEthAmountForDecimals(userPositionData.supply.toString(), collAsset.decimals); // this is actual token supply
1306
+ const supplied = fluidTokenAmount(userPositionData.supply, collAsset.decimals); // this is actual token supply
1306
1307
  const borrowShares = getEthAmountForDecimals(userPositionData.borrow.toString(), 18); // this is actual token borrow
1307
1308
 
1308
- const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare!).toString();
1309
- const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare!).toString();
1309
+ const borrowed0 = fluidTokenAmount(userPositionData.borrow, debtAsset0.decimals, assetsData[debtAsset0.symbol].tokenPerBorrowShare!);
1310
+ const borrowed1 = fluidTokenAmount(userPositionData.borrow, debtAsset1.decimals, assetsData[debtAsset1.symbol].tokenPerBorrowShare!);
1310
1311
 
1311
1312
  const collUsedAsset: Partial<FluidUsedAsset> = {
1312
1313
  symbol: collAsset.symbol,
@@ -1374,11 +1375,11 @@ const parseT4UserData = (userPositionData: FluidUserPositionStructOutputStruct,
1374
1375
  const supplyShares = getEthAmountForDecimals(userPositionData.supply.toString(), 18); // this is actual token supply
1375
1376
  const borrowShares = getEthAmountForDecimals(userPositionData.borrow.toString(), 18); // this is actual token borrow
1376
1377
 
1377
- const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare!).toString();
1378
- const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare!).toString();
1378
+ const supplied0 = fluidTokenAmount(userPositionData.supply, collAsset0.decimals, assetsData[collAsset0.symbol].tokenPerSupplyShare!);
1379
+ const supplied1 = fluidTokenAmount(userPositionData.supply, collAsset1.decimals, assetsData[collAsset1.symbol].tokenPerSupplyShare!);
1379
1380
 
1380
- const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare!).toString();
1381
- const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare!).toString();
1381
+ const borrowed0 = fluidTokenAmount(userPositionData.borrow, debtAsset0.decimals, assetsData[debtAsset0.symbol].tokenPerBorrowShare!);
1382
+ const borrowed1 = fluidTokenAmount(userPositionData.borrow, debtAsset1.decimals, assetsData[debtAsset1.symbol].tokenPerBorrowShare!);
1382
1383
 
1383
1384
  const collUsedAsset0: Partial<FluidUsedAsset> = {
1384
1385
  symbol: collAsset0.symbol,
@@ -0,0 +1,41 @@
1
+ import Dec from 'decimal.js';
2
+ import { getAssetInfoByAddress } from '@defisaver/tokens';
3
+ import { Client } from 'viem';
4
+ import { AaveMarketInfo, SparkMarketData } from '../types';
5
+ import {
6
+ Blockish, EthAddress, NetworkNumber, PositionBalances,
7
+ } from '../types/common';
8
+ import { createViemContractFromConfigFunc } from '../contracts';
9
+ import { setViemBlockNumber } from '../services/viem';
10
+ import { wethToEth, wethToEthByAddress } from '../services/utils';
11
+
12
+ /** Raw token balances shared by Aave/Spark getters and lending previews. */
13
+ export async function getAaveLikeBalances(
14
+ client: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean,
15
+ address: EthAddress, market: Pick<AaveMarketInfo | SparkMarketData, 'providerAddress' | 'protocolData' | 'protocolDataAddress'>,
16
+ view: 'AaveLoanInfoV2' | 'AaveV3View' | 'SparkView', tokens?: EthAddress[],
17
+ ): Promise<PositionBalances> {
18
+ const balances: PositionBalances = { collateral: {}, debt: {} };
19
+ if (!address) return balances;
20
+ let reserves: { tokenAddress: EthAddress; symbol: string }[];
21
+ if (tokens) reserves = tokens.map(tokenAddress => ({ tokenAddress, symbol: getAssetInfoByAddress(tokenAddress, network).symbol }));
22
+ else {
23
+ if (!market.protocolData) throw new Error('Missing protocol data provider');
24
+ reserves = [...await createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress as EthAddress)(client, network)
25
+ .read.getAllReservesTokens(setViemBlockNumber(block))];
26
+ }
27
+ const addresses = reserves.map(token => token.tokenAddress);
28
+ const contract = createViemContractFromConfigFunc(view)(client, network, block);
29
+ const middle = tokens ? Math.ceil(addresses.length / 2) : Math.floor(addresses.length / 2);
30
+ // Preserve legacy V2 single-call and V3/Spark two-call behavior.
31
+ const parts = !tokens && view === 'AaveLoanInfoV2' ? [addresses] : [addresses.slice(0, middle), addresses.slice(middle)];
32
+ const data = (await Promise.all((tokens ? parts.filter(part => part.length) : parts)
33
+ .map(part => contract.read.getTokenBalances([market.providerAddress, address, part], setViemBlockNumber(block))))).flat();
34
+ data.forEach((token, i) => {
35
+ // The views leave token.token unset; input order identifies the reserve.
36
+ const key = addressMapping ? wethToEthByAddress(reserves[i].tokenAddress, network).toLowerCase() : wethToEth(reserves[i].symbol);
37
+ balances.collateral![key] = token.balance.toString();
38
+ balances.debt![key] = new Dec(token.borrowsStable.toString()).add(token.borrowsVariable.toString()).toString();
39
+ });
40
+ return balances;
41
+ }
@@ -198,13 +198,17 @@ export const isLeveragedPosAaveV4 = (usedAssets: AaveV4UsedReserveAssets, dustLi
198
198
  let supplyUnstable = 0;
199
199
  let longAsset = '';
200
200
  let shortAsset = '';
201
+ let stableCollAsset = '';
201
202
  Object.values(usedAssets).forEach(({
202
203
  symbol, suppliedUsd, borrowedUsd, collateral, reserveId,
203
204
  }) => {
204
205
  const spokeAsset = `${symbol}-${reserveId}`;
205
206
  const isSupplied = (+suppliedUsd) > dustLimit; // ignore dust like <limit leftover supply
206
207
  const isBorrowed = (+borrowedUsd) > dustLimit; // ignore dust like <limit leftover supply
207
- if (isSupplied && STABLE_ASSETS.includes(symbol) && collateral) supplyStable += 1;
208
+ if (isSupplied && STABLE_ASSETS.includes(symbol) && collateral) {
209
+ supplyStable += 1;
210
+ stableCollAsset = spokeAsset;
211
+ }
208
212
  if (isBorrowed && STABLE_ASSETS.includes(symbol)) borrowStable += 1;
209
213
  if (isBorrowed && !STABLE_ASSETS.includes(symbol)) {
210
214
  borrowUnstable += 1;
@@ -218,6 +222,7 @@ export const isLeveragedPosAaveV4 = (usedAssets: AaveV4UsedReserveAssets, dustLi
218
222
  const isLong = borrowStable > 0 && borrowUnstable === 0 && supplyUnstable === 1 && supplyStable === 0;
219
223
  const isShort = supplyStable > 0 && supplyUnstable === 0 && borrowUnstable === 1 && borrowStable === 0;
220
224
  const isVolatilePair = supplyUnstable === 1 && borrowUnstable === 1 && supplyStable === 0 && borrowStable === 0;
225
+ const isStablePair = supplyStable === 1 && borrowStable === 1 && supplyUnstable === 0 && borrowUnstable === 0;
221
226
  if (isLong) {
222
227
  return {
223
228
  leveragedType: LeverageType.Long,
@@ -236,6 +241,12 @@ export const isLeveragedPosAaveV4 = (usedAssets: AaveV4UsedReserveAssets, dustLi
236
241
  leveragedAsset: longAsset,
237
242
  };
238
243
  }
244
+ if (isStablePair) {
245
+ return {
246
+ leveragedType: LeverageType.StablePair,
247
+ leveragedAsset: stableCollAsset,
248
+ };
249
+ }
239
250
  return {
240
251
  leveragedType: LeverageType.None,
241
252
  leveragedAsset: '',
@@ -0,0 +1,34 @@
1
+ import Dec from 'decimal.js';
2
+ import { getAssetInfoByAddress } from '@defisaver/tokens';
3
+ import { FluidUserPositionStructOutputStruct, FluidVaultDataStructOutputStruct } from '../types';
4
+ import { NetworkNumber, PositionBalances } from '../types/common';
5
+
6
+ /** Convert raw tokens, or raw 18-decimal shares with a human-readable token/share ratio. */
7
+ export const fluidTokenAmount = (amount: bigint, decimals: number, perShare?: string): string => (
8
+ new Dec(amount.toString()).div(new Dec(10).pow(perShare === undefined ? decimals : 18)).mul(perShare ?? 1).toString()
9
+ );
10
+
11
+ /** The same token/share conversion used by the full Fluid user parsers, without prices or yield. */
12
+ export function parseFluidBalances(position: FluidUserPositionStructOutputStruct, vault: FluidVaultDataStructOutputStruct, network: NetworkNumber): PositionBalances {
13
+ const type = Number(vault.vaultType);
14
+ if (![10000, 20000, 30000, 40000].includes(type)) throw new Error('Unsupported Fluid vault');
15
+ const side = (amount: bigint, tokens: string[], ratios: bigint[] | undefined) => {
16
+ const balances: Record<string, string> = {};
17
+ tokens.forEach((address, i) => {
18
+ const token = getAssetInfoByAddress(address, network);
19
+ if (!Number.isFinite(token.decimals) || !token.symbol) throw new Error('Fluid token metadata unavailable');
20
+ const perShare = ratios ? fluidTokenAmount(ratios[i], token.decimals) : undefined;
21
+ const value = fluidTokenAmount(amount, token.decimals, perShare);
22
+ balances[token.symbol] = new Dec(balances[token.symbol] || 0).add(value).toString();
23
+ });
24
+ return balances;
25
+ };
26
+ const smartSupply = type === 20000 || type === 40000;
27
+ const smartDebt = type === 30000 || type === 40000;
28
+ return {
29
+ collateral: side(position.supply, smartSupply ? [vault.supplyToken0, vault.supplyToken1] : [vault.supplyToken0],
30
+ smartSupply ? [vault.dexSupplyData.token0PerSupplyShare, vault.dexSupplyData.token1PerSupplyShare] : undefined),
31
+ debt: side(position.borrow, smartDebt ? [vault.borrowToken0, vault.borrowToken1] : [vault.borrowToken0],
32
+ smartDebt ? [vault.dexBorrowData.token0PerBorrowShare, vault.dexBorrowData.token1PerBorrowShare] : undefined),
33
+ };
34
+ }
@@ -152,7 +152,7 @@ const getUserTroves = async (
152
152
  return getUserTroves(provider, network, isLegacy, account, marketAddress, newStartIndex, newStartIndex + 100, existingTroves);
153
153
  };
154
154
 
155
- const nftContractCreationBlockMapping = {
155
+ export const nftContractCreationBlockMapping = {
156
156
  [LiquityV2Versions.LiquityV2Eth]: 22516079,
157
157
  [LiquityV2Versions.LiquityV2WstEth]: 22516099,
158
158
  [LiquityV2Versions.LiquityV2REth]: 22516118,
@@ -168,7 +168,7 @@ const getStatusForUser = (bandRange: string[], activeBand: string, debtSupplied:
168
168
  return LlamaLendStatus.Nonexistant;
169
169
  };
170
170
 
171
- export const _getLlamaLendAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress): Promise<PositionBalances> => {
171
+ export const _getLlamaLendAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, controllerAddress: EthAddress, includeDeposited = false): Promise<PositionBalances> => {
172
172
  let balances: PositionBalances = {
173
173
  collateral: {},
174
174
  debt: {},
@@ -192,6 +192,11 @@ export const _getLlamaLendAccountBalances = async (provider: Client, network: Ne
192
192
  },
193
193
  };
194
194
 
195
+ if (includeDeposited) {
196
+ balances.deposited = {
197
+ [addressMapping ? getAssetInfo(wethToEth(selectedMarket.baseAsset), network).address.toLowerCase() : wethToEth(selectedMarket.baseAsset)]: data.debtTokenCollateralAmount.toString(),
198
+ };
199
+ }
195
200
  return balances;
196
201
  };
197
202
 
@@ -712,21 +712,6 @@ export const MORPHO_BLUE_SWBTC_WBTC_945 = (networkId: NetworkNumber = NetworkNum
712
712
  marketId: '0x514efda728a646dcafe4fdc9afe4ea214709e110ac1b2b78185ae00c1782cc82',
713
713
  protocolName: 'morpho-blue',
714
714
  });
715
- export const MORPHO_BLUE_OSETH_ETH_860 = (networkId: NetworkNumber = NetworkNumber.Eth): MorphoBlueMarketData => ({
716
- chainIds: [NetworkNumber.Eth],
717
- label: 'Morpho Blue',
718
- shortLabel: 'osETH/ETH',
719
- value: MorphoBlueVersions.MorphoBlueOsEthEth_860,
720
- url: 'osethweth-d5211d0e',
721
- loanToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
722
- collateralToken: '0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38',
723
- oracle: '0x224F2F1333b45E34fFCfC3bD01cE43C73A914498',
724
- oracleType: MorphoBlueOracleType.MARKET_RATE,
725
- irm: '0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC',
726
- lltv: 0.86,
727
- marketId: '0xd5211d0e3f4a30d5c98653d988585792bb7812221f04801be73a44ceecb11e89',
728
- protocolName: 'morpho-blue',
729
- });
730
715
  export const MORPHO_BLUE_WOETH_ETH_860 = (networkId: NetworkNumber = NetworkNumber.Eth): MorphoBlueMarketData => ({
731
716
  chainIds: [NetworkNumber.Eth],
732
717
  label: 'Morpho Blue',
@@ -1878,7 +1863,6 @@ export const MorphoBlueMarkets = (networkId: NetworkNumber) => ({
1878
1863
  [MorphoBlueVersions.MorphoBlueRsEthEth_945]: MORPHO_BLUE_RSETH_ETH_945(networkId),
1879
1864
  [MorphoBlueVersions.MorphoBlueRswEthEth_945]: MORPHO_BLUE_RSWETH_ETH_945(networkId),
1880
1865
  [MorphoBlueVersions.MorphoBlueWeEthEth_860]: MORPHO_BLUE_WEETH_ETH_860(networkId),
1881
- [MorphoBlueVersions.MorphoBlueOsEthEth_860]: MORPHO_BLUE_OSETH_ETH_860(networkId),
1882
1866
  [MorphoBlueVersions.MorphoBlueWoEthEth_860]: MORPHO_BLUE_WOETH_ETH_860(networkId),
1883
1867
  [MorphoBlueVersions.MorphoBluePTweETHUSDA_860]: MORPHO_BLUE_PTWEETH_USDA_860(networkId),
1884
1868
  [MorphoBlueVersions.MorphoBlueSwBTCWBTC_945]: MORPHO_BLUE_SWBTC_WBTC_945(networkId),
@@ -13,7 +13,7 @@ export const calcShortLiqPrice = (assetPrice: string, borrowedUsd: string, borro
13
13
 
14
14
  export const calcLeverageLiqPrice = (leverageType: LeverageType, assetPrice: string, borrowedUsd: string, borrowLimitUsd: string) => {
15
15
  if (leverageType === LeverageType.Short || leverageType === LeverageType.VolatilePairReverse) return calcShortLiqPrice(assetPrice, borrowedUsd, borrowLimitUsd);
16
- if (leverageType === LeverageType.Long || leverageType === LeverageType.VolatilePair) return calcLongLiqPrice(assetPrice, borrowedUsd, borrowLimitUsd);
16
+ if (leverageType === LeverageType.Long || leverageType === LeverageType.VolatilePair || leverageType === LeverageType.StablePair) return calcLongLiqPrice(assetPrice, borrowedUsd, borrowLimitUsd);
17
17
  console.error('invalid leverageType', leverageType);
18
18
  return '0';
19
19
  };
@@ -37,12 +37,16 @@ export const isLeveragedPos = (usedAssets: MMUsedAssets, dustLimit = 5) => {
37
37
  let supplyUnstable = 0;
38
38
  let longAsset = '';
39
39
  let shortAsset = '';
40
+ let stableCollAsset = '';
40
41
  Object.values(usedAssets).forEach(({
41
42
  symbol, suppliedUsd, borrowedUsd, collateral,
42
43
  }) => {
43
44
  const isSupplied = (+suppliedUsd) > dustLimit; // ignore dust like <limit leftover supply
44
45
  const isBorrowed = (+borrowedUsd) > dustLimit; // ignore dust like <limit leftover supply
45
- if (isSupplied && STABLE_ASSETS.includes(symbol) && collateral) supplyStable += 1;
46
+ if (isSupplied && STABLE_ASSETS.includes(symbol) && collateral) {
47
+ supplyStable += 1;
48
+ stableCollAsset = symbol;
49
+ }
46
50
  if (isBorrowed && STABLE_ASSETS.includes(symbol)) borrowStable += 1;
47
51
  if (isBorrowed && !STABLE_ASSETS.includes(symbol)) {
48
52
  borrowUnstable += 1;
@@ -56,6 +60,7 @@ export const isLeveragedPos = (usedAssets: MMUsedAssets, dustLimit = 5) => {
56
60
  const isLong = borrowStable > 0 && borrowUnstable === 0 && supplyUnstable === 1 && supplyStable === 0;
57
61
  const isShort = supplyStable > 0 && supplyUnstable === 0 && borrowUnstable === 1 && borrowStable === 0;
58
62
  const isVolatilePair = supplyUnstable === 1 && borrowUnstable === 1 && supplyStable === 0 && borrowStable === 0;
63
+ const isStablePair = supplyStable === 1 && borrowStable === 1 && supplyUnstable === 0 && borrowUnstable === 0;
59
64
  if (isLong) {
60
65
  return {
61
66
  leveragedType: LeverageType.Long,
@@ -74,6 +79,12 @@ export const isLeveragedPos = (usedAssets: MMUsedAssets, dustLimit = 5) => {
74
79
  leveragedAsset: longAsset,
75
80
  };
76
81
  }
82
+ if (isStablePair) {
83
+ return {
84
+ leveragedType: LeverageType.StablePair,
85
+ leveragedAsset: stableCollAsset,
86
+ };
87
+ }
77
88
  return {
78
89
  leveragedType: LeverageType.None,
79
90
  leveragedAsset: '',
@@ -222,7 +222,7 @@ export async function getMorphoMidnightAccountData(provider: EthereumProvider, n
222
222
  return _getMorphoMidnightAccountData(getViemProvider(provider, network), network, account, selectedMarket, marketInfo);
223
223
  }
224
224
 
225
- export const _getMorphoMidnightAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData): Promise<PositionBalances> => {
225
+ export const _getMorphoMidnightAccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData, includeCredit = false): Promise<PositionBalances> => {
226
226
  const balances: PositionBalances = { collateral: {}, debt: {} };
227
227
  if (!address) return balances;
228
228
 
@@ -244,6 +244,11 @@ export const _getMorphoMidnightAccountBalances = async (provider: Client, networ
244
244
  });
245
245
  balances.collateral = collateral;
246
246
 
247
+ if (includeCredit) {
248
+ balances.deposited = {
249
+ [addressMapping ? loanTokenInfo.address.toLowerCase() : wethToEth(loanTokenInfo.symbol)]: assetAmountInEth(positionInfo.credit.toString(), wethToEth(loanTokenInfo.symbol)),
250
+ };
251
+ }
247
252
  return balances;
248
253
  };
249
254
 
@@ -849,3 +849,5 @@ export async function getShifterPortfolioData(provider: EthereumProvider, networ
849
849
  }
850
850
 
851
851
  export * from './discovery';
852
+
853
+ export { getWalletLendingSummaries } from './lendingSummaries';