@defisaver/positions-sdk 2.0.15-dev → 2.0.15-dev-2

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 (152) hide show
  1. package/.mocharc.json +4 -4
  2. package/.nvmrc +1 -1
  3. package/README.md +64 -64
  4. package/cjs/aaveV2/index.js +9 -5
  5. package/cjs/aaveV3/index.js +50 -40
  6. package/cjs/aaveV3/merit.d.ts +17 -0
  7. package/cjs/aaveV3/merit.js +95 -0
  8. package/cjs/aaveV3/{rewards.d.ts → merkl.d.ts} +7 -2
  9. package/cjs/aaveV3/{rewards.js → merkl.js} +30 -14
  10. package/cjs/compoundV2/index.js +13 -7
  11. package/cjs/compoundV3/index.js +7 -2
  12. package/cjs/config/contracts.d.ts +6510 -1851
  13. package/cjs/config/contracts.js +33 -12
  14. package/cjs/contracts.d.ts +178 -0
  15. package/cjs/eulerV2/index.js +11 -2
  16. package/cjs/fluid/index.js +105 -34
  17. package/cjs/helpers/aaveHelpers/index.js +0 -1
  18. package/cjs/helpers/compoundHelpers/index.d.ts +3 -5
  19. package/cjs/helpers/compoundHelpers/index.js +15 -11
  20. package/cjs/helpers/eulerHelpers/index.d.ts +0 -5
  21. package/cjs/helpers/eulerHelpers/index.js +2 -31
  22. package/cjs/helpers/fluidHelpers/index.js +2 -0
  23. package/cjs/helpers/liquityV2Helpers/index.js +3 -2
  24. package/cjs/helpers/morphoBlueHelpers/index.js +66 -66
  25. package/cjs/liquityV2/index.js +10 -2
  26. package/cjs/llamaLend/index.js +10 -2
  27. package/cjs/morphoBlue/index.js +20 -6
  28. package/cjs/spark/index.js +20 -30
  29. package/cjs/staking/eligibility.d.ts +11 -0
  30. package/cjs/staking/eligibility.js +43 -0
  31. package/cjs/staking/index.d.ts +1 -0
  32. package/cjs/staking/index.js +1 -0
  33. package/cjs/staking/staking.d.ts +1 -7
  34. package/cjs/staking/staking.js +29 -55
  35. package/cjs/types/aave.d.ts +1 -7
  36. package/cjs/types/common.d.ts +16 -4
  37. package/cjs/types/common.js +10 -1
  38. package/cjs/types/euler.d.ts +3 -3
  39. package/cjs/types/fluid.d.ts +3 -5
  40. package/cjs/types/liquityV2.d.ts +3 -3
  41. package/cjs/types/llamaLend.d.ts +3 -1
  42. package/cjs/types/morphoBlue.d.ts +3 -5
  43. package/cjs/types/spark.d.ts +0 -3
  44. package/esm/aaveV2/index.js +9 -5
  45. package/esm/aaveV3/index.js +48 -38
  46. package/esm/aaveV3/merit.d.ts +17 -0
  47. package/esm/aaveV3/merit.js +90 -0
  48. package/esm/aaveV3/{rewards.d.ts → merkl.d.ts} +7 -2
  49. package/esm/aaveV3/{rewards.js → merkl.js} +28 -13
  50. package/esm/compoundV2/index.js +13 -7
  51. package/esm/compoundV3/index.js +7 -2
  52. package/esm/config/contracts.d.ts +6510 -1851
  53. package/esm/config/contracts.js +33 -12
  54. package/esm/contracts.d.ts +178 -0
  55. package/esm/eulerV2/index.js +11 -2
  56. package/esm/fluid/index.js +106 -35
  57. package/esm/helpers/aaveHelpers/index.js +0 -1
  58. package/esm/helpers/compoundHelpers/index.d.ts +3 -5
  59. package/esm/helpers/compoundHelpers/index.js +16 -12
  60. package/esm/helpers/eulerHelpers/index.d.ts +0 -5
  61. package/esm/helpers/eulerHelpers/index.js +2 -30
  62. package/esm/helpers/fluidHelpers/index.js +2 -0
  63. package/esm/helpers/liquityV2Helpers/index.js +3 -2
  64. package/esm/helpers/morphoBlueHelpers/index.js +66 -66
  65. package/esm/liquityV2/index.js +11 -3
  66. package/esm/llamaLend/index.js +11 -3
  67. package/esm/morphoBlue/index.js +21 -7
  68. package/esm/spark/index.js +21 -31
  69. package/esm/staking/eligibility.d.ts +11 -0
  70. package/esm/staking/eligibility.js +36 -0
  71. package/esm/staking/index.d.ts +1 -0
  72. package/esm/staking/index.js +1 -0
  73. package/esm/staking/staking.d.ts +1 -7
  74. package/esm/staking/staking.js +28 -53
  75. package/esm/types/aave.d.ts +1 -7
  76. package/esm/types/common.d.ts +16 -4
  77. package/esm/types/common.js +9 -0
  78. package/esm/types/euler.d.ts +3 -3
  79. package/esm/types/fluid.d.ts +3 -5
  80. package/esm/types/liquityV2.d.ts +3 -3
  81. package/esm/types/llamaLend.d.ts +3 -1
  82. package/esm/types/morphoBlue.d.ts +3 -5
  83. package/esm/types/spark.d.ts +0 -3
  84. package/package.json +47 -47
  85. package/src/aaveV2/index.ts +239 -236
  86. package/src/aaveV3/index.ts +511 -493
  87. package/src/aaveV3/merit.ts +98 -0
  88. package/src/aaveV3/{rewards.ts → merkl.ts} +141 -125
  89. package/src/compoundV2/index.ts +244 -240
  90. package/src/compoundV3/index.ts +274 -270
  91. package/src/config/contracts.ts +1129 -1108
  92. package/src/constants/index.ts +6 -6
  93. package/src/contracts.ts +107 -107
  94. package/src/curveUsd/index.ts +250 -250
  95. package/src/eulerV2/index.ts +324 -314
  96. package/src/exchange/index.ts +25 -25
  97. package/src/fluid/index.ts +1636 -1568
  98. package/src/helpers/aaveHelpers/index.ts +169 -170
  99. package/src/helpers/compoundHelpers/index.ts +267 -261
  100. package/src/helpers/curveUsdHelpers/index.ts +40 -40
  101. package/src/helpers/eulerHelpers/index.ts +222 -259
  102. package/src/helpers/fluidHelpers/index.ts +326 -324
  103. package/src/helpers/index.ts +10 -10
  104. package/src/helpers/liquityV2Helpers/index.ts +82 -80
  105. package/src/helpers/llamaLendHelpers/index.ts +53 -53
  106. package/src/helpers/makerHelpers/index.ts +52 -52
  107. package/src/helpers/morphoBlueHelpers/index.ts +390 -390
  108. package/src/helpers/sparkHelpers/index.ts +155 -155
  109. package/src/index.ts +45 -45
  110. package/src/liquity/index.ts +104 -104
  111. package/src/liquityV2/index.ts +418 -408
  112. package/src/llamaLend/index.ts +305 -296
  113. package/src/maker/index.ts +223 -223
  114. package/src/markets/aave/index.ts +116 -116
  115. package/src/markets/aave/marketAssets.ts +49 -49
  116. package/src/markets/compound/index.ts +227 -227
  117. package/src/markets/compound/marketsAssets.ts +90 -90
  118. package/src/markets/curveUsd/index.ts +69 -69
  119. package/src/markets/euler/index.ts +26 -26
  120. package/src/markets/fluid/index.ts +2456 -2456
  121. package/src/markets/index.ts +25 -25
  122. package/src/markets/liquityV2/index.ts +102 -102
  123. package/src/markets/llamaLend/contractAddresses.ts +141 -141
  124. package/src/markets/llamaLend/index.ts +235 -235
  125. package/src/markets/morphoBlue/index.ts +895 -895
  126. package/src/markets/spark/index.ts +29 -29
  127. package/src/markets/spark/marketAssets.ts +11 -11
  128. package/src/moneymarket/moneymarketCommonService.ts +80 -80
  129. package/src/morphoBlue/index.ts +236 -222
  130. package/src/portfolio/index.ts +285 -285
  131. package/src/services/priceService.ts +159 -159
  132. package/src/services/utils.ts +63 -63
  133. package/src/services/viem.ts +32 -32
  134. package/src/setup.ts +8 -8
  135. package/src/spark/index.ts +444 -456
  136. package/src/staking/eligibility.ts +37 -0
  137. package/src/staking/index.ts +2 -1
  138. package/src/staking/staking.ts +169 -194
  139. package/src/types/aave.ts +189 -195
  140. package/src/types/common.ts +103 -88
  141. package/src/types/compound.ts +136 -136
  142. package/src/types/curveUsd.ts +121 -121
  143. package/src/types/euler.ts +175 -174
  144. package/src/types/fluid.ts +448 -450
  145. package/src/types/index.ts +11 -11
  146. package/src/types/liquity.ts +30 -30
  147. package/src/types/liquityV2.ts +126 -126
  148. package/src/types/llamaLend.ts +159 -157
  149. package/src/types/maker.ts +63 -63
  150. package/src/types/morphoBlue.ts +194 -194
  151. package/src/types/portfolio.ts +60 -60
  152. package/src/types/spark.ts +135 -137
