@defisaver/positions-sdk 1.0.11-fluid-dev12 → 1.0.11-fluid-dev13

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 (100) hide show
  1. package/.mocharc.json +4 -4
  2. package/.nvmrc +1 -1
  3. package/README.md +69 -69
  4. package/cjs/config/contracts.d.ts +113 -53
  5. package/cjs/config/contracts.js +10 -0
  6. package/cjs/contracts.d.ts +1 -0
  7. package/cjs/contracts.js +2 -1
  8. package/cjs/fluid/index.js +27 -0
  9. package/cjs/helpers/morphoBlueHelpers/index.js +66 -66
  10. package/cjs/markets/fluid/index.d.ts +0 -2
  11. package/cjs/markets/fluid/index.js +26 -24
  12. package/cjs/services/priceService.d.ts +2 -0
  13. package/cjs/services/priceService.js +13 -1
  14. package/cjs/types/contracts/generated/BTCPriceFeed.d.ts +135 -0
  15. package/cjs/types/contracts/generated/BTCPriceFeed.js +5 -0
  16. package/cjs/types/contracts/generated/index.d.ts +1 -0
  17. package/esm/config/contracts.d.ts +113 -53
  18. package/esm/config/contracts.js +10 -0
  19. package/esm/contracts.d.ts +1 -0
  20. package/esm/contracts.js +1 -0
  21. package/esm/fluid/index.js +28 -1
  22. package/esm/helpers/morphoBlueHelpers/index.js +66 -66
  23. package/esm/markets/fluid/index.d.ts +0 -2
  24. package/esm/markets/fluid/index.js +24 -21
  25. package/esm/services/priceService.d.ts +2 -0
  26. package/esm/services/priceService.js +11 -1
  27. package/esm/types/contracts/generated/BTCPriceFeed.d.ts +135 -0
  28. package/esm/types/contracts/generated/BTCPriceFeed.js +4 -0
  29. package/esm/types/contracts/generated/index.d.ts +1 -0
  30. package/package.json +54 -54
  31. package/src/aaveV2/index.ts +227 -227
  32. package/src/aaveV3/index.ts +624 -624
  33. package/src/assets/index.ts +60 -60
  34. package/src/chickenBonds/index.ts +123 -123
  35. package/src/compoundV2/index.ts +220 -220
  36. package/src/compoundV3/index.ts +291 -291
  37. package/src/config/contracts.js +1165 -1155
  38. package/src/constants/index.ts +6 -6
  39. package/src/contracts.ts +136 -135
  40. package/src/curveUsd/index.ts +239 -239
  41. package/src/eulerV2/index.ts +303 -303
  42. package/src/exchange/index.ts +17 -17
  43. package/src/fluid/index.ts +1320 -1289
  44. package/src/helpers/aaveHelpers/index.ts +203 -203
  45. package/src/helpers/chickenBondsHelpers/index.ts +23 -23
  46. package/src/helpers/compoundHelpers/index.ts +248 -248
  47. package/src/helpers/curveUsdHelpers/index.ts +40 -40
  48. package/src/helpers/eulerHelpers/index.ts +234 -234
  49. package/src/helpers/fluidHelpers/index.ts +325 -325
  50. package/src/helpers/index.ts +11 -11
  51. package/src/helpers/liquityV2Helpers/index.ts +80 -80
  52. package/src/helpers/llamaLendHelpers/index.ts +53 -53
  53. package/src/helpers/makerHelpers/index.ts +94 -94
  54. package/src/helpers/morphoBlueHelpers/index.ts +367 -367
  55. package/src/helpers/sparkHelpers/index.ts +154 -154
  56. package/src/index.ts +52 -52
  57. package/src/liquity/index.ts +116 -116
  58. package/src/liquityV2/index.ts +295 -295
  59. package/src/llamaLend/index.ts +275 -275
  60. package/src/maker/index.ts +117 -117
  61. package/src/markets/aave/index.ts +152 -152
  62. package/src/markets/aave/marketAssets.ts +46 -46
  63. package/src/markets/compound/index.ts +213 -213
  64. package/src/markets/compound/marketsAssets.ts +82 -82
  65. package/src/markets/curveUsd/index.ts +69 -69
  66. package/src/markets/euler/index.ts +26 -26
  67. package/src/markets/fluid/index.ts +2456 -2454
  68. package/src/markets/index.ts +27 -27
  69. package/src/markets/liquityV2/index.ts +54 -54
  70. package/src/markets/llamaLend/contractAddresses.ts +141 -141
  71. package/src/markets/llamaLend/index.ts +235 -235
  72. package/src/markets/morphoBlue/index.ts +895 -895
  73. package/src/markets/spark/index.ts +29 -29
  74. package/src/markets/spark/marketAssets.ts +10 -10
  75. package/src/moneymarket/moneymarketCommonService.ts +80 -80
  76. package/src/morphoAaveV2/index.ts +256 -256
  77. package/src/morphoAaveV3/index.ts +630 -630
  78. package/src/morphoBlue/index.ts +202 -202
  79. package/src/multicall/index.ts +33 -33
  80. package/src/services/priceService.ts +143 -130
  81. package/src/services/utils.ts +59 -59
  82. package/src/setup.ts +8 -8
  83. package/src/spark/index.ts +460 -460
  84. package/src/staking/staking.ts +217 -217
  85. package/src/types/aave.ts +275 -275
  86. package/src/types/chickenBonds.ts +45 -45
  87. package/src/types/common.ts +84 -84
  88. package/src/types/compound.ts +133 -133
  89. package/src/types/contracts/generated/BTCPriceFeed.ts +202 -0
  90. package/src/types/contracts/generated/index.ts +1 -0
  91. package/src/types/curveUsd.ts +119 -119
  92. package/src/types/euler.ts +173 -173
  93. package/src/types/fluid.ts +330 -330
  94. package/src/types/index.ts +11 -11
  95. package/src/types/liquity.ts +30 -30
  96. package/src/types/liquityV2.ts +119 -119
  97. package/src/types/llamaLend.ts +155 -155
  98. package/src/types/maker.ts +50 -50
  99. package/src/types/morphoBlue.ts +194 -194
  100. package/src/types/spark.ts +135 -135
