@defisaver/positions-sdk 2.1.54 → 2.1.56-dev-exposure

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 (184) hide show
  1. package/.mocharc.json +4 -4
  2. package/.nvmrc +1 -1
  3. package/README.md +64 -64
  4. package/cjs/aaveV3/index.d.ts +1 -0
  5. package/cjs/aaveV3/index.js +5 -2
  6. package/cjs/compoundV2/index.d.ts +1 -0
  7. package/cjs/compoundV2/index.js +1 -0
  8. package/cjs/compoundV3/index.d.ts +1 -0
  9. package/cjs/compoundV3/index.js +1 -0
  10. package/cjs/eulerV2/index.d.ts +1 -0
  11. package/cjs/eulerV2/index.js +1 -0
  12. package/cjs/fluid/index.d.ts +3 -0
  13. package/cjs/helpers/aaveHelpers/index.js +1 -0
  14. package/cjs/helpers/compoundHelpers/index.js +2 -0
  15. package/cjs/helpers/curveUsdHelpers/index.js +1 -0
  16. package/cjs/helpers/eulerHelpers/index.js +1 -0
  17. package/cjs/helpers/fluidHelpers/index.js +1 -0
  18. package/cjs/helpers/liquityV2Helpers/index.js +1 -0
  19. package/cjs/helpers/llamaLendHelpers/index.js +1 -0
  20. package/cjs/helpers/morphoBlueHelpers/index.js +67 -66
  21. package/cjs/helpers/sparkHelpers/index.js +1 -0
  22. package/cjs/liquity/index.js +2 -0
  23. package/cjs/maker/index.js +2 -0
  24. package/cjs/markets/morphoBlue/index.d.ts +4 -0
  25. package/cjs/markets/morphoBlue/index.js +36 -2
  26. package/cjs/moneymarket/moneymarketCommonService.d.ts +1 -0
  27. package/cjs/moneymarket/moneymarketCommonService.js +8 -1
  28. package/cjs/savings/morphoVaults/index.js +17 -17
  29. package/cjs/spark/index.d.ts +1 -0
  30. package/cjs/spark/index.js +1 -0
  31. package/cjs/types/aave.d.ts +1 -0
  32. package/cjs/types/common.d.ts +1 -0
  33. package/cjs/types/compound.d.ts +1 -0
  34. package/cjs/types/curveUsd.d.ts +2 -0
  35. package/cjs/types/euler.d.ts +1 -0
  36. package/cjs/types/fluid.d.ts +1 -0
  37. package/cjs/types/liquity.d.ts +1 -0
  38. package/cjs/types/liquityV2.d.ts +2 -0
  39. package/cjs/types/llamaLend.d.ts +2 -0
  40. package/cjs/types/maker.d.ts +1 -0
  41. package/cjs/types/morphoBlue.d.ts +4 -0
  42. package/cjs/types/morphoBlue.js +2 -0
  43. package/cjs/types/spark.d.ts +1 -0
  44. package/esm/aaveV3/index.d.ts +1 -0
  45. package/esm/aaveV3/index.js +5 -2
  46. package/esm/compoundV2/index.d.ts +1 -0
  47. package/esm/compoundV2/index.js +1 -0
  48. package/esm/compoundV3/index.d.ts +1 -0
  49. package/esm/compoundV3/index.js +1 -0
  50. package/esm/eulerV2/index.d.ts +1 -0
  51. package/esm/eulerV2/index.js +1 -0
  52. package/esm/fluid/index.d.ts +3 -0
  53. package/esm/helpers/aaveHelpers/index.js +2 -1
  54. package/esm/helpers/compoundHelpers/index.js +3 -1
  55. package/esm/helpers/curveUsdHelpers/index.js +2 -1
  56. package/esm/helpers/eulerHelpers/index.js +2 -1
  57. package/esm/helpers/fluidHelpers/index.js +2 -1
  58. package/esm/helpers/liquityV2Helpers/index.js +2 -1
  59. package/esm/helpers/llamaLendHelpers/index.js +2 -1
  60. package/esm/helpers/morphoBlueHelpers/index.js +68 -67
  61. package/esm/helpers/sparkHelpers/index.js +2 -1
  62. package/esm/liquity/index.js +2 -0
  63. package/esm/maker/index.js +2 -0
  64. package/esm/markets/morphoBlue/index.d.ts +4 -0
  65. package/esm/markets/morphoBlue/index.js +32 -0
  66. package/esm/moneymarket/moneymarketCommonService.d.ts +1 -0
  67. package/esm/moneymarket/moneymarketCommonService.js +6 -0
  68. package/esm/savings/morphoVaults/index.js +17 -17
  69. package/esm/spark/index.d.ts +1 -0
  70. package/esm/spark/index.js +1 -0
  71. package/esm/types/aave.d.ts +1 -0
  72. package/esm/types/common.d.ts +1 -0
  73. package/esm/types/compound.d.ts +1 -0
  74. package/esm/types/curveUsd.d.ts +2 -0
  75. package/esm/types/euler.d.ts +1 -0
  76. package/esm/types/fluid.d.ts +1 -0
  77. package/esm/types/liquity.d.ts +1 -0
  78. package/esm/types/liquityV2.d.ts +2 -0
  79. package/esm/types/llamaLend.d.ts +2 -0
  80. package/esm/types/maker.d.ts +1 -0
  81. package/esm/types/morphoBlue.d.ts +4 -0
  82. package/esm/types/morphoBlue.js +2 -0
  83. package/esm/types/spark.d.ts +1 -0
  84. package/package.json +48 -48
  85. package/src/aaveV2/index.ts +240 -240
  86. package/src/aaveV3/index.ts +638 -635
  87. package/src/aaveV3/merit.ts +97 -97
  88. package/src/aaveV3/merkl.ts +74 -74
  89. package/src/claiming/aaveV3.ts +154 -154
  90. package/src/claiming/compV3.ts +22 -22
  91. package/src/claiming/ethena.ts +61 -61
  92. package/src/claiming/index.ts +12 -12
  93. package/src/claiming/king.ts +66 -66
  94. package/src/claiming/morphoBlue.ts +118 -118
  95. package/src/claiming/spark.ts +225 -225
  96. package/src/compoundV2/index.ts +245 -244
  97. package/src/compoundV3/index.ts +275 -274
  98. package/src/config/contracts.ts +1320 -1320
  99. package/src/constants/index.ts +10 -10
  100. package/src/contracts.ts +171 -171
  101. package/src/curveUsd/index.ts +254 -254
  102. package/src/eulerV2/index.ts +325 -324
  103. package/src/exchange/index.ts +25 -25
  104. package/src/fluid/index.ts +1800 -1800
  105. package/src/helpers/aaveHelpers/index.ts +203 -202
  106. package/src/helpers/compoundHelpers/index.ts +278 -276
  107. package/src/helpers/curveUsdHelpers/index.ts +44 -40
  108. package/src/helpers/eulerHelpers/index.ts +230 -229
  109. package/src/helpers/fluidHelpers/index.ts +338 -335
  110. package/src/helpers/index.ts +10 -10
  111. package/src/helpers/liquityV2Helpers/index.ts +85 -82
  112. package/src/helpers/llamaLendHelpers/index.ts +56 -53
  113. package/src/helpers/makerHelpers/index.ts +52 -52
  114. package/src/helpers/morphoBlueHelpers/index.ts +406 -405
  115. package/src/helpers/sparkHelpers/index.ts +170 -169
  116. package/src/index.ts +49 -49
  117. package/src/liquity/index.ts +161 -159
  118. package/src/liquityV2/index.ts +703 -703
  119. package/src/llamaLend/index.ts +305 -305
  120. package/src/maker/index.ts +225 -223
  121. package/src/markets/aave/index.ts +118 -118
  122. package/src/markets/aave/marketAssets.ts +54 -54
  123. package/src/markets/compound/index.ts +243 -243
  124. package/src/markets/compound/marketsAssets.ts +97 -97
  125. package/src/markets/curveUsd/index.ts +69 -69
  126. package/src/markets/euler/index.ts +26 -26
  127. package/src/markets/fluid/index.ts +2900 -2900
  128. package/src/markets/index.ts +25 -25
  129. package/src/markets/liquityV2/index.ts +102 -102
  130. package/src/markets/llamaLend/contractAddresses.ts +141 -141
  131. package/src/markets/llamaLend/index.ts +235 -235
  132. package/src/markets/morphoBlue/index.ts +1020 -988
  133. package/src/markets/spark/index.ts +29 -29
  134. package/src/markets/spark/marketAssets.ts +12 -12
  135. package/src/moneymarket/moneymarketCommonService.ts +90 -84
  136. package/src/morphoBlue/index.ts +274 -274
  137. package/src/portfolio/index.ts +586 -586
  138. package/src/savings/index.ts +95 -95
  139. package/src/savings/makerDsr/index.ts +53 -53
  140. package/src/savings/makerDsr/options.ts +9 -9
  141. package/src/savings/morphoVaults/index.ts +80 -80
  142. package/src/savings/morphoVaults/options.ts +193 -193
  143. package/src/savings/skyOptions/index.ts +95 -95
  144. package/src/savings/skyOptions/options.ts +10 -10
  145. package/src/savings/sparkSavingsVaults/index.ts +60 -60
  146. package/src/savings/sparkSavingsVaults/options.ts +35 -35
  147. package/src/savings/yearnV3Vaults/index.ts +61 -61
  148. package/src/savings/yearnV3Vaults/options.ts +55 -55
  149. package/src/savings/yearnVaults/index.ts +73 -73
  150. package/src/savings/yearnVaults/options.ts +32 -32
  151. package/src/services/priceService.ts +278 -278
  152. package/src/services/utils.ts +115 -115
  153. package/src/services/viem.ts +57 -57
  154. package/src/setup.ts +8 -8
  155. package/src/spark/index.ts +460 -459
  156. package/src/staking/eligibility.ts +53 -53
  157. package/src/staking/index.ts +1 -1
  158. package/src/staking/staking.ts +192 -192
  159. package/src/types/aave.ts +200 -199
  160. package/src/types/claiming.ts +114 -114
  161. package/src/types/common.ts +116 -115
  162. package/src/types/compound.ts +146 -145
  163. package/src/types/curveUsd.ts +125 -123
  164. package/src/types/euler.ts +177 -176
  165. package/src/types/fluid.ts +486 -485
  166. package/src/types/index.ts +15 -15
  167. package/src/types/liquity.ts +31 -30
  168. package/src/types/liquityV2.ts +130 -128
  169. package/src/types/llamaLend.ts +163 -161
  170. package/src/types/maker.ts +64 -63
  171. package/src/types/merit.ts +1 -1
  172. package/src/types/merkl.ts +70 -70
  173. package/src/types/morphoBlue.ts +206 -202
  174. package/src/types/portfolio.ts +60 -60
  175. package/src/types/savings/index.ts +23 -23
  176. package/src/types/savings/makerDsr.ts +13 -13
  177. package/src/types/savings/morphoVaults.ts +32 -32
  178. package/src/types/savings/sky.ts +14 -14
  179. package/src/types/savings/sparkSavingsVaults.ts +15 -15
  180. package/src/types/savings/yearnV3Vaults.ts +17 -17
  181. package/src/types/savings/yearnVaults.ts +14 -14
  182. package/src/types/spark.ts +136 -135
  183. package/src/umbrella/index.ts +69 -69
  184. package/src/umbrella/umbrellaUtils.ts +29 -29