@@ -1,493 +1,511 @@
1
- import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
2
- import { Client } from 'viem';
3
- import Dec from 'decimal.js';
4
- import {
5
- AaveIncentiveDataProviderV3ContractViem,
6
- AaveV3ViewContractViem,
7
- createViemContractFromConfigFunc,
8
- } from '../contracts';
9
- import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
10
- import { AAVE_V3 } from '../markets/aave';
11
- import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
12
- import {
13
- ethToWeth, isEnabledOnBitmap, isLayer2Network, wethToEth, wethToEthByAddress,
14
- } from '../services/utils';
15
- import { getStakingApy, STAKING_ASSETS } from '../staking';
16
- import {
17
- AaveMarketInfo,
18
- AaveV3AssetData,
19
- AaveV3AssetsData,
20
- AaveV3MarketData,
21
- AaveV3PositionData,
22
- AaveV3UsedAsset,
23
- AaveV3UsedAssets,
24
- EModeCategoriesData,
25
- EModeCategoryData,
26
- EModeCategoryDataMapping,
27
- } from '../types/aave';
28
- import {
29
- Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances,
30
- } from '../types/common';
31
- import { getViemProvider, setViemBlockNumber } from '../services/viem';
32
- import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './rewards';
33
-
34
- export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: AaveV3UsedAssets) => {
35
- const { eModeCategoriesData }: { assetsData: AaveV3AssetsData, eModeCategoriesData: EModeCategoriesData } = extractedState;
36
- const usedAssetsValues = Object.values(usedAssets);
37
-
38
- const categoriesMapping: { [key: number]: EModeCategoryDataMapping } = {};
39
-
40
- Object.values(eModeCategoriesData).forEach((e: EModeCategoryData) => {
41
- const borrowingOnlyFromCategory = e.id === 0
42
- ? true
43
- : !usedAssetsValues.filter(u => u.isBorrowed && !e.borrowAssets.includes(u.symbol)).length;
44
- const afterEnteringCategory = aaveAnyGetAggregatedPositionData({
45
- ...extractedState, usedAssets, eModeCategory: e.id,
46
- });
47
- const willStayOverCollateralized = new Dec(afterEnteringCategory.ratio).eq(0) || new Dec(afterEnteringCategory.ratio).gt(afterEnteringCategory.liqPercent);
48
- const enteringTerms = [borrowingOnlyFromCategory, willStayOverCollateralized];
49
- categoriesMapping[e.id] = {
50
- enteringTerms,
51
- canEnterCategory: !enteringTerms.includes(false),
52
- id: e.id,
53
- enabledData: {
54
- ratio: afterEnteringCategory.ratio,
55
- liqRatio: afterEnteringCategory.liqRatio,
56
- liqPercent: afterEnteringCategory.liqPercent,
57
- collRatio: afterEnteringCategory.collRatio,
58
- },
59
- };
60
- });
61
- return categoriesMapping;
62
- };
63
-
64
- export async function _getAaveV3MarketData(provider: Client, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
65
- const _addresses = market.assets.map(a => getAssetInfo(ethToWeth(a), network).address);
66
-
67
- const isL2 = isLayer2Network(network);
68
- const loanInfoContract = AaveV3ViewContractViem(provider, network);
69
- const aaveIncentivesContract = AaveIncentiveDataProviderV3ContractViem(provider, network);
70
- const marketAddress = market.providerAddress;
71
- const networksWithIncentives = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Opt, NetworkNumber.Linea];
72
-
73
- // eslint-disable-next-line prefer-const
74
- let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap] = await Promise.all([
75
- loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]], setViemBlockNumber(blockNumber)),
76
- loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
77
- loanInfoContract.read.isBorrowAllowed([marketAddress], setViemBlockNumber(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
78
- networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
79
- getMerkleCampaigns(network),
80
- ]);
81
- isBorrowAllowed = isLayer2Network(network) ? isBorrowAllowed : true;
82
-
83
- const eModeCategoriesData: EModeCategoriesData = {};
84
- for (let i = 0; i < eModesInfo.length; i++) {
85
- if (!eModesInfo[i].label) break;
86
- eModeCategoriesData[i + 1] = {
87
- label: eModesInfo[i].label,
88
- id: i + 1,
89
- liquidationBonus: new Dec(eModesInfo[i].liquidationBonus).div(10000).toString(),
90
- liquidationRatio: new Dec(eModesInfo[i].liquidationThreshold).div(10000).toString(),
91
- collateralFactor: new Dec(eModesInfo[i].ltv).div(10000).toString(),
92
- borrowableBitmap: eModesInfo[i].borrowableBitmap.toString(),
93
- collateralBitmap: eModesInfo[i].collateralBitmap.toString(),
94
- borrowAssets: [],
95
- collateralAssets: [],
96
- };
97
- }
98
-
99
- if (networksWithIncentives.includes(network) && rewardInfo) {
100
- rewardInfo = rewardInfo.reduce((all: any, _market: any) => {
101
- // eslint-disable-next-line no-param-reassign
102
- all[_market.underlyingAsset] = _market;
103
- return all;
104
- }, {});
105
- }
106
-
107
- const assetsData: AaveV3AssetData[] = await Promise.all(loanInfo
108
- .map(async (tokenMarket, i) => {
109
- const symbol = market.assets[i];
110
-
111
- // eslint-disable-next-line guard-for-in
112
- for (const eModeIndex in eModeCategoriesData) {
113
- if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].collateralBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].collateralAssets.push(symbol);
114
- if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].borrowableBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].borrowAssets.push(symbol);
115
- }
116
-
117
- const borrowCap = tokenMarket.borrowCap.toString();
118
-
119
- const borrowCapInWei = new Dec(assetAmountInWei(borrowCap, symbol));
120
- let marketLiquidity = borrowCapInWei.lt(new Dec(tokenMarket.totalSupply.toString()))
121
- ? assetAmountInEth(borrowCapInWei
122
- .sub(tokenMarket.totalBorrow.toString())
123
- .toString(), symbol)
124
- : assetAmountInEth(new Dec(tokenMarket.totalSupply.toString())
125
- .sub(tokenMarket.totalBorrow.toString())
126
- .toString(), symbol);
127
-
128
- if (new Dec(marketLiquidity).lt(0)) {
129
- marketLiquidity = '0';
130
- }
131
- return ({
132
- symbol,
133
- isIsolated: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).gt(0),
134
- debtCeilingForIsolationMode: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).div(100).toString(),
135
- isSiloed: tokenMarket.isSiloedForBorrowing,
136
- isolationModeTotalDebt: new Dec(tokenMarket.isolationModeTotalDebt.toString()).div(100).toString(),
137
- assetId: Number(tokenMarket.assetId),
138
- underlyingTokenAddress: tokenMarket.underlyingTokenAddress,
139
- supplyRate: aprToApy(new Dec(tokenMarket.supplyRate.toString()).div(1e25).toString()),
140
- borrowRate: aprToApy(new Dec(tokenMarket.borrowRateVariable.toString()).div(1e25).toString()),
141
- borrowRateStable: aprToApy(new Dec(tokenMarket.borrowRateStable.toString()).div(1e25).toString()),
142
- collateralFactor: new Dec(tokenMarket.collateralFactor.toString()).div(10000).toString(),
143
- liquidationBonus: new Dec(tokenMarket.liquidationBonus.toString()).div(10000).toString(),
144
- liquidationRatio: new Dec(tokenMarket.liquidationRatio.toString()).div(10000).toString(),
145
- marketLiquidity,
146
- utilization: new Dec(tokenMarket.totalBorrow.toString()).times(100).div(new Dec(tokenMarket.totalSupply.toString())).toString(),
147
- usageAsCollateralEnabled: tokenMarket.usageAsCollateralEnabled,
148
- supplyCap: tokenMarket.supplyCap.toString(),
149
- borrowCap,
150
- totalSupply: assetAmountInEth(tokenMarket.totalSupply.toString(), symbol),
151
- isInactive: !tokenMarket.isActive,
152
- isFrozen: tokenMarket.isFrozen,
153
- isPaused: tokenMarket.isPaused,
154
- canBeBorrowed: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen && tokenMarket.borrowingEnabled && isBorrowAllowed,
155
- canBeSupplied: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen,
156
- canBeWithdrawn: tokenMarket.isActive && !tokenMarket.isPaused,
157
- canBePayBacked: tokenMarket.isActive && !tokenMarket.isPaused,
158
- disabledStableBorrowing: !tokenMarket.stableBorrowRateEnabled,
159
- totalBorrow: assetAmountInEth(tokenMarket.totalBorrow.toString(), symbol),
160
- totalBorrowVar: assetAmountInEth(tokenMarket.totalBorrowVar.toString(), symbol),
161
- price: new Dec(tokenMarket.price.toString()).div(1e8).toString(), // is actually price in USD
162
- isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
163
- isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
164
- aTokenAddress: tokenMarket.aTokenAddress,
165
- supplyIncentives: [],
166
- borrowIncentives: [],
167
- });
168
- }),
169
- );
170
-
171
- // Get incentives data
172
- await Promise.all(assetsData.map(async (_market: AaveV3AssetData, index) => {
173
- /* eslint-disable no-param-reassign */
174
- // @ts-ignore
175
- const rewardForMarket = rewardInfo?.[_market.underlyingTokenAddress];
176
- const isStakingAsset = STAKING_ASSETS.includes(_market.symbol);
177
-
178
- if (isStakingAsset) {
179
- _market.incentiveSupplyApy = await getStakingApy(_market.symbol);
180
- _market.incentiveSupplyToken = _market.symbol;
181
- _market.supplyIncentives.push({
182
- apy: _market.incentiveSupplyApy || '0',
183
- token: _market.symbol,
184
- incentiveKind: 'staking',
185
- description: `Native ${_market.symbol} yield.`,
186
- });
187
- if (_market.canBeBorrowed) {
188
- // when borrowing assets whose value increases over time
189
- _market.incentiveBorrowApy = new Dec(_market.incentiveSupplyApy).mul(-1).toString();
190
- _market.incentiveBorrowToken = _market.symbol;
191
- _market.borrowIncentives.push({
192
- apy: _market.incentiveBorrowApy,
193
- token: _market.incentiveBorrowToken,
194
- incentiveKind: 'reward',
195
- description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
196
- });
197
- }
198
- }
199
-
200
- const aTokenAddress = (_market as any).aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
201
- if (merkleRewardsMap[aTokenAddress]?.supply) {
202
- const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenAddress].supply;
203
- _market.supplyIncentives.push({
204
- apy: aprToApy(apr),
205
- token: rewardTokenSymbol,
206
- incentiveKind: 'reward',
207
- description,
208
- });
209
- }
210
-
211
- // const aTokenDebtAddress = '0xTODO'; // variableDebtTokenAddress is not in loanInfo ATM
212
- // if (merkleRewardsMap[aTokenDebtAddress]?.supply) {
213
- // const { apr, rewardTokenSymbol, description } = merkleRewardsMap[aTokenDebtAddress].supply;
214
- // _market.borrowIncentives.push({
215
- // apy: aprToApy(apr),
216
- // token: rewardTokenSymbol,
217
- // incentiveKind: 'reward',
218
- // description,
219
- // });
220
- // }
221
-
222
- if (!rewardForMarket) return;
223
- // @ts-ignore
224
- rewardForMarket.aIncentiveData.rewardsTokenInformation.forEach(supplyRewardData => {
225
- if (supplyRewardData) {
226
- if (+(supplyRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
227
- _market.incentiveSupplyToken = supplyRewardData.rewardTokenSymbol;
228
- // reward token is aave asset
229
- if (supplyRewardData.rewardTokenSymbol.startsWith('a') && supplyRewardData.rewardTokenSymbol.includes(_market.symbol)) _market.incentiveSupplyToken = _market.symbol;
230
- const supplyEmissionPerSecond = supplyRewardData.emissionPerSecond;
231
- const supplyRewardPrice = new Dec(supplyRewardData.rewardPriceFeed).div(10 ** +supplyRewardData.priceFeedDecimals)
232
- .toString();
233
- const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +supplyRewardData.rewardTokenDecimals) / 100)
234
- .mul(365 * 24 * 3600)
235
- .mul(supplyRewardPrice)
236
- .div(_market.price)
237
- .div(_market.totalSupply)
238
- .toString();
239
- _market.incentiveSupplyApy = new Dec(_market.incentiveSupplyApy || '0').add(rewardApy)
240
- .toString();
241
- _market.supplyIncentives.push({
242
- token: getAaveUnderlyingSymbol(supplyRewardData.rewardTokenSymbol),
243
- apy: rewardApy,
244
- incentiveKind: 'reward',
245
- description: 'Eligible for protocol-level incentives.',
246
- });
247
- }
248
- });
249
- // @ts-ignore
250
- rewardForMarket.vIncentiveData.rewardsTokenInformation.forEach(borrowRewardData => {
251
- if (borrowRewardData) {
252
- if (+(borrowRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
253
- _market.incentiveBorrowToken = borrowRewardData.rewardTokenSymbol;
254
- if (borrowRewardData.rewardTokenSymbol.startsWith('a') && borrowRewardData.rewardTokenSymbol.includes(_market.symbol)) _market.incentiveBorrowToken = _market.symbol;
255
- const supplyEmissionPerSecond = borrowRewardData.emissionPerSecond;
256
- const supplyRewardPrice = new Dec(borrowRewardData.rewardPriceFeed).div(10 ** +borrowRewardData.priceFeedDecimals)
257
- .toString();
258
- const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +borrowRewardData.rewardTokenDecimals) / 100)
259
- .mul(365 * 24 * 3600)
260
- .mul(supplyRewardPrice)
261
- .div(_market.price)
262
- .div(_market.totalBorrowVar)
263
- .toString();
264
- _market.incentiveBorrowApy = new Dec(_market.incentiveBorrowApy || '0').add(rewardApy)
265
- .toString();
266
- _market.borrowIncentives.push({
267
- token: getAaveUnderlyingSymbol(borrowRewardData.rewardTokenSymbol),
268
- apy: rewardApy,
269
- incentiveKind: 'reward',
270
- description: 'Eligible for protocol-level incentives.',
271
- });
272
- }
273
- });
274
- }));
275
-
276
- const payload: AaveV3AssetsData = {};
277
- // Sort by market size
278
- assetsData
279
- .sort((a, b) => {
280
- const aMarket = new Dec(a.price).times(a.totalSupply).toString();
281
- const bMarket = new Dec(b.price).times(b.totalSupply).toString();
282
-
283
- return new Dec(bMarket).minus(aMarket).toNumber();
284
- })
285
- .forEach((assetData: AaveV3AssetData, i) => {
286
- payload[assetData.symbol] = { ...assetData, sortIndex: i };
287
- });
288
-
289
- eModeCategoriesData[0] = {
290
- id: 0,
291
- label: '',
292
- liquidationBonus: '0',
293
- liquidationRatio: '0',
294
- collateralFactor: '0',
295
- collateralAssets: assetsData.map((a) => a.symbol),
296
- borrowAssets: assetsData.map((a) => a.symbol),
297
- };
298
-
299
- return { assetsData: payload, eModeCategoriesData };
300
- }
301
-
302
- export async function getAaveV3MarketData(provider: EthereumProvider, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
303
- return _getAaveV3MarketData(getViemProvider(provider, network), network, market, blockNumber);
304
- }
305
-
306
- export const EMPTY_AAVE_DATA = {
307
- usedAssets: {},
308
- suppliedUsd: '0',
309
- borrowedUsd: '0',
310
- borrowLimitUsd: '0',
311
- leftToBorrowUsd: '0',
312
- ratio: '0',
313
- minRatio: '0',
314
- netApy: '0',
315
- incentiveUsd: '0',
316
- totalInterestUsd: '0',
317
- isSubscribedToAutomation: false,
318
- automationResubscribeRequired: false,
319
- eModeCategory: 0,
320
- isInIsolationMode: false,
321
- isInSiloedMode: false,
322
- totalSupplied: '0',
323
- eModeCategories: [],
324
- collRatio: '0',
325
- suppliedCollateralUsd: '0',
326
- };
327
-
328
- export const _getAaveV3AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
329
- let balances: PositionBalances = {
330
- collateral: {},
331
- debt: {},
332
- };
333
-
334
- if (!address) {
335
- return balances;
336
- }
337
-
338
- const loanInfoContract = AaveV3ViewContractViem(provider, network, block);
339
-
340
- const market = AAVE_V3(network);
341
- const marketAddress = market.providerAddress;
342
- // @ts-ignore
343
- const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
344
-
345
- const reserveTokens = await protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block));
346
- const symbols = reserveTokens.map(({ symbol }: { symbol: string }) => symbol);
347
- const _addresses = reserveTokens.map(({ tokenAddress }: { tokenAddress: EthAddress }) => tokenAddress);
348
-
349
- // split addresses in half to avoid gas limit by multicall
350
- const middleAddressIndex = Math.floor(_addresses.length / 2);
351
-
352
- const [tokenBalances1, tokenBalances2] = await Promise.all([
353
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
354
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
355
- ]);
356
-
357
- const loanInfo = [...tokenBalances1, ...tokenBalances2];
358
-
359
- loanInfo.forEach((tokenInfo: any, i: number) => {
360
- const asset = wethToEth(symbols[i]);
361
- const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
362
-
363
- balances = {
364
- collateral: {
365
- ...balances.collateral,
366
- [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString(),
367
- },
368
- debt: {
369
- ...balances.debt,
370
- [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString(),
371
- },
372
- };
373
- });
374
-
375
- return balances;
376
- };
377
-
378
- export const getAaveV3AccountBalances = async (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => _getAaveV3AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address);
379
-
380
- export const _getAaveV3AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, extractedState: any, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3PositionData> => {
381
- const {
382
- selectedMarket: market, assetsData,
383
- } = extractedState;
384
- let payload: AaveV3PositionData = {
385
- ...EMPTY_AAVE_DATA,
386
- lastUpdated: Date.now(),
387
- };
388
- if (!address) {
389
- return payload;
390
- }
391
-
392
- const loanInfoContract = AaveV3ViewContractViem(provider, network);
393
- const lendingPoolContract = createViemContractFromConfigFunc(market.lendingPool, market.lendingPoolAddress)(provider, network);
394
- const marketAddress = market.providerAddress;
395
- const _addresses = market.assets.map((a: string[]) => getAssetInfo(ethToWeth(a), network).address);
396
-
397
- const middleAddressIndex = Math.floor(_addresses.length / 2); // split addresses in half to avoid gas limit by multicall
398
-
399
- const [eModeCategory, tokenBalances1, tokenBalances2] = await Promise.all([
400
- lendingPoolContract.read.getUserEMode([address], setViemBlockNumber(blockNumber)),
401
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex) as EthAddress[]], setViemBlockNumber(blockNumber)),
402
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length) as EthAddress[]], setViemBlockNumber(blockNumber)),
403
- ]);
404
-
405
- const loanInfo = [...tokenBalances1, ...tokenBalances2];
406
-
407
- const usedAssets = {} as AaveV3UsedAssets;
408
- loanInfo.map(async (tokenInfo, i) => {
409
- const asset = market.assets[i];
410
- const isSupplied = tokenInfo.balance.toString() !== '0';
411
- const isBorrowed = tokenInfo.borrowsStable.toString() !== '0' || tokenInfo.borrowsVariable.toString() !== '0';
412
- if (!isSupplied && !isBorrowed) return;
413
-
414
- const supplied = assetAmountInEth(tokenInfo.balance.toString(), asset);
415
- const borrowedStable = assetAmountInEth(tokenInfo.borrowsStable.toString(), asset);
416
- const borrowedVariable = assetAmountInEth(tokenInfo.borrowsVariable.toString(), asset);
417
- const enabledAsCollateral = assetsData[asset].usageAsCollateralEnabled ? tokenInfo.enabledAsCollateral : false;
418
-
419
- let interestMode;
420
- if (borrowedVariable === '0' && borrowedStable !== '0') {
421
- interestMode = '1';
422
- } else if (borrowedVariable !== '0' && borrowedStable === '0') {
423
- interestMode = '2';
424
- } else {
425
- interestMode = 'both';
426
- }
427
- if (!usedAssets[asset]) usedAssets[asset] = {} as AaveV3UsedAsset;
428
- const borrowed = new Dec(borrowedStable).add(borrowedVariable).toString();
429
-
430
- usedAssets[asset] = {
431
- ...usedAssets[asset],
432
- symbol: asset,
433
- supplied,
434
- suppliedUsd: new Dec(supplied).mul(assetsData[asset].price).toString(),
435
- isSupplied,
436
- collateral: enabledAsCollateral,
437
- stableBorrowRate: aprToApy(new Dec(tokenInfo.stableBorrowRate.toString()).div(1e25).toString()),
438
- borrowedStable,
439
- borrowedVariable,
440
- borrowedUsdStable: new Dec(borrowedStable).mul(assetsData[asset].price).toString(),
441
- borrowedUsdVariable: new Dec(borrowedVariable).mul(assetsData[asset].price).toString(),
442
- borrowed,
443
- borrowedUsd: new Dec(new Dec(borrowedVariable).add(borrowedStable)).mul(assetsData[asset].price).toString(),
444
- isBorrowed,
445
- interestMode,
446
- };
447
- });
448
-
449
- payload.eModeCategory = +(eModeCategory as BigInt).toString();
450
- payload = {
451
- ...payload,
452
- usedAssets,
453
- ...aaveAnyGetAggregatedPositionData({
454
- ...extractedState, usedAssets, eModeCategory: payload.eModeCategory,
455
- }),
456
- };
457
- payload.eModeCategories = aaveV3EmodeCategoriesMapping(extractedState, usedAssets);
458
- payload.isInIsolationMode = aaveV3IsInIsolationMode({ usedAssets, assetsData });
459
- payload.isInSiloedMode = aaveV3IsInSiloedMode({ usedAssets, assetsData });
460
-
461
- payload.ratio = payload.borrowedUsd && payload.borrowedUsd !== '0'
462
- ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString()
463
- : '0';
464
- payload.minRatio = '100';
465
- payload.collRatio = payload.borrowedUsd && payload.borrowedUsd !== '0'
466
- ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString()
467
- : '0';
468
-
469
- // Calculate borrow limits per asset
470
- Object.values(payload.usedAssets).forEach((item) => {
471
- if (item.isBorrowed) {
472
- // eslint-disable-next-line no-param-reassign
473
- item.stableLimit = calculateBorrowingAssetLimit(item.borrowedUsdStable, payload.borrowLimitUsd);
474
- // eslint-disable-next-line no-param-reassign
475
- item.variableLimit = calculateBorrowingAssetLimit(item.borrowedUsdVariable, payload.borrowLimitUsd);
476
- // eslint-disable-next-line no-param-reassign
477
- item.limit = calculateBorrowingAssetLimit(item.borrowedUsd, payload.borrowLimitUsd);
478
- }
479
- });
480
-
481
- payload.isSubscribedToAutomation = false;
482
- payload.automationResubscribeRequired = false;
483
-
484
- return payload;
485
- };
486
-
487
- export const getAaveV3AccountData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, extractedState: any, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3PositionData> => _getAaveV3AccountData(getViemProvider(provider, network), network, address, extractedState, blockNumber);
488
-
489
- export const getAaveV3FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, market: AaveMarketInfo): Promise<AaveV3PositionData> => {
490
- const marketData = await getAaveV3MarketData(provider, network, market);
491
- const positionData = await getAaveV3AccountData(provider, network, address, { assetsData: marketData.assetsData, selectedMarket: market, eModeCategoriesData: marketData.eModeCategoriesData });
492
- return positionData;
493
- };
1
+ import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
2
+ import { Client } from 'viem';
3
+ import Dec from 'decimal.js';
4
+ import {
5
+ AaveIncentiveDataProviderV3ContractViem,
6
+ AaveV3ViewContractViem,
7
+ createViemContractFromConfigFunc,
8
+ } from '../contracts';
9
+ import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
10
+ import { AAVE_V3 } from '../markets/aave';
11
+ import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
12
+ import {
13
+ ethToWeth, isEnabledOnBitmap, isLayer2Network, wethToEth, wethToEthByAddress,
14
+ } from '../services/utils';
15
+ import { getStakingApy, STAKING_ASSETS } from '../staking';
16
+ import {
17
+ AaveMarketInfo,
18
+ AaveV3AssetData,
19
+ AaveV3AssetsData,
20
+ AaveV3MarketData,
21
+ AaveV3PositionData,
22
+ AaveV3UsedAsset,
23
+ AaveV3UsedAssets,
24
+ EModeCategoriesData,
25
+ EModeCategoryData,
26
+ EModeCategoryDataMapping,
27
+ } from '../types/aave';
28
+ import {
29
+ Blockish, EthAddress, EthereumProvider, IncentiveEligibilityId, IncentiveKind, NetworkNumber, PositionBalances,
30
+ } from '../types/common';
31
+ import { getViemProvider, setViemBlockNumber } from '../services/viem';
32
+ import { getMeritCampaigns } from './merit';
33
+ import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './merkl';
34
+
35
+ export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: AaveV3UsedAssets) => {
36
+ const { eModeCategoriesData }: { assetsData: AaveV3AssetsData, eModeCategoriesData: EModeCategoriesData } = extractedState;
37
+ const usedAssetsValues = Object.values(usedAssets);
38
+
39
+ const categoriesMapping: { [key: number]: EModeCategoryDataMapping } = {};
40
+
41
+ Object.values(eModeCategoriesData).forEach((e: EModeCategoryData) => {
42
+ const borrowingOnlyFromCategory = e.id === 0
43
+ ? true
44
+ : !usedAssetsValues.filter(u => u.isBorrowed && !e.borrowAssets.includes(u.symbol)).length;
45
+ const afterEnteringCategory = aaveAnyGetAggregatedPositionData({
46
+ ...extractedState, usedAssets, eModeCategory: e.id,
47
+ });
48
+ const willStayOverCollateralized = new Dec(afterEnteringCategory.ratio).eq(0) || new Dec(afterEnteringCategory.ratio).gt(afterEnteringCategory.liqPercent);
49
+ const enteringTerms = [borrowingOnlyFromCategory, willStayOverCollateralized];
50
+ categoriesMapping[e.id] = {
51
+ enteringTerms,
52
+ canEnterCategory: !enteringTerms.includes(false),
53
+ id: e.id,
54
+ enabledData: {
55
+ ratio: afterEnteringCategory.ratio,
56
+ liqRatio: afterEnteringCategory.liqRatio,
57
+ liqPercent: afterEnteringCategory.liqPercent,
58
+ collRatio: afterEnteringCategory.collRatio,
59
+ },
60
+ };
61
+ });
62
+ return categoriesMapping;
63
+ };
64
+
65
+ export async function _getAaveV3MarketData(provider: Client, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
66
+ const _addresses = market.assets.map(a => getAssetInfo(ethToWeth(a), network).address);
67
+
68
+ const isL2 = isLayer2Network(network);
69
+ const loanInfoContract = AaveV3ViewContractViem(provider, network);
70
+ const aaveIncentivesContract = AaveIncentiveDataProviderV3ContractViem(provider, network);
71
+ const marketAddress = market.providerAddress;
72
+ const networksWithIncentives = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Opt, NetworkNumber.Linea];
73
+
74
+ // eslint-disable-next-line prefer-const
75
+ let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap, meritRewardsMap] = await Promise.all([
76
+ loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]], setViemBlockNumber(blockNumber)),
77
+ loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
78
+ loanInfoContract.read.isBorrowAllowed([marketAddress], setViemBlockNumber(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
79
+ networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
80
+ getMerkleCampaigns(network),
81
+ getMeritCampaigns(network, market.value),
82
+ ]);
83
+ isBorrowAllowed = isLayer2Network(network) ? isBorrowAllowed : true;
84
+
85
+ const eModeCategoriesData: EModeCategoriesData = {};
86
+ for (let i = 0; i < eModesInfo.length; i++) {
87
+ if (!eModesInfo[i].label) break;
88
+ eModeCategoriesData[i + 1] = {
89
+ label: eModesInfo[i].label,
90
+ id: i + 1,
91
+ liquidationBonus: new Dec(eModesInfo[i].liquidationBonus).div(10000).toString(),
92
+ liquidationRatio: new Dec(eModesInfo[i].liquidationThreshold).div(10000).toString(),
93
+ collateralFactor: new Dec(eModesInfo[i].ltv).div(10000).toString(),
94
+ borrowableBitmap: eModesInfo[i].borrowableBitmap.toString(),
95
+ collateralBitmap: eModesInfo[i].collateralBitmap.toString(),
96
+ borrowAssets: [],
97
+ collateralAssets: [],
98
+ };
99
+ }
100
+
101
+ if (networksWithIncentives.includes(network) && rewardInfo) {
102
+ rewardInfo = rewardInfo.reduce((all: any, _market: any) => {
103
+ // eslint-disable-next-line no-param-reassign
104
+ all[_market.underlyingAsset] = _market;
105
+ return all;
106
+ }, {});
107
+ }
108
+
109
+ const assetsData: AaveV3AssetData[] = await Promise.all(loanInfo
110
+ .map(async (tokenMarket, i) => {
111
+ const symbol = market.assets[i];
112
+
113
+ // eslint-disable-next-line guard-for-in
114
+ for (const eModeIndex in eModeCategoriesData) {
115
+ if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].collateralBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].collateralAssets.push(symbol);
116
+ if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].borrowableBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].borrowAssets.push(symbol);
117
+ }
118
+
119
+ const borrowCap = tokenMarket.borrowCap.toString();
120
+
121
+ const borrowCapInWei = new Dec(assetAmountInWei(borrowCap, symbol));
122
+ let marketLiquidity = borrowCapInWei.lt(new Dec(tokenMarket.totalSupply.toString()))
123
+ ? assetAmountInEth(borrowCapInWei
124
+ .sub(tokenMarket.totalBorrow.toString())
125
+ .toString(), symbol)
126
+ : assetAmountInEth(new Dec(tokenMarket.totalSupply.toString())
127
+ .sub(tokenMarket.totalBorrow.toString())
128
+ .toString(), symbol);
129
+
130
+ if (new Dec(marketLiquidity).lt(0)) {
131
+ marketLiquidity = '0';
132
+ }
133
+ return ({
134
+ symbol,
135
+ isIsolated: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).gt(0),
136
+ debtCeilingForIsolationMode: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).div(100).toString(),
137
+ isSiloed: tokenMarket.isSiloedForBorrowing,
138
+ isolationModeTotalDebt: new Dec(tokenMarket.isolationModeTotalDebt.toString()).div(100).toString(),
139
+ assetId: Number(tokenMarket.assetId),
140
+ underlyingTokenAddress: tokenMarket.underlyingTokenAddress,
141
+ supplyRate: aprToApy(new Dec(tokenMarket.supplyRate.toString()).div(1e25).toString()),
142
+ borrowRate: aprToApy(new Dec(tokenMarket.borrowRateVariable.toString()).div(1e25).toString()),
143
+ borrowRateStable: aprToApy(new Dec(tokenMarket.borrowRateStable.toString()).div(1e25).toString()),
144
+ collateralFactor: new Dec(tokenMarket.collateralFactor.toString()).div(10000).toString(),
145
+ liquidationBonus: new Dec(tokenMarket.liquidationBonus.toString()).div(10000).toString(),
146
+ liquidationRatio: new Dec(tokenMarket.liquidationRatio.toString()).div(10000).toString(),
147
+ marketLiquidity,
148
+ utilization: new Dec(tokenMarket.totalBorrow.toString()).times(100).div(new Dec(tokenMarket.totalSupply.toString())).toString(),
149
+ usageAsCollateralEnabled: tokenMarket.usageAsCollateralEnabled,
150
+ supplyCap: tokenMarket.supplyCap.toString(),
151
+ borrowCap,
152
+ totalSupply: assetAmountInEth(tokenMarket.totalSupply.toString(), symbol),
153
+ isInactive: !tokenMarket.isActive,
154
+ isFrozen: tokenMarket.isFrozen,
155
+ isPaused: tokenMarket.isPaused,
156
+ canBeBorrowed: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen && tokenMarket.borrowingEnabled && isBorrowAllowed,
157
+ canBeSupplied: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen,
158
+ canBeWithdrawn: tokenMarket.isActive && !tokenMarket.isPaused,
159
+ canBePayBacked: tokenMarket.isActive && !tokenMarket.isPaused,
160
+ disabledStableBorrowing: !tokenMarket.stableBorrowRateEnabled,
161
+ totalBorrow: assetAmountInEth(tokenMarket.totalBorrow.toString(), symbol),
162
+ totalBorrowVar: assetAmountInEth(tokenMarket.totalBorrowVar.toString(), symbol),
163
+ price: new Dec(tokenMarket.price.toString()).div(1e8).toString(), // is actually price in USD
164
+ isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
165
+ isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
166
+ aTokenAddress: tokenMarket.aTokenAddress,
167
+ vTokenAddress: tokenMarket.debtTokenAddress,
168
+ supplyIncentives: [],
169
+ borrowIncentives: [],
170
+ });
171
+ }),
172
+ );
173
+
174
+ // Get incentives data
175
+ await Promise.all(assetsData.map(async (_market: AaveV3AssetData, index) => {
176
+ /* eslint-disable no-param-reassign */
177
+ // @ts-ignore
178
+ const rewardForMarket = rewardInfo?.[_market.underlyingTokenAddress];
179
+ const isStakingAsset = STAKING_ASSETS.includes(_market.symbol);
180
+
181
+ if (isStakingAsset) {
182
+ const yieldApy = await getStakingApy(_market.symbol);
183
+ _market.supplyIncentives.push({
184
+ apy: yieldApy,
185
+ token: _market.symbol,
186
+ incentiveKind: IncentiveKind.Staking,
187
+ description: `Native ${_market.symbol} yield.`,
188
+ });
189
+ if (_market.canBeBorrowed) {
190
+ // when borrowing assets whose value increases over time
191
+ _market.borrowIncentives.push({
192
+ apy: new Dec(yieldApy).mul(-1).toString(),
193
+ token: _market.symbol,
194
+ incentiveKind: IncentiveKind.Reward,
195
+ description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
196
+ });
197
+ }
198
+ }
199
+
200
+ const aTokenAddress = (_market as any).aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
201
+ if (merkleRewardsMap[aTokenAddress]?.supply) {
202
+ const {
203
+ apy, rewardTokenSymbol, description, identifier,
204
+ } = merkleRewardsMap[aTokenAddress].supply;
205
+ _market.supplyIncentives.push({
206
+ apy,
207
+ token: rewardTokenSymbol,
208
+ incentiveKind: IncentiveKind.Reward,
209
+ description,
210
+ eligibilityId: identifier as IncentiveEligibilityId,
211
+ });
212
+ }
213
+
214
+ const vTokenAddress = (_market as any).vTokenAddress.toLowerCase(); // DEV: Should vTokenAddress be in AaveV3AssetData type?
215
+ if (merkleRewardsMap[vTokenAddress]?.borrow) {
216
+ const {
217
+ apy, rewardTokenSymbol, description, identifier,
218
+ } = merkleRewardsMap[vTokenAddress].borrow;
219
+ _market.borrowIncentives.push({
220
+ apy,
221
+ token: rewardTokenSymbol,
222
+ incentiveKind: IncentiveKind.Reward,
223
+ description,
224
+ eligibilityId: identifier as IncentiveEligibilityId,
225
+ });
226
+ }
227
+
228
+ if (meritRewardsMap.supply[_market.symbol]) {
229
+ const { apy, rewardTokenSymbol, description } = meritRewardsMap.supply[_market.symbol];
230
+ _market.supplyIncentives.push({
231
+ apy,
232
+ token: rewardTokenSymbol,
233
+ incentiveKind: IncentiveKind.Reward,
234
+ description,
235
+ });
236
+ }
237
+
238
+ if (meritRewardsMap.borrow[_market.symbol]) {
239
+ const { apy, rewardTokenSymbol, description } = meritRewardsMap.borrow[_market.symbol];
240
+ _market.borrowIncentives.push({
241
+ apy,
242
+ token: rewardTokenSymbol,
243
+ incentiveKind: IncentiveKind.Reward,
244
+ description,
245
+ });
246
+ }
247
+
248
+ if (!rewardForMarket) return;
249
+ // @ts-ignore
250
+ rewardForMarket.aIncentiveData.rewardsTokenInformation.forEach(supplyRewardData => {
251
+ if (supplyRewardData) {
252
+ if (+(supplyRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
253
+ // reward token is aave asset
254
+ const supplyEmissionPerSecond = supplyRewardData.emissionPerSecond;
255
+ const supplyRewardPrice = new Dec(supplyRewardData.rewardPriceFeed).div(10 ** +supplyRewardData.priceFeedDecimals)
256
+ .toString();
257
+ const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +supplyRewardData.rewardTokenDecimals) / 100)
258
+ .mul(365 * 24 * 3600)
259
+ .mul(supplyRewardPrice)
260
+ .div(_market.price)
261
+ .div(_market.totalSupply)
262
+ .toString();
263
+ _market.supplyIncentives.push({
264
+ token: getAaveUnderlyingSymbol(supplyRewardData.rewardTokenSymbol),
265
+ apy: rewardApy,
266
+ incentiveKind: IncentiveKind.Reward,
267
+ description: 'Eligible for protocol-level incentives.',
268
+ });
269
+ }
270
+ });
271
+ // @ts-ignore
272
+ rewardForMarket.vIncentiveData.rewardsTokenInformation.forEach(borrowRewardData => {
273
+ if (borrowRewardData) {
274
+ if (+(borrowRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
275
+ const supplyEmissionPerSecond = borrowRewardData.emissionPerSecond;
276
+ const supplyRewardPrice = new Dec(borrowRewardData.rewardPriceFeed).div(10 ** +borrowRewardData.priceFeedDecimals)
277
+ .toString();
278
+ const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +borrowRewardData.rewardTokenDecimals) / 100)
279
+ .mul(365 * 24 * 3600)
280
+ .mul(supplyRewardPrice)
281
+ .div(_market.price)
282
+ .div(_market.totalBorrowVar)
283
+ .toString();
284
+ _market.borrowIncentives.push({
285
+ token: getAaveUnderlyingSymbol(borrowRewardData.rewardTokenSymbol),
286
+ apy: rewardApy,
287
+ incentiveKind: IncentiveKind.Reward,
288
+ description: 'Eligible for protocol-level incentives.',
289
+ });
290
+ }
291
+ });
292
+ }));
293
+
294
+ const payload: AaveV3AssetsData = {};
295
+ // Sort by market size
296
+ assetsData
297
+ .sort((a, b) => {
298
+ const aMarket = new Dec(a.price).times(a.totalSupply).toString();
299
+ const bMarket = new Dec(b.price).times(b.totalSupply).toString();
300
+
301
+ return new Dec(bMarket).minus(aMarket).toNumber();
302
+ })
303
+ .forEach((assetData: AaveV3AssetData, i) => {
304
+ payload[assetData.symbol] = { ...assetData, sortIndex: i };
305
+ });
306
+
307
+ eModeCategoriesData[0] = {
308
+ id: 0,
309
+ label: '',
310
+ liquidationBonus: '0',
311
+ liquidationRatio: '0',
312
+ collateralFactor: '0',
313
+ collateralAssets: assetsData.map((a) => a.symbol),
314
+ borrowAssets: assetsData.map((a) => a.symbol),
315
+ };
316
+
317
+ return { assetsData: payload, eModeCategoriesData };
318
+ }
319
+
320
+ export async function getAaveV3MarketData(provider: EthereumProvider, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
321
+ return _getAaveV3MarketData(getViemProvider(provider, network), network, market, blockNumber);
322
+ }
323
+
324
+ export const EMPTY_AAVE_DATA = {
325
+ usedAssets: {},
326
+ suppliedUsd: '0',
327
+ borrowedUsd: '0',
328
+ borrowLimitUsd: '0',
329
+ leftToBorrowUsd: '0',
330
+ ratio: '0',
331
+ minRatio: '0',
332
+ netApy: '0',
333
+ incentiveUsd: '0',
334
+ totalInterestUsd: '0',
335
+ isSubscribedToAutomation: false,
336
+ automationResubscribeRequired: false,
337
+ eModeCategory: 0,
338
+ isInIsolationMode: false,
339
+ isInSiloedMode: false,
340
+ totalSupplied: '0',
341
+ eModeCategories: [],
342
+ collRatio: '0',
343
+ suppliedCollateralUsd: '0',
344
+ };
345
+
346
+ export const _getAaveV3AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
347
+ let balances: PositionBalances = {
348
+ collateral: {},
349
+ debt: {},
350
+ };
351
+
352
+ if (!address) {
353
+ return balances;
354
+ }
355
+
356
+ const loanInfoContract = AaveV3ViewContractViem(provider, network, block);
357
+
358
+ const market = AAVE_V3(network);
359
+ const marketAddress = market.providerAddress;
360
+ // @ts-ignore
361
+ const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
362
+
363
+ const reserveTokens = await protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block));
364
+ const symbols = reserveTokens.map(({ symbol }: { symbol: string }) => symbol);
365
+ const _addresses = reserveTokens.map(({ tokenAddress }: { tokenAddress: EthAddress }) => tokenAddress);
366
+
367
+ // split addresses in half to avoid gas limit by multicall
368
+ const middleAddressIndex = Math.floor(_addresses.length / 2);
369
+
370
+ const [tokenBalances1, tokenBalances2] = await Promise.all([
371
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
372
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
373
+ ]);
374
+
375
+ const loanInfo = [...tokenBalances1, ...tokenBalances2];
376
+
377
+ loanInfo.forEach((tokenInfo: any, i: number) => {
378
+ const asset = wethToEth(symbols[i]);
379
+ const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
380
+
381
+ balances = {
382
+ collateral: {
383
+ ...balances.collateral,
384
+ [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString(),
385
+ },
386
+ debt: {
387
+ ...balances.debt,
388
+ [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString(),
389
+ },
390
+ };
391
+ });
392
+
393
+ return balances;
394
+ };
395
+
396
+ export const getAaveV3AccountBalances = async (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => _getAaveV3AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address);
397
+
398
+ export const _getAaveV3AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, extractedState: any, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3PositionData> => {
399
+ const {
400
+ selectedMarket: market, assetsData,
401
+ } = extractedState;
402
+ let payload: AaveV3PositionData = {
403
+ ...EMPTY_AAVE_DATA,
404
+ lastUpdated: Date.now(),
405
+ };
406
+ if (!address) {
407
+ return payload;
408
+ }
409
+
410
+ const loanInfoContract = AaveV3ViewContractViem(provider, network);
411
+ const lendingPoolContract = createViemContractFromConfigFunc(market.lendingPool, market.lendingPoolAddress)(provider, network);
412
+ const marketAddress = market.providerAddress;
413
+ const _addresses = market.assets.map((a: string[]) => getAssetInfo(ethToWeth(a), network).address);
414
+
415
+ const middleAddressIndex = Math.floor(_addresses.length / 2); // split addresses in half to avoid gas limit by multicall
416
+
417
+ const [eModeCategory, tokenBalances1, tokenBalances2] = await Promise.all([
418
+ lendingPoolContract.read.getUserEMode([address], setViemBlockNumber(blockNumber)),
419
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex) as EthAddress[]], setViemBlockNumber(blockNumber)),
420
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length) as EthAddress[]], setViemBlockNumber(blockNumber)),
421
+ ]);
422
+
423
+ const loanInfo = [...tokenBalances1, ...tokenBalances2];
424
+
425
+ const usedAssets = {} as AaveV3UsedAssets;
426
+ loanInfo.map(async (tokenInfo, i) => {
427
+ const asset = market.assets[i];
428
+ const isSupplied = tokenInfo.balance.toString() !== '0';
429
+ const isBorrowed = tokenInfo.borrowsStable.toString() !== '0' || tokenInfo.borrowsVariable.toString() !== '0';
430
+ if (!isSupplied && !isBorrowed) return;
431
+
432
+ const supplied = assetAmountInEth(tokenInfo.balance.toString(), asset);
433
+ const borrowedStable = assetAmountInEth(tokenInfo.borrowsStable.toString(), asset);
434
+ const borrowedVariable = assetAmountInEth(tokenInfo.borrowsVariable.toString(), asset);
435
+ const enabledAsCollateral = assetsData[asset].usageAsCollateralEnabled ? tokenInfo.enabledAsCollateral : false;
436
+
437
+ let interestMode;
438
+ if (borrowedVariable === '0' && borrowedStable !== '0') {
439
+ interestMode = '1';
440
+ } else if (borrowedVariable !== '0' && borrowedStable === '0') {
441
+ interestMode = '2';
442
+ } else {
443
+ interestMode = 'both';
444
+ }
445
+ if (!usedAssets[asset]) usedAssets[asset] = {} as AaveV3UsedAsset;
446
+ const borrowed = new Dec(borrowedStable).add(borrowedVariable).toString();
447
+
448
+ usedAssets[asset] = {
449
+ ...usedAssets[asset],
450
+ symbol: asset,
451
+ supplied,
452
+ suppliedUsd: new Dec(supplied).mul(assetsData[asset].price).toString(),
453
+ isSupplied,
454
+ collateral: enabledAsCollateral,
455
+ stableBorrowRate: aprToApy(new Dec(tokenInfo.stableBorrowRate.toString()).div(1e25).toString()),
456
+ borrowedStable,
457
+ borrowedVariable,
458
+ borrowedUsdStable: new Dec(borrowedStable).mul(assetsData[asset].price).toString(),
459
+ borrowedUsdVariable: new Dec(borrowedVariable).mul(assetsData[asset].price).toString(),
460
+ borrowed,
461
+ borrowedUsd: new Dec(new Dec(borrowedVariable).add(borrowedStable)).mul(assetsData[asset].price).toString(),
462
+ isBorrowed,
463
+ interestMode,
464
+ };
465
+ });
466
+
467
+ payload.eModeCategory = +(eModeCategory as BigInt).toString();
468
+ payload = {
469
+ ...payload,
470
+ usedAssets,
471
+ ...aaveAnyGetAggregatedPositionData({
472
+ ...extractedState, usedAssets, eModeCategory: payload.eModeCategory,
473
+ }),
474
+ };
475
+ payload.eModeCategories = aaveV3EmodeCategoriesMapping(extractedState, usedAssets);
476
+ payload.isInIsolationMode = aaveV3IsInIsolationMode({ usedAssets, assetsData });
477
+ payload.isInSiloedMode = aaveV3IsInSiloedMode({ usedAssets, assetsData });
478
+
479
+ payload.ratio = payload.borrowedUsd && payload.borrowedUsd !== '0'
480
+ ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString()
481
+ : '0';
482
+ payload.minRatio = '100';
483
+ payload.collRatio = payload.borrowedUsd && payload.borrowedUsd !== '0'
484
+ ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString()
485
+ : '0';
486
+
487
+ // Calculate borrow limits per asset
488
+ Object.values(payload.usedAssets).forEach((item) => {
489
+ if (item.isBorrowed) {
490
+ // eslint-disable-next-line no-param-reassign
491
+ item.stableLimit = calculateBorrowingAssetLimit(item.borrowedUsdStable, payload.borrowLimitUsd);
492
+ // eslint-disable-next-line no-param-reassign
493
+ item.variableLimit = calculateBorrowingAssetLimit(item.borrowedUsdVariable, payload.borrowLimitUsd);
494
+ // eslint-disable-next-line no-param-reassign
495
+ item.limit = calculateBorrowingAssetLimit(item.borrowedUsd, payload.borrowLimitUsd);
496
+ }
497
+ });
498
+
499
+ payload.isSubscribedToAutomation = false;
500
+ payload.automationResubscribeRequired = false;
501
+
502
+ return payload;
503
+ };
504
+
505
+ export const getAaveV3AccountData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, extractedState: any, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3PositionData> => _getAaveV3AccountData(getViemProvider(provider, network), network, address, extractedState, blockNumber);
506
+
507
+ export const getAaveV3FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, market: AaveMarketInfo): Promise<AaveV3PositionData> => {
508
+ const marketData = await getAaveV3MarketData(provider, network, market);
509
+ const positionData = await getAaveV3AccountData(provider, network, address, { assetsData: marketData.assetsData, selectedMarket: market, eModeCategoriesData: marketData.eModeCategoriesData });
510
+ return positionData;
511
+ };