@@ -1,1290 +1,1321 @@
1
- import Web3 from 'web3';
2
- import Dec from 'decimal.js';
3
- import {
4
- assetAmountInEth,
5
- AssetData, getAssetInfo, getAssetInfoByAddress,
6
- } from '@defisaver/tokens';
7
- import { EthAddress, NetworkNumber } from '../types/common';
8
- import {
9
- FluidAggregatedVaultData,
10
- FluidAssetData, FluidAssetsData,
11
- FluidMarketData,
12
- FluidMarketInfo,
13
- FluidUsedAsset,
14
- FluidUsedAssets,
15
- FluidVaultData,
16
- FluidVaultType, InnerFluidMarketData,
17
- } from '../types';
18
- import { DFSFeedRegistryContract, FeedRegistryContract, FluidViewContract } from '../contracts';
19
- import { getEthAmountForDecimals, isMainnetNetwork } from '../services/utils';
20
- import {
21
- getFluidAggregatedData,
22
- mergeAssetData,
23
- mergeUsedAssets,
24
- parseDexBorrowData,
25
- parseDexSupplyData,
26
- } from '../helpers/fluidHelpers';
27
- import { FluidView } from '../types/contracts/generated';
28
- import { chunkAndMulticall } from '../multicall';
29
- import { getFluidMarketInfoById, getFluidVersionsDataForNetwork, getFTokenAddress } from '../markets';
30
- import { USD_QUOTE } from '../constants';
31
- import {
32
- getChainlinkAssetAddress,
33
- getWeETHChainLinkPriceCalls,
34
- getWstETHChainLinkPriceCalls,
35
- getWstETHPriceFluid,
36
- parseWeETHPriceCalls,
37
- parseWstETHPriceCalls,
38
- } from '../services/priceService';
39
- import { getStakingApy, STAKING_ASSETS } from '../staking';
40
-
41
- export const EMPTY_USED_ASSET = {
42
- isSupplied: false,
43
- isBorrowed: false,
44
- supplied: '0',
45
- suppliedUsd: '0',
46
- borrowed: '0',
47
- borrowedUsd: '0',
48
- symbol: '',
49
- collateral: false,
50
- };
51
-
52
- const parseVaultType = (vaultType: number) => {
53
- switch (vaultType) {
54
- case 10000: return FluidVaultType.T1;
55
- case 20000: return FluidVaultType.T2;
56
- case 30000: return FluidVaultType.T3;
57
- case 40000: return FluidVaultType.T4;
58
- default: return FluidVaultType.Unknown;
59
- }
60
- };
61
-
62
- const getChainLinkPricesForTokens = async (
63
- tokens: string[],
64
- network: NetworkNumber,
65
- web3: Web3,
66
- ): Promise<{ [key: string]: string }> => {
67
- const isMainnet = isMainnetNetwork(network);
68
-
69
- const noDuplicateTokens = new Array(...new Set(tokens));
70
-
71
- const calls = noDuplicateTokens.flatMap((address) => {
72
- const assetInfo = getAssetInfoByAddress(address, network);
73
- const isTokenUSDA = assetInfo.symbol === 'USDA';
74
- if (isTokenUSDA) return;
75
- const chainLinkFeedAddress = getChainlinkAssetAddress(assetInfo.symbol, network);
76
-
77
- if (assetInfo.symbol === 'wstETH') return getWstETHChainLinkPriceCalls(web3, network);
78
- if (assetInfo.symbol === 'weETH') return getWeETHChainLinkPriceCalls(web3, network);
79
-
80
- if (isMainnet) {
81
- const feedRegistryContract = FeedRegistryContract(web3, NetworkNumber.Eth);
82
- return ({
83
- target: feedRegistryContract.options.address,
84
- abiItem: feedRegistryContract.options.jsonInterface.find(({ name }) => name === 'latestAnswer'),
85
- params: [chainLinkFeedAddress, USD_QUOTE],
86
- });
87
- }
88
-
89
- const feedRegistryContract = DFSFeedRegistryContract(web3, network);
90
- return ({
91
- target: feedRegistryContract.options.address,
92
- abiItem: feedRegistryContract.options.jsonInterface.find(({ name }) => name === 'latestRoundData'),
93
- params: [chainLinkFeedAddress, USD_QUOTE],
94
- });
95
- });
96
-
97
- const prices = await chunkAndMulticall(calls, 10, 'latest', web3, network);
98
- let offset = 0; // wstETH has 3 calls, while others have only 1, so we need to keep track
99
-
100
- return noDuplicateTokens.reduce((acc, token, i) => {
101
- const assetInfo = getAssetInfoByAddress(token, network);
102
- switch (assetInfo.symbol) {
103
- case 'USDA':
104
- acc[token] = '100000000';
105
- break;
106
-
107
- case 'wstETH': {
108
- const {
109
- ethPrice,
110
- wstETHRate,
111
- } = parseWstETHPriceCalls(prices[i + offset][0], prices[i + offset + 1], prices[i + offset + 2][0]);
112
- offset += 2;
113
- acc[token] = new Dec(ethPrice).mul(wstETHRate).toString();
114
- break;
115
- }
116
-
117
- case 'weETH': {
118
- const {
119
- ethPrice,
120
- weETHRate,
121
- } = parseWeETHPriceCalls(prices[i + offset][0], prices[i + offset + 1], prices[i + offset + 2][0]);
122
- offset += 2;
123
- acc[token] = new Dec(ethPrice).mul(weETHRate).toString();
124
- break;
125
- }
126
-
127
- default:
128
- acc[token] = new Dec(prices[i + offset].answer).div(1e8).toString();
129
- break;
130
- }
131
- return acc;
132
- }, {} as { [key: string]: string });
133
- };
134
-
135
-
136
- const getTokenPriceFromChainlink = async (asset: AssetData, network: NetworkNumber, web3: Web3) => {
137
- const isTokenUSDA = asset.symbol === 'USDA';
138
- const isMainnet = isMainnetNetwork(network);
139
- const loanTokenFeedAddress = getChainlinkAssetAddress(asset.symbol, network);
140
-
141
- let loanTokenPrice;
142
- if (asset.symbol === 'wstETH') {
143
- // need to handle wstETH for l2s inside getWstETHPrice
144
- loanTokenPrice = await getWstETHPriceFluid(web3, network);
145
- } else if (isMainnet) {
146
- const feedRegistryContract = FeedRegistryContract(web3, NetworkNumber.Eth);
147
- loanTokenPrice = isTokenUSDA ? '100000000' : await feedRegistryContract.methods.latestAnswer(loanTokenFeedAddress, USD_QUOTE).call();
148
- } else {
149
- // Currently only base network is supported
150
- const feedRegistryContract = DFSFeedRegistryContract(web3, network);
151
- const roundPriceData = isTokenUSDA ? { answer: '100000000' } : await feedRegistryContract.methods.latestRoundData(loanTokenFeedAddress, USD_QUOTE).call();
152
- loanTokenPrice = roundPriceData.answer;
153
- }
154
-
155
- return new Dec(loanTokenPrice).div(1e8).toString();
156
- };
157
-
158
- const getMarketRateForDex = (token1PerShare: string, token0PerShare: string, rate0: string, rate1: string, price0: string, price1: string) => {
159
- const token0PerShareUsd = new Dec(token0PerShare).mul(price0).toString();
160
- const token1PerShareUsd = new Dec(token1PerShare).mul(price1).toString();
161
- const sharesCombinedUsd = new Dec(token0PerShareUsd).plus(token1PerShareUsd);
162
-
163
- const rate0PerShare = new Dec(rate0).mul(token0PerShareUsd).div(sharesCombinedUsd).toString();
164
-
165
- const rate1PerShare = new Dec(rate1).mul(token1PerShareUsd).div(sharesCombinedUsd).toString();
166
-
167
- return new Dec(rate0PerShare).plus(rate1PerShare).toString();
168
- };
169
-
170
- const getAdditionalMarketRateForDex = (token1PerShare: string, token0PerShare: string, incentiveSupplyRate0: string, incentiveSupplyRate1: string, price0: string, price1: string) => {
171
- const token0PerShareUsd = new Dec(token0PerShare).mul(price0).toString();
172
- const token1PerShareUsd = new Dec(token1PerShare).mul(price1).toString();
173
- const sharesCombinedUsd = new Dec(token0PerShareUsd).plus(token1PerShareUsd);
174
-
175
- const rate0PerShare = incentiveSupplyRate0 ? new Dec(incentiveSupplyRate0).mul(token0PerShareUsd).div(sharesCombinedUsd).toString() : 0;
176
-
177
- const rate1PerShare = incentiveSupplyRate1 ? new Dec(incentiveSupplyRate1).mul(token1PerShareUsd).div(sharesCombinedUsd).toString() : 0;
178
-
179
- return new Dec(rate0PerShare).plus(rate1PerShare).toString();
180
- };
181
-
182
- const getTradingApy = async (poolAddress: EthAddress) => {
183
- const res = await fetch(`https://api.fluid.instadapp.io/v2/1/dexes/${poolAddress}/apy`);
184
- if (!res.ok) {
185
- return '0';
186
- }
187
- const data = await res.json();
188
- return new Dec(data.tradingApy).div(100).toString();
189
- };
190
-
191
- const parseT1MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
192
- const collAsset = getAssetInfoByAddress(data.supplyToken0, network);
193
- const debtAsset = getAssetInfoByAddress(data.borrowToken0, network);
194
-
195
- const supplyRate = new Dec(data.supplyRateVault).div(100).toString();
196
- const borrowRate = new Dec(data.borrowRateVault).div(100).toString();
197
-
198
- const oracleScaleFactor = new Dec(27).add(debtAsset.decimals).sub(collAsset.decimals).toString();
199
- const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
200
- const oraclePrice = new Dec(data.oraclePriceOperate).div(oracleScale).toString();
201
- const debtPriceParsed = await getTokenPriceFromChainlink(debtAsset, network, web3);
202
-
203
- const collAssetData: FluidAssetData = {
204
- symbol: collAsset.symbol,
205
- address: collAsset.address,
206
- price: new Dec(debtPriceParsed).mul(oraclePrice).toString(),
207
- totalSupply: data.totalSupplyVault,
208
- totalBorrow: data.totalBorrowVault,
209
- canBeSupplied: true,
210
- canBeBorrowed: false,
211
- supplyRate,
212
- borrowRate: '0',
213
- };
214
-
215
- if (STAKING_ASSETS.includes(collAsset.symbol)) {
216
- collAssetData.incentiveSupplyApy = await getStakingApy(collAsset.symbol, mainnetWeb3);
217
- collAssetData.incentiveSupplyToken = collAsset.symbol;
218
- }
219
-
220
- const incentiveSupplyRate = collAssetData.incentiveSupplyApy;
221
-
222
- const debtAssetData: FluidAssetData = {
223
- symbol: debtAsset.symbol,
224
- address: debtAsset.address,
225
- price: debtPriceParsed,
226
- totalSupply: data.totalSupplyVault,
227
- totalBorrow: data.totalBorrowVault,
228
- canBeSupplied: false,
229
- canBeBorrowed: true,
230
- supplyRate: '0',
231
- borrowRate,
232
- };
233
- if (STAKING_ASSETS.includes(debtAssetData.symbol)) {
234
- debtAssetData.incentiveBorrowApy = await getStakingApy(debtAsset.symbol, mainnetWeb3);
235
- debtAssetData.incentiveBorrowToken = debtAsset.symbol;
236
- }
237
-
238
- const incentiveBorrowRate = debtAssetData.incentiveBorrowApy;
239
-
240
- const assetsData = {
241
- [collAsset.symbol]: collAssetData,
242
- [debtAsset.symbol]: debtAssetData,
243
- };
244
- const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
245
- const totalSupplyVault = getEthAmountForDecimals(data.totalSupplyVault, collAsset.decimals);
246
- const totalBorrowVault = getEthAmountForDecimals(data.totalBorrowVault, debtAsset.decimals);
247
-
248
- const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
249
- const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
250
- const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
251
-
252
- const marketData = {
253
- vaultId: +data.vaultId,
254
- vaultValue: marketInfo?.value,
255
- isSmartColl: data.isSmartColl,
256
- isSmartDebt: data.isSmartDebt,
257
- marketAddress: data.vault,
258
- vaultType: parseVaultType(+data.vaultType),
259
- oracle: data.oracle,
260
- liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
261
- collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
262
- liquidationRatio: liqRatio,
263
- liqFactor,
264
- minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
265
- collAsset0: collAsset.symbol,
266
- debtAsset0: debtAsset.symbol,
267
- totalPositions: data.totalPositions,
268
- totalSupplyVault,
269
- totalBorrowVault,
270
- totalSupplyVaultUsd: new Dec(totalSupplyVault).mul(collAssetData.price).toString(),
271
- totalBorrowVaultUsd: new Dec(totalBorrowVault).mul(debtAssetData.price).toString(),
272
- withdrawalLimit: getEthAmountForDecimals(data.withdrawalLimit, collAsset.decimals),
273
- withdrawableUntilLimit: getEthAmountForDecimals(data.withdrawableUntilLimit, collAsset.decimals),
274
- withdrawable: getEthAmountForDecimals(data.withdrawable, collAsset.decimals),
275
- borrowLimit: getEthAmountForDecimals(data.borrowLimit, debtAsset.decimals),
276
- borrowableUntilLimit: getEthAmountForDecimals(data.borrowableUntilLimit, debtAsset.decimals),
277
- borrowable: getEthAmountForDecimals(data.borrowable, debtAsset.decimals),
278
- borrowLimitUtilization: getEthAmountForDecimals(data.borrowLimitUtilization, debtAsset.decimals),
279
- maxBorrowLimit: getEthAmountForDecimals(data.maxBorrowLimit, debtAsset.decimals),
280
- baseBorrowLimit: getEthAmountForDecimals(data.baseBorrowLimit, debtAsset.decimals),
281
- minimumBorrowing: getEthAmountForDecimals(data.minimumBorrowing, debtAsset.decimals),
282
- liquidationMaxLimit,
283
- borrowRate,
284
- supplyRate,
285
- incentiveSupplyRate,
286
- incentiveBorrowRate,
287
- oraclePrice,
288
- };
289
-
290
- return {
291
- assetsData,
292
- marketData,
293
- } as FluidMarketData;
294
- };
295
-
296
- const parseT2MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
297
- const collAsset0 = getAssetInfoByAddress(data.supplyToken0, network);
298
- const collAsset1 = getAssetInfoByAddress(data.supplyToken1, network);
299
- const debtAsset = getAssetInfoByAddress(data.borrowToken0, network);
300
-
301
- // 18 because collateral is represented in shares for which they use 18 decimals
302
- const oracleScaleFactor = new Dec(27).add(debtAsset.decimals).sub(18).toString();
303
- const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
304
- const oraclePrice = new Dec(data.oraclePriceOperate).div(oracleScale).toString();
305
-
306
- const prices = await getChainLinkPricesForTokens([collAsset0.address, collAsset1.address, debtAsset.address], network, web3);
307
-
308
- const {
309
- supplyDexFee,
310
- totalSupplyShares,
311
- supplyRate1,
312
- totalSupplyToken1,
313
- token0PerSupplyShare,
314
- token1PerSupplyShare,
315
- totalSupplyToken0,
316
- maxSupplyShares,
317
- withdrawableToken0,
318
- withdrawable0,
319
- withdrawableToken1,
320
- withdrawable1,
321
- supplyRate0,
322
- utilizationSupply0,
323
- utilizationSupply1,
324
- withdrawableShares,
325
- reservesSupplyToken0,
326
- reservesSupplyToken1,
327
- } = parseDexSupplyData(data.dexSupplyData, collAsset0.symbol, collAsset1.symbol);
328
-
329
- const collFirstAssetData: Partial<FluidAssetData> = {
330
- symbol: collAsset0.symbol,
331
- address: collAsset0.address,
332
- price: prices[collAsset0.address],
333
- totalSupply: new Dec(totalSupplyShares).mul(token0PerSupplyShare).toString(),
334
- canBeSupplied: true,
335
- supplyRate: supplyRate0,
336
- utilization: utilizationSupply0,
337
- withdrawable: withdrawable0,
338
- tokenPerSupplyShare: token0PerSupplyShare,
339
- supplyReserves: reservesSupplyToken0,
340
- };
341
- if (STAKING_ASSETS.includes(collFirstAssetData.symbol!)) {
342
- collFirstAssetData.incentiveSupplyApy = await getStakingApy(collAsset0.symbol, mainnetWeb3);
343
- collFirstAssetData.incentiveSupplyToken = collAsset0.symbol;
344
- }
345
-
346
- const collSecondAssetData: Partial<FluidAssetData> = {
347
- symbol: collAsset1.symbol,
348
- address: collAsset1.address,
349
- price: prices[collAsset1.address],
350
- totalSupply: new Dec(totalSupplyShares).mul(token1PerSupplyShare).toString(),
351
- canBeSupplied: true,
352
- supplyRate: supplyRate1,
353
- withdrawable: withdrawable1,
354
- utilization: utilizationSupply1,
355
- tokenPerSupplyShare: token1PerSupplyShare,
356
- supplyReserves: reservesSupplyToken1,
357
- };
358
- if (STAKING_ASSETS.includes(collSecondAssetData.symbol!)) {
359
- collSecondAssetData.incentiveSupplyApy = await getStakingApy(collAsset1.symbol, mainnetWeb3);
360
- collSecondAssetData.incentiveSupplyToken = collAsset1.symbol;
361
- }
362
-
363
- const marketSupplyRate = getMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, supplyRate0, supplyRate1, collFirstAssetData.price!, collSecondAssetData.price!);
364
- const incentiveSupplyRate = getAdditionalMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, collFirstAssetData.incentiveSupplyApy!, collSecondAssetData.incentiveSupplyApy!, collFirstAssetData.price!, collSecondAssetData.price!);
365
- const tradingSupplyRate = await getTradingApy(data.dexSupplyData.dexPool);
366
-
367
- const borrowRate = new Dec(data.borrowRateVault).div(100).toString();
368
- const debtAssetData: Partial<FluidAssetData> = {
369
- symbol: debtAsset.symbol,
370
- price: prices[debtAsset.address],
371
- address: debtAsset.address,
372
- totalBorrow: data.totalBorrowVault,
373
- canBeBorrowed: true,
374
- borrowRate,
375
- };
376
- if (STAKING_ASSETS.includes(debtAssetData.symbol!)) {
377
- debtAssetData.incentiveBorrowApy = await getStakingApy(debtAsset.symbol, mainnetWeb3);
378
- debtAssetData.incentiveBorrowToken = debtAsset.symbol;
379
- }
380
-
381
- const incentiveBorrowRate = debtAssetData.incentiveBorrowApy;
382
-
383
- const assetsData: FluidAssetsData = ([
384
- [collAsset0.symbol, collFirstAssetData],
385
- [collAsset1.symbol, collSecondAssetData],
386
- [debtAsset.symbol, debtAssetData],
387
- ] as [string, FluidAssetData][])
388
- .reduce((acc, [symbol, partialData]) => ({
389
- ...acc,
390
- [symbol]: mergeAssetData(acc[symbol], partialData),
391
- }), {} as Record<string, FluidAssetData>) as FluidAssetsData;
392
-
393
- const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
394
-
395
- const totalBorrowVault = getEthAmountForDecimals(data.totalBorrowVault, debtAsset.decimals);
396
-
397
- const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
398
- const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
399
- const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
400
-
401
- const totalSupplySharesInVault = assetAmountInEth(data.totalSupplyVault);
402
- const collSharePrice = new Dec(oraclePrice).mul(prices[debtAsset.address]).toString();
403
- const totalSupplyVaultUsd = new Dec(totalSupplySharesInVault).mul(collSharePrice).toString();
404
- const maxSupplySharesUsd = new Dec(maxSupplyShares).mul(collSharePrice).toString();
405
-
406
- const withdrawableUSD = new Dec(withdrawableShares).mul(collSharePrice).toString();
407
-
408
- const marketData = {
409
- vaultId: +data.vaultId,
410
- vaultValue: marketInfo?.value,
411
- isSmartColl: data.isSmartColl,
412
- isSmartDebt: data.isSmartDebt,
413
- marketAddress: data.vault,
414
- vaultType: parseVaultType(+data.vaultType),
415
- oracle: data.oracle,
416
- liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
417
- collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
418
- liquidationRatio: liqRatio,
419
- liqFactor,
420
- minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
421
- collAsset0: collAsset0.symbol,
422
- collAsset1: collAsset1.symbol,
423
- debtAsset0: debtAsset.symbol,
424
- totalPositions: data.totalPositions,
425
- totalSupplyVault: totalSupplyShares,
426
- totalBorrowVault,
427
- totalSupplyVaultUsd,
428
- collSharePrice,
429
- totalBorrowVaultUsd: new Dec(totalBorrowVault).mul(assetsData[debtAsset.symbol].price).toString(),
430
- borrowLimit: getEthAmountForDecimals(data.borrowLimit, debtAsset.decimals),
431
- borrowableUntilLimit: getEthAmountForDecimals(data.borrowableUntilLimit, debtAsset.decimals),
432
- borrowable: getEthAmountForDecimals(data.borrowable, debtAsset.decimals),
433
- borrowLimitUtilization: getEthAmountForDecimals(data.borrowLimitUtilization, debtAsset.decimals),
434
- maxBorrowLimit: getEthAmountForDecimals(data.maxBorrowLimit, debtAsset.decimals),
435
- baseBorrowLimit: getEthAmountForDecimals(data.baseBorrowLimit, debtAsset.decimals),
436
- minimumBorrowing: getEthAmountForDecimals(data.minimumBorrowing, debtAsset.decimals),
437
- liquidationMaxLimit,
438
- borrowRate,
439
- supplyRate: marketSupplyRate,
440
- incentiveSupplyRate,
441
- incentiveBorrowRate,
442
- totalSupplyToken0,
443
- totalSupplyToken1,
444
- withdrawableToken0,
445
- withdrawableToken1,
446
- withdrawableUSD,
447
- withdrawable: withdrawableShares,
448
- withdrawableDex: new Dec(maxSupplyShares).minus(totalSupplyShares).toString(),
449
- maxSupplyShares,
450
- maxSupplySharesUsd,
451
- collDexFee: supplyDexFee,
452
- oraclePrice,
453
- tradingSupplyRate,
454
- tradingBorrowRate: '0',
455
- };
456
-
457
- return {
458
- assetsData,
459
- marketData,
460
- } as FluidMarketData;
461
- };
462
-
463
- const parseT3MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
464
- const collAsset = getAssetInfoByAddress(data.supplyToken0, network);
465
- const debtAsset0 = getAssetInfoByAddress(data.borrowToken0, network);
466
- const debtAsset1 = getAssetInfoByAddress(data.borrowToken1, network);
467
-
468
- const {
469
- borrowableShares,
470
- maxBorrowShares,
471
- borrowDexFee,
472
- utilizationBorrow0,
473
- utilizationBorrow1,
474
- borrowable0,
475
- borrowable1,
476
- borrowRate0,
477
- borrowRate1,
478
- totalBorrowShares,
479
- token0PerBorrowShare,
480
- token1PerBorrowShare,
481
- borrowableToken0,
482
- borrowableToken1,
483
- totalBorrowToken0,
484
- totalBorrowToken1,
485
- reservesBorrowToken0,
486
- reservesBorrowToken1,
487
- } = parseDexBorrowData(data.dexBorrowData, debtAsset0.symbol, debtAsset1.symbol);
488
-
489
- // 18 because debt is represented in shares for which they use 18 decimals
490
- const oracleScaleFactor = new Dec(27).add(18).sub(collAsset.decimals).toString();
491
- const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
492
- const oraclePrice = new Dec(1).div(new Dec(data.oraclePriceOperate).div(oracleScale)).toString();
493
-
494
- const prices = await getChainLinkPricesForTokens([collAsset.address, debtAsset0.address, debtAsset1.address], network, web3);
495
-
496
- const supplyRate = new Dec(data.supplyRateVault).div(100).toString();
497
- const collAssetData: Partial<FluidAssetData> = {
498
- symbol: collAsset.symbol,
499
- address: collAsset.address,
500
- price: prices[collAsset.address],
501
- totalSupply: data.totalSupplyVault,
502
- canBeSupplied: true,
503
- supplyRate,
504
- };
505
- if (STAKING_ASSETS.includes(collAssetData.symbol!)) {
506
- collAssetData.incentiveSupplyApy = await getStakingApy(collAsset.symbol, mainnetWeb3);
507
- collAssetData.incentiveSupplyToken = collAsset.symbol;
508
- }
509
-
510
- const incentiveSupplyRate = collAssetData.incentiveSupplyApy;
511
-
512
- const debtAsset0Data: Partial<FluidAssetData> = {
513
- symbol: debtAsset0.symbol,
514
- address: debtAsset0.address,
515
- price: prices[debtAsset0.address],
516
- totalBorrow: new Dec(totalBorrowShares).mul(token0PerBorrowShare).toString(),
517
- canBeBorrowed: true,
518
- borrowRate: borrowRate0,
519
- borrowable: borrowable0,
520
- utilization: utilizationBorrow0,
521
- tokenPerBorrowShare: token0PerBorrowShare,
522
- borrowReserves: reservesBorrowToken0,
523
- };
524
- if (STAKING_ASSETS.includes(debtAsset0Data.symbol!)) {
525
- debtAsset0Data.incentiveSupplyApy = await getStakingApy(debtAsset0.symbol, mainnetWeb3);
526
- debtAsset0Data.incentiveSupplyToken = debtAsset0.symbol;
527
- }
528
-
529
- const debtAsset1Data: Partial<FluidAssetData> = {
530
- symbol: debtAsset1.symbol,
531
- address: debtAsset1.address,
532
- price: prices[debtAsset1.address],
533
- totalBorrow: new Dec(totalBorrowShares).mul(token1PerBorrowShare).toString(),
534
- canBeBorrowed: true,
535
- borrowRate: borrowRate1,
536
- borrowable: borrowable1,
537
- utilization: utilizationBorrow1,
538
- tokenPerBorrowShare: token1PerBorrowShare,
539
- borrowReserves: reservesBorrowToken1,
540
- };
541
- if (STAKING_ASSETS.includes(debtAsset1Data.symbol!)) {
542
- debtAsset1Data.incentiveSupplyApy = await getStakingApy(debtAsset1.symbol, mainnetWeb3);
543
- debtAsset1Data.incentiveSupplyToken = debtAsset1.symbol;
544
- }
545
- const marketBorrowRate = getMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, borrowRate0, borrowRate1, debtAsset0Data.price!, debtAsset1Data.price!);
546
- const incentiveBorrowRate = getAdditionalMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, debtAsset0Data.incentiveSupplyApy!, debtAsset1Data.incentiveSupplyApy!, debtAsset0Data.price!, debtAsset1Data.price!);
547
- const tradingBorrowRate = await getTradingApy(data.dexBorrowData.dexPool);
548
-
549
- const assetsData: FluidAssetsData = ([
550
- [collAsset.symbol, collAssetData],
551
- [debtAsset0.symbol, debtAsset0Data],
552
- [debtAsset1.symbol, debtAsset1Data],
553
- ] as [string, FluidAssetData][])
554
- .reduce((acc, [symbol, partialData]) => ({
555
- ...acc,
556
- [symbol]: mergeAssetData(acc[symbol], partialData),
557
- }), {} as Record<string, FluidAssetData>) as FluidAssetsData;
558
-
559
- const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
560
-
561
- const totalSupplyVault = getEthAmountForDecimals(data.totalSupplyVault, collAsset.decimals);
562
-
563
- const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
564
- const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
565
- const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
566
-
567
- const debtSharePrice = new Dec(oraclePrice).mul(prices[collAsset.address]).toString();
568
-
569
- const totalBorrowSharesInVault = assetAmountInEth(data.totalBorrowVault);
570
-
571
- const totalBorrowVaultUsd = new Dec(totalBorrowSharesInVault).mul(debtSharePrice).toString();
572
-
573
- const borrowableUSD = new Dec(borrowableShares).mul(debtSharePrice).toString();
574
- const maxBorrowSharesUsd = new Dec(maxBorrowShares).mul(debtSharePrice).toString();
575
-
576
- const marketData = {
577
- vaultId: +data.vaultId,
578
- vaultValue: marketInfo?.value,
579
- isSmartColl: data.isSmartColl,
580
- isSmartDebt: data.isSmartDebt,
581
- marketAddress: data.vault,
582
- vaultType: parseVaultType(+data.vaultType),
583
- oracle: data.oracle,
584
- liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
585
- collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
586
- liquidationRatio: liqRatio,
587
- liqFactor,
588
- minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
589
- collAsset0: collAsset.symbol,
590
- debtAsset0: debtAsset0.symbol,
591
- debtAsset1: debtAsset1.symbol,
592
- totalPositions: data.totalPositions,
593
- totalSupplyVault,
594
- totalBorrowVault: totalBorrowShares,
595
- totalSupplyVaultUsd: new Dec(totalSupplyVault).mul(assetsData[collAsset.symbol].price).toString(),
596
- totalBorrowVaultUsd,
597
- withdrawalLimit: getEthAmountForDecimals(data.withdrawalLimit, collAsset.decimals),
598
- withdrawableUntilLimit: getEthAmountForDecimals(data.withdrawableUntilLimit, collAsset.decimals),
599
- withdrawable: getEthAmountForDecimals(data.withdrawable, collAsset.decimals),
600
- liquidationMaxLimit,
601
- borrowRate: marketBorrowRate,
602
- supplyRate,
603
- incentiveBorrowRate,
604
- incentiveSupplyRate,
605
- tradingBorrowRate,
606
- tradingSupplyRate: '0',
607
- borrowableToken0,
608
- borrowableToken1,
609
- totalBorrowToken0,
610
- totalBorrowToken1,
611
- borrowableUSD,
612
- borrowable: borrowableShares,
613
- borrowableDex: new Dec(maxBorrowShares).minus(totalBorrowShares).toString(),
614
- maxBorrowShares,
615
- maxBorrowSharesUsd,
616
- borrowDexFee,
617
- debtSharePrice,
618
- oraclePrice,
619
- };
620
-
621
- return {
622
- assetsData,
623
- marketData,
624
- } as FluidMarketData;
625
- };
626
-
627
- const parseT4MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
628
- const collAsset0 = getAssetInfoByAddress(data.supplyToken0, network);
629
- const collAsset1 = getAssetInfoByAddress(data.supplyToken1, network);
630
- const debtAsset0 = getAssetInfoByAddress(data.borrowToken0, network);
631
- const debtAsset1 = getAssetInfoByAddress(data.borrowToken1, network);
632
- const quoteToken = getAssetInfoByAddress(data.dexBorrowData.quoteToken, network);
633
-
634
- // 27 - 18 + 18
635
- const oracleScaleFactor = new Dec(27).toString();
636
- const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
637
- const oraclePrice = new Dec(data.oraclePriceOperate).div(oracleScale).toString();
638
-
639
- const prices = await getChainLinkPricesForTokens(
640
- [collAsset0.address, collAsset1.address, debtAsset0.address, debtAsset1.address],
641
- network, web3);
642
-
643
- const {
644
- supplyDexFee,
645
- totalSupplyShares,
646
- supplyRate1,
647
- token0PerSupplyShare,
648
- token1PerSupplyShare,
649
- totalSupplyToken0,
650
- totalSupplyToken1,
651
- maxSupplyShares,
652
- withdrawableToken0,
653
- withdrawable0,
654
- withdrawableToken1,
655
- withdrawable1,
656
- supplyRate0,
657
- utilizationSupply0,
658
- utilizationSupply1,
659
- withdrawableShares,
660
- reservesSupplyToken0,
661
- reservesSupplyToken1,
662
- } = parseDexSupplyData(data.dexSupplyData, collAsset0.symbol, collAsset1.symbol);
663
-
664
- const {
665
- borrowableShares,
666
- maxBorrowShares,
667
- borrowDexFee,
668
- utilizationBorrow0,
669
- utilizationBorrow1,
670
- borrowable0,
671
- borrowable1,
672
- borrowRate0,
673
- borrowRate1,
674
- totalBorrowShares,
675
- token0PerBorrowShare,
676
- token1PerBorrowShare,
677
- borrowableToken0,
678
- borrowableToken1,
679
- totalBorrowToken0,
680
- totalBorrowToken1,
681
- quoteTokensPerShare,
682
- reservesBorrowToken0,
683
- reservesBorrowToken1,
684
- } = parseDexBorrowData(data.dexBorrowData, debtAsset0.symbol, debtAsset1.symbol);
685
-
686
- const collAsset0Data: Partial<FluidAssetData> = {
687
- symbol: collAsset0.symbol,
688
- address: collAsset0.address,
689
- price: prices[collAsset0.address],
690
- totalSupply: new Dec(totalSupplyShares).mul(token0PerSupplyShare).toString(),
691
- canBeSupplied: true,
692
- supplyRate: supplyRate0,
693
- utilization: utilizationSupply0,
694
- withdrawable: withdrawable0,
695
- tokenPerSupplyShare: token0PerSupplyShare,
696
- supplyReserves: reservesSupplyToken0,
697
- };
698
- if (STAKING_ASSETS.includes(collAsset0Data.symbol!)) {
699
- collAsset0Data.incentiveSupplyApy = await getStakingApy(collAsset0.symbol, mainnetWeb3);
700
- collAsset0Data.incentiveSupplyToken = collAsset0.symbol;
701
- }
702
-
703
- const collAsset1Data: Partial<FluidAssetData> = {
704
- symbol: collAsset1.symbol,
705
- address: collAsset1.address,
706
- price: prices[collAsset1.address],
707
- totalSupply: new Dec(totalSupplyShares).mul(token1PerSupplyShare).toString(),
708
- canBeSupplied: true,
709
- supplyRate: supplyRate1,
710
- withdrawable: withdrawable1,
711
- utilization: utilizationSupply1,
712
- tokenPerSupplyShare: token1PerSupplyShare,
713
- supplyReserves: reservesSupplyToken1,
714
- };
715
- if (STAKING_ASSETS.includes(collAsset1Data.symbol!)) {
716
- collAsset1Data.incentiveSupplyApy = await getStakingApy(collAsset1.symbol, mainnetWeb3);
717
- collAsset1Data.incentiveSupplyToken = collAsset1.symbol;
718
- }
719
-
720
- const debtAsset0Data: Partial<FluidAssetData> = {
721
- symbol: debtAsset0.symbol,
722
- address: debtAsset0.address,
723
- price: prices[debtAsset0.address],
724
- totalBorrow: new Dec(totalBorrowShares).mul(token0PerBorrowShare).toString(),
725
- canBeBorrowed: true,
726
- borrowRate: borrowRate0,
727
- borrowable: borrowable0,
728
- utilization: utilizationBorrow0,
729
- tokenPerBorrowShare: token0PerBorrowShare,
730
- borrowReserves: reservesBorrowToken0,
731
- };
732
- if (STAKING_ASSETS.includes(debtAsset0Data.symbol!)) {
733
- debtAsset0Data.incentiveSupplyApy = await getStakingApy(debtAsset0.symbol, mainnetWeb3);
734
- debtAsset0Data.incentiveSupplyToken = debtAsset0.symbol;
735
- }
736
-
737
- const debtAsset1Data: Partial<FluidAssetData> = {
738
- symbol: debtAsset1.symbol,
739
- address: debtAsset1.address,
740
- price: prices[debtAsset1.address],
741
- totalBorrow: new Dec(totalBorrowShares).mul(token1PerBorrowShare).toString(),
742
- canBeBorrowed: true,
743
- borrowRate: borrowRate1,
744
- borrowable: borrowable1,
745
- utilization: utilizationBorrow1,
746
- tokenPerBorrowShare: token1PerBorrowShare,
747
- borrowReserves: reservesBorrowToken1,
748
- };
749
- if (STAKING_ASSETS.includes(debtAsset1Data.symbol!)) {
750
- debtAsset1Data.incentiveSupplyApy = await getStakingApy(debtAsset1.symbol, mainnetWeb3);
751
- debtAsset1Data.incentiveSupplyToken = debtAsset1.symbol;
752
- }
753
- const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
754
-
755
- const marketBorrowRate = getMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, borrowRate0, borrowRate1, debtAsset0Data.price!, debtAsset1Data.price!);
756
- const incentiveBorrowRate = getAdditionalMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, debtAsset0Data.incentiveSupplyApy!, debtAsset1Data.incentiveSupplyApy!, debtAsset0Data.price!, debtAsset1Data.price!);
757
- const tradingBorrowRate = await getTradingApy(data.dexBorrowData.dexPool);
758
-
759
- const marketSupplyRate = getMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, supplyRate0, supplyRate1, collAsset0Data.price!, collAsset1Data.price!);
760
- const incentiveSupplyRate = getAdditionalMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, collAsset0Data.incentiveSupplyApy!, collAsset1Data.incentiveSupplyApy!, collAsset0Data.price!, collAsset1Data.price!);
761
- const tradingSupplyRate = await getTradingApy(data.dexSupplyData.dexPool);
762
-
763
- const assetsData: FluidAssetsData = ([
764
- [collAsset0.symbol, collAsset0Data],
765
- [collAsset1.symbol, collAsset1Data],
766
- [debtAsset0.symbol, debtAsset0Data],
767
- [debtAsset1.symbol, debtAsset1Data],
768
- ] as [string, FluidAssetData][])
769
- .reduce((acc, [symbol, partialData]) => ({
770
- ...acc,
771
- [symbol]: mergeAssetData(acc[symbol], partialData),
772
- }), {} as Record<string, FluidAssetData>) as FluidAssetsData;
773
-
774
-
775
- const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
776
- const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
777
- const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
778
-
779
- const totalBorrowSharesInVault = assetAmountInEth(data.totalBorrowVault);
780
- const debtSharePrice = new Dec(quoteTokensPerShare).mul(prices[quoteToken.address]).toString();
781
- const totalBorrowVaultUsd = new Dec(totalBorrowSharesInVault).mul(debtSharePrice).toString();
782
- const maxBorrowSharesUsd = new Dec(maxBorrowShares).mul(debtSharePrice).toString();
783
- const borrowableUSD = new Dec(borrowableShares).mul(debtSharePrice).toString();
784
-
785
- const totalSupplySharesInVault = assetAmountInEth(data.totalSupplyVault);
786
- const collSharePrice = new Dec(oraclePrice).mul(debtSharePrice).toString();
787
- const totalSupplyVaultUsd = new Dec(totalSupplySharesInVault).mul(collSharePrice).toString();
788
- const maxSupplySharesUsd = new Dec(maxSupplyShares).mul(collSharePrice).toString();
789
- const withdrawableUSD = new Dec(withdrawableShares).mul(collSharePrice).toString();
790
-
791
- const marketData = {
792
- vaultId: +data.vaultId,
793
- vaultValue: marketInfo?.value,
794
- isSmartColl: data.isSmartColl,
795
- isSmartDebt: data.isSmartDebt,
796
- marketAddress: data.vault,
797
- vaultType: parseVaultType(+data.vaultType),
798
- oracle: data.oracle,
799
- liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
800
- collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
801
- liquidationRatio: liqRatio,
802
- liqFactor,
803
- minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
804
- collAsset0: collAsset0.symbol,
805
- collAsset1: collAsset1.symbol,
806
- debtAsset0: debtAsset0.symbol,
807
- debtAsset1: debtAsset1.symbol,
808
- totalPositions: data.totalPositions,
809
- totalSupplyVault: totalSupplyShares,
810
- totalBorrowVault: totalBorrowShares,
811
- totalSupplyVaultUsd,
812
- totalBorrowVaultUsd,
813
- liquidationMaxLimit,
814
- borrowRate: marketBorrowRate,
815
- incentiveBorrowRate,
816
- supplyRate: marketSupplyRate,
817
- incentiveSupplyRate,
818
- borrowableToken0,
819
- borrowableToken1,
820
- totalBorrowToken0,
821
- totalBorrowToken1,
822
- borrowableUSD,
823
- borrowable: borrowableShares,
824
- borrowableDex: new Dec(maxBorrowShares).minus(totalBorrowShares).toString(),
825
- maxBorrowShares,
826
- maxBorrowSharesUsd,
827
- borrowDexFee,
828
- totalSupplyToken0,
829
- totalSupplyToken1,
830
- withdrawableToken0,
831
- withdrawableToken1,
832
- withdrawableUSD,
833
- withdrawable: withdrawableShares,
834
- withdrawableDex: new Dec(maxSupplyShares).minus(totalSupplyShares).toString(),
835
- maxSupplyShares,
836
- maxSupplySharesUsd,
837
- collDexFee: supplyDexFee,
838
- collSharePrice,
839
- debtSharePrice,
840
- oraclePrice,
841
- tradingBorrowRate,
842
- tradingSupplyRate,
843
- };
844
-
845
- return {
846
- assetsData,
847
- marketData,
848
- } as FluidMarketData;
849
- };
850
-
851
- const parseMarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
852
- const vaultType = parseVaultType(+data.vaultType);
853
- switch (vaultType) {
854
- case FluidVaultType.T1:
855
- return parseT1MarketData(web3, data, network, mainnetWeb3);
856
- case FluidVaultType.T2:
857
- return parseT2MarketData(web3, data, network, mainnetWeb3);
858
- case FluidVaultType.T3:
859
- return parseT3MarketData(web3, data, network, mainnetWeb3);
860
- case FluidVaultType.T4:
861
- return parseT4MarketData(web3, data, network, mainnetWeb3);
862
- default:
863
- throw new Error(`Unknown vault type: ${vaultType}`);
864
- }
865
- };
866
-
867
- export const EMPTY_FLUID_DATA = {
868
- usedAssets: {},
869
- suppliedUsd: '0',
870
- borrowedUsd: '0',
871
- borrowLimitUsd: '0',
872
- leftToBorrowUsd: '0',
873
- ratio: '0',
874
- minRatio: '0',
875
- netApy: '0',
876
- incentiveUsd: '0',
877
- totalInterestUsd: '0',
878
- isSubscribedToAutomation: false,
879
- automationResubscribeRequired: false,
880
- lastUpdated: Date.now(),
881
- };
882
-
883
- const parseT1UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
884
- const {
885
- assetsData,
886
- marketData,
887
- } = vaultData;
888
-
889
- const payload = {
890
- owner: userPositionData.owner,
891
- vaultId: marketData.vaultId,
892
- ...EMPTY_FLUID_DATA,
893
- lastUpdated: Date.now(),
894
- };
895
- const collAsset = getAssetInfo(marketData.collAsset0);
896
- const debtAsset = getAssetInfo(marketData.debtAsset0);
897
-
898
- // for T2 and T4 - this is the number of shares
899
- const supplied = getEthAmountForDecimals(userPositionData.supply, collAsset.decimals);
900
- const borrowed = getEthAmountForDecimals(userPositionData.borrow, debtAsset.decimals);
901
-
902
- const collUsedAsset: FluidUsedAsset = {
903
- ...EMPTY_USED_ASSET,
904
- symbol: collAsset.symbol,
905
- collateral: true,
906
- supplied,
907
- suppliedUsd: new Dec(supplied).mul(assetsData[collAsset.symbol].price).toString(),
908
- isSupplied: new Dec(supplied).gt(0),
909
- };
910
-
911
- const debtUsedAsset: FluidUsedAsset = {
912
- ...EMPTY_USED_ASSET,
913
- symbol: debtAsset.symbol,
914
- collateral: false,
915
- borrowed,
916
- borrowedUsd: new Dec(borrowed).mul(assetsData[debtAsset.symbol].price).toString(),
917
- isBorrowed: new Dec(borrowed).gt(0),
918
- };
919
-
920
- const usedAssets: FluidUsedAssets = {
921
- [collAsset.symbol]: collUsedAsset,
922
- [debtAsset.symbol]: debtUsedAsset,
923
- };
924
-
925
- return {
926
- ...payload,
927
- usedAssets,
928
- ...(getFluidAggregatedData({
929
- usedAssets,
930
- assetsData,
931
- marketData,
932
- }) as FluidAggregatedVaultData),
933
- };
934
- };
935
-
936
- const parseT2UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
937
- const {
938
- assetsData,
939
- marketData,
940
- } = vaultData;
941
-
942
- const payload = {
943
- owner: userPositionData.owner,
944
- vaultId: marketData.vaultId,
945
- ...EMPTY_FLUID_DATA,
946
- lastUpdated: Date.now(),
947
- };
948
-
949
- const collAsset0 = getAssetInfo(marketData.collAsset0);
950
- const collAsset1 = getAssetInfo(marketData.collAsset1);
951
- const debtAsset = getAssetInfo(marketData.debtAsset0);
952
-
953
- const supplyShares = getEthAmountForDecimals(userPositionData.supply, 18); // this is supplied in coll shares
954
- const borrowed = getEthAmountForDecimals(userPositionData.borrow, debtAsset.decimals); // this is actual token borrow
955
-
956
- const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare!).toString();
957
- const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare!).toString();
958
-
959
- const collUsedAsset0: Partial<FluidUsedAsset> = {
960
- symbol: collAsset0.symbol,
961
- collateral: true,
962
- supplied: supplied0,
963
- suppliedUsd: new Dec(supplied0).mul(assetsData[collAsset0.symbol].price).toString(),
964
- isSupplied: new Dec(supplied0).gt(0),
965
- };
966
-
967
- const collUsedAsset1: Partial<FluidUsedAsset> = {
968
- symbol: collAsset1.symbol,
969
- collateral: true,
970
- supplied: supplied1,
971
- suppliedUsd: new Dec(supplied1).mul(assetsData[collAsset1.symbol].price).toString(),
972
- isSupplied: new Dec(supplied1).gt(0),
973
- };
974
-
975
- const debtUsedAsset: Partial<FluidUsedAsset> = {
976
- symbol: debtAsset.symbol,
977
- borrowed,
978
- borrowedUsd: new Dec(borrowed).mul(assetsData[debtAsset.symbol].price).toString(),
979
- isBorrowed: new Dec(borrowed).gt(0),
980
- };
981
-
982
- const usedAssets: FluidUsedAssets = ([
983
- [collAsset0.symbol, collUsedAsset0],
984
- [collAsset1.symbol, collUsedAsset1],
985
- [debtAsset.symbol, debtUsedAsset],
986
- ] as [string, FluidUsedAsset][])
987
- .reduce((acc, [symbol, partialData]) => {
988
- acc[symbol] = mergeUsedAssets(acc[symbol], partialData);
989
- return acc;
990
- }, {} as Record<string, FluidUsedAsset>) as FluidUsedAssets;
991
-
992
- return {
993
- ...payload,
994
- usedAssets,
995
- supplyShares,
996
- ...(getFluidAggregatedData({
997
- usedAssets,
998
- assetsData,
999
- marketData,
1000
- }, supplyShares) as FluidAggregatedVaultData),
1001
- };
1002
- };
1003
-
1004
- const parseT3UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
1005
- const {
1006
- assetsData,
1007
- marketData,
1008
- } = vaultData;
1009
-
1010
- const payload = {
1011
- owner: userPositionData.owner,
1012
- vaultId: marketData.vaultId,
1013
- ...EMPTY_FLUID_DATA,
1014
- lastUpdated: Date.now(),
1015
- };
1016
-
1017
- const collAsset = getAssetInfo(marketData.collAsset0);
1018
- const debtAsset0 = getAssetInfo(marketData.debtAsset0);
1019
- const debtAsset1 = getAssetInfo(marketData.debtAsset1);
1020
-
1021
- const supplied = getEthAmountForDecimals(userPositionData.supply, collAsset.decimals); // this is actual token supply
1022
- const borrowShares = getEthAmountForDecimals(userPositionData.borrow, 18); // this is actual token borrow
1023
-
1024
- const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare!).toString();
1025
- const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare!).toString();
1026
-
1027
- const collUsedAsset: Partial<FluidUsedAsset> = {
1028
- symbol: collAsset.symbol,
1029
- collateral: true,
1030
- supplied,
1031
- suppliedUsd: new Dec(supplied).mul(assetsData[collAsset.symbol].price).toString(),
1032
- isSupplied: new Dec(supplied).gt(0),
1033
- };
1034
-
1035
- const debtUsedAsset0: Partial<FluidUsedAsset> = {
1036
- symbol: debtAsset0.symbol,
1037
- borrowed: borrowed0,
1038
- borrowedUsd: new Dec(borrowed0).mul(assetsData[debtAsset0.symbol].price).toString(),
1039
- isBorrowed: new Dec(borrowed0).gt(0),
1040
- };
1041
-
1042
- const debtUsedAsset1: Partial<FluidUsedAsset> = {
1043
- symbol: debtAsset1.symbol,
1044
- borrowed: borrowed1,
1045
- borrowedUsd: new Dec(borrowed1).mul(assetsData[debtAsset1.symbol].price).toString(),
1046
- isBorrowed: new Dec(borrowed1).gt(0),
1047
- };
1048
-
1049
- const usedAssets: FluidUsedAssets = ([
1050
- [collAsset.symbol, collUsedAsset],
1051
- [debtAsset0.symbol, debtUsedAsset0],
1052
- [debtAsset1.symbol, debtUsedAsset1],
1053
- ] as [string, FluidUsedAsset][])
1054
- .reduce((acc, [symbol, partialData]) => {
1055
- acc[symbol] = mergeUsedAssets(acc[symbol], partialData);
1056
- return acc;
1057
- }, {} as Record<string, FluidUsedAsset>) as FluidUsedAssets;
1058
-
1059
-
1060
- return {
1061
- ...payload,
1062
- usedAssets,
1063
- borrowShares,
1064
- ...(getFluidAggregatedData({
1065
- usedAssets,
1066
- assetsData,
1067
- marketData,
1068
- }, '', borrowShares) as FluidAggregatedVaultData),
1069
- };
1070
- };
1071
-
1072
- const parseT4UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
1073
- const {
1074
- assetsData,
1075
- marketData,
1076
- } = vaultData;
1077
-
1078
- const payload = {
1079
- owner: userPositionData.owner,
1080
- vaultId: marketData.vaultId,
1081
- ...EMPTY_FLUID_DATA,
1082
- lastUpdated: Date.now(),
1083
- };
1084
-
1085
- const collAsset0 = getAssetInfo(marketData.collAsset0);
1086
- const collAsset1 = getAssetInfo(marketData.collAsset1);
1087
- const debtAsset0 = getAssetInfo(marketData.debtAsset0);
1088
- const debtAsset1 = getAssetInfo(marketData.debtAsset1);
1089
-
1090
- const supplyShares = getEthAmountForDecimals(userPositionData.supply, 18); // this is actual token supply
1091
- const borrowShares = getEthAmountForDecimals(userPositionData.borrow, 18); // this is actual token borrow
1092
-
1093
- const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare!).toString();
1094
- const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare!).toString();
1095
-
1096
- const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare!).toString();
1097
- const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare!).toString();
1098
-
1099
- const collUsedAsset0: Partial<FluidUsedAsset> = {
1100
- symbol: collAsset0.symbol,
1101
- collateral: true,
1102
- supplied: supplied0,
1103
- suppliedUsd: new Dec(supplied0).mul(assetsData[collAsset0.symbol].price).toString(),
1104
- isSupplied: new Dec(supplied0).gt(0),
1105
- };
1106
- const collUsedAsset1: Partial<FluidUsedAsset> = {
1107
- symbol: collAsset1.symbol,
1108
- collateral: true,
1109
- supplied: supplied1,
1110
- suppliedUsd: new Dec(supplied1).mul(assetsData[collAsset1.symbol].price).toString(),
1111
- isSupplied: new Dec(supplied1).gt(0),
1112
- };
1113
-
1114
- const debtUsedAsset0: Partial<FluidUsedAsset> = {
1115
- symbol: debtAsset0.symbol,
1116
- borrowed: borrowed0,
1117
- borrowedUsd: new Dec(borrowed0).mul(assetsData[debtAsset0.symbol].price).toString(),
1118
- isBorrowed: new Dec(borrowed0).gt(0),
1119
- };
1120
- const debtUsedAsset1: Partial<FluidUsedAsset> = {
1121
- symbol: debtAsset1.symbol,
1122
- borrowed: borrowed1,
1123
- borrowedUsd: new Dec(borrowed1).mul(assetsData[debtAsset1.symbol].price).toString(),
1124
- isBorrowed: new Dec(borrowed1).gt(0),
1125
- };
1126
-
1127
- const usedAssets: FluidUsedAssets = ([
1128
- [collAsset0.symbol, collUsedAsset0],
1129
- [collAsset1.symbol, collUsedAsset1],
1130
- [debtAsset0.symbol, debtUsedAsset0],
1131
- [debtAsset1.symbol, debtUsedAsset1],
1132
- ] as [string, FluidUsedAsset][])
1133
- .reduce((acc, [symbol, partialData]) => {
1134
- acc[symbol] = mergeUsedAssets(acc[symbol], partialData);
1135
- return acc;
1136
- }, {} as Record<string, FluidUsedAsset>) as FluidUsedAssets;
1137
-
1138
- return {
1139
- ...payload,
1140
- usedAssets,
1141
- supplyShares,
1142
- borrowShares,
1143
- ...(getFluidAggregatedData({
1144
- usedAssets,
1145
- assetsData,
1146
- marketData,
1147
- }, supplyShares, borrowShares) as FluidAggregatedVaultData),
1148
- };
1149
- };
1150
-
1151
- const parseUserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData) => {
1152
- const vaultType = vaultData.marketData.vaultType;
1153
- switch (vaultType) {
1154
- case FluidVaultType.T1:
1155
- return parseT1UserData(userPositionData, vaultData);
1156
- case FluidVaultType.T2:
1157
- return parseT2UserData(userPositionData, vaultData);
1158
- case FluidVaultType.T3:
1159
- return parseT3UserData(userPositionData, vaultData);
1160
- case FluidVaultType.T4:
1161
- return parseT4UserData(userPositionData, vaultData);
1162
- default:
1163
- throw new Error(`Unknown vault type: ${vaultType}`);
1164
- }
1165
- };
1166
-
1167
- export const getFluidMarketData = async (web3: Web3, network: NetworkNumber, market: FluidMarketInfo, mainnetWeb3: Web3) => {
1168
- const view = FluidViewContract(web3, network);
1169
-
1170
- const data = await view.methods.getVaultData(market.marketAddress).call();
1171
-
1172
- return parseMarketData(web3, data, network, mainnetWeb3);
1173
- };
1174
-
1175
- export const getFluidVaultIdsForUser = async (web3: Web3,
1176
- network:NetworkNumber,
1177
- user: EthAddress): Promise<string[]> => {
1178
- const view = FluidViewContract(web3, network);
1179
-
1180
- return view.methods.getUserNftIds(user).call();
1181
- };
1182
-
1183
-
1184
- export const getFluidPosition = async (
1185
- web3: Web3,
1186
- network: NetworkNumber,
1187
- vaultId: string,
1188
- extractedState: {
1189
- assetsData: FluidAssetsData
1190
- marketData: InnerFluidMarketData,
1191
- },
1192
- ): Promise<FluidVaultData> => {
1193
- const view = FluidViewContract(web3, network);
1194
-
1195
- const data = await view.methods.getPositionByNftId(vaultId).call();
1196
-
1197
- const userPositionData = data[0];
1198
-
1199
- return parseUserData(userPositionData, extractedState);
1200
- };
1201
-
1202
- export const getFluidPositionWithMarket = async (web3: Web3, network: NetworkNumber, vaultId: string, mainnetWeb3: Web3) => {
1203
- const view = FluidViewContract(web3, network);
1204
- const data = await view.methods.getPositionByNftId(vaultId).call();
1205
- const marketData = await parseMarketData(web3, data.vault, network, mainnetWeb3);
1206
- const userData = parseUserData(data.position, marketData);
1207
-
1208
- return {
1209
- userData,
1210
- marketData,
1211
- };
1212
- };
1213
-
1214
- export const getAllFluidMarketDataChunked = async (network: NetworkNumber, web3: Web3, mainnetWeb3: Web3) => {
1215
- const versions = getFluidVersionsDataForNetwork(network);
1216
- const view = FluidViewContract(web3, network);
1217
- const calls = versions.map((version) => ({
1218
- target: view.options.address,
1219
- abiItem: view.options.jsonInterface.find((item) => item.name === 'getVaultData'),
1220
- params: [version.marketAddress],
1221
- }));
1222
-
1223
- const data = await chunkAndMulticall(calls, 10, 'latest', web3, network);
1224
- // @ts-ignore
1225
- return Promise.all(data.map(async (item, i) => parseMarketData(web3, item.vaultData, network, mainnetWeb3)));
1226
- };
1227
-
1228
- export const getFluidTokenData = async (web3: Web3, network: NetworkNumber, token: string) => {
1229
- const view = FluidViewContract(web3, network);
1230
- const fTokenAddress = getFTokenAddress(token, network);
1231
- const data = await view.methods.getFTokenData(fTokenAddress).call();
1232
- const supplyRate = new Dec(data.supplyRate).div(100).toString();
1233
- const rewardsRate = new Dec(data.rewardsRate).div(1e12).toString();
1234
- const decimals = data.decimals;
1235
-
1236
- const depositRate = new Dec(getEthAmountForDecimals(data.convertToShares, decimals)).toString();
1237
- const withdrawRate = new Dec(getEthAmountForDecimals(data.convertToAssets, decimals)).toString();
1238
-
1239
- return {
1240
- fTokenAddress,
1241
- fTokenSymbol: data.symbol,
1242
- decimals,
1243
- totalDeposited: getEthAmountForDecimals(data.totalAssets, decimals),
1244
- withdrawable: getEthAmountForDecimals(data.withdrawable, decimals),
1245
- apy: new Dec(supplyRate).add(rewardsRate).toString(),
1246
- depositRate,
1247
- withdrawRate,
1248
- };
1249
- };
1250
-
1251
- export const getFluidDepositData = async (web3: Web3, network: NetworkNumber, token: string, address: EthAddress) => {
1252
- const view = FluidViewContract(web3, network);
1253
- const fTokenAddress = getFTokenAddress(token, network);
1254
- const { fTokenData, userPosition } = await view.methods.getUserEarnPositionWithFToken(fTokenAddress, address).call();
1255
-
1256
- const supplyRate = new Dec(fTokenData.supplyRate).div(100).toString();
1257
- const rewardsRate = new Dec(fTokenData.rewardsRate).div(1e12).toString();
1258
- const decimals = fTokenData.decimals;
1259
-
1260
- const depositRate = new Dec(getEthAmountForDecimals(fTokenData.convertToShares, decimals)).toString();
1261
- const withdrawRate = new Dec(getEthAmountForDecimals(fTokenData.convertToAssets, decimals)).toString();
1262
-
1263
- return {
1264
- fTokenAddress,
1265
- fTokenSymbol: fTokenData.symbol,
1266
- decimals,
1267
- totalDeposited: getEthAmountForDecimals(fTokenData.totalAssets, decimals),
1268
- withdrawable: getEthAmountForDecimals(fTokenData.withdrawable, decimals),
1269
- apy: new Dec(supplyRate).add(rewardsRate).toString(),
1270
- depositRate,
1271
- withdrawRate,
1272
- deposited: getEthAmountForDecimals(userPosition.underlyingAssets, decimals),
1273
- depositedShares: getEthAmountForDecimals(userPosition.fTokenShares, decimals),
1274
- };
1275
- };
1276
-
1277
- export const getUserPositions = async (web3: Web3, network: NetworkNumber, user: EthAddress, mainnetWeb3: Web3) => {
1278
- const view = FluidViewContract(web3, network);
1279
-
1280
- const data = await view.methods.getUserPositions(user).call();
1281
-
1282
- const parsedMarketData = await Promise.all(data.vaults.map(async (vaultData) => parseMarketData(web3, vaultData, network, mainnetWeb3)));
1283
-
1284
- const userData = data.positions.map((position, i) => ({ ...parseUserData(position, parsedMarketData[i]), nftId: position.nftId }));
1285
-
1286
- return parsedMarketData.map((market, i) => ({
1287
- marketData: market,
1288
- userData: userData[i],
1289
- }));
1
+ import Web3 from 'web3';
2
+ import Dec from 'decimal.js';
3
+ import {
4
+ assetAmountInEth,
5
+ AssetData, getAssetInfo, getAssetInfoByAddress,
6
+ } from '@defisaver/tokens';
7
+ import { EthAddress, NetworkNumber } from '../types/common';
8
+ import {
9
+ FluidAggregatedVaultData,
10
+ FluidAssetData, FluidAssetsData,
11
+ FluidMarketData,
12
+ FluidMarketInfo,
13
+ FluidUsedAsset,
14
+ FluidUsedAssets,
15
+ FluidVaultData,
16
+ FluidVaultType, InnerFluidMarketData,
17
+ } from '../types';
18
+ import { DFSFeedRegistryContract, FeedRegistryContract, FluidViewContract } from '../contracts';
19
+ import { getEthAmountForDecimals, isMainnetNetwork } from '../services/utils';
20
+ import {
21
+ getFluidAggregatedData,
22
+ mergeAssetData,
23
+ mergeUsedAssets,
24
+ parseDexBorrowData,
25
+ parseDexSupplyData,
26
+ } from '../helpers/fluidHelpers';
27
+ import { FluidView } from '../types/contracts/generated';
28
+ import { chunkAndMulticall } from '../multicall';
29
+ import { getFluidMarketInfoById, getFluidVersionsDataForNetwork, getFTokenAddress } from '../markets';
30
+ import { USD_QUOTE } from '../constants';
31
+ import {
32
+ getChainlinkAssetAddress,
33
+ getWeETHChainLinkPriceCalls,
34
+ getWstETHChainLinkPriceCalls,
35
+ getWstETHPriceFluid,
36
+ parseWeETHPriceCalls,
37
+ parseWstETHPriceCalls,
38
+ getEthPriceForFluid,
39
+ getBTCPriceForFluid,
40
+ } from '../services/priceService';
41
+ import { getStakingApy, STAKING_ASSETS } from '../staking';
42
+
43
+ export const EMPTY_USED_ASSET = {
44
+ isSupplied: false,
45
+ isBorrowed: false,
46
+ supplied: '0',
47
+ suppliedUsd: '0',
48
+ borrowed: '0',
49
+ borrowedUsd: '0',
50
+ symbol: '',
51
+ collateral: false,
52
+ };
53
+
54
+ const parseVaultType = (vaultType: number) => {
55
+ switch (vaultType) {
56
+ case 10000: return FluidVaultType.T1;
57
+ case 20000: return FluidVaultType.T2;
58
+ case 30000: return FluidVaultType.T3;
59
+ case 40000: return FluidVaultType.T4;
60
+ default: return FluidVaultType.Unknown;
61
+ }
62
+ };
63
+
64
+ const getChainLinkPricesForTokens = async (
65
+ tokens: string[],
66
+ network: NetworkNumber,
67
+ web3: Web3,
68
+ ): Promise<{ [key: string]: string }> => {
69
+ const isMainnet = isMainnetNetwork(network);
70
+
71
+ const noDuplicateTokens = new Array(...new Set(tokens));
72
+
73
+ // TODO: this needs to be refactored
74
+ const ethPriceChainlink = await getEthPriceForFluid(web3, network);
75
+ const btcPriceChainlink = await getBTCPriceForFluid(web3, network);
76
+
77
+ const calls = noDuplicateTokens.flatMap((address) => {
78
+ const assetInfo = getAssetInfoByAddress(address, network);
79
+ const isTokenUSDA = assetInfo.symbol === 'USDA';
80
+ if (isTokenUSDA) return;
81
+ const chainLinkFeedAddress = getChainlinkAssetAddress(assetInfo.symbol, network);
82
+
83
+ if (assetInfo.symbol === 'wstETH') return getWstETHChainLinkPriceCalls(web3, network);
84
+ if (assetInfo.symbol === 'weETH') return getWeETHChainLinkPriceCalls(web3, network);
85
+
86
+ if (isMainnet) {
87
+ const feedRegistryContract = FeedRegistryContract(web3, NetworkNumber.Eth);
88
+ return ({
89
+ target: feedRegistryContract.options.address,
90
+ abiItem: feedRegistryContract.options.jsonInterface.find(({ name }) => name === 'latestAnswer'),
91
+ params: [chainLinkFeedAddress, USD_QUOTE],
92
+ });
93
+ }
94
+
95
+ const feedRegistryContract = DFSFeedRegistryContract(web3, network);
96
+ return ({
97
+ target: feedRegistryContract.options.address,
98
+ abiItem: feedRegistryContract.options.jsonInterface.find(({ name }) => name === 'latestRoundData'),
99
+ params: [chainLinkFeedAddress, USD_QUOTE],
100
+ });
101
+ });
102
+
103
+ const prices = await chunkAndMulticall(calls, 10, 'latest', web3, network);
104
+
105
+ let offset = 0; // wstETH has 3 calls, while others have only 1, so we need to keep track
106
+ return noDuplicateTokens.reduce((acc, token, i) => {
107
+ const assetInfo = getAssetInfoByAddress(token, network);
108
+ switch (assetInfo.symbol) {
109
+ case 'USDA':
110
+ acc[token] = '100000000';
111
+ break;
112
+
113
+ case 'wstETH': {
114
+ const {
115
+ ethPrice,
116
+ wstETHRate,
117
+ } = parseWstETHPriceCalls(prices[i + offset][0], prices[i + offset + 1], prices[i + offset + 2][0]);
118
+ offset += 2;
119
+ acc[token] = new Dec(ethPrice).mul(wstETHRate).toString();
120
+ break;
121
+ }
122
+
123
+ // TODO: These addresses do not have chainlink feeds, so we need to handle them separately, this is hotfix
124
+ case 'ezETH': {
125
+ acc[token] = new Dec(ethPriceChainlink).mul(1.049).toString();
126
+ break;
127
+ }
128
+ case 'rsETH': {
129
+ acc[token] = new Dec(ethPriceChainlink).mul(1.0454).toString();
130
+ break;
131
+ }
132
+ case 'weETHs': {
133
+ acc[token] = new Dec(ethPriceChainlink).mul(1.026).toString();
134
+ break;
135
+ }
136
+ case 'LBTC': {
137
+ acc[token] = new Dec(btcPriceChainlink).toString();
138
+ break;
139
+ }
140
+ case 'sUSDS': {
141
+ acc[token] = new Dec('105276929').toString();
142
+ break;
143
+ }
144
+
145
+ case 'weETH': {
146
+ const {
147
+ ethPrice,
148
+ weETHRate,
149
+ } = parseWeETHPriceCalls(prices[i + offset][0], prices[i + offset + 1], prices[i + offset + 2][0]);
150
+ offset += 2;
151
+ acc[token] = new Dec(ethPrice).mul(weETHRate).toString();
152
+ break;
153
+ }
154
+
155
+ default:
156
+ acc[token] = new Dec(prices[i + offset].answer).div(1e8).toString();
157
+ break;
158
+ }
159
+ return acc;
160
+ }, {} as { [key: string]: string });
161
+ };
162
+
163
+
164
+ const getTokenPriceFromChainlink = async (asset: AssetData, network: NetworkNumber, web3: Web3) => {
165
+ if (asset.symbol === 'sUSDS') {
166
+ return new Dec('105276929').div(1e8).toString();
167
+ }
168
+ const isTokenUSDA = asset.symbol === 'USDA';
169
+ const isMainnet = isMainnetNetwork(network);
170
+ const loanTokenFeedAddress = getChainlinkAssetAddress(asset.symbol, network);
171
+
172
+ let loanTokenPrice;
173
+ if (asset.symbol === 'wstETH') {
174
+ // need to handle wstETH for l2s inside getWstETHPrice
175
+ loanTokenPrice = await getWstETHPriceFluid(web3, network);
176
+ } else if (isMainnet) {
177
+ const feedRegistryContract = FeedRegistryContract(web3, NetworkNumber.Eth);
178
+ loanTokenPrice = isTokenUSDA ? '100000000' : await feedRegistryContract.methods.latestAnswer(loanTokenFeedAddress, USD_QUOTE).call();
179
+ } else {
180
+ // Currently only base network is supported
181
+ const feedRegistryContract = DFSFeedRegistryContract(web3, network);
182
+ const roundPriceData = isTokenUSDA ? { answer: '100000000' } : await feedRegistryContract.methods.latestRoundData(loanTokenFeedAddress, USD_QUOTE).call();
183
+ loanTokenPrice = roundPriceData.answer;
184
+ }
185
+
186
+ return new Dec(loanTokenPrice).div(1e8).toString();
187
+ };
188
+
189
+ const getMarketRateForDex = (token1PerShare: string, token0PerShare: string, rate0: string, rate1: string, price0: string, price1: string) => {
190
+ const token0PerShareUsd = new Dec(token0PerShare).mul(price0).toString();
191
+ const token1PerShareUsd = new Dec(token1PerShare).mul(price1).toString();
192
+ const sharesCombinedUsd = new Dec(token0PerShareUsd).plus(token1PerShareUsd);
193
+
194
+ const rate0PerShare = new Dec(rate0).mul(token0PerShareUsd).div(sharesCombinedUsd).toString();
195
+
196
+ const rate1PerShare = new Dec(rate1).mul(token1PerShareUsd).div(sharesCombinedUsd).toString();
197
+
198
+ return new Dec(rate0PerShare).plus(rate1PerShare).toString();
199
+ };
200
+
201
+ const getAdditionalMarketRateForDex = (token1PerShare: string, token0PerShare: string, incentiveSupplyRate0: string, incentiveSupplyRate1: string, price0: string, price1: string) => {
202
+ const token0PerShareUsd = new Dec(token0PerShare).mul(price0).toString();
203
+ const token1PerShareUsd = new Dec(token1PerShare).mul(price1).toString();
204
+ const sharesCombinedUsd = new Dec(token0PerShareUsd).plus(token1PerShareUsd);
205
+
206
+ const rate0PerShare = incentiveSupplyRate0 ? new Dec(incentiveSupplyRate0).mul(token0PerShareUsd).div(sharesCombinedUsd).toString() : 0;
207
+
208
+ const rate1PerShare = incentiveSupplyRate1 ? new Dec(incentiveSupplyRate1).mul(token1PerShareUsd).div(sharesCombinedUsd).toString() : 0;
209
+
210
+ return new Dec(rate0PerShare).plus(rate1PerShare).toString();
211
+ };
212
+
213
+ const getTradingApy = async (poolAddress: EthAddress) => {
214
+ const res = await fetch(`https://api.fluid.instadapp.io/v2/1/dexes/${poolAddress}/apy`);
215
+ if (!res.ok) {
216
+ return '0';
217
+ }
218
+ const data = await res.json();
219
+ return new Dec(data.tradingApy).div(100).toString();
220
+ };
221
+
222
+ const parseT1MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
223
+ const collAsset = getAssetInfoByAddress(data.supplyToken0, network);
224
+ const debtAsset = getAssetInfoByAddress(data.borrowToken0, network);
225
+
226
+ const supplyRate = new Dec(data.supplyRateVault).div(100).toString();
227
+ const borrowRate = new Dec(data.borrowRateVault).div(100).toString();
228
+
229
+ const oracleScaleFactor = new Dec(27).add(debtAsset.decimals).sub(collAsset.decimals).toString();
230
+ const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
231
+ const oraclePrice = new Dec(data.oraclePriceOperate).div(oracleScale).toString();
232
+ const debtPriceParsed = await getTokenPriceFromChainlink(debtAsset, network, web3);
233
+
234
+ const collAssetData: FluidAssetData = {
235
+ symbol: collAsset.symbol,
236
+ address: collAsset.address,
237
+ price: new Dec(debtPriceParsed).mul(oraclePrice).toString(),
238
+ totalSupply: data.totalSupplyVault,
239
+ totalBorrow: data.totalBorrowVault,
240
+ canBeSupplied: true,
241
+ canBeBorrowed: false,
242
+ supplyRate,
243
+ borrowRate: '0',
244
+ };
245
+
246
+ if (STAKING_ASSETS.includes(collAsset.symbol)) {
247
+ collAssetData.incentiveSupplyApy = await getStakingApy(collAsset.symbol, mainnetWeb3);
248
+ collAssetData.incentiveSupplyToken = collAsset.symbol;
249
+ }
250
+
251
+ const incentiveSupplyRate = collAssetData.incentiveSupplyApy;
252
+
253
+ const debtAssetData: FluidAssetData = {
254
+ symbol: debtAsset.symbol,
255
+ address: debtAsset.address,
256
+ price: debtPriceParsed,
257
+ totalSupply: data.totalSupplyVault,
258
+ totalBorrow: data.totalBorrowVault,
259
+ canBeSupplied: false,
260
+ canBeBorrowed: true,
261
+ supplyRate: '0',
262
+ borrowRate,
263
+ };
264
+ if (STAKING_ASSETS.includes(debtAssetData.symbol)) {
265
+ debtAssetData.incentiveBorrowApy = await getStakingApy(debtAsset.symbol, mainnetWeb3);
266
+ debtAssetData.incentiveBorrowToken = debtAsset.symbol;
267
+ }
268
+
269
+ const incentiveBorrowRate = debtAssetData.incentiveBorrowApy;
270
+
271
+ const assetsData = {
272
+ [collAsset.symbol]: collAssetData,
273
+ [debtAsset.symbol]: debtAssetData,
274
+ };
275
+ const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
276
+ const totalSupplyVault = getEthAmountForDecimals(data.totalSupplyVault, collAsset.decimals);
277
+ const totalBorrowVault = getEthAmountForDecimals(data.totalBorrowVault, debtAsset.decimals);
278
+
279
+ const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
280
+ const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
281
+ const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
282
+
283
+ const marketData = {
284
+ vaultId: +data.vaultId,
285
+ vaultValue: marketInfo?.value,
286
+ isSmartColl: data.isSmartColl,
287
+ isSmartDebt: data.isSmartDebt,
288
+ marketAddress: data.vault,
289
+ vaultType: parseVaultType(+data.vaultType),
290
+ oracle: data.oracle,
291
+ liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
292
+ collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
293
+ liquidationRatio: liqRatio,
294
+ liqFactor,
295
+ minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
296
+ collAsset0: collAsset.symbol,
297
+ debtAsset0: debtAsset.symbol,
298
+ totalPositions: data.totalPositions,
299
+ totalSupplyVault,
300
+ totalBorrowVault,
301
+ totalSupplyVaultUsd: new Dec(totalSupplyVault).mul(collAssetData.price).toString(),
302
+ totalBorrowVaultUsd: new Dec(totalBorrowVault).mul(debtAssetData.price).toString(),
303
+ withdrawalLimit: getEthAmountForDecimals(data.withdrawalLimit, collAsset.decimals),
304
+ withdrawableUntilLimit: getEthAmountForDecimals(data.withdrawableUntilLimit, collAsset.decimals),
305
+ withdrawable: getEthAmountForDecimals(data.withdrawable, collAsset.decimals),
306
+ borrowLimit: getEthAmountForDecimals(data.borrowLimit, debtAsset.decimals),
307
+ borrowableUntilLimit: getEthAmountForDecimals(data.borrowableUntilLimit, debtAsset.decimals),
308
+ borrowable: getEthAmountForDecimals(data.borrowable, debtAsset.decimals),
309
+ borrowLimitUtilization: getEthAmountForDecimals(data.borrowLimitUtilization, debtAsset.decimals),
310
+ maxBorrowLimit: getEthAmountForDecimals(data.maxBorrowLimit, debtAsset.decimals),
311
+ baseBorrowLimit: getEthAmountForDecimals(data.baseBorrowLimit, debtAsset.decimals),
312
+ minimumBorrowing: getEthAmountForDecimals(data.minimumBorrowing, debtAsset.decimals),
313
+ liquidationMaxLimit,
314
+ borrowRate,
315
+ supplyRate,
316
+ incentiveSupplyRate,
317
+ incentiveBorrowRate,
318
+ oraclePrice,
319
+ };
320
+
321
+ return {
322
+ assetsData,
323
+ marketData,
324
+ } as FluidMarketData;
325
+ };
326
+
327
+ const parseT2MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
328
+ const collAsset0 = getAssetInfoByAddress(data.supplyToken0, network);
329
+ const collAsset1 = getAssetInfoByAddress(data.supplyToken1, network);
330
+ const debtAsset = getAssetInfoByAddress(data.borrowToken0, network);
331
+
332
+ // 18 because collateral is represented in shares for which they use 18 decimals
333
+ const oracleScaleFactor = new Dec(27).add(debtAsset.decimals).sub(18).toString();
334
+ const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
335
+ const oraclePrice = new Dec(data.oraclePriceOperate).div(oracleScale).toString();
336
+
337
+ const prices = await getChainLinkPricesForTokens([collAsset0.address, collAsset1.address, debtAsset.address], network, web3);
338
+
339
+ const {
340
+ supplyDexFee,
341
+ totalSupplyShares,
342
+ supplyRate1,
343
+ totalSupplyToken1,
344
+ token0PerSupplyShare,
345
+ token1PerSupplyShare,
346
+ totalSupplyToken0,
347
+ maxSupplyShares,
348
+ withdrawableToken0,
349
+ withdrawable0,
350
+ withdrawableToken1,
351
+ withdrawable1,
352
+ supplyRate0,
353
+ utilizationSupply0,
354
+ utilizationSupply1,
355
+ withdrawableShares,
356
+ reservesSupplyToken0,
357
+ reservesSupplyToken1,
358
+ } = parseDexSupplyData(data.dexSupplyData, collAsset0.symbol, collAsset1.symbol);
359
+
360
+ const collFirstAssetData: Partial<FluidAssetData> = {
361
+ symbol: collAsset0.symbol,
362
+ address: collAsset0.address,
363
+ price: prices[collAsset0.address],
364
+ totalSupply: new Dec(totalSupplyShares).mul(token0PerSupplyShare).toString(),
365
+ canBeSupplied: true,
366
+ supplyRate: supplyRate0,
367
+ utilization: utilizationSupply0,
368
+ withdrawable: withdrawable0,
369
+ tokenPerSupplyShare: token0PerSupplyShare,
370
+ supplyReserves: reservesSupplyToken0,
371
+ };
372
+ if (STAKING_ASSETS.includes(collFirstAssetData.symbol!)) {
373
+ collFirstAssetData.incentiveSupplyApy = await getStakingApy(collAsset0.symbol, mainnetWeb3);
374
+ collFirstAssetData.incentiveSupplyToken = collAsset0.symbol;
375
+ }
376
+
377
+ const collSecondAssetData: Partial<FluidAssetData> = {
378
+ symbol: collAsset1.symbol,
379
+ address: collAsset1.address,
380
+ price: prices[collAsset1.address],
381
+ totalSupply: new Dec(totalSupplyShares).mul(token1PerSupplyShare).toString(),
382
+ canBeSupplied: true,
383
+ supplyRate: supplyRate1,
384
+ withdrawable: withdrawable1,
385
+ utilization: utilizationSupply1,
386
+ tokenPerSupplyShare: token1PerSupplyShare,
387
+ supplyReserves: reservesSupplyToken1,
388
+ };
389
+ if (STAKING_ASSETS.includes(collSecondAssetData.symbol!)) {
390
+ collSecondAssetData.incentiveSupplyApy = await getStakingApy(collAsset1.symbol, mainnetWeb3);
391
+ collSecondAssetData.incentiveSupplyToken = collAsset1.symbol;
392
+ }
393
+
394
+ const marketSupplyRate = getMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, supplyRate0, supplyRate1, collFirstAssetData.price!, collSecondAssetData.price!);
395
+ const incentiveSupplyRate = getAdditionalMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, collFirstAssetData.incentiveSupplyApy!, collSecondAssetData.incentiveSupplyApy!, collFirstAssetData.price!, collSecondAssetData.price!);
396
+ const tradingSupplyRate = await getTradingApy(data.dexSupplyData.dexPool);
397
+
398
+ const borrowRate = new Dec(data.borrowRateVault).div(100).toString();
399
+ const debtAssetData: Partial<FluidAssetData> = {
400
+ symbol: debtAsset.symbol,
401
+ price: prices[debtAsset.address],
402
+ address: debtAsset.address,
403
+ totalBorrow: data.totalBorrowVault,
404
+ canBeBorrowed: true,
405
+ borrowRate,
406
+ };
407
+ if (STAKING_ASSETS.includes(debtAssetData.symbol!)) {
408
+ debtAssetData.incentiveBorrowApy = await getStakingApy(debtAsset.symbol, mainnetWeb3);
409
+ debtAssetData.incentiveBorrowToken = debtAsset.symbol;
410
+ }
411
+
412
+ const incentiveBorrowRate = debtAssetData.incentiveBorrowApy;
413
+
414
+ const assetsData: FluidAssetsData = ([
415
+ [collAsset0.symbol, collFirstAssetData],
416
+ [collAsset1.symbol, collSecondAssetData],
417
+ [debtAsset.symbol, debtAssetData],
418
+ ] as [string, FluidAssetData][])
419
+ .reduce((acc, [symbol, partialData]) => ({
420
+ ...acc,
421
+ [symbol]: mergeAssetData(acc[symbol], partialData),
422
+ }), {} as Record<string, FluidAssetData>) as FluidAssetsData;
423
+
424
+ const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
425
+
426
+ const totalBorrowVault = getEthAmountForDecimals(data.totalBorrowVault, debtAsset.decimals);
427
+
428
+ const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
429
+ const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
430
+ const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
431
+
432
+ const totalSupplySharesInVault = assetAmountInEth(data.totalSupplyVault);
433
+ const collSharePrice = new Dec(oraclePrice).mul(prices[debtAsset.address]).toString();
434
+ const totalSupplyVaultUsd = new Dec(totalSupplySharesInVault).mul(collSharePrice).toString();
435
+ const maxSupplySharesUsd = new Dec(maxSupplyShares).mul(collSharePrice).toString();
436
+
437
+ const withdrawableUSD = new Dec(withdrawableShares).mul(collSharePrice).toString();
438
+
439
+ const marketData = {
440
+ vaultId: +data.vaultId,
441
+ vaultValue: marketInfo?.value,
442
+ isSmartColl: data.isSmartColl,
443
+ isSmartDebt: data.isSmartDebt,
444
+ marketAddress: data.vault,
445
+ vaultType: parseVaultType(+data.vaultType),
446
+ oracle: data.oracle,
447
+ liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
448
+ collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
449
+ liquidationRatio: liqRatio,
450
+ liqFactor,
451
+ minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
452
+ collAsset0: collAsset0.symbol,
453
+ collAsset1: collAsset1.symbol,
454
+ debtAsset0: debtAsset.symbol,
455
+ totalPositions: data.totalPositions,
456
+ totalSupplyVault: totalSupplyShares,
457
+ totalBorrowVault,
458
+ totalSupplyVaultUsd,
459
+ collSharePrice,
460
+ totalBorrowVaultUsd: new Dec(totalBorrowVault).mul(assetsData[debtAsset.symbol].price).toString(),
461
+ borrowLimit: getEthAmountForDecimals(data.borrowLimit, debtAsset.decimals),
462
+ borrowableUntilLimit: getEthAmountForDecimals(data.borrowableUntilLimit, debtAsset.decimals),
463
+ borrowable: getEthAmountForDecimals(data.borrowable, debtAsset.decimals),
464
+ borrowLimitUtilization: getEthAmountForDecimals(data.borrowLimitUtilization, debtAsset.decimals),
465
+ maxBorrowLimit: getEthAmountForDecimals(data.maxBorrowLimit, debtAsset.decimals),
466
+ baseBorrowLimit: getEthAmountForDecimals(data.baseBorrowLimit, debtAsset.decimals),
467
+ minimumBorrowing: getEthAmountForDecimals(data.minimumBorrowing, debtAsset.decimals),
468
+ liquidationMaxLimit,
469
+ borrowRate,
470
+ supplyRate: marketSupplyRate,
471
+ incentiveSupplyRate,
472
+ incentiveBorrowRate,
473
+ totalSupplyToken0,
474
+ totalSupplyToken1,
475
+ withdrawableToken0,
476
+ withdrawableToken1,
477
+ withdrawableUSD,
478
+ withdrawable: withdrawableShares,
479
+ withdrawableDex: new Dec(maxSupplyShares).minus(totalSupplyShares).toString(),
480
+ maxSupplyShares,
481
+ maxSupplySharesUsd,
482
+ collDexFee: supplyDexFee,
483
+ oraclePrice,
484
+ tradingSupplyRate,
485
+ tradingBorrowRate: '0',
486
+ };
487
+
488
+ return {
489
+ assetsData,
490
+ marketData,
491
+ } as FluidMarketData;
492
+ };
493
+
494
+ const parseT3MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
495
+ const collAsset = getAssetInfoByAddress(data.supplyToken0, network);
496
+ const debtAsset0 = getAssetInfoByAddress(data.borrowToken0, network);
497
+ const debtAsset1 = getAssetInfoByAddress(data.borrowToken1, network);
498
+
499
+ const {
500
+ borrowableShares,
501
+ maxBorrowShares,
502
+ borrowDexFee,
503
+ utilizationBorrow0,
504
+ utilizationBorrow1,
505
+ borrowable0,
506
+ borrowable1,
507
+ borrowRate0,
508
+ borrowRate1,
509
+ totalBorrowShares,
510
+ token0PerBorrowShare,
511
+ token1PerBorrowShare,
512
+ borrowableToken0,
513
+ borrowableToken1,
514
+ totalBorrowToken0,
515
+ totalBorrowToken1,
516
+ reservesBorrowToken0,
517
+ reservesBorrowToken1,
518
+ } = parseDexBorrowData(data.dexBorrowData, debtAsset0.symbol, debtAsset1.symbol);
519
+
520
+ // 18 because debt is represented in shares for which they use 18 decimals
521
+ const oracleScaleFactor = new Dec(27).add(18).sub(collAsset.decimals).toString();
522
+ const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
523
+ const oraclePrice = new Dec(1).div(new Dec(data.oraclePriceOperate).div(oracleScale)).toString();
524
+
525
+ const prices = await getChainLinkPricesForTokens([collAsset.address, debtAsset0.address, debtAsset1.address], network, web3);
526
+
527
+ const supplyRate = new Dec(data.supplyRateVault).div(100).toString();
528
+ const collAssetData: Partial<FluidAssetData> = {
529
+ symbol: collAsset.symbol,
530
+ address: collAsset.address,
531
+ price: prices[collAsset.address],
532
+ totalSupply: data.totalSupplyVault,
533
+ canBeSupplied: true,
534
+ supplyRate,
535
+ };
536
+ if (STAKING_ASSETS.includes(collAssetData.symbol!)) {
537
+ collAssetData.incentiveSupplyApy = await getStakingApy(collAsset.symbol, mainnetWeb3);
538
+ collAssetData.incentiveSupplyToken = collAsset.symbol;
539
+ }
540
+
541
+ const incentiveSupplyRate = collAssetData.incentiveSupplyApy;
542
+
543
+ const debtAsset0Data: Partial<FluidAssetData> = {
544
+ symbol: debtAsset0.symbol,
545
+ address: debtAsset0.address,
546
+ price: prices[debtAsset0.address],
547
+ totalBorrow: new Dec(totalBorrowShares).mul(token0PerBorrowShare).toString(),
548
+ canBeBorrowed: true,
549
+ borrowRate: borrowRate0,
550
+ borrowable: borrowable0,
551
+ utilization: utilizationBorrow0,
552
+ tokenPerBorrowShare: token0PerBorrowShare,
553
+ borrowReserves: reservesBorrowToken0,
554
+ };
555
+ if (STAKING_ASSETS.includes(debtAsset0Data.symbol!)) {
556
+ debtAsset0Data.incentiveSupplyApy = await getStakingApy(debtAsset0.symbol, mainnetWeb3);
557
+ debtAsset0Data.incentiveSupplyToken = debtAsset0.symbol;
558
+ }
559
+
560
+ const debtAsset1Data: Partial<FluidAssetData> = {
561
+ symbol: debtAsset1.symbol,
562
+ address: debtAsset1.address,
563
+ price: prices[debtAsset1.address],
564
+ totalBorrow: new Dec(totalBorrowShares).mul(token1PerBorrowShare).toString(),
565
+ canBeBorrowed: true,
566
+ borrowRate: borrowRate1,
567
+ borrowable: borrowable1,
568
+ utilization: utilizationBorrow1,
569
+ tokenPerBorrowShare: token1PerBorrowShare,
570
+ borrowReserves: reservesBorrowToken1,
571
+ };
572
+ if (STAKING_ASSETS.includes(debtAsset1Data.symbol!)) {
573
+ debtAsset1Data.incentiveSupplyApy = await getStakingApy(debtAsset1.symbol, mainnetWeb3);
574
+ debtAsset1Data.incentiveSupplyToken = debtAsset1.symbol;
575
+ }
576
+ const marketBorrowRate = getMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, borrowRate0, borrowRate1, debtAsset0Data.price!, debtAsset1Data.price!);
577
+ const incentiveBorrowRate = getAdditionalMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, debtAsset0Data.incentiveSupplyApy!, debtAsset1Data.incentiveSupplyApy!, debtAsset0Data.price!, debtAsset1Data.price!);
578
+ const tradingBorrowRate = await getTradingApy(data.dexBorrowData.dexPool);
579
+
580
+ const assetsData: FluidAssetsData = ([
581
+ [collAsset.symbol, collAssetData],
582
+ [debtAsset0.symbol, debtAsset0Data],
583
+ [debtAsset1.symbol, debtAsset1Data],
584
+ ] as [string, FluidAssetData][])
585
+ .reduce((acc, [symbol, partialData]) => ({
586
+ ...acc,
587
+ [symbol]: mergeAssetData(acc[symbol], partialData),
588
+ }), {} as Record<string, FluidAssetData>) as FluidAssetsData;
589
+
590
+ const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
591
+
592
+ const totalSupplyVault = getEthAmountForDecimals(data.totalSupplyVault, collAsset.decimals);
593
+
594
+ const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
595
+ const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
596
+ const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
597
+
598
+ const debtSharePrice = new Dec(oraclePrice).mul(prices[collAsset.address]).toString();
599
+
600
+ const totalBorrowSharesInVault = assetAmountInEth(data.totalBorrowVault);
601
+
602
+ const totalBorrowVaultUsd = new Dec(totalBorrowSharesInVault).mul(debtSharePrice).toString();
603
+
604
+ const borrowableUSD = new Dec(borrowableShares).mul(debtSharePrice).toString();
605
+ const maxBorrowSharesUsd = new Dec(maxBorrowShares).mul(debtSharePrice).toString();
606
+
607
+ const marketData = {
608
+ vaultId: +data.vaultId,
609
+ vaultValue: marketInfo?.value,
610
+ isSmartColl: data.isSmartColl,
611
+ isSmartDebt: data.isSmartDebt,
612
+ marketAddress: data.vault,
613
+ vaultType: parseVaultType(+data.vaultType),
614
+ oracle: data.oracle,
615
+ liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
616
+ collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
617
+ liquidationRatio: liqRatio,
618
+ liqFactor,
619
+ minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
620
+ collAsset0: collAsset.symbol,
621
+ debtAsset0: debtAsset0.symbol,
622
+ debtAsset1: debtAsset1.symbol,
623
+ totalPositions: data.totalPositions,
624
+ totalSupplyVault,
625
+ totalBorrowVault: totalBorrowShares,
626
+ totalSupplyVaultUsd: new Dec(totalSupplyVault).mul(assetsData[collAsset.symbol].price).toString(),
627
+ totalBorrowVaultUsd,
628
+ withdrawalLimit: getEthAmountForDecimals(data.withdrawalLimit, collAsset.decimals),
629
+ withdrawableUntilLimit: getEthAmountForDecimals(data.withdrawableUntilLimit, collAsset.decimals),
630
+ withdrawable: getEthAmountForDecimals(data.withdrawable, collAsset.decimals),
631
+ liquidationMaxLimit,
632
+ borrowRate: marketBorrowRate,
633
+ supplyRate,
634
+ incentiveBorrowRate,
635
+ incentiveSupplyRate,
636
+ tradingBorrowRate,
637
+ tradingSupplyRate: '0',
638
+ borrowableToken0,
639
+ borrowableToken1,
640
+ totalBorrowToken0,
641
+ totalBorrowToken1,
642
+ borrowableUSD,
643
+ borrowable: borrowableShares,
644
+ borrowableDex: new Dec(maxBorrowShares).minus(totalBorrowShares).toString(),
645
+ maxBorrowShares,
646
+ maxBorrowSharesUsd,
647
+ borrowDexFee,
648
+ debtSharePrice,
649
+ oraclePrice,
650
+ };
651
+
652
+ return {
653
+ assetsData,
654
+ marketData,
655
+ } as FluidMarketData;
656
+ };
657
+
658
+ const parseT4MarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
659
+ const collAsset0 = getAssetInfoByAddress(data.supplyToken0, network);
660
+ const collAsset1 = getAssetInfoByAddress(data.supplyToken1, network);
661
+ const debtAsset0 = getAssetInfoByAddress(data.borrowToken0, network);
662
+ const debtAsset1 = getAssetInfoByAddress(data.borrowToken1, network);
663
+ const quoteToken = getAssetInfoByAddress(data.dexBorrowData.quoteToken, network);
664
+
665
+ // 27 - 18 + 18
666
+ const oracleScaleFactor = new Dec(27).toString();
667
+ const oracleScale = new Dec(10).pow(oracleScaleFactor).toString();
668
+ const oraclePrice = new Dec(data.oraclePriceOperate).div(oracleScale).toString();
669
+
670
+ const prices = await getChainLinkPricesForTokens(
671
+ [collAsset0.address, collAsset1.address, debtAsset0.address, debtAsset1.address],
672
+ network, web3);
673
+
674
+ const {
675
+ supplyDexFee,
676
+ totalSupplyShares,
677
+ supplyRate1,
678
+ token0PerSupplyShare,
679
+ token1PerSupplyShare,
680
+ totalSupplyToken0,
681
+ totalSupplyToken1,
682
+ maxSupplyShares,
683
+ withdrawableToken0,
684
+ withdrawable0,
685
+ withdrawableToken1,
686
+ withdrawable1,
687
+ supplyRate0,
688
+ utilizationSupply0,
689
+ utilizationSupply1,
690
+ withdrawableShares,
691
+ reservesSupplyToken0,
692
+ reservesSupplyToken1,
693
+ } = parseDexSupplyData(data.dexSupplyData, collAsset0.symbol, collAsset1.symbol);
694
+
695
+ const {
696
+ borrowableShares,
697
+ maxBorrowShares,
698
+ borrowDexFee,
699
+ utilizationBorrow0,
700
+ utilizationBorrow1,
701
+ borrowable0,
702
+ borrowable1,
703
+ borrowRate0,
704
+ borrowRate1,
705
+ totalBorrowShares,
706
+ token0PerBorrowShare,
707
+ token1PerBorrowShare,
708
+ borrowableToken0,
709
+ borrowableToken1,
710
+ totalBorrowToken0,
711
+ totalBorrowToken1,
712
+ quoteTokensPerShare,
713
+ reservesBorrowToken0,
714
+ reservesBorrowToken1,
715
+ } = parseDexBorrowData(data.dexBorrowData, debtAsset0.symbol, debtAsset1.symbol);
716
+
717
+ const collAsset0Data: Partial<FluidAssetData> = {
718
+ symbol: collAsset0.symbol,
719
+ address: collAsset0.address,
720
+ price: prices[collAsset0.address],
721
+ totalSupply: new Dec(totalSupplyShares).mul(token0PerSupplyShare).toString(),
722
+ canBeSupplied: true,
723
+ supplyRate: supplyRate0,
724
+ utilization: utilizationSupply0,
725
+ withdrawable: withdrawable0,
726
+ tokenPerSupplyShare: token0PerSupplyShare,
727
+ supplyReserves: reservesSupplyToken0,
728
+ };
729
+ if (STAKING_ASSETS.includes(collAsset0Data.symbol!)) {
730
+ collAsset0Data.incentiveSupplyApy = await getStakingApy(collAsset0.symbol, mainnetWeb3);
731
+ collAsset0Data.incentiveSupplyToken = collAsset0.symbol;
732
+ }
733
+
734
+ const collAsset1Data: Partial<FluidAssetData> = {
735
+ symbol: collAsset1.symbol,
736
+ address: collAsset1.address,
737
+ price: prices[collAsset1.address],
738
+ totalSupply: new Dec(totalSupplyShares).mul(token1PerSupplyShare).toString(),
739
+ canBeSupplied: true,
740
+ supplyRate: supplyRate1,
741
+ withdrawable: withdrawable1,
742
+ utilization: utilizationSupply1,
743
+ tokenPerSupplyShare: token1PerSupplyShare,
744
+ supplyReserves: reservesSupplyToken1,
745
+ };
746
+ if (STAKING_ASSETS.includes(collAsset1Data.symbol!)) {
747
+ collAsset1Data.incentiveSupplyApy = await getStakingApy(collAsset1.symbol, mainnetWeb3);
748
+ collAsset1Data.incentiveSupplyToken = collAsset1.symbol;
749
+ }
750
+
751
+ const debtAsset0Data: Partial<FluidAssetData> = {
752
+ symbol: debtAsset0.symbol,
753
+ address: debtAsset0.address,
754
+ price: prices[debtAsset0.address],
755
+ totalBorrow: new Dec(totalBorrowShares).mul(token0PerBorrowShare).toString(),
756
+ canBeBorrowed: true,
757
+ borrowRate: borrowRate0,
758
+ borrowable: borrowable0,
759
+ utilization: utilizationBorrow0,
760
+ tokenPerBorrowShare: token0PerBorrowShare,
761
+ borrowReserves: reservesBorrowToken0,
762
+ };
763
+ if (STAKING_ASSETS.includes(debtAsset0Data.symbol!)) {
764
+ debtAsset0Data.incentiveSupplyApy = await getStakingApy(debtAsset0.symbol, mainnetWeb3);
765
+ debtAsset0Data.incentiveSupplyToken = debtAsset0.symbol;
766
+ }
767
+
768
+ const debtAsset1Data: Partial<FluidAssetData> = {
769
+ symbol: debtAsset1.symbol,
770
+ address: debtAsset1.address,
771
+ price: prices[debtAsset1.address],
772
+ totalBorrow: new Dec(totalBorrowShares).mul(token1PerBorrowShare).toString(),
773
+ canBeBorrowed: true,
774
+ borrowRate: borrowRate1,
775
+ borrowable: borrowable1,
776
+ utilization: utilizationBorrow1,
777
+ tokenPerBorrowShare: token1PerBorrowShare,
778
+ borrowReserves: reservesBorrowToken1,
779
+ };
780
+ if (STAKING_ASSETS.includes(debtAsset1Data.symbol!)) {
781
+ debtAsset1Data.incentiveSupplyApy = await getStakingApy(debtAsset1.symbol, mainnetWeb3);
782
+ debtAsset1Data.incentiveSupplyToken = debtAsset1.symbol;
783
+ }
784
+ const marketInfo = getFluidMarketInfoById(+data.vaultId, network);
785
+
786
+ const marketBorrowRate = getMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, borrowRate0, borrowRate1, debtAsset0Data.price!, debtAsset1Data.price!);
787
+ const incentiveBorrowRate = getAdditionalMarketRateForDex(token1PerBorrowShare, token0PerBorrowShare, debtAsset0Data.incentiveSupplyApy!, debtAsset1Data.incentiveSupplyApy!, debtAsset0Data.price!, debtAsset1Data.price!);
788
+ const tradingBorrowRate = await getTradingApy(data.dexBorrowData.dexPool);
789
+
790
+ const marketSupplyRate = getMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, supplyRate0, supplyRate1, collAsset0Data.price!, collAsset1Data.price!);
791
+ const incentiveSupplyRate = getAdditionalMarketRateForDex(token1PerSupplyShare, token0PerSupplyShare, collAsset0Data.incentiveSupplyApy!, collAsset1Data.incentiveSupplyApy!, collAsset0Data.price!, collAsset1Data.price!);
792
+ const tradingSupplyRate = await getTradingApy(data.dexSupplyData.dexPool);
793
+
794
+ const assetsData: FluidAssetsData = ([
795
+ [collAsset0.symbol, collAsset0Data],
796
+ [collAsset1.symbol, collAsset1Data],
797
+ [debtAsset0.symbol, debtAsset0Data],
798
+ [debtAsset1.symbol, debtAsset1Data],
799
+ ] as [string, FluidAssetData][])
800
+ .reduce((acc, [symbol, partialData]) => ({
801
+ ...acc,
802
+ [symbol]: mergeAssetData(acc[symbol], partialData),
803
+ }), {} as Record<string, FluidAssetData>) as FluidAssetsData;
804
+
805
+
806
+ const liqRatio = new Dec(data.liquidationThreshold).div(100).toString();
807
+ const liquidationMaxLimit = new Dec(data.liquidationMaxLimit).div(100).toString();
808
+ const liqFactor = new Dec(data.liquidationThreshold).div(10_000).toString();
809
+
810
+ const totalBorrowSharesInVault = assetAmountInEth(data.totalBorrowVault);
811
+ const debtSharePrice = new Dec(quoteTokensPerShare).mul(prices[quoteToken.address]).toString();
812
+ const totalBorrowVaultUsd = new Dec(totalBorrowSharesInVault).mul(debtSharePrice).toString();
813
+ const maxBorrowSharesUsd = new Dec(maxBorrowShares).mul(debtSharePrice).toString();
814
+ const borrowableUSD = new Dec(borrowableShares).mul(debtSharePrice).toString();
815
+
816
+ const totalSupplySharesInVault = assetAmountInEth(data.totalSupplyVault);
817
+ const collSharePrice = new Dec(oraclePrice).mul(debtSharePrice).toString();
818
+ const totalSupplyVaultUsd = new Dec(totalSupplySharesInVault).mul(collSharePrice).toString();
819
+ const maxSupplySharesUsd = new Dec(maxSupplyShares).mul(collSharePrice).toString();
820
+ const withdrawableUSD = new Dec(withdrawableShares).mul(collSharePrice).toString();
821
+
822
+ const marketData = {
823
+ vaultId: +data.vaultId,
824
+ vaultValue: marketInfo?.value,
825
+ isSmartColl: data.isSmartColl,
826
+ isSmartDebt: data.isSmartDebt,
827
+ marketAddress: data.vault,
828
+ vaultType: parseVaultType(+data.vaultType),
829
+ oracle: data.oracle,
830
+ liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
831
+ collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
832
+ liquidationRatio: liqRatio,
833
+ liqFactor,
834
+ minRatio: new Dec(1).div(liqFactor).mul(100).toString(),
835
+ collAsset0: collAsset0.symbol,
836
+ collAsset1: collAsset1.symbol,
837
+ debtAsset0: debtAsset0.symbol,
838
+ debtAsset1: debtAsset1.symbol,
839
+ totalPositions: data.totalPositions,
840
+ totalSupplyVault: totalSupplyShares,
841
+ totalBorrowVault: totalBorrowShares,
842
+ totalSupplyVaultUsd,
843
+ totalBorrowVaultUsd,
844
+ liquidationMaxLimit,
845
+ borrowRate: marketBorrowRate,
846
+ incentiveBorrowRate,
847
+ supplyRate: marketSupplyRate,
848
+ incentiveSupplyRate,
849
+ borrowableToken0,
850
+ borrowableToken1,
851
+ totalBorrowToken0,
852
+ totalBorrowToken1,
853
+ borrowableUSD,
854
+ borrowable: borrowableShares,
855
+ borrowableDex: new Dec(maxBorrowShares).minus(totalBorrowShares).toString(),
856
+ maxBorrowShares,
857
+ maxBorrowSharesUsd,
858
+ borrowDexFee,
859
+ totalSupplyToken0,
860
+ totalSupplyToken1,
861
+ withdrawableToken0,
862
+ withdrawableToken1,
863
+ withdrawableUSD,
864
+ withdrawable: withdrawableShares,
865
+ withdrawableDex: new Dec(maxSupplyShares).minus(totalSupplyShares).toString(),
866
+ maxSupplyShares,
867
+ maxSupplySharesUsd,
868
+ collDexFee: supplyDexFee,
869
+ collSharePrice,
870
+ debtSharePrice,
871
+ oraclePrice,
872
+ tradingBorrowRate,
873
+ tradingSupplyRate,
874
+ };
875
+
876
+ return {
877
+ assetsData,
878
+ marketData,
879
+ } as FluidMarketData;
880
+ };
881
+
882
+ const parseMarketData = async (web3: Web3, data: FluidView.VaultDataStructOutputStruct, network: NetworkNumber, mainnetWeb3: Web3) => {
883
+ const vaultType = parseVaultType(+data.vaultType);
884
+ switch (vaultType) {
885
+ case FluidVaultType.T1:
886
+ return parseT1MarketData(web3, data, network, mainnetWeb3);
887
+ case FluidVaultType.T2:
888
+ return parseT2MarketData(web3, data, network, mainnetWeb3);
889
+ case FluidVaultType.T3:
890
+ return parseT3MarketData(web3, data, network, mainnetWeb3);
891
+ case FluidVaultType.T4:
892
+ return parseT4MarketData(web3, data, network, mainnetWeb3);
893
+ default:
894
+ throw new Error(`Unknown vault type: ${vaultType}`);
895
+ }
896
+ };
897
+
898
+ export const EMPTY_FLUID_DATA = {
899
+ usedAssets: {},
900
+ suppliedUsd: '0',
901
+ borrowedUsd: '0',
902
+ borrowLimitUsd: '0',
903
+ leftToBorrowUsd: '0',
904
+ ratio: '0',
905
+ minRatio: '0',
906
+ netApy: '0',
907
+ incentiveUsd: '0',
908
+ totalInterestUsd: '0',
909
+ isSubscribedToAutomation: false,
910
+ automationResubscribeRequired: false,
911
+ lastUpdated: Date.now(),
912
+ };
913
+
914
+ const parseT1UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
915
+ const {
916
+ assetsData,
917
+ marketData,
918
+ } = vaultData;
919
+
920
+ const payload = {
921
+ owner: userPositionData.owner,
922
+ vaultId: marketData.vaultId,
923
+ ...EMPTY_FLUID_DATA,
924
+ lastUpdated: Date.now(),
925
+ };
926
+ const collAsset = getAssetInfo(marketData.collAsset0);
927
+ const debtAsset = getAssetInfo(marketData.debtAsset0);
928
+
929
+ // for T2 and T4 - this is the number of shares
930
+ const supplied = getEthAmountForDecimals(userPositionData.supply, collAsset.decimals);
931
+ const borrowed = getEthAmountForDecimals(userPositionData.borrow, debtAsset.decimals);
932
+
933
+ const collUsedAsset: FluidUsedAsset = {
934
+ ...EMPTY_USED_ASSET,
935
+ symbol: collAsset.symbol,
936
+ collateral: true,
937
+ supplied,
938
+ suppliedUsd: new Dec(supplied).mul(assetsData[collAsset.symbol].price).toString(),
939
+ isSupplied: new Dec(supplied).gt(0),
940
+ };
941
+
942
+ const debtUsedAsset: FluidUsedAsset = {
943
+ ...EMPTY_USED_ASSET,
944
+ symbol: debtAsset.symbol,
945
+ collateral: false,
946
+ borrowed,
947
+ borrowedUsd: new Dec(borrowed).mul(assetsData[debtAsset.symbol].price).toString(),
948
+ isBorrowed: new Dec(borrowed).gt(0),
949
+ };
950
+
951
+ const usedAssets: FluidUsedAssets = {
952
+ [collAsset.symbol]: collUsedAsset,
953
+ [debtAsset.symbol]: debtUsedAsset,
954
+ };
955
+
956
+ return {
957
+ ...payload,
958
+ usedAssets,
959
+ ...(getFluidAggregatedData({
960
+ usedAssets,
961
+ assetsData,
962
+ marketData,
963
+ }) as FluidAggregatedVaultData),
964
+ };
965
+ };
966
+
967
+ const parseT2UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
968
+ const {
969
+ assetsData,
970
+ marketData,
971
+ } = vaultData;
972
+
973
+ const payload = {
974
+ owner: userPositionData.owner,
975
+ vaultId: marketData.vaultId,
976
+ ...EMPTY_FLUID_DATA,
977
+ lastUpdated: Date.now(),
978
+ };
979
+
980
+ const collAsset0 = getAssetInfo(marketData.collAsset0);
981
+ const collAsset1 = getAssetInfo(marketData.collAsset1);
982
+ const debtAsset = getAssetInfo(marketData.debtAsset0);
983
+
984
+ const supplyShares = getEthAmountForDecimals(userPositionData.supply, 18); // this is supplied in coll shares
985
+ const borrowed = getEthAmountForDecimals(userPositionData.borrow, debtAsset.decimals); // this is actual token borrow
986
+
987
+ const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare!).toString();
988
+ const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare!).toString();
989
+
990
+ const collUsedAsset0: Partial<FluidUsedAsset> = {
991
+ symbol: collAsset0.symbol,
992
+ collateral: true,
993
+ supplied: supplied0,
994
+ suppliedUsd: new Dec(supplied0).mul(assetsData[collAsset0.symbol].price).toString(),
995
+ isSupplied: new Dec(supplied0).gt(0),
996
+ };
997
+
998
+ const collUsedAsset1: Partial<FluidUsedAsset> = {
999
+ symbol: collAsset1.symbol,
1000
+ collateral: true,
1001
+ supplied: supplied1,
1002
+ suppliedUsd: new Dec(supplied1).mul(assetsData[collAsset1.symbol].price).toString(),
1003
+ isSupplied: new Dec(supplied1).gt(0),
1004
+ };
1005
+
1006
+ const debtUsedAsset: Partial<FluidUsedAsset> = {
1007
+ symbol: debtAsset.symbol,
1008
+ borrowed,
1009
+ borrowedUsd: new Dec(borrowed).mul(assetsData[debtAsset.symbol].price).toString(),
1010
+ isBorrowed: new Dec(borrowed).gt(0),
1011
+ };
1012
+
1013
+ const usedAssets: FluidUsedAssets = ([
1014
+ [collAsset0.symbol, collUsedAsset0],
1015
+ [collAsset1.symbol, collUsedAsset1],
1016
+ [debtAsset.symbol, debtUsedAsset],
1017
+ ] as [string, FluidUsedAsset][])
1018
+ .reduce((acc, [symbol, partialData]) => {
1019
+ acc[symbol] = mergeUsedAssets(acc[symbol], partialData);
1020
+ return acc;
1021
+ }, {} as Record<string, FluidUsedAsset>) as FluidUsedAssets;
1022
+
1023
+ return {
1024
+ ...payload,
1025
+ usedAssets,
1026
+ supplyShares,
1027
+ ...(getFluidAggregatedData({
1028
+ usedAssets,
1029
+ assetsData,
1030
+ marketData,
1031
+ }, supplyShares) as FluidAggregatedVaultData),
1032
+ };
1033
+ };
1034
+
1035
+ const parseT3UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
1036
+ const {
1037
+ assetsData,
1038
+ marketData,
1039
+ } = vaultData;
1040
+
1041
+ const payload = {
1042
+ owner: userPositionData.owner,
1043
+ vaultId: marketData.vaultId,
1044
+ ...EMPTY_FLUID_DATA,
1045
+ lastUpdated: Date.now(),
1046
+ };
1047
+
1048
+ const collAsset = getAssetInfo(marketData.collAsset0);
1049
+ const debtAsset0 = getAssetInfo(marketData.debtAsset0);
1050
+ const debtAsset1 = getAssetInfo(marketData.debtAsset1);
1051
+
1052
+ const supplied = getEthAmountForDecimals(userPositionData.supply, collAsset.decimals); // this is actual token supply
1053
+ const borrowShares = getEthAmountForDecimals(userPositionData.borrow, 18); // this is actual token borrow
1054
+
1055
+ const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare!).toString();
1056
+ const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare!).toString();
1057
+
1058
+ const collUsedAsset: Partial<FluidUsedAsset> = {
1059
+ symbol: collAsset.symbol,
1060
+ collateral: true,
1061
+ supplied,
1062
+ suppliedUsd: new Dec(supplied).mul(assetsData[collAsset.symbol].price).toString(),
1063
+ isSupplied: new Dec(supplied).gt(0),
1064
+ };
1065
+
1066
+ const debtUsedAsset0: Partial<FluidUsedAsset> = {
1067
+ symbol: debtAsset0.symbol,
1068
+ borrowed: borrowed0,
1069
+ borrowedUsd: new Dec(borrowed0).mul(assetsData[debtAsset0.symbol].price).toString(),
1070
+ isBorrowed: new Dec(borrowed0).gt(0),
1071
+ };
1072
+
1073
+ const debtUsedAsset1: Partial<FluidUsedAsset> = {
1074
+ symbol: debtAsset1.symbol,
1075
+ borrowed: borrowed1,
1076
+ borrowedUsd: new Dec(borrowed1).mul(assetsData[debtAsset1.symbol].price).toString(),
1077
+ isBorrowed: new Dec(borrowed1).gt(0),
1078
+ };
1079
+
1080
+ const usedAssets: FluidUsedAssets = ([
1081
+ [collAsset.symbol, collUsedAsset],
1082
+ [debtAsset0.symbol, debtUsedAsset0],
1083
+ [debtAsset1.symbol, debtUsedAsset1],
1084
+ ] as [string, FluidUsedAsset][])
1085
+ .reduce((acc, [symbol, partialData]) => {
1086
+ acc[symbol] = mergeUsedAssets(acc[symbol], partialData);
1087
+ return acc;
1088
+ }, {} as Record<string, FluidUsedAsset>) as FluidUsedAssets;
1089
+
1090
+
1091
+ return {
1092
+ ...payload,
1093
+ usedAssets,
1094
+ borrowShares,
1095
+ ...(getFluidAggregatedData({
1096
+ usedAssets,
1097
+ assetsData,
1098
+ marketData,
1099
+ }, '', borrowShares) as FluidAggregatedVaultData),
1100
+ };
1101
+ };
1102
+
1103
+ const parseT4UserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
1104
+ const {
1105
+ assetsData,
1106
+ marketData,
1107
+ } = vaultData;
1108
+
1109
+ const payload = {
1110
+ owner: userPositionData.owner,
1111
+ vaultId: marketData.vaultId,
1112
+ ...EMPTY_FLUID_DATA,
1113
+ lastUpdated: Date.now(),
1114
+ };
1115
+
1116
+ const collAsset0 = getAssetInfo(marketData.collAsset0);
1117
+ const collAsset1 = getAssetInfo(marketData.collAsset1);
1118
+ const debtAsset0 = getAssetInfo(marketData.debtAsset0);
1119
+ const debtAsset1 = getAssetInfo(marketData.debtAsset1);
1120
+
1121
+ const supplyShares = getEthAmountForDecimals(userPositionData.supply, 18); // this is actual token supply
1122
+ const borrowShares = getEthAmountForDecimals(userPositionData.borrow, 18); // this is actual token borrow
1123
+
1124
+ const supplied0 = new Dec(supplyShares).mul(assetsData[collAsset0.symbol].tokenPerSupplyShare!).toString();
1125
+ const supplied1 = new Dec(supplyShares).mul(assetsData[collAsset1.symbol].tokenPerSupplyShare!).toString();
1126
+
1127
+ const borrowed0 = new Dec(borrowShares).mul(assetsData[debtAsset0.symbol].tokenPerBorrowShare!).toString();
1128
+ const borrowed1 = new Dec(borrowShares).mul(assetsData[debtAsset1.symbol].tokenPerBorrowShare!).toString();
1129
+
1130
+ const collUsedAsset0: Partial<FluidUsedAsset> = {
1131
+ symbol: collAsset0.symbol,
1132
+ collateral: true,
1133
+ supplied: supplied0,
1134
+ suppliedUsd: new Dec(supplied0).mul(assetsData[collAsset0.symbol].price).toString(),
1135
+ isSupplied: new Dec(supplied0).gt(0),
1136
+ };
1137
+ const collUsedAsset1: Partial<FluidUsedAsset> = {
1138
+ symbol: collAsset1.symbol,
1139
+ collateral: true,
1140
+ supplied: supplied1,
1141
+ suppliedUsd: new Dec(supplied1).mul(assetsData[collAsset1.symbol].price).toString(),
1142
+ isSupplied: new Dec(supplied1).gt(0),
1143
+ };
1144
+
1145
+ const debtUsedAsset0: Partial<FluidUsedAsset> = {
1146
+ symbol: debtAsset0.symbol,
1147
+ borrowed: borrowed0,
1148
+ borrowedUsd: new Dec(borrowed0).mul(assetsData[debtAsset0.symbol].price).toString(),
1149
+ isBorrowed: new Dec(borrowed0).gt(0),
1150
+ };
1151
+ const debtUsedAsset1: Partial<FluidUsedAsset> = {
1152
+ symbol: debtAsset1.symbol,
1153
+ borrowed: borrowed1,
1154
+ borrowedUsd: new Dec(borrowed1).mul(assetsData[debtAsset1.symbol].price).toString(),
1155
+ isBorrowed: new Dec(borrowed1).gt(0),
1156
+ };
1157
+
1158
+ const usedAssets: FluidUsedAssets = ([
1159
+ [collAsset0.symbol, collUsedAsset0],
1160
+ [collAsset1.symbol, collUsedAsset1],
1161
+ [debtAsset0.symbol, debtUsedAsset0],
1162
+ [debtAsset1.symbol, debtUsedAsset1],
1163
+ ] as [string, FluidUsedAsset][])
1164
+ .reduce((acc, [symbol, partialData]) => {
1165
+ acc[symbol] = mergeUsedAssets(acc[symbol], partialData);
1166
+ return acc;
1167
+ }, {} as Record<string, FluidUsedAsset>) as FluidUsedAssets;
1168
+
1169
+ return {
1170
+ ...payload,
1171
+ usedAssets,
1172
+ supplyShares,
1173
+ borrowShares,
1174
+ ...(getFluidAggregatedData({
1175
+ usedAssets,
1176
+ assetsData,
1177
+ marketData,
1178
+ }, supplyShares, borrowShares) as FluidAggregatedVaultData),
1179
+ };
1180
+ };
1181
+
1182
+ const parseUserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData) => {
1183
+ const vaultType = vaultData.marketData.vaultType;
1184
+ switch (vaultType) {
1185
+ case FluidVaultType.T1:
1186
+ return parseT1UserData(userPositionData, vaultData);
1187
+ case FluidVaultType.T2:
1188
+ return parseT2UserData(userPositionData, vaultData);
1189
+ case FluidVaultType.T3:
1190
+ return parseT3UserData(userPositionData, vaultData);
1191
+ case FluidVaultType.T4:
1192
+ return parseT4UserData(userPositionData, vaultData);
1193
+ default:
1194
+ throw new Error(`Unknown vault type: ${vaultType}`);
1195
+ }
1196
+ };
1197
+
1198
+ export const getFluidMarketData = async (web3: Web3, network: NetworkNumber, market: FluidMarketInfo, mainnetWeb3: Web3) => {
1199
+ const view = FluidViewContract(web3, network);
1200
+
1201
+ const data = await view.methods.getVaultData(market.marketAddress).call();
1202
+
1203
+ return parseMarketData(web3, data, network, mainnetWeb3);
1204
+ };
1205
+
1206
+ export const getFluidVaultIdsForUser = async (web3: Web3,
1207
+ network:NetworkNumber,
1208
+ user: EthAddress): Promise<string[]> => {
1209
+ const view = FluidViewContract(web3, network);
1210
+
1211
+ return view.methods.getUserNftIds(user).call();
1212
+ };
1213
+
1214
+
1215
+ export const getFluidPosition = async (
1216
+ web3: Web3,
1217
+ network: NetworkNumber,
1218
+ vaultId: string,
1219
+ extractedState: {
1220
+ assetsData: FluidAssetsData
1221
+ marketData: InnerFluidMarketData,
1222
+ },
1223
+ ): Promise<FluidVaultData> => {
1224
+ const view = FluidViewContract(web3, network);
1225
+
1226
+ const data = await view.methods.getPositionByNftId(vaultId).call();
1227
+
1228
+ const userPositionData = data[0];
1229
+
1230
+ return parseUserData(userPositionData, extractedState);
1231
+ };
1232
+
1233
+ export const getFluidPositionWithMarket = async (web3: Web3, network: NetworkNumber, vaultId: string, mainnetWeb3: Web3) => {
1234
+ const view = FluidViewContract(web3, network);
1235
+ const data = await view.methods.getPositionByNftId(vaultId).call();
1236
+ const marketData = await parseMarketData(web3, data.vault, network, mainnetWeb3);
1237
+ const userData = parseUserData(data.position, marketData);
1238
+
1239
+ return {
1240
+ userData,
1241
+ marketData,
1242
+ };
1243
+ };
1244
+
1245
+ export const getAllFluidMarketDataChunked = async (network: NetworkNumber, web3: Web3, mainnetWeb3: Web3) => {
1246
+ const versions = getFluidVersionsDataForNetwork(network);
1247
+ const view = FluidViewContract(web3, network);
1248
+ const calls = versions.map((version) => ({
1249
+ target: view.options.address,
1250
+ abiItem: view.options.jsonInterface.find((item) => item.name === 'getVaultData'),
1251
+ params: [version.marketAddress],
1252
+ }));
1253
+
1254
+ const data = await chunkAndMulticall(calls, 10, 'latest', web3, network);
1255
+ // @ts-ignore
1256
+ return Promise.all(data.map(async (item, i) => parseMarketData(web3, item.vaultData, network, mainnetWeb3)));
1257
+ };
1258
+
1259
+ export const getFluidTokenData = async (web3: Web3, network: NetworkNumber, token: string) => {
1260
+ const view = FluidViewContract(web3, network);
1261
+ const fTokenAddress = getFTokenAddress(token, network);
1262
+ const data = await view.methods.getFTokenData(fTokenAddress).call();
1263
+ const supplyRate = new Dec(data.supplyRate).div(100).toString();
1264
+ const rewardsRate = new Dec(data.rewardsRate).div(1e12).toString();
1265
+ const decimals = data.decimals;
1266
+
1267
+ const depositRate = new Dec(getEthAmountForDecimals(data.convertToShares, decimals)).toString();
1268
+ const withdrawRate = new Dec(getEthAmountForDecimals(data.convertToAssets, decimals)).toString();
1269
+
1270
+ return {
1271
+ fTokenAddress,
1272
+ fTokenSymbol: data.symbol,
1273
+ decimals,
1274
+ totalDeposited: getEthAmountForDecimals(data.totalAssets, decimals),
1275
+ withdrawable: getEthAmountForDecimals(data.withdrawable, decimals),
1276
+ apy: new Dec(supplyRate).add(rewardsRate).toString(),
1277
+ depositRate,
1278
+ withdrawRate,
1279
+ };
1280
+ };
1281
+
1282
+ export const getFluidDepositData = async (web3: Web3, network: NetworkNumber, token: string, address: EthAddress) => {
1283
+ const view = FluidViewContract(web3, network);
1284
+ const fTokenAddress = getFTokenAddress(token, network);
1285
+ const { fTokenData, userPosition } = await view.methods.getUserEarnPositionWithFToken(fTokenAddress, address).call();
1286
+
1287
+ const supplyRate = new Dec(fTokenData.supplyRate).div(100).toString();
1288
+ const rewardsRate = new Dec(fTokenData.rewardsRate).div(1e12).toString();
1289
+ const decimals = fTokenData.decimals;
1290
+
1291
+ const depositRate = new Dec(getEthAmountForDecimals(fTokenData.convertToShares, decimals)).toString();
1292
+ const withdrawRate = new Dec(getEthAmountForDecimals(fTokenData.convertToAssets, decimals)).toString();
1293
+
1294
+ return {
1295
+ fTokenAddress,
1296
+ fTokenSymbol: fTokenData.symbol,
1297
+ decimals,
1298
+ totalDeposited: getEthAmountForDecimals(fTokenData.totalAssets, decimals),
1299
+ withdrawable: getEthAmountForDecimals(fTokenData.withdrawable, decimals),
1300
+ apy: new Dec(supplyRate).add(rewardsRate).toString(),
1301
+ depositRate,
1302
+ withdrawRate,
1303
+ deposited: getEthAmountForDecimals(userPosition.underlyingAssets, decimals),
1304
+ depositedShares: getEthAmountForDecimals(userPosition.fTokenShares, decimals),
1305
+ };
1306
+ };
1307
+
1308
+ export const getUserPositions = async (web3: Web3, network: NetworkNumber, user: EthAddress, mainnetWeb3: Web3) => {
1309
+ const view = FluidViewContract(web3, network);
1310
+
1311
+ const data = await view.methods.getUserPositions(user).call();
1312
+
1313
+ const parsedMarketData = await Promise.all(data.vaults.map(async (vaultData) => parseMarketData(web3, vaultData, network, mainnetWeb3)));
1314
+
1315
+ const userData = data.positions.map((position, i) => ({ ...parseUserData(position, parsedMarketData[i]), nftId: position.nftId }));
1316
+
1317
+ return parsedMarketData.map((market, i) => ({
1318
+ marketData: market,
1319
+ userData: userData[i],
1320
+ }));
1290
1321
  };