@@ -1,635 +1,638 @@
1
- import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
2
- import { Client } from 'viem';
3
- import Dec from 'decimal.js';
4
- import {
5
- AaveIncentiveDataProviderV3ContractViem,
6
- AaveIncentivesControllerViem,
7
- AaveV3ViewContractViem,
8
- createViemContractFromConfigFunc,
9
- StkAAVEViem,
10
- } from '../contracts';
11
- import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
12
- import { AAVE_V3 } from '../markets/aave';
13
- import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
14
- import {
15
- getWrappedNativeAssetFromUnwrapped,
16
- isEnabledOnBitmap,
17
- isLayer2Network,
18
- wethToEth,
19
- wethToEthByAddress,
20
- } from '../services/utils';
21
- import { getStakingApy, STAKING_ASSETS } from '../staking';
22
- import {
23
- AaveMarketInfo,
24
- AaveV3AssetData,
25
- AaveV3AssetsData,
26
- AaveV3MarketData,
27
- AaveV3PositionData,
28
- AaveV3UsedAsset,
29
- AaveV3UsedAssets,
30
- EModeCategoriesData,
31
- EModeCategoryData,
32
- EModeCategoryDataMapping,
33
- } from '../types';
34
- import {
35
- Blockish,
36
- EthAddress,
37
- EthereumProvider,
38
- IncentiveEligibilityId,
39
- IncentiveKind,
40
- NetworkNumber,
41
- PositionBalances,
42
- HexString,
43
- } from '../types/common';
44
- import { getViemProvider, setViemBlockNumber } from '../services/viem';
45
- import { getMeritCampaigns } from './merit';
46
- import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './merkl';
47
- import { SECONDS_PER_YEAR } from '../constants';
48
-
49
- export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: AaveV3UsedAssets) => {
50
- const { eModeCategoriesData }: { assetsData: AaveV3AssetsData, eModeCategoriesData: EModeCategoriesData } = extractedState;
51
- const usedAssetsValues = Object.values(usedAssets);
52
-
53
- const categoriesMapping: { [key: number]: EModeCategoryDataMapping } = {};
54
-
55
- Object.values(eModeCategoriesData).forEach((e: EModeCategoryData) => {
56
- const borrowingOnlyFromCategory = e.id === 0
57
- ? true
58
- : !usedAssetsValues.filter(u => u.isBorrowed && !e.borrowAssets.includes(u.symbol)).length;
59
- const afterEnteringCategory = aaveAnyGetAggregatedPositionData({
60
- ...extractedState, usedAssets, eModeCategory: e.id,
61
- });
62
- const willStayOverCollateralized = new Dec(afterEnteringCategory.ratio).eq(0) || new Dec(afterEnteringCategory.ratio).gt(afterEnteringCategory.liqPercent);
63
- const enteringTerms = [borrowingOnlyFromCategory, willStayOverCollateralized];
64
- categoriesMapping[e.id] = {
65
- enteringTerms,
66
- canEnterCategory: !enteringTerms.includes(false),
67
- id: e.id,
68
- enabledData: {
69
- ratio: afterEnteringCategory.ratio,
70
- liqRatio: afterEnteringCategory.liqRatio,
71
- liqPercent: afterEnteringCategory.liqPercent,
72
- collRatio: afterEnteringCategory.collRatio,
73
- },
74
- };
75
- });
76
- return categoriesMapping;
77
- };
78
-
79
- export async function _getAaveV3MarketData(provider: Client, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
80
- const _addresses = market.assets.map(a => getAssetInfo(getWrappedNativeAssetFromUnwrapped(a), network).address);
81
-
82
- const isL2 = isLayer2Network(network);
83
- const loanInfoContract = AaveV3ViewContractViem(provider, network);
84
- const aaveIncentivesContract = AaveIncentiveDataProviderV3ContractViem(provider, network);
85
- const marketAddress = market.providerAddress;
86
- const networksWithIncentives = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Opt, NetworkNumber.Linea, NetworkNumber.Plasma];
87
- // eslint-disable-next-line prefer-const
88
- let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap, meritRewardsMap] = await Promise.all([
89
- loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]], setViemBlockNumber(blockNumber)),
90
- loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
91
- loanInfoContract.read.isBorrowAllowed([marketAddress], setViemBlockNumber(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
92
- networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
93
- getMerkleCampaigns(network),
94
- getMeritCampaigns(network, market.value),
95
- ]);
96
- isBorrowAllowed = isLayer2Network(network) ? isBorrowAllowed : true;
97
-
98
- // same break logic as view contract
99
- let missCounter = 0;
100
- const eModeCategoriesData: EModeCategoriesData = {};
101
- for (let i = 0; i < eModesInfo.length; i++) {
102
- if (eModesInfo[i].liquidationThreshold !== 0) {
103
- eModeCategoriesData[i + 1] = {
104
- label: eModesInfo[i].label,
105
- id: i + 1,
106
- liquidationBonus: new Dec(eModesInfo[i].liquidationBonus).div(10000).toString(),
107
- liquidationRatio: new Dec(eModesInfo[i].liquidationThreshold).div(10000).toString(),
108
- collateralFactor: new Dec(eModesInfo[i].ltv).div(10000).toString(),
109
- borrowableBitmap: eModesInfo[i].borrowableBitmap.toString(),
110
- collateralBitmap: eModesInfo[i].collateralBitmap.toString(),
111
- ltvzeroBitmap: eModesInfo[i].ltvzeroBitmap.toString(),
112
- borrowAssets: [],
113
- collateralAssets: [],
114
- ltvZeroAssets: [],
115
- };
116
- missCounter = 0;
117
- } else {
118
- ++missCounter;
119
- if (missCounter > 2) break;
120
- }
121
- }
122
-
123
- if (networksWithIncentives.includes(network) && rewardInfo) {
124
- rewardInfo = rewardInfo.reduce((all: any, _market: any) => {
125
- // eslint-disable-next-line no-param-reassign
126
- all[_market.underlyingAsset] = _market;
127
- return all;
128
- }, {});
129
- }
130
-
131
- const assetsData: AaveV3AssetData[] = await Promise.all(loanInfo
132
- .map(async (tokenMarket, i) => {
133
- const symbol = market.assets[i];
134
-
135
- // eslint-disable-next-line guard-for-in
136
- for (const eModeIndex in eModeCategoriesData) {
137
- if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].collateralBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].collateralAssets.push(symbol);
138
- if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].borrowableBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].borrowAssets.push(symbol);
139
- if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].ltvzeroBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].ltvZeroAssets.push(symbol);
140
- }
141
-
142
- const borrowCap = tokenMarket.borrowCap.toString();
143
-
144
- const borrowCapInWei = new Dec(assetAmountInWei(borrowCap, symbol));
145
- let marketLiquidity = borrowCapInWei.lt(new Dec(tokenMarket.totalSupply.toString()))
146
- ? assetAmountInEth(borrowCapInWei
147
- .sub(tokenMarket.totalBorrow.toString())
148
- .toString(), symbol)
149
- : assetAmountInEth(new Dec(tokenMarket.totalSupply.toString())
150
- .sub(tokenMarket.totalBorrow.toString())
151
- .toString(), symbol);
152
-
153
- if (new Dec(marketLiquidity).lt(0)) {
154
- marketLiquidity = '0';
155
- }
156
- return ({
157
- symbol,
158
- isIsolated: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).gt(0),
159
- debtCeilingForIsolationMode: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).div(100).toString(),
160
- isSiloed: tokenMarket.isSiloedForBorrowing,
161
- isolationModeTotalDebt: new Dec(tokenMarket.isolationModeTotalDebt.toString()).div(100).toString(),
162
- assetId: Number(tokenMarket.assetId),
163
- underlyingTokenAddress: tokenMarket.underlyingTokenAddress,
164
- supplyRate: aprToApy(new Dec(tokenMarket.supplyRate.toString()).div(1e25).toString()),
165
- borrowRate: aprToApy(new Dec(tokenMarket.borrowRateVariable.toString()).div(1e25).toString()),
166
- borrowRateStable: aprToApy(new Dec(tokenMarket.borrowRateStable.toString()).div(1e25).toString()),
167
- collateralFactor: new Dec(tokenMarket.collateralFactor.toString()).div(10000).toString(),
168
- liquidationBonus: new Dec(tokenMarket.liquidationBonus.toString()).div(10000).toString(),
169
- liquidationRatio: new Dec(tokenMarket.liquidationRatio.toString()).div(10000).toString(),
170
- marketLiquidity,
171
- utilization: new Dec(tokenMarket.totalBorrow.toString()).times(100).div(new Dec(tokenMarket.totalSupply.toString())).toString(),
172
- usageAsCollateralEnabled: tokenMarket.usageAsCollateralEnabled,
173
- supplyCap: tokenMarket.supplyCap.toString(),
174
- borrowCap,
175
- totalSupply: assetAmountInEth(tokenMarket.totalSupply.toString(), symbol),
176
- isInactive: !tokenMarket.isActive,
177
- isFrozen: tokenMarket.isFrozen,
178
- isPaused: tokenMarket.isPaused,
179
- canBeBorrowed: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen && tokenMarket.borrowingEnabled && isBorrowAllowed,
180
- canBeSupplied: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen,
181
- canBeWithdrawn: tokenMarket.isActive && !tokenMarket.isPaused,
182
- canBePayBacked: tokenMarket.isActive && !tokenMarket.isPaused,
183
- disabledStableBorrowing: !tokenMarket.stableBorrowRateEnabled,
184
- totalBorrow: assetAmountInEth(tokenMarket.totalBorrow.toString(), symbol),
185
- totalBorrowVar: assetAmountInEth(tokenMarket.totalBorrowVar.toString(), symbol),
186
- price: new Dec(tokenMarket.price.toString()).div(1e8).toString(), // is actually price in USD
187
- isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
188
- isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
189
- aTokenAddress: tokenMarket.aTokenAddress,
190
- vTokenAddress: tokenMarket.debtTokenAddress,
191
- supplyIncentives: [],
192
- borrowIncentives: [],
193
- });
194
- }),
195
- );
196
-
197
- // Get incentives data
198
- await Promise.all(assetsData.map(async (_market: AaveV3AssetData, index) => {
199
- /* eslint-disable no-param-reassign */
200
- // @ts-ignore
201
- const rewardForMarket = rewardInfo?.[_market.underlyingTokenAddress];
202
- const isStakingAsset = STAKING_ASSETS.includes(_market.symbol);
203
-
204
- if (isStakingAsset) {
205
- const yieldApy = await getStakingApy(_market.symbol, network as NetworkNumber);
206
- _market.supplyIncentives.push({
207
- apy: yieldApy,
208
- token: _market.symbol,
209
- incentiveKind: IncentiveKind.Staking,
210
- description: `Native ${_market.symbol} yield.`,
211
- });
212
- if (_market.canBeBorrowed) {
213
- // when borrowing assets whose value increases over time
214
- _market.borrowIncentives.push({
215
- apy: new Dec(yieldApy).mul(-1).toString(),
216
- token: _market.symbol,
217
- incentiveKind: IncentiveKind.Reward,
218
- description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
219
- });
220
- }
221
- }
222
-
223
- const aTokenAddress = (_market as any).aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
224
- if (merkleRewardsMap[aTokenAddress]?.supply) {
225
- const {
226
- apy, rewardTokenSymbol, description, identifier,
227
- } = merkleRewardsMap[aTokenAddress].supply;
228
- _market.supplyIncentives.push({
229
- apy,
230
- token: rewardTokenSymbol,
231
- incentiveKind: IncentiveKind.Reward,
232
- description,
233
- eligibilityId: identifier as IncentiveEligibilityId,
234
- });
235
- }
236
-
237
- const vTokenAddress = (_market as any).vTokenAddress.toLowerCase(); // DEV: Should vTokenAddress be in AaveV3AssetData type?
238
- if (merkleRewardsMap[vTokenAddress]?.borrow) {
239
- const {
240
- apy, rewardTokenSymbol, description, identifier,
241
- } = merkleRewardsMap[vTokenAddress].borrow;
242
- _market.borrowIncentives.push({
243
- apy,
244
- token: rewardTokenSymbol,
245
- incentiveKind: IncentiveKind.Reward,
246
- description,
247
- eligibilityId: identifier as IncentiveEligibilityId,
248
- });
249
- }
250
-
251
- if (meritRewardsMap.supply[_market.symbol]) {
252
- const { apy, rewardTokenSymbol, description } = meritRewardsMap.supply[_market.symbol];
253
- _market.supplyIncentives.push({
254
- apy,
255
- token: rewardTokenSymbol,
256
- incentiveKind: IncentiveKind.Reward,
257
- description,
258
- });
259
- }
260
-
261
- if (meritRewardsMap.borrow[_market.symbol]) {
262
- const { apy, rewardTokenSymbol, description } = meritRewardsMap.borrow[_market.symbol];
263
- _market.borrowIncentives.push({
264
- apy,
265
- token: rewardTokenSymbol,
266
- incentiveKind: IncentiveKind.Reward,
267
- description,
268
- });
269
- }
270
-
271
- if (!rewardForMarket) return;
272
- // @ts-ignore
273
- rewardForMarket.aIncentiveData.rewardsTokenInformation.forEach(supplyRewardData => {
274
- if (supplyRewardData) {
275
- if (+(supplyRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
276
- // reward token is aave asset
277
- const supplyEmissionPerSecond = supplyRewardData.emissionPerSecond;
278
- const supplyRewardPrice = new Dec(supplyRewardData.rewardPriceFeed).div(10 ** +supplyRewardData.priceFeedDecimals)
279
- .toString();
280
- const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +supplyRewardData.rewardTokenDecimals) / 100)
281
- .mul(365 * 24 * 3600)
282
- .mul(supplyRewardPrice)
283
- .div(_market.price)
284
- .div(_market.totalSupply)
285
- .toString();
286
- _market.supplyIncentives.push({
287
- token: getAaveUnderlyingSymbol(supplyRewardData.rewardTokenSymbol),
288
- apy: rewardApy,
289
- incentiveKind: IncentiveKind.Reward,
290
- description: 'Eligible for protocol-level incentives.',
291
- });
292
- }
293
- });
294
- // @ts-ignore
295
- rewardForMarket.vIncentiveData.rewardsTokenInformation.forEach(borrowRewardData => {
296
- if (borrowRewardData) {
297
- if (+(borrowRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
298
- const supplyEmissionPerSecond = borrowRewardData.emissionPerSecond;
299
- const supplyRewardPrice = new Dec(borrowRewardData.rewardPriceFeed).div(10 ** +borrowRewardData.priceFeedDecimals)
300
- .toString();
301
- const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +borrowRewardData.rewardTokenDecimals) / 100)
302
- .mul(365 * 24 * 3600)
303
- .mul(supplyRewardPrice)
304
- .div(_market.price)
305
- .div(_market.totalBorrowVar)
306
- .toString();
307
- _market.borrowIncentives.push({
308
- token: getAaveUnderlyingSymbol(borrowRewardData.rewardTokenSymbol),
309
- apy: rewardApy,
310
- incentiveKind: IncentiveKind.Reward,
311
- description: 'Eligible for protocol-level incentives.',
312
- });
313
- }
314
- });
315
- }));
316
-
317
- const payload: AaveV3AssetsData = {};
318
- // Sort by market size
319
- assetsData
320
- .sort((a, b) => {
321
- const aMarket = new Dec(a.price).times(a.totalSupply).toString();
322
- const bMarket = new Dec(b.price).times(b.totalSupply).toString();
323
-
324
- return new Dec(bMarket).minus(aMarket).toNumber();
325
- })
326
- .forEach((assetData: AaveV3AssetData, i) => {
327
- payload[assetData.symbol] = { ...assetData, sortIndex: i };
328
- });
329
-
330
- eModeCategoriesData[0] = {
331
- id: 0,
332
- label: '',
333
- liquidationBonus: '0',
334
- liquidationRatio: '0',
335
- collateralFactor: '0',
336
- collateralAssets: assetsData.map((a) => a.symbol),
337
- borrowAssets: assetsData.map((a) => a.symbol),
338
- ltvZeroAssets: [],
339
- };
340
-
341
- return { assetsData: payload, eModeCategoriesData };
342
- }
343
-
344
- export async function getAaveV3MarketData(provider: EthereumProvider, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
345
- return _getAaveV3MarketData(getViemProvider(provider, network), network, market, blockNumber);
346
- }
347
-
348
- export const EMPTY_AAVE_DATA = {
349
- usedAssets: {},
350
- suppliedUsd: '0',
351
- borrowedUsd: '0',
352
- borrowLimitUsd: '0',
353
- leftToBorrowUsd: '0',
354
- ratio: '0',
355
- minRatio: '0',
356
- netApy: '0',
357
- incentiveUsd: '0',
358
- totalInterestUsd: '0',
359
- isSubscribedToAutomation: false,
360
- automationResubscribeRequired: false,
361
- eModeCategory: 0,
362
- isInIsolationMode: false,
363
- isInSiloedMode: false,
364
- totalSupplied: '0',
365
- eModeCategories: [],
366
- collRatio: '0',
367
- suppliedCollateralUsd: '0',
368
- };
369
-
370
- export const _getAaveV3AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
371
- let balances: PositionBalances = {
372
- collateral: {},
373
- debt: {},
374
- };
375
-
376
- if (!address) {
377
- return balances;
378
- }
379
-
380
- const loanInfoContract = AaveV3ViewContractViem(provider, network, block);
381
-
382
- const market = AAVE_V3(network);
383
- const marketAddress = market.providerAddress;
384
- // @ts-ignore
385
- const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
386
-
387
- // @ts-ignore
388
- const reserveTokens = await protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block)) as { symbol: string, tokenAddress: EthAddress }[];
389
- const symbols = reserveTokens.map(({ symbol }: { symbol: string }) => symbol);
390
- const _addresses = reserveTokens.map(({ tokenAddress }: { tokenAddress: EthAddress }) => tokenAddress);
391
-
392
- // split addresses in half to avoid gas limit by multicall
393
- const middleAddressIndex = Math.floor(_addresses.length / 2);
394
-
395
- const [tokenBalances1, tokenBalances2] = await Promise.all([
396
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
397
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
398
- ]);
399
-
400
- const loanInfo = [...tokenBalances1, ...tokenBalances2];
401
-
402
- loanInfo.forEach((tokenInfo: any, i: number) => {
403
- const asset = wethToEth(symbols[i]);
404
- const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
405
-
406
- balances = {
407
- collateral: {
408
- ...balances.collateral,
409
- [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString(),
410
- },
411
- debt: {
412
- ...balances.debt,
413
- [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString(),
414
- },
415
- };
416
- });
417
-
418
- return balances;
419
- };
420
-
421
- export const getAaveV3AccountBalances = async (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => _getAaveV3AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address);
422
-
423
- export const _getAaveV3AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, extractedState: any, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3PositionData> => {
424
- const {
425
- selectedMarket: market, assetsData,
426
- } = extractedState;
427
- let payload: AaveV3PositionData = {
428
- ...EMPTY_AAVE_DATA,
429
- lastUpdated: Date.now(),
430
- };
431
- if (!address) {
432
- return payload;
433
- }
434
-
435
- const loanInfoContract = AaveV3ViewContractViem(provider, network);
436
- const lendingPoolContract = createViemContractFromConfigFunc(market.lendingPool, market.lendingPoolAddress)(provider, network);
437
- const marketAddress = market.providerAddress;
438
- const _addresses = market.assets.map((a: string) => getAssetInfo(getWrappedNativeAssetFromUnwrapped(a), network).address);
439
-
440
- const middleAddressIndex = Math.floor(_addresses.length / 2); // split addresses in half to avoid gas limit by multicall
441
-
442
- const [eModeCategory, tokenBalances1, tokenBalances2] = await Promise.all([
443
- lendingPoolContract.read.getUserEMode([address], setViemBlockNumber(blockNumber)),
444
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex) as EthAddress[]], setViemBlockNumber(blockNumber)),
445
- loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length) as EthAddress[]], setViemBlockNumber(blockNumber)),
446
- ]);
447
-
448
- const loanInfo = [...tokenBalances1, ...tokenBalances2];
449
-
450
- const usedAssets = {} as AaveV3UsedAssets;
451
- loanInfo.map(async (tokenInfo, i) => {
452
- const asset = market.assets[i];
453
- const isSupplied = tokenInfo.balance.toString() !== '0';
454
- const isBorrowed = tokenInfo.borrowsStable.toString() !== '0' || tokenInfo.borrowsVariable.toString() !== '0';
455
- if (!isSupplied && !isBorrowed) return;
456
-
457
- const supplied = assetAmountInEth(tokenInfo.balance.toString(), asset);
458
- const borrowedStable = assetAmountInEth(tokenInfo.borrowsStable.toString(), asset);
459
- const borrowedVariable = assetAmountInEth(tokenInfo.borrowsVariable.toString(), asset);
460
- const enabledAsCollateral = assetsData[asset].usageAsCollateralEnabled ? tokenInfo.enabledAsCollateral : false;
461
-
462
- let interestMode;
463
- if (borrowedVariable === '0' && borrowedStable !== '0') {
464
- interestMode = '1';
465
- } else if (borrowedVariable !== '0' && borrowedStable === '0') {
466
- interestMode = '2';
467
- } else {
468
- interestMode = 'both';
469
- }
470
- if (!usedAssets[asset]) usedAssets[asset] = {} as AaveV3UsedAsset;
471
- const borrowed = new Dec(borrowedStable).add(borrowedVariable).toString();
472
-
473
- usedAssets[asset] = {
474
- ...usedAssets[asset],
475
- symbol: asset,
476
- supplied,
477
- suppliedUsd: new Dec(supplied).mul(assetsData[asset].price).toString(),
478
- isSupplied,
479
- collateral: enabledAsCollateral,
480
- stableBorrowRate: aprToApy(new Dec(tokenInfo.stableBorrowRate.toString()).div(1e25).toString()),
481
- borrowedStable,
482
- borrowedVariable,
483
- borrowedUsdStable: new Dec(borrowedStable).mul(assetsData[asset].price).toString(),
484
- borrowedUsdVariable: new Dec(borrowedVariable).mul(assetsData[asset].price).toString(),
485
- borrowed,
486
- borrowedUsd: new Dec(new Dec(borrowedVariable).add(borrowedStable)).mul(assetsData[asset].price).toString(),
487
- isBorrowed,
488
- interestMode,
489
- };
490
- });
491
-
492
- payload.eModeCategory = +(eModeCategory as BigInt).toString();
493
- payload = {
494
- ...payload,
495
- usedAssets,
496
- ...aaveAnyGetAggregatedPositionData({
497
- ...extractedState, usedAssets, eModeCategory: payload.eModeCategory,
498
- }),
499
- };
500
- payload.eModeCategories = aaveV3EmodeCategoriesMapping(extractedState, usedAssets);
501
- payload.isInIsolationMode = aaveV3IsInIsolationMode({ usedAssets, assetsData });
502
- payload.isInSiloedMode = aaveV3IsInSiloedMode({ usedAssets, assetsData });
503
-
504
- payload.ratio = payload.borrowedUsd && payload.borrowedUsd !== '0'
505
- ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString()
506
- : '0';
507
- payload.minRatio = '100';
508
- payload.collRatio = payload.borrowedUsd && payload.borrowedUsd !== '0'
509
- ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString()
510
- : '0';
511
-
512
- // Calculate borrow limits per asset
513
- Object.values(payload.usedAssets).forEach((item) => {
514
- if (item.isBorrowed) {
515
- // eslint-disable-next-line no-param-reassign
516
- item.stableLimit = calculateBorrowingAssetLimit(item.borrowedUsdStable, payload.borrowLimitUsd);
517
- // eslint-disable-next-line no-param-reassign
518
- item.variableLimit = calculateBorrowingAssetLimit(item.borrowedUsdVariable, payload.borrowLimitUsd);
519
- // eslint-disable-next-line no-param-reassign
520
- item.limit = calculateBorrowingAssetLimit(item.borrowedUsd, payload.borrowLimitUsd);
521
- }
522
- });
523
-
524
- payload.isSubscribedToAutomation = false;
525
- payload.automationResubscribeRequired = false;
526
-
527
- return payload;
528
- };
529
-
530
- 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);
531
-
532
- export const getAaveV3FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, market: AaveMarketInfo): Promise<AaveV3PositionData> => {
533
- const marketData = await getAaveV3MarketData(provider, network, market);
534
- const positionData = await getAaveV3AccountData(provider, network, address, { assetsData: marketData.assetsData, selectedMarket: market, eModeCategoriesData: marketData.eModeCategoriesData });
535
- return positionData;
536
- };
537
-
538
- // aTokens eligible for AAVE rewards
539
- export const REWARDABLE_ASSETS = [
540
- '0x028171bCA77440897B824Ca71D1c56caC55b68A3', // DAI
541
- '0x6C3c78838c761c6Ac7bE9F59fe808ea2A6E4379d',
542
- '0xD37EE7e4f452C6638c96536e68090De8cBcdb583', // GUSD
543
- '0x279AF5b99540c1A3A7E3CDd326e19659401eF99e',
544
- '0xBcca60bB61934080951369a648Fb03DF4F96263C', // USDC
545
- '0x619beb58998eD2278e08620f97007e1116D5D25b',
546
- '0x3Ed3B47Dd13EC9a98b44e6204A523E766B225811', // USDT
547
- '0x531842cEbbdD378f8ee36D171d6cC9C4fcf475Ec',
548
- '0x9ff58f4fFB29fA2266Ab25e75e2A8b3503311656', // WBTC
549
- '0x9c39809Dec7F95F5e0713634a4D0701329B3b4d2',
550
- '0x030bA81f1c18d280636F32af80b9AAd02Cf0854e', // WETH
551
- '0xF63B34710400CAd3e044cFfDcAb00a0f32E33eCf',
552
- '0xa06bC25B5805d5F8d82847D191Cb4Af5A3e873E0', // LINK
553
- '0x0b8f12b1788BFdE65Aa1ca52E3e9F3Ba401be16D',
554
- '0x6C5024Cd4F8A59110119C56f8933403A539555EB', // SUSD
555
- '0xdC6a3Ab17299D9C2A412B0e0a4C1f55446AE0817',
556
- '0x5165d24277cD063F5ac44Efd447B27025e888f37', // YFI
557
- '0x7EbD09022Be45AD993BAA1CEc61166Fcc8644d97',
558
- '0xF256CC7847E919FAc9B808cC216cAc87CCF2f47a', // xSUSHI
559
- '0xfAFEDF95E21184E3d880bd56D4806c4b8d31c69A',
560
- '0xB9D7CB55f463405CDfBe4E90a6D2Df01C2B92BF1', // UNI
561
- '0x5BdB050A92CADcCfCDcCCBFC17204a1C9cC0Ab73',
562
- '0xc713e5E149D5D0715DcD1c156a020976e7E56B88', // MKR
563
- '0xba728eAd5e496BE00DCF66F650b6d7758eCB50f8',
564
- '0x101cc05f4A51C0319f570d5E146a8C625198e636', // TUSD
565
- '0x01C0eb1f8c6F1C1bF74ae028697ce7AA2a8b0E92',
566
- '0xc9BC48c72154ef3e5425641a3c747242112a46AF', // RAI
567
- '0xB5385132EE8321977FfF44b60cDE9fE9AB0B4e6b',
568
- '0x272F97b7a56a387aE942350bBC7Df5700f8a4576', // BAL
569
- '0x13210D4Fe0d5402bd7Ecbc4B5bC5cFcA3b71adB0',
570
- '0x2e8f4bdbe3d47d7d7de490437aea9915d930f1a3', // USDP
571
- '0xfdb93b3b10936cf81fa59a02a7523b6e2149b2b7',
572
- '0xA361718326c15715591c299427c62086F69923D9', // BUSD
573
- '0xbA429f7011c9fa04cDd46a2Da24dc0FF0aC6099c',
574
- '0xd4937682df3C8aEF4FE912A96A74121C0829E664', // FRAX
575
- '0xfE8F19B17fFeF0fDbfe2671F248903055AFAA8Ca',
576
- '0x683923dB55Fead99A79Fa01A27EeC3cB19679cC3', // FEI
577
- '0xC2e10006AccAb7B45D9184FcF5b7EC7763f5BaAe',
578
- '0x8dAE6Cb04688C62d939ed9B68d32Bc62e49970b1', // CRV
579
- '0x00ad8eBF64F141f1C81e9f8f792d3d1631c6c684',
580
- '0x6F634c6135D2EBD550000ac92F494F9CB8183dAe', // DPI
581
- '0x4dDff5885a67E4EffeC55875a3977D7E60F82ae0',
582
- ] as const;
583
-
584
- export const fetchYearlyMeritApyForStakingGho = async () => {
585
- try {
586
- const response = await fetch('https://apps.aavechan.com/api/merit/aprs', { signal: AbortSignal.timeout(5000) });
587
- const data = await response.json();
588
- const apr = data?.currentAPR?.actionsAPR?.['ethereum-stkgho'] || '0' as string;
589
- const apy = aprToApy(apr);
590
- const apyWithDFSBonus = new Dec(apy).mul(1.05).toString(); // 5% bonus for DFS users
591
- return apyWithDFSBonus;
592
- } catch (e) {
593
- const message = 'External API Failure: Failed to fetch yearly merit APY for staking GHO';
594
- console.error(message, e);
595
- return '0';
596
- }
597
- };
598
-
599
- export const getStakeAaveData = async (provider: Client, network: NetworkNumber, address: EthAddress) => {
600
- const stkGhoAddress = getAssetInfo('stkGHO').address as HexString;
601
- const stkAaveAddress = getAssetInfo('stkAAVE').address as HexString;
602
-
603
- const AaveIncentivesController = AaveIncentivesControllerViem(provider, network);
604
- const stkAAVE = StkAAVEViem(provider, network);
605
- const stkGHO = createViemContractFromConfigFunc('Erc20', stkGhoAddress as HexString)(provider, network);
606
-
607
-
608
- const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy] = await Promise.all([
609
- AaveIncentivesController.read.getRewardsBalance([REWARDABLE_ASSETS, address]),
610
- stkAAVE.read.assets([stkAaveAddress]),
611
- stkAAVE.read.balanceOf([address]),
612
- stkAAVE.read.totalSupply(),
613
- stkGHO.read.balanceOf([address]),
614
- fetchYearlyMeritApyForStakingGho(),
615
- ]);
616
-
617
-
618
- const stkAaveApy = new Dec(assetAmountInEth(emissionsPerSecond[0].toString(), 'GHO') || 0).mul(SECONDS_PER_YEAR).mul(100).div(assetAmountInEth(stkAAVETotalSupply.toString(), 'stkAAVE'))
619
- .toString();
620
- return {
621
- activatedCooldown: '0',
622
- activatedCooldownAmount: '0',
623
- stkAaveRewardsBalance: '0',
624
- aaveRewardsBalance: assetAmountInEth(aaveRewardsBalance.toString(), 'AAVE'),
625
- stkAaveBalance: assetAmountInEth(stkAAVEBalance.toString(), 'stkAAVE'),
626
- stkGhoBalance: assetAmountInEth(stkGHOBalance.toString(), 'GHO'),
627
- ghoMeritApy,
628
- stkAaveApy,
629
- };
630
- };
631
-
632
- export {
633
- getMeritCampaigns,
634
- getMerkleCampaigns,
635
- };
1
+ import { assetAmountInEth, assetAmountInWei, getAssetInfo } from '@defisaver/tokens';
2
+ import { Client } from 'viem';
3
+ import Dec from 'decimal.js';
4
+ import {
5
+ AaveIncentiveDataProviderV3ContractViem,
6
+ AaveIncentivesControllerViem,
7
+ AaveV3ViewContractViem,
8
+ createViemContractFromConfigFunc,
9
+ StkAAVEViem,
10
+ } from '../contracts';
11
+ import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
12
+ import { AAVE_V3 } from '../markets/aave';
13
+ import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
14
+ import {
15
+ getWrappedNativeAssetFromUnwrapped,
16
+ isEnabledOnBitmap,
17
+ isLayer2Network,
18
+ wethToEth,
19
+ wethToEthByAddress,
20
+ } from '../services/utils';
21
+ import { getStakingApy, STAKING_ASSETS } from '../staking';
22
+ import {
23
+ AaveMarketInfo,
24
+ AaveV3AssetData,
25
+ AaveV3AssetsData,
26
+ AaveV3MarketData,
27
+ AaveV3PositionData,
28
+ AaveV3UsedAsset,
29
+ AaveV3UsedAssets,
30
+ EModeCategoriesData,
31
+ EModeCategoryData,
32
+ EModeCategoryDataMapping,
33
+ } from '../types';
34
+ import {
35
+ Blockish,
36
+ EthAddress,
37
+ EthereumProvider,
38
+ IncentiveEligibilityId,
39
+ IncentiveKind,
40
+ NetworkNumber,
41
+ PositionBalances,
42
+ HexString,
43
+ } from '../types/common';
44
+ import { getViemProvider, setViemBlockNumber } from '../services/viem';
45
+ import { getMeritCampaigns } from './merit';
46
+ import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './merkl';
47
+ import { SECONDS_PER_YEAR } from '../constants';
48
+
49
+ export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: AaveV3UsedAssets) => {
50
+ const { eModeCategoriesData }: { assetsData: AaveV3AssetsData, eModeCategoriesData: EModeCategoriesData } = extractedState;
51
+ const usedAssetsValues = Object.values(usedAssets);
52
+
53
+ const categoriesMapping: { [key: number]: EModeCategoryDataMapping } = {};
54
+
55
+ Object.values(eModeCategoriesData).forEach((e: EModeCategoryData) => {
56
+ const borrowingOnlyFromCategory = e.id === 0
57
+ ? true
58
+ : !usedAssetsValues.filter(u => u.isBorrowed && !e.borrowAssets.includes(u.symbol)).length;
59
+ const afterEnteringCategory = aaveAnyGetAggregatedPositionData({
60
+ ...extractedState, usedAssets, eModeCategory: e.id,
61
+ });
62
+ const willStayOverCollateralized = new Dec(afterEnteringCategory.ratio).eq(0) || new Dec(afterEnteringCategory.ratio).gt(afterEnteringCategory.liqPercent);
63
+ const enteringTerms = [borrowingOnlyFromCategory, willStayOverCollateralized];
64
+ categoriesMapping[e.id] = {
65
+ enteringTerms,
66
+ canEnterCategory: !enteringTerms.includes(false),
67
+ id: e.id,
68
+ enabledData: {
69
+ ratio: afterEnteringCategory.ratio,
70
+ liqRatio: afterEnteringCategory.liqRatio,
71
+ liqPercent: afterEnteringCategory.liqPercent,
72
+ collRatio: afterEnteringCategory.collRatio,
73
+ },
74
+ };
75
+ });
76
+ return categoriesMapping;
77
+ };
78
+
79
+ export async function _getAaveV3MarketData(provider: Client, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
80
+ const _addresses = market.assets.map(a => getAssetInfo(getWrappedNativeAssetFromUnwrapped(a), network).address);
81
+
82
+ const isL2 = isLayer2Network(network);
83
+ const loanInfoContract = AaveV3ViewContractViem(provider, network);
84
+ const aaveIncentivesContract = AaveIncentiveDataProviderV3ContractViem(provider, network);
85
+ const marketAddress = market.providerAddress;
86
+ const networksWithIncentives = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Opt, NetworkNumber.Linea, NetworkNumber.Plasma];
87
+ // eslint-disable-next-line prefer-const
88
+ let [loanInfo, eModesInfo, isBorrowAllowed, rewardInfo, merkleRewardsMap, meritRewardsMap] = await Promise.all([
89
+ loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]], setViemBlockNumber(blockNumber)),
90
+ loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
91
+ loanInfoContract.read.isBorrowAllowed([marketAddress], setViemBlockNumber(blockNumber)), // Used on L2s check for PriceOracleSentinel (mainnet will always return true)
92
+ networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
93
+ getMerkleCampaigns(network),
94
+ getMeritCampaigns(network, market.value),
95
+ ]);
96
+ isBorrowAllowed = isLayer2Network(network) ? isBorrowAllowed : true;
97
+
98
+ // same break logic as view contract
99
+ let missCounter = 0;
100
+ const eModeCategoriesData: EModeCategoriesData = {};
101
+ for (let i = 0; i < eModesInfo.length; i++) {
102
+ if (eModesInfo[i].liquidationThreshold !== 0) {
103
+ eModeCategoriesData[i + 1] = {
104
+ label: eModesInfo[i].label,
105
+ id: i + 1,
106
+ liquidationBonus: new Dec(eModesInfo[i].liquidationBonus).div(10000).toString(),
107
+ liquidationRatio: new Dec(eModesInfo[i].liquidationThreshold).div(10000).toString(),
108
+ collateralFactor: new Dec(eModesInfo[i].ltv).div(10000).toString(),
109
+ borrowableBitmap: eModesInfo[i].borrowableBitmap.toString(),
110
+ collateralBitmap: eModesInfo[i].collateralBitmap.toString(),
111
+ ltvzeroBitmap: eModesInfo[i].ltvzeroBitmap.toString(),
112
+ borrowAssets: [],
113
+ collateralAssets: [],
114
+ ltvZeroAssets: [],
115
+ };
116
+ missCounter = 0;
117
+ } else {
118
+ ++missCounter;
119
+ if (missCounter > 2) break;
120
+ }
121
+ }
122
+
123
+ if (networksWithIncentives.includes(network) && rewardInfo) {
124
+ rewardInfo = rewardInfo.reduce((all: any, _market: any) => {
125
+ // eslint-disable-next-line no-param-reassign
126
+ all[_market.underlyingAsset] = _market;
127
+ return all;
128
+ }, {});
129
+ }
130
+
131
+ const assetsData: AaveV3AssetData[] = await Promise.all(loanInfo
132
+ .map(async (tokenMarket, i) => {
133
+ const symbol = market.assets[i];
134
+
135
+ // eslint-disable-next-line guard-for-in
136
+ for (const eModeIndex in eModeCategoriesData) {
137
+ if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].collateralBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].collateralAssets.push(symbol);
138
+ if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].borrowableBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].borrowAssets.push(symbol);
139
+ if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].ltvzeroBitmap), Number(tokenMarket.assetId))) eModeCategoriesData[eModeIndex].ltvZeroAssets.push(symbol);
140
+ }
141
+
142
+ const borrowCap = tokenMarket.borrowCap.toString();
143
+
144
+ const borrowCapInWei = new Dec(assetAmountInWei(borrowCap, symbol));
145
+ let marketLiquidity = borrowCapInWei.lt(new Dec(tokenMarket.totalSupply.toString()))
146
+ ? assetAmountInEth(borrowCapInWei
147
+ .sub(tokenMarket.totalBorrow.toString())
148
+ .toString(), symbol)
149
+ : assetAmountInEth(new Dec(tokenMarket.totalSupply.toString())
150
+ .sub(tokenMarket.totalBorrow.toString())
151
+ .toString(), symbol);
152
+
153
+ if (new Dec(marketLiquidity).lt(0)) {
154
+ marketLiquidity = '0';
155
+ }
156
+ return ({
157
+ symbol,
158
+ isIsolated: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).gt(0),
159
+ debtCeilingForIsolationMode: new Dec(tokenMarket.debtCeilingForIsolationMode.toString()).div(100).toString(),
160
+ isSiloed: tokenMarket.isSiloedForBorrowing,
161
+ isolationModeTotalDebt: new Dec(tokenMarket.isolationModeTotalDebt.toString()).div(100).toString(),
162
+ assetId: Number(tokenMarket.assetId),
163
+ underlyingTokenAddress: tokenMarket.underlyingTokenAddress,
164
+ supplyRate: aprToApy(new Dec(tokenMarket.supplyRate.toString()).div(1e25).toString()),
165
+ borrowRate: aprToApy(new Dec(tokenMarket.borrowRateVariable.toString()).div(1e25).toString()),
166
+ borrowRateStable: aprToApy(new Dec(tokenMarket.borrowRateStable.toString()).div(1e25).toString()),
167
+ collateralFactor: new Dec(tokenMarket.collateralFactor.toString()).div(10000).toString(),
168
+ liquidationBonus: new Dec(tokenMarket.liquidationBonus.toString()).div(10000).toString(),
169
+ liquidationRatio: new Dec(tokenMarket.liquidationRatio.toString()).div(10000).toString(),
170
+ marketLiquidity,
171
+ utilization: new Dec(tokenMarket.totalBorrow.toString()).times(100).div(new Dec(tokenMarket.totalSupply.toString())).toString(),
172
+ usageAsCollateralEnabled: tokenMarket.usageAsCollateralEnabled,
173
+ supplyCap: tokenMarket.supplyCap.toString(),
174
+ borrowCap,
175
+ totalSupply: assetAmountInEth(tokenMarket.totalSupply.toString(), symbol),
176
+ isInactive: !tokenMarket.isActive,
177
+ isFrozen: tokenMarket.isFrozen,
178
+ isPaused: tokenMarket.isPaused,
179
+ canBeBorrowed: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen && tokenMarket.borrowingEnabled && isBorrowAllowed,
180
+ canBeSupplied: tokenMarket.isActive && !tokenMarket.isPaused && !tokenMarket.isFrozen,
181
+ canBeWithdrawn: tokenMarket.isActive && !tokenMarket.isPaused,
182
+ canBePayBacked: tokenMarket.isActive && !tokenMarket.isPaused,
183
+ disabledStableBorrowing: !tokenMarket.stableBorrowRateEnabled,
184
+ totalBorrow: assetAmountInEth(tokenMarket.totalBorrow.toString(), symbol),
185
+ totalBorrowVar: assetAmountInEth(tokenMarket.totalBorrowVar.toString(), symbol),
186
+ price: new Dec(tokenMarket.price.toString()).div(1e8).toString(), // is actually price in USD
187
+ isolationModeBorrowingEnabled: tokenMarket.isolationModeBorrowingEnabled,
188
+ isFlashLoanEnabled: tokenMarket.isFlashLoanEnabled,
189
+ aTokenAddress: tokenMarket.aTokenAddress,
190
+ vTokenAddress: tokenMarket.debtTokenAddress,
191
+ supplyIncentives: [],
192
+ borrowIncentives: [],
193
+ });
194
+ }),
195
+ );
196
+
197
+ // Get incentives data
198
+ await Promise.all(assetsData.map(async (_market: AaveV3AssetData, index) => {
199
+ /* eslint-disable no-param-reassign */
200
+ // @ts-ignore
201
+ const rewardForMarket = rewardInfo?.[_market.underlyingTokenAddress];
202
+ const isStakingAsset = STAKING_ASSETS.includes(_market.symbol);
203
+
204
+ if (isStakingAsset) {
205
+ const yieldApy = await getStakingApy(_market.symbol, network as NetworkNumber);
206
+ _market.supplyIncentives.push({
207
+ apy: yieldApy,
208
+ token: _market.symbol,
209
+ incentiveKind: IncentiveKind.Staking,
210
+ description: `Native ${_market.symbol} yield.`,
211
+ });
212
+ if (_market.canBeBorrowed) {
213
+ // when borrowing assets whose value increases over time
214
+ _market.borrowIncentives.push({
215
+ apy: new Dec(yieldApy).mul(-1).toString(),
216
+ token: _market.symbol,
217
+ incentiveKind: IncentiveKind.Reward,
218
+ description: `Due to the native yield of ${_market.symbol}, the value of the debt would increase over time.`,
219
+ });
220
+ }
221
+ }
222
+
223
+ const aTokenAddress = (_market as any).aTokenAddress.toLowerCase(); // DEV: Should aTokenAddress be in AaveV3AssetData type?
224
+ if (merkleRewardsMap[aTokenAddress]?.supply) {
225
+ const {
226
+ apy, rewardTokenSymbol, description, identifier,
227
+ } = merkleRewardsMap[aTokenAddress].supply;
228
+ _market.supplyIncentives.push({
229
+ apy,
230
+ token: rewardTokenSymbol,
231
+ incentiveKind: IncentiveKind.Reward,
232
+ description,
233
+ eligibilityId: identifier as IncentiveEligibilityId,
234
+ });
235
+ }
236
+
237
+ const vTokenAddress = (_market as any).vTokenAddress.toLowerCase(); // DEV: Should vTokenAddress be in AaveV3AssetData type?
238
+ if (merkleRewardsMap[vTokenAddress]?.borrow) {
239
+ const {
240
+ apy, rewardTokenSymbol, description, identifier,
241
+ } = merkleRewardsMap[vTokenAddress].borrow;
242
+ _market.borrowIncentives.push({
243
+ apy,
244
+ token: rewardTokenSymbol,
245
+ incentiveKind: IncentiveKind.Reward,
246
+ description,
247
+ eligibilityId: identifier as IncentiveEligibilityId,
248
+ });
249
+ }
250
+
251
+ if (meritRewardsMap.supply[_market.symbol]) {
252
+ const { apy, rewardTokenSymbol, description } = meritRewardsMap.supply[_market.symbol];
253
+ _market.supplyIncentives.push({
254
+ apy,
255
+ token: rewardTokenSymbol,
256
+ incentiveKind: IncentiveKind.Reward,
257
+ description,
258
+ });
259
+ }
260
+
261
+ if (meritRewardsMap.borrow[_market.symbol]) {
262
+ const { apy, rewardTokenSymbol, description } = meritRewardsMap.borrow[_market.symbol];
263
+ _market.borrowIncentives.push({
264
+ apy,
265
+ token: rewardTokenSymbol,
266
+ incentiveKind: IncentiveKind.Reward,
267
+ description,
268
+ });
269
+ }
270
+
271
+ if (!rewardForMarket) return;
272
+ // @ts-ignore
273
+ rewardForMarket.aIncentiveData.rewardsTokenInformation.forEach(supplyRewardData => {
274
+ if (supplyRewardData) {
275
+ if (+(supplyRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
276
+ // reward token is aave asset
277
+ const supplyEmissionPerSecond = supplyRewardData.emissionPerSecond;
278
+ const supplyRewardPrice = new Dec(supplyRewardData.rewardPriceFeed).div(10 ** +supplyRewardData.priceFeedDecimals)
279
+ .toString();
280
+ const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +supplyRewardData.rewardTokenDecimals) / 100)
281
+ .mul(365 * 24 * 3600)
282
+ .mul(supplyRewardPrice)
283
+ .div(_market.price)
284
+ .div(_market.totalSupply)
285
+ .toString();
286
+ _market.supplyIncentives.push({
287
+ token: getAaveUnderlyingSymbol(supplyRewardData.rewardTokenSymbol),
288
+ apy: rewardApy,
289
+ incentiveKind: IncentiveKind.Reward,
290
+ description: 'Eligible for protocol-level incentives.',
291
+ });
292
+ }
293
+ });
294
+ // @ts-ignore
295
+ rewardForMarket.vIncentiveData.rewardsTokenInformation.forEach(borrowRewardData => {
296
+ if (borrowRewardData) {
297
+ if (+(borrowRewardData.emissionEndTimestamp.toString()) * 1000 < Date.now()) return;
298
+ const supplyEmissionPerSecond = borrowRewardData.emissionPerSecond;
299
+ const supplyRewardPrice = new Dec(borrowRewardData.rewardPriceFeed).div(10 ** +borrowRewardData.priceFeedDecimals)
300
+ .toString();
301
+ const rewardApy = new Dec(supplyEmissionPerSecond).div((10 ** +borrowRewardData.rewardTokenDecimals) / 100)
302
+ .mul(365 * 24 * 3600)
303
+ .mul(supplyRewardPrice)
304
+ .div(_market.price)
305
+ .div(_market.totalBorrowVar)
306
+ .toString();
307
+ _market.borrowIncentives.push({
308
+ token: getAaveUnderlyingSymbol(borrowRewardData.rewardTokenSymbol),
309
+ apy: rewardApy,
310
+ incentiveKind: IncentiveKind.Reward,
311
+ description: 'Eligible for protocol-level incentives.',
312
+ });
313
+ }
314
+ });
315
+ }));
316
+
317
+ const payload: AaveV3AssetsData = {};
318
+ // Sort by market size
319
+ assetsData
320
+ .sort((a, b) => {
321
+ const aMarket = new Dec(a.price).times(a.totalSupply).toString();
322
+ const bMarket = new Dec(b.price).times(b.totalSupply).toString();
323
+
324
+ return new Dec(bMarket).minus(aMarket).toNumber();
325
+ })
326
+ .forEach((assetData: AaveV3AssetData, i) => {
327
+ payload[assetData.symbol] = { ...assetData, sortIndex: i };
328
+ });
329
+
330
+ eModeCategoriesData[0] = {
331
+ id: 0,
332
+ label: '',
333
+ liquidationBonus: '0',
334
+ liquidationRatio: '0',
335
+ collateralFactor: '0',
336
+ collateralAssets: assetsData.map((a) => a.symbol),
337
+ borrowAssets: assetsData.map((a) => a.symbol),
338
+ ltvZeroAssets: [],
339
+ };
340
+
341
+ return { assetsData: payload, eModeCategoriesData };
342
+ }
343
+
344
+ export async function getAaveV3MarketData(provider: EthereumProvider, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
345
+ return _getAaveV3MarketData(getViemProvider(provider, network), network, market, blockNumber);
346
+ }
347
+
348
+ export const EMPTY_AAVE_DATA = {
349
+ usedAssets: {},
350
+ suppliedUsd: '0',
351
+ borrowedUsd: '0',
352
+ borrowLimitUsd: '0',
353
+ leftToBorrowUsd: '0',
354
+ ratio: '0',
355
+ minRatio: '0',
356
+ netApy: '0',
357
+ incentiveUsd: '0',
358
+ totalInterestUsd: '0',
359
+ isSubscribedToAutomation: false,
360
+ automationResubscribeRequired: false,
361
+ eModeCategory: 0,
362
+ isInIsolationMode: false,
363
+ isInSiloedMode: false,
364
+ totalSupplied: '0',
365
+ eModeCategories: [],
366
+ collRatio: '0',
367
+ suppliedCollateralUsd: '0',
368
+ exposure: 'N/A',
369
+ };
370
+
371
+ export const _getAaveV3AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
372
+ let balances: PositionBalances = {
373
+ collateral: {},
374
+ debt: {},
375
+ };
376
+
377
+ if (!address) {
378
+ return balances;
379
+ }
380
+
381
+ const loanInfoContract = AaveV3ViewContractViem(provider, network, block);
382
+
383
+ const market = AAVE_V3(network);
384
+ const marketAddress = market.providerAddress;
385
+ // @ts-ignore
386
+ const protocolDataProviderContract = createViemContractFromConfigFunc(market.protocolData, market.protocolDataAddress)(provider, network);
387
+
388
+ // @ts-ignore
389
+ const reserveTokens = await protocolDataProviderContract.read.getAllReservesTokens(setViemBlockNumber(block)) as { symbol: string, tokenAddress: EthAddress }[];
390
+ const symbols = reserveTokens.map(({ symbol }: { symbol: string }) => symbol);
391
+ const _addresses = reserveTokens.map(({ tokenAddress }: { tokenAddress: EthAddress }) => tokenAddress);
392
+
393
+ // split addresses in half to avoid gas limit by multicall
394
+ const middleAddressIndex = Math.floor(_addresses.length / 2);
395
+
396
+ const [tokenBalances1, tokenBalances2] = await Promise.all([
397
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex)], setViemBlockNumber(block)),
398
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length)], setViemBlockNumber(block)),
399
+ ]);
400
+
401
+ const loanInfo = [...tokenBalances1, ...tokenBalances2];
402
+
403
+ loanInfo.forEach((tokenInfo: any, i: number) => {
404
+ const asset = wethToEth(symbols[i]);
405
+ const assetAddr = wethToEthByAddress(_addresses[i], network).toLowerCase();
406
+
407
+ balances = {
408
+ collateral: {
409
+ ...balances.collateral,
410
+ [addressMapping ? assetAddr : asset]: tokenInfo.balance.toString(),
411
+ },
412
+ debt: {
413
+ ...balances.debt,
414
+ [addressMapping ? assetAddr : asset]: new Dec(tokenInfo.borrowsStable.toString()).add(tokenInfo.borrowsVariable.toString()).toString(),
415
+ },
416
+ };
417
+ });
418
+
419
+ return balances;
420
+ };
421
+
422
+ export const getAaveV3AccountBalances = async (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => _getAaveV3AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address);
423
+
424
+ export const _getAaveV3AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, extractedState: any, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3PositionData> => {
425
+ const {
426
+ selectedMarket: market, assetsData, eModeCategoriesData,
427
+ } = extractedState;
428
+ let payload: AaveV3PositionData = {
429
+ ...EMPTY_AAVE_DATA,
430
+ lastUpdated: Date.now(),
431
+ };
432
+ if (!address) {
433
+ return payload;
434
+ }
435
+
436
+ const loanInfoContract = AaveV3ViewContractViem(provider, network);
437
+ const lendingPoolContract = createViemContractFromConfigFunc(market.lendingPool, market.lendingPoolAddress)(provider, network);
438
+ const marketAddress = market.providerAddress;
439
+ const _addresses = market.assets.map((a: string) => getAssetInfo(getWrappedNativeAssetFromUnwrapped(a), network).address);
440
+
441
+ const middleAddressIndex = Math.floor(_addresses.length / 2); // split addresses in half to avoid gas limit by multicall
442
+
443
+ const [eModeCategory, tokenBalances1, tokenBalances2] = await Promise.all([
444
+ lendingPoolContract.read.getUserEMode([address], setViemBlockNumber(blockNumber)),
445
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(0, middleAddressIndex) as EthAddress[]], setViemBlockNumber(blockNumber)),
446
+ loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses.slice(middleAddressIndex, _addresses.length) as EthAddress[]], setViemBlockNumber(blockNumber)),
447
+ ]);
448
+
449
+ const loanInfo = [...tokenBalances1, ...tokenBalances2];
450
+
451
+ const usedAssets = {} as AaveV3UsedAssets;
452
+ loanInfo.map(async (tokenInfo, i) => {
453
+ const asset = market.assets[i];
454
+ const isSupplied = tokenInfo.balance.toString() !== '0';
455
+ const isBorrowed = tokenInfo.borrowsStable.toString() !== '0' || tokenInfo.borrowsVariable.toString() !== '0';
456
+ if (!isSupplied && !isBorrowed) return;
457
+
458
+ const supplied = assetAmountInEth(tokenInfo.balance.toString(), asset);
459
+ const borrowedStable = assetAmountInEth(tokenInfo.borrowsStable.toString(), asset);
460
+ const borrowedVariable = assetAmountInEth(tokenInfo.borrowsVariable.toString(), asset);
461
+ const eModeCategoryData = eModeCategoriesData[+(eModeCategory as BigInt).toString()];
462
+ const usageAsCollateralIsEnabledInEmode = eModeCategoryData?.collateralAssets.includes(asset);
463
+ const enabledAsCollateral = (assetsData[asset].usageAsCollateralEnabled || usageAsCollateralIsEnabledInEmode) ? tokenInfo.enabledAsCollateral : false;
464
+
465
+ let interestMode;
466
+ if (borrowedVariable === '0' && borrowedStable !== '0') {
467
+ interestMode = '1';
468
+ } else if (borrowedVariable !== '0' && borrowedStable === '0') {
469
+ interestMode = '2';
470
+ } else {
471
+ interestMode = 'both';
472
+ }
473
+ if (!usedAssets[asset]) usedAssets[asset] = {} as AaveV3UsedAsset;
474
+ const borrowed = new Dec(borrowedStable).add(borrowedVariable).toString();
475
+
476
+ usedAssets[asset] = {
477
+ ...usedAssets[asset],
478
+ symbol: asset,
479
+ supplied,
480
+ suppliedUsd: new Dec(supplied).mul(assetsData[asset].price).toString(),
481
+ isSupplied,
482
+ collateral: enabledAsCollateral,
483
+ stableBorrowRate: aprToApy(new Dec(tokenInfo.stableBorrowRate.toString()).div(1e25).toString()),
484
+ borrowedStable,
485
+ borrowedVariable,
486
+ borrowedUsdStable: new Dec(borrowedStable).mul(assetsData[asset].price).toString(),
487
+ borrowedUsdVariable: new Dec(borrowedVariable).mul(assetsData[asset].price).toString(),
488
+ borrowed,
489
+ borrowedUsd: new Dec(new Dec(borrowedVariable).add(borrowedStable)).mul(assetsData[asset].price).toString(),
490
+ isBorrowed,
491
+ interestMode,
492
+ };
493
+ });
494
+
495
+ payload.eModeCategory = +(eModeCategory as BigInt).toString();
496
+ payload = {
497
+ ...payload,
498
+ usedAssets,
499
+ ...aaveAnyGetAggregatedPositionData({
500
+ ...extractedState, usedAssets, eModeCategory: payload.eModeCategory,
501
+ }),
502
+ };
503
+ payload.eModeCategories = aaveV3EmodeCategoriesMapping(extractedState, usedAssets);
504
+ payload.isInIsolationMode = aaveV3IsInIsolationMode({ usedAssets, assetsData });
505
+ payload.isInSiloedMode = aaveV3IsInSiloedMode({ usedAssets, assetsData });
506
+
507
+ payload.ratio = payload.borrowedUsd && payload.borrowedUsd !== '0'
508
+ ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString()
509
+ : '0';
510
+ payload.minRatio = '100';
511
+ payload.collRatio = payload.borrowedUsd && payload.borrowedUsd !== '0'
512
+ ? new Dec(payload.suppliedCollateralUsd).div(payload.borrowedUsd).mul(100).toString()
513
+ : '0';
514
+
515
+ // Calculate borrow limits per asset
516
+ Object.values(payload.usedAssets).forEach((item) => {
517
+ if (item.isBorrowed) {
518
+ // eslint-disable-next-line no-param-reassign
519
+ item.stableLimit = calculateBorrowingAssetLimit(item.borrowedUsdStable, payload.borrowLimitUsd);
520
+ // eslint-disable-next-line no-param-reassign
521
+ item.variableLimit = calculateBorrowingAssetLimit(item.borrowedUsdVariable, payload.borrowLimitUsd);
522
+ // eslint-disable-next-line no-param-reassign
523
+ item.limit = calculateBorrowingAssetLimit(item.borrowedUsd, payload.borrowLimitUsd);
524
+ }
525
+ });
526
+
527
+ payload.isSubscribedToAutomation = false;
528
+ payload.automationResubscribeRequired = false;
529
+
530
+ return payload;
531
+ };
532
+
533
+ 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);
534
+
535
+ export const getAaveV3FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, market: AaveMarketInfo): Promise<AaveV3PositionData> => {
536
+ const marketData = await getAaveV3MarketData(provider, network, market);
537
+ const positionData = await getAaveV3AccountData(provider, network, address, { assetsData: marketData.assetsData, selectedMarket: market, eModeCategoriesData: marketData.eModeCategoriesData });
538
+ return positionData;
539
+ };
540
+
541
+ // aTokens eligible for AAVE rewards
542
+ export const REWARDABLE_ASSETS = [
543
+ '0x028171bCA77440897B824Ca71D1c56caC55b68A3', // DAI
544
+ '0x6C3c78838c761c6Ac7bE9F59fe808ea2A6E4379d',
545
+ '0xD37EE7e4f452C6638c96536e68090De8cBcdb583', // GUSD
546
+ '0x279AF5b99540c1A3A7E3CDd326e19659401eF99e',
547
+ '0xBcca60bB61934080951369a648Fb03DF4F96263C', // USDC
548
+ '0x619beb58998eD2278e08620f97007e1116D5D25b',
549
+ '0x3Ed3B47Dd13EC9a98b44e6204A523E766B225811', // USDT
550
+ '0x531842cEbbdD378f8ee36D171d6cC9C4fcf475Ec',
551
+ '0x9ff58f4fFB29fA2266Ab25e75e2A8b3503311656', // WBTC
552
+ '0x9c39809Dec7F95F5e0713634a4D0701329B3b4d2',
553
+ '0x030bA81f1c18d280636F32af80b9AAd02Cf0854e', // WETH
554
+ '0xF63B34710400CAd3e044cFfDcAb00a0f32E33eCf',
555
+ '0xa06bC25B5805d5F8d82847D191Cb4Af5A3e873E0', // LINK
556
+ '0x0b8f12b1788BFdE65Aa1ca52E3e9F3Ba401be16D',
557
+ '0x6C5024Cd4F8A59110119C56f8933403A539555EB', // SUSD
558
+ '0xdC6a3Ab17299D9C2A412B0e0a4C1f55446AE0817',
559
+ '0x5165d24277cD063F5ac44Efd447B27025e888f37', // YFI
560
+ '0x7EbD09022Be45AD993BAA1CEc61166Fcc8644d97',
561
+ '0xF256CC7847E919FAc9B808cC216cAc87CCF2f47a', // xSUSHI
562
+ '0xfAFEDF95E21184E3d880bd56D4806c4b8d31c69A',
563
+ '0xB9D7CB55f463405CDfBe4E90a6D2Df01C2B92BF1', // UNI
564
+ '0x5BdB050A92CADcCfCDcCCBFC17204a1C9cC0Ab73',
565
+ '0xc713e5E149D5D0715DcD1c156a020976e7E56B88', // MKR
566
+ '0xba728eAd5e496BE00DCF66F650b6d7758eCB50f8',
567
+ '0x101cc05f4A51C0319f570d5E146a8C625198e636', // TUSD
568
+ '0x01C0eb1f8c6F1C1bF74ae028697ce7AA2a8b0E92',
569
+ '0xc9BC48c72154ef3e5425641a3c747242112a46AF', // RAI
570
+ '0xB5385132EE8321977FfF44b60cDE9fE9AB0B4e6b',
571
+ '0x272F97b7a56a387aE942350bBC7Df5700f8a4576', // BAL
572
+ '0x13210D4Fe0d5402bd7Ecbc4B5bC5cFcA3b71adB0',
573
+ '0x2e8f4bdbe3d47d7d7de490437aea9915d930f1a3', // USDP
574
+ '0xfdb93b3b10936cf81fa59a02a7523b6e2149b2b7',
575
+ '0xA361718326c15715591c299427c62086F69923D9', // BUSD
576
+ '0xbA429f7011c9fa04cDd46a2Da24dc0FF0aC6099c',
577
+ '0xd4937682df3C8aEF4FE912A96A74121C0829E664', // FRAX
578
+ '0xfE8F19B17fFeF0fDbfe2671F248903055AFAA8Ca',
579
+ '0x683923dB55Fead99A79Fa01A27EeC3cB19679cC3', // FEI
580
+ '0xC2e10006AccAb7B45D9184FcF5b7EC7763f5BaAe',
581
+ '0x8dAE6Cb04688C62d939ed9B68d32Bc62e49970b1', // CRV
582
+ '0x00ad8eBF64F141f1C81e9f8f792d3d1631c6c684',
583
+ '0x6F634c6135D2EBD550000ac92F494F9CB8183dAe', // DPI
584
+ '0x4dDff5885a67E4EffeC55875a3977D7E60F82ae0',
585
+ ] as const;
586
+
587
+ export const fetchYearlyMeritApyForStakingGho = async () => {
588
+ try {
589
+ const response = await fetch('https://apps.aavechan.com/api/merit/aprs', { signal: AbortSignal.timeout(5000) });
590
+ const data = await response.json();
591
+ const apr = data?.currentAPR?.actionsAPR?.['ethereum-stkgho'] || '0' as string;
592
+ const apy = aprToApy(apr);
593
+ const apyWithDFSBonus = new Dec(apy).mul(1.05).toString(); // 5% bonus for DFS users
594
+ return apyWithDFSBonus;
595
+ } catch (e) {
596
+ const message = 'External API Failure: Failed to fetch yearly merit APY for staking GHO';
597
+ console.error(message, e);
598
+ return '0';
599
+ }
600
+ };
601
+
602
+ export const getStakeAaveData = async (provider: Client, network: NetworkNumber, address: EthAddress) => {
603
+ const stkGhoAddress = getAssetInfo('stkGHO').address as HexString;
604
+ const stkAaveAddress = getAssetInfo('stkAAVE').address as HexString;
605
+
606
+ const AaveIncentivesController = AaveIncentivesControllerViem(provider, network);
607
+ const stkAAVE = StkAAVEViem(provider, network);
608
+ const stkGHO = createViemContractFromConfigFunc('Erc20', stkGhoAddress as HexString)(provider, network);
609
+
610
+
611
+ const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy] = await Promise.all([
612
+ AaveIncentivesController.read.getRewardsBalance([REWARDABLE_ASSETS, address]),
613
+ stkAAVE.read.assets([stkAaveAddress]),
614
+ stkAAVE.read.balanceOf([address]),
615
+ stkAAVE.read.totalSupply(),
616
+ stkGHO.read.balanceOf([address]),
617
+ fetchYearlyMeritApyForStakingGho(),
618
+ ]);
619
+
620
+
621
+ const stkAaveApy = new Dec(assetAmountInEth(emissionsPerSecond[0].toString(), 'GHO') || 0).mul(SECONDS_PER_YEAR).mul(100).div(assetAmountInEth(stkAAVETotalSupply.toString(), 'stkAAVE'))
622
+ .toString();
623
+ return {
624
+ activatedCooldown: '0',
625
+ activatedCooldownAmount: '0',
626
+ stkAaveRewardsBalance: '0',
627
+ aaveRewardsBalance: assetAmountInEth(aaveRewardsBalance.toString(), 'AAVE'),
628
+ stkAaveBalance: assetAmountInEth(stkAAVEBalance.toString(), 'stkAAVE'),
629
+ stkGhoBalance: assetAmountInEth(stkGHOBalance.toString(), 'GHO'),
630
+ ghoMeritApy,
631
+ stkAaveApy,
632
+ };
633
+ };
634
+
635
+ export {
636
+ getMeritCampaigns,
637
+ getMerkleCampaigns,
638
+ };