impermax-sdk 1.0.0

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 (103) hide show
  1. package/.idea/impermax-sdk.iml +12 -0
  2. package/.idea/misc.xml +6 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/workspace.xml +642 -0
  5. package/abis/ImpermaxABI.ts +3 -0
  6. package/abis/contracts/BAllowance.json +4735 -0
  7. package/abis/contracts/BDeployer.json +1195 -0
  8. package/abis/contracts/BInterestRateModel.json +10796 -0
  9. package/abis/contracts/BSetter.json +6219 -0
  10. package/abis/contracts/BStorage.json +2613 -0
  11. package/abis/contracts/Borrowable.json +19937 -0
  12. package/abis/contracts/CDeployer.json +1104 -0
  13. package/abis/contracts/CSetter.json +5094 -0
  14. package/abis/contracts/CStorage.json +516 -0
  15. package/abis/contracts/ClaimAggregator.json +2015 -0
  16. package/abis/contracts/Collateral.json +21615 -0
  17. package/abis/contracts/ERC20.json +819 -0
  18. package/abis/contracts/Factory.json +21986 -0
  19. package/abis/contracts/FarmingPool.json +8601 -0
  20. package/abis/contracts/IBDeployer.json +351 -0
  21. package/abis/contracts/IBorrowTracker.json +346 -0
  22. package/abis/contracts/IBorrowable.json +13207 -0
  23. package/abis/contracts/ICDeployer.json +294 -0
  24. package/abis/contracts/IClaimable.json +406 -0
  25. package/abis/contracts/ICollateral.json +8952 -0
  26. package/abis/contracts/IERC20.json +2376 -0
  27. package/abis/contracts/IFactory.json +3660 -0
  28. package/abis/contracts/IFarmingPool.json +3584 -0
  29. package/abis/contracts/IImpermaxCallee.json +679 -0
  30. package/abis/contracts/IMerkleDistributor.json +1134 -0
  31. package/abis/contracts/IPoolToken.json +5343 -0
  32. package/abis/contracts/IRouter01.json +6891 -0
  33. package/abis/contracts/IRouter02.json +7283 -0
  34. package/abis/contracts/ISimpleUniswapOracle.json +1469 -0
  35. package/abis/contracts/IStakedLPToken.json +7309 -0
  36. package/abis/contracts/IStakingRewards.json +1036 -0
  37. package/abis/contracts/IUniswapV2Callee.json +403 -0
  38. package/abis/contracts/IUniswapV2ERC20.json +3155 -0
  39. package/abis/contracts/IUniswapV2Factory.json +1690 -0
  40. package/abis/contracts/IUniswapV2Pair.json +6761 -0
  41. package/abis/contracts/IWETH.json +561 -0
  42. package/abis/contracts/ImpermaxChef.json +20945 -0
  43. package/abis/contracts/ImpermaxERC20.json +12095 -0
  44. package/abis/contracts/Math.json +1966 -0
  45. package/abis/contracts/MockERC20.json +8884 -0
  46. package/abis/contracts/PoolToken.json +10784 -0
  47. package/abis/contracts/Router01.json +43963 -0
  48. package/abis/contracts/SafeMath.json +6828 -0
  49. package/abis/contracts/SimpleUniswapOracle.json +9640 -0
  50. package/abis/contracts/TransferHelper.json +4875 -0
  51. package/abis/contracts/UQ112x112.json +1201 -0
  52. package/abis/contracts/UniswapV2ERC20.json +10969 -0
  53. package/abis/contracts/UniswapV2Factory.json +5521 -0
  54. package/abis/contracts/UniswapV2Library.json +13789 -0
  55. package/abis/contracts/UniswapV2Pair.json +30782 -0
  56. package/abis/contracts/WETH9.json +6613 -0
  57. package/config/amms.ts +199 -0
  58. package/config/contracts/claim-aggregators.ts +16 -0
  59. package/config/contracts/impermax-chef.ts +16 -0
  60. package/config/contracts/imxes.ts +16 -0
  61. package/config/contracts/merkle-distributors.ts +13 -0
  62. package/config/contracts/routers.ts +36 -0
  63. package/config/contracts/simple-uniswap-oracles.ts +33 -0
  64. package/config/contracts/weths.ts +18 -0
  65. package/config/debank-ids.ts +15 -0
  66. package/config/endpoints/merkle-distributors.ts +13 -0
  67. package/config/eth.ts +32 -0
  68. package/config/factories.ts +26 -0
  69. package/config/farms.ts +119 -0
  70. package/config/general.ts +8 -0
  71. package/config/subgraphs.ts +69 -0
  72. package/config/types.ts +81 -0
  73. package/impermax-router/Account.ts +123 -0
  74. package/impermax-router/AccountBorrowable.ts +110 -0
  75. package/impermax-router/AccountCollateral.ts +40 -0
  76. package/impermax-router/AccountLendingPool.ts +231 -0
  77. package/impermax-router/AccountPoolToken.ts +76 -0
  78. package/impermax-router/Borrowable.ts +86 -0
  79. package/impermax-router/Collateral.ts +26 -0
  80. package/impermax-router/ContractsHelper.ts +64 -0
  81. package/impermax-router/ImpermaxFactory.ts +47 -0
  82. package/impermax-router/Interactions.ts +94 -0
  83. package/impermax-router/InteractionsLendingPool.ts +129 -0
  84. package/impermax-router/InteractionsPoolToken.ts +187 -0
  85. package/impermax-router/LendingPool.ts +256 -0
  86. package/impermax-router/PoolToken.ts +112 -0
  87. package/impermax-router/index.ts +49 -0
  88. package/impermax-router/interfaces.ts +233 -0
  89. package/index.ts +5 -0
  90. package/package.json +23 -0
  91. package/subgraph/Account.ts +93 -0
  92. package/subgraph/AccountLendingPool.ts +60 -0
  93. package/subgraph/AccountPoolToken.ts +60 -0
  94. package/subgraph/LendingPool.ts +179 -0
  95. package/subgraph/PoolToken.ts +381 -0
  96. package/subgraph/PriceHelper.ts +150 -0
  97. package/subgraph/SolidexHelper.ts +54 -0
  98. package/subgraph/index.ts +166 -0
  99. package/subgraph/initializer.ts +509 -0
  100. package/subgraph/query.ts +224 -0
  101. package/tsconfig.json +16 -0
  102. package/utils/ether-utils.ts +22 -0
  103. package/utils/index.ts +12 -0
@@ -0,0 +1,381 @@
1
+ import { BorrowableData, PoolTokenData, BorrowablePastData } from "../impermax-router/interfaces";
2
+ import { toAPR } from "../utils";
3
+
4
+ import LendingPool from "./LendingPool";
5
+ import { Address, PoolTokenType } from '../config/types';
6
+ import { ETH_NAME, ETH_SYMBOL } from '../config/eth';
7
+ import { IMX } from '../config/contracts/imxes';
8
+ import { WETH } from '../config/contracts/weths';
9
+
10
+ export default class PoolToken {
11
+ lendingPool: LendingPool;
12
+ poolTokenType: PoolTokenType;
13
+
14
+ constructor(lendingPool: LendingPool, poolTokenType: PoolTokenType) {
15
+ this.lendingPool = lendingPool;
16
+ this.poolTokenType = poolTokenType;
17
+ }
18
+
19
+ // Subgraph calls
20
+ async getPoolTokenData() : Promise<PoolTokenData> {
21
+ const lendingPoolData = await this.lendingPool.getLendingPoolData();
22
+ return lendingPoolData[this.poolTokenType];
23
+ }
24
+
25
+ // Helpers
26
+ private async getPoolTokenParam(param: string) : Promise<string> {
27
+ const poolTokenData = await this.getPoolTokenData() as any;
28
+ return poolTokenData[param];
29
+ }
30
+ private async getPoolTokenParamFloat(param: string) : Promise<number> {
31
+ return parseFloat(await this.getPoolTokenParam(param));
32
+ }
33
+ private async getUnderlyingParam(param: string) : Promise<string> {
34
+ const poolTokenData = await this.getPoolTokenData() as any;
35
+ return poolTokenData.underlying[param];
36
+ }
37
+
38
+ // Name
39
+ async getName() : Promise<string> {
40
+ if (this.poolTokenType == PoolTokenType.Collateral) {
41
+ const nameA = await this.lendingPool.poolTokens[PoolTokenType.BorrowableA].getName();
42
+ const nameB = await this.lendingPool.poolTokens[PoolTokenType.BorrowableB].getName();
43
+ return nameA + '-' + nameB + ' LP';
44
+ }
45
+ const underlying = await this.getUnderlyingAddress();
46
+ if (underlying.toLowerCase() === WETH[this.lendingPool.subgraph.network].toLowerCase()) return ETH_NAME[this.lendingPool.subgraph.network];
47
+ if (underlying.toLowerCase() === "0xa3fa99a148fa48d14ed51d610c367c61876997f1") return "MIMATIC";
48
+ if (underlying.toLowerCase() === "0x2e9a6df78e42a30712c10a9dc4b1c8656f8f2879") return "Maker";
49
+ return this.getUnderlyingParam("name");
50
+ }
51
+
52
+ // Symbol
53
+ async getSymbol() : Promise<string> {
54
+ if (this.poolTokenType == PoolTokenType.Collateral) {
55
+ const symbolA = await this.lendingPool.poolTokens[PoolTokenType.BorrowableA].getSymbol();
56
+ const symbolB = await this.lendingPool.poolTokens[PoolTokenType.BorrowableB].getSymbol();
57
+ return symbolA + '-' + symbolB;
58
+ }
59
+ const underlying = await this.getUnderlyingAddress();
60
+ if (underlying.toLowerCase() === WETH[this.lendingPool.subgraph.network].toLowerCase()) return ETH_SYMBOL[this.lendingPool.subgraph.network];
61
+ if (underlying.toLowerCase() === "0xa3fa99a148fa48d14ed51d610c367c61876997f1") return "MAI";
62
+ if (underlying.toLowerCase() === "0x2e9a6df78e42a30712c10a9dc4b1c8656f8f2879") return "MKR";
63
+ if (underlying.toLowerCase() === "0xc165d941481e68696f43ee6e99bfb2b23e0e3114") return "OXDv1";
64
+ if (underlying.toLowerCase() === "0xc5a9848b9d145965d821aaec8fa32aaee026492d") return "OXDv2";
65
+ if (underlying.toLowerCase() === "0x6ae7dfc73e0dde2aa99ac063dcf7e8a63265108c") return "JPYCv1";
66
+ if (underlying.toLowerCase() === "0x431d5dff03120afa4bdf332c61a6e1766ef37bdb") return "JPYCv2";
67
+ return this.getUnderlyingParam("symbol");
68
+ }
69
+
70
+ // Decimals
71
+ async getDecimals() : Promise<number> {
72
+ if (this.poolTokenType == PoolTokenType.Collateral) return 18;
73
+ return parseInt(await this.getUnderlyingParam("decimals"));
74
+ }
75
+
76
+ // ExchangeRate
77
+ async getExchangeRate() : Promise<number> {
78
+ return this.getPoolTokenParamFloat("exchangeRate");
79
+ }
80
+
81
+ // Underlying Address
82
+ async getUnderlyingAddress() : Promise<Address> {
83
+ if (this.poolTokenType == PoolTokenType.Collateral) return this.lendingPool.pairAddress;
84
+ return this.getUnderlyingParam("id");
85
+ }
86
+
87
+ // Total balance
88
+ async getTotalBalance() : Promise<number> {
89
+ return this.getPoolTokenParamFloat("totalBalance");
90
+ }
91
+ async getTotalBalanceUSD() : Promise<number> {
92
+ const totalBalance = await this.getTotalBalance();
93
+ const tokenPrice = await this.getTokenPriceFast();
94
+ return totalBalance * tokenPrice;
95
+ }
96
+
97
+ // Reserve Factor
98
+ async getReserveFactor() : Promise<number> {
99
+ return this.getPoolTokenParamFloat("reserveFactor");
100
+ }
101
+
102
+ // Kink Borrow Rate
103
+ async getKinkBorrowRate() : Promise<number> {
104
+ return this.getPoolTokenParamFloat("kinkBorrowRate");
105
+ }
106
+
107
+ // Kink Utilization Rate
108
+ async getKinkUtilizationRate() : Promise<number> {
109
+ return this.getPoolTokenParamFloat("kinkUtilizationRate");
110
+ }
111
+
112
+ // Borrow Index
113
+ async getBorrowIndex() : Promise<number> {
114
+ return this.getPoolTokenParamFloat("borrowIndex");
115
+ }
116
+
117
+ // Accrue Timestamp
118
+ async getAccrualTimestamp() : Promise<number> {
119
+ return this.getPoolTokenParamFloat("accrualTimestamp");
120
+ }
121
+
122
+ // Total borrows
123
+ async getTotalBorrows() : Promise<number> {
124
+ return this.getPoolTokenParamFloat("totalBorrows");
125
+ }
126
+ async getCurrentTotalBorrows() : Promise<number> {
127
+ const storedAmount = await this.getTotalBorrows();
128
+ const accrualTimestamp = await this.getAccrualTimestamp();
129
+ const borrowRate = await this.getBorrowRate();
130
+ return storedAmount * (1 + (Date.now() / 1000 - accrualTimestamp) * borrowRate);
131
+ }
132
+ async getTotalBorrowsUSD() : Promise<number> {
133
+ const totalBorrows = await this.getCurrentTotalBorrows();
134
+ const tokenPrice = await this.getTokenPriceFast();
135
+ return totalBorrows * tokenPrice;
136
+ }
137
+
138
+ // Borrow rate
139
+ async getBorrowRate() : Promise<number> {
140
+ return this.getPoolTokenParamFloat("borrowRate");
141
+ }
142
+ async getBorrowAPR() : Promise<number> {
143
+ const borrowRate = await this.getBorrowRate();
144
+ return toAPR(borrowRate);
145
+ }
146
+ async getNextBorrowRate(borrowAmount: number) : Promise<number> {
147
+ const totalBorrows = await this.getTotalBorrows();
148
+ const supply = await this.getSupply();
149
+ const UR = (borrowAmount + totalBorrows) / supply;
150
+ const kinkBR = await this.getKinkBorrowRate();
151
+ const kinkUR = await this.getKinkUtilizationRate();
152
+ if (UR < kinkUR) return UR / kinkUR * kinkBR;
153
+ const kinkMultiplier = this.lendingPool.getKinkMultiplier();
154
+ return ((UR - kinkUR) / (1 - kinkUR) * (kinkMultiplier - 1) + 1) * kinkBR;
155
+ }
156
+ async getNextBorrowAPR(borrowAmount: number) : Promise<number> {
157
+ const borrowRate = await this.getNextBorrowRate(borrowAmount);
158
+ return toAPR(borrowRate);
159
+ }
160
+
161
+ // Supply
162
+ async getSupply() : Promise<number> {
163
+ const totalBalance = await this.getTotalBalance();
164
+ const totalBorrows = await this.getTotalBorrows();
165
+ return totalBalance + totalBorrows;
166
+ }
167
+ async getCurrentSupply() : Promise<number> {
168
+ const storedAmount = await this.getSupply();
169
+ const accrualTimestamp = await this.getAccrualTimestamp();
170
+ const supplyRate = await this.getSupplyRate();
171
+ return storedAmount * (1 + (Date.now() / 1000 - accrualTimestamp) * supplyRate);
172
+ }
173
+ async getSupplyUSD() : Promise<number> {
174
+ const supply = await this.getCurrentSupply();
175
+ const tokenPrice = await this.getTokenPriceFast();
176
+ return supply * tokenPrice;
177
+ }
178
+
179
+ // Utilization Rate
180
+ async getUtilizationRate() : Promise<number> {
181
+ const supply = await this.getSupply();
182
+ if (supply == 0) return 0;
183
+ const totalBalance = await this.getTotalBorrows();
184
+ return totalBalance / supply;
185
+ }
186
+
187
+ // Supply Rate
188
+ async getSupplyRate() : Promise<number> {
189
+ const borrowRate = await this.getBorrowRate();
190
+ const utilizationRate = await this.getUtilizationRate();
191
+ const reserveFactor = await this.getReserveFactor();
192
+ return borrowRate * utilizationRate * (1 - reserveFactor);
193
+ }
194
+ async getSupplyAPR() : Promise<number> {
195
+ const supplyRate = await this.getSupplyRate();
196
+ return toAPR(supplyRate);
197
+ }
198
+ async getNextSupplyRate(supplyAmount: number) : Promise<number> {
199
+ const totalBorrows = await this.getTotalBorrows();
200
+ const supply = await this.getSupply();
201
+ const UR = totalBorrows / (supply + supplyAmount);
202
+ const kinkBR = await this.getKinkBorrowRate();
203
+ const kinkUR = await this.getKinkUtilizationRate();
204
+ const reserveFactor = await this.getReserveFactor();
205
+ if (UR < kinkUR) return UR / kinkUR * kinkBR * UR * (1 - reserveFactor);
206
+ const kinkMultiplier = this.lendingPool.getKinkMultiplier();
207
+ return ((UR - kinkUR) / (1 - kinkUR) * (kinkMultiplier - 1) + 1) * kinkBR * UR * (1 - reserveFactor);
208
+ }
209
+ async getNextSupplyAPR(supplyAmount: number) : Promise<number> {
210
+ const supplyRate = await this.getNextSupplyRate(supplyAmount);
211
+ return toAPR(supplyRate);
212
+ }
213
+
214
+ // Reward Speed
215
+ async getFarmingRewardsRate() : Promise<Array<{
216
+ rewardToken: string,
217
+ rewardRate: number
218
+ }>> {
219
+ const poolTokenData = await this.getPoolTokenData() as BorrowableData;
220
+ const rewards = poolTokenData.rewards;
221
+ if (rewards && rewards.length > 0) return rewards;
222
+
223
+ const FINISH_DELAY = 3600 * 24;
224
+ const farmingPoolData = poolTokenData.farmingPool;
225
+ if (farmingPoolData === null) return [];
226
+ const segmentLength = parseInt(farmingPoolData.segmentLength);
227
+ const epochAmount = parseFloat(farmingPoolData.epochAmount);
228
+ const epochBegin = parseInt(farmingPoolData.epochBegin);
229
+ const epochEnd = epochBegin + segmentLength;
230
+ const timestamp = (new Date()).getTime() / 1000;
231
+ if (timestamp - FINISH_DELAY > epochEnd) {
232
+ // How to manage better this case? Maybe check shares on distributor
233
+ return [];
234
+ }
235
+ return [{
236
+ rewardToken: IMX[this.lendingPool.subgraph.network],
237
+ rewardRate: epochAmount / segmentLength
238
+ }];
239
+ }
240
+
241
+ // Farming
242
+ async getFarmingRewards() : Promise<Array<{
243
+ APR: number,
244
+ symbol: string,
245
+ }>> {
246
+ return this.getNextFarmingRewards(0);
247
+ }
248
+ async getNextFarmingRewards(borrowAmount: number) : Promise<Array<{
249
+ APR: number,
250
+ symbol: string,
251
+ }>> {
252
+ const farmingRewards = await this.getFarmingRewardsRate();
253
+ const currentBorrowedUSD = await this.getTotalBorrowsUSD();
254
+ const tokenPrice = await this.getTokenPriceFast();
255
+ const additionalBorrowsUSD = borrowAmount * tokenPrice;
256
+ const totalBorrowedUSD = currentBorrowedUSD + additionalBorrowsUSD;
257
+ if (totalBorrowedUSD === 0) return [];
258
+
259
+ const rewards = [];
260
+ for(const reward of farmingRewards) {
261
+ const rewardPrice = await this.lendingPool.subgraph.priceHelper.getDebankTokenPrice(reward.rewardToken);
262
+ rewards.push({
263
+ APR: toAPR((rewardPrice * reward.rewardRate) / totalBorrowedUSD),
264
+ symbol:
265
+ reward.rewardToken == "0x98878b06940ae243284ca214f92bb71a2b032b8a" ? "WMOVR" :
266
+ reward.rewardToken == "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270" ? "WMATIC" :
267
+ "IMX",
268
+ });
269
+ }
270
+ return rewards;
271
+ }
272
+ async getFarmingAPR() : Promise<number> {
273
+ return this.getNextFarmingAPR(0);
274
+ }
275
+ async getNextFarmingAPR(borrowAmount: number) : Promise<number> {
276
+ const rewards = await this.getNextFarmingRewards(borrowAmount);
277
+ let APR = 0;
278
+ for (const reward of rewards) {
279
+ APR += reward.APR
280
+ }
281
+ return APR;
282
+ }
283
+
284
+ // Past Data
285
+ async getPoolTokenDataPast24h() : Promise<BorrowablePastData> {
286
+ const lendingPoolDataPast = await this.lendingPool.getLendingPoolDataPast24h();
287
+ if (!lendingPoolDataPast) return undefined;
288
+ return lendingPoolDataPast[this.poolTokenType];
289
+ }
290
+ async getPoolTokenDataPast7d() : Promise<BorrowablePastData> {
291
+ const lendingPoolDataPast = await this.lendingPool.getLendingPoolDataPast7d();
292
+ if (!lendingPoolDataPast) return undefined;
293
+ return lendingPoolDataPast[this.poolTokenType];
294
+ }
295
+
296
+ // Average Borrow APR
297
+ private async getAverageBorrowAPR(poolTokenDataPast: BorrowablePastData, fallback: Promise<number>) : Promise<number> {
298
+ if (poolTokenDataPast) {
299
+ const accrualTimestampPast = parseFloat(poolTokenDataPast.accrualTimestamp);
300
+ const borrowIndexPast = parseFloat(poolTokenDataPast.borrowIndex);
301
+ const accrualTimestampNow = await this.getAccrualTimestamp();
302
+ const borrowIndexNow = await this.getBorrowIndex();
303
+ if (accrualTimestampNow > accrualTimestampPast) {
304
+ const borrowRate = (borrowIndexNow / borrowIndexPast - 1) / (accrualTimestampNow - accrualTimestampPast);
305
+ return borrowRate * 3600 * 24 * 365;
306
+ }
307
+ }
308
+ return fallback;
309
+ }
310
+ async getAverage24hBorrowAPR() : Promise<number> {
311
+ const poolTokenDataPast = await this.getPoolTokenDataPast24h();
312
+ return this.getAverageBorrowAPR(poolTokenDataPast, this.getBorrowAPR());
313
+ }
314
+ async getAverage7dBorrowAPR() : Promise<number> {
315
+ const poolTokenDataPast = await this.getPoolTokenDataPast7d();
316
+ return this.getAverageBorrowAPR(poolTokenDataPast, this.getAverage24hBorrowAPR());
317
+ }
318
+
319
+ // Average Supply APR
320
+ private async getAverageSupplyAPR(poolTokenDataPast: BorrowablePastData, fallback: Promise<number>) : Promise<number> {
321
+ if (poolTokenDataPast) {
322
+ const accrualTimestampPast = parseFloat(poolTokenDataPast.accrualTimestamp);
323
+ const exchangeRatePast = parseFloat(poolTokenDataPast.exchangeRate);
324
+ const accrualTimestampNow = await this.getAccrualTimestamp();
325
+ const exchangeRateNow = await this.getExchangeRate();
326
+ if (accrualTimestampNow > accrualTimestampPast) {
327
+ const supplyRate = (exchangeRateNow / exchangeRatePast - 1) / (accrualTimestampNow - accrualTimestampPast);
328
+ return supplyRate * 3600 * 24 * 365;
329
+ }
330
+ }
331
+ return fallback;
332
+ }
333
+ async getAverage24hSupplyAPR() : Promise<number> {
334
+ const poolTokenDataPast = await this.getPoolTokenDataPast24h();
335
+ return this.getAverageSupplyAPR(poolTokenDataPast, this.getSupplyAPR());
336
+ }
337
+ async getAverage7dSupplyAPR() : Promise<number> {
338
+ const poolTokenDataPast = await this.getPoolTokenDataPast7d();
339
+ return this.getAverageSupplyAPR(poolTokenDataPast, this.getAverage24hSupplyAPR());
340
+ }
341
+
342
+ // Calculate collateral price -> returns the price of the collateral, not necessarily of the underlying LP
343
+ calculateCollateralPrice(reserve0: number, reserve1: number, totalSupply: number, price0: number, price1: number) : number {
344
+ if (totalSupply === 0) {
345
+ console.error("Warning: totalSupply is 0");
346
+ return 0;
347
+ }
348
+ const reserve0USD = reserve0 * price0;
349
+ const reserve1USD = reserve1 * price1;
350
+ // adjust reserves taking the latest price passed as parameters
351
+ const adjustedReserveUSD = Math.sqrt(reserve0USD * reserve1USD) * 2;
352
+ return adjustedReserveUSD / totalSupply;
353
+ }
354
+
355
+ // Token price getters
356
+ async getTokenPriceFast(fallback: boolean = true) : Promise<number> {
357
+ let tokenPrice = 0;
358
+ if (this.poolTokenType != PoolTokenType.Collateral) {
359
+ //const poolTokenData = await this.getPoolTokenData() as BorrowableData;
360
+ //tokenPrice = parseFloat(poolTokenData.underlying.derivedUSD);
361
+ let tokenAddress = await this.getUnderlyingAddress();
362
+ let tokenPrices = await this.lendingPool.subgraph.priceHelper.getSubgraphTokenPrice();
363
+ tokenPrice = tokenPrices[tokenAddress];
364
+ } else {
365
+ tokenPrice = await this.lendingPool.getCollateralPrice(false)
366
+ }
367
+ if (tokenPrice > 0) return tokenPrice;
368
+ if (fallback) {
369
+ return this.getTokenPriceAccurate();
370
+ }
371
+ return 0;
372
+ }
373
+ async getTokenPriceAccurate() : Promise<number> {
374
+ if (this.poolTokenType === PoolTokenType.Collateral) {
375
+ return this.lendingPool.getCollateralPrice(false)
376
+ }
377
+ let tokenAddress = await this.getUnderlyingAddress();
378
+ return this.lendingPool.subgraph.priceHelper.getDebankTokenPrice(tokenAddress);
379
+ }
380
+
381
+ }
@@ -0,0 +1,150 @@
1
+ import Subgraph from ".";
2
+ import { DEBANK_IDS } from '../config/debank-ids';
3
+ import { Address, Factory } from '../config/types';
4
+ import { IMX } from '../config/contracts/imxes';
5
+
6
+ // coingecko has priority over debank for initialized tokens
7
+ const coingecko_ids : {[key in Address]: string} = {
8
+ // Arbitrum
9
+ "0xb348b87b23d5977e2948e6f36ca07e1ec94d7328": "swapfish",
10
+ "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f": "wrapped-bitcoin",
11
+ }
12
+
13
+ export default class PriceHelper {
14
+ subgraph: Subgraph;
15
+ subgraphTokenPrice: Promise<{
16
+ [key in Address]?: number
17
+ }>;
18
+ debankTokenPrice: {
19
+ [key in Address]?: Promise<number>
20
+ };
21
+
22
+ constructor(subgraph: Subgraph) {
23
+ this.subgraph = subgraph;
24
+ this.debankTokenPrice = {};
25
+ }
26
+
27
+ cleanCache() {
28
+ this.subgraphTokenPrice = null;
29
+ this.debankTokenPrice = {};
30
+ }
31
+
32
+ // First source of token price: Subgraph (less accurate, faster)
33
+
34
+ private async initializeSubgraphTokenPrice() : Promise<{[key in Address]: number}> {
35
+ const lendingPoolsData = await this.subgraph.getLendingPoolsData();
36
+ const subgraphTokenPrice: {[key in Address]: number} = {};
37
+ for (const factory of Object.keys(lendingPoolsData) as Factory[]) {
38
+ for (const id of Object.keys(lendingPoolsData[factory]) as Address[]) {
39
+ const lendingPool = lendingPoolsData[factory][id];
40
+ subgraphTokenPrice[lendingPool.borrowable0.underlying.id] = parseFloat(lendingPool.borrowable0.underlying.derivedUSD);
41
+ subgraphTokenPrice[lendingPool.borrowable1.underlying.id] = parseFloat(lendingPool.borrowable1.underlying.derivedUSD);
42
+ for (const reward of lendingPool.pair.rewards) {
43
+ subgraphTokenPrice[reward.rewardsToken.id] = parseFloat(reward.rewardsToken.derivedUSD);
44
+ }
45
+ }
46
+ }
47
+ //fix for IMX
48
+ subgraphTokenPrice["0x9c67ee39e3c4954396b9142010653f17257dd39c"] = 0;
49
+ subgraphTokenPrice["0x7b35ce522cb72e4077baeb96cb923a5529764a00"] = 0;
50
+ subgraphTokenPrice["0xea6887e4a9cda1b77e70129e5fba830cdb5cddef"] = 0;
51
+ subgraphTokenPrice["0x60bb3d364b765c497c8ce50ae0ae3f0882c5bd05"] = 0;
52
+ subgraphTokenPrice["0x900f1ec5819fa087d368877cd03b265bf1802667"] = 0;
53
+ subgraphTokenPrice["0xea38f1ccf77bf43f352636241b05dd8f6f5f52b2"] = 0;
54
+ return subgraphTokenPrice;
55
+ }
56
+ async getSubgraphTokenPrice() : Promise<{[key in Address]: number}> {
57
+ if (!this.subgraphTokenPrice) this.subgraphTokenPrice = this.initializeSubgraphTokenPrice();
58
+ return this.subgraphTokenPrice;
59
+ }
60
+
61
+ // Second source of token price: Debank (more accurate, slower)
62
+
63
+ private async getCoingeckoTokenPrice(tokenAddress: Address) : Promise<number> {
64
+ try {
65
+ const tokenId = coingecko_ids[tokenAddress];
66
+ const response = await fetch("https://api.coingecko.com/api/v3/simple/price?ids=" + tokenId + "&vs_currencies=usd");
67
+ if (response.status != 200) return 0;
68
+ const data = await response.json();
69
+ if (!data) return 0;
70
+ return data[tokenId].usd ? data[tokenId].usd : 0;
71
+ }
72
+ catch {
73
+ return 0;
74
+ }
75
+ }
76
+ private async initializeDebankTokenPrice(tokenAddress: Address) : Promise<number> {
77
+ if (Object.keys(coingecko_ids).includes(tokenAddress.toLowerCase())) {
78
+ const result = this.getCoingeckoTokenPrice(tokenAddress.toLowerCase());
79
+ if (result) return result;
80
+ }
81
+ try {
82
+ const response = await fetch("https://openapi.debank.com/v1/token?chain_id=" + DEBANK_IDS[this.subgraph.network] + "&id=" + tokenAddress);
83
+ /*const response = await fetch(
84
+ "https://pro-openapi.debank.com/v1/token?chain_id=" + debank_chain_ids[this.subgraph.network] + "&id=" + tokenAddress,
85
+ {headers: {"AccessKey": "0ac0fba6aeb0905b4c9a1c5cfd9d48d74fbc60e0"}}
86
+ );*/
87
+ if (response.status != 200) return 0;
88
+ const data = await response.json();
89
+ if (!data) return 0;
90
+ return data.price ? data.price : 0;
91
+ }
92
+ catch {
93
+ return 0;
94
+ }
95
+ }
96
+ async getDebankTokenPrice(tokenAddress: Address) : Promise<number> {
97
+ if (tokenAddress.toLowerCase() === '0xb348b87b23d5977e2948e6f36ca07e1ec94d7328') { // fix for FISH
98
+ //return 0.07;
99
+ }
100
+ if (tokenAddress.toLowerCase() === '0xf28164a485b0b2c90639e47b0f377b4a438a16b1') { // fix for dQuick
101
+ return (await this.getDebankTokenPrice('0x831753dd7087cac61ab5644b308642cc1c33dc13')) * 1.68;
102
+ }
103
+ if (tokenAddress.toLowerCase() === '0x63468133ed352e602beb61dd254d6060ad2fe419') { // fix for sTHO
104
+ return (await this.getDebankTokenPrice('0xae4aa155d2987b454c29450ef4f862cf00907b61')) * 1.1;
105
+ }
106
+ if (tokenAddress.toLowerCase() === '0xfcef8a994209d6916eb2c86cdd2afd60aa6f54b1') { // fix for fBEETS
107
+ return (await this.getDebankTokenPrice('0xf24bcf4d1e507740041c9cfd2dddb29585adce1e')) * 0.93;
108
+ }
109
+ if (tokenAddress.toLowerCase() === '0x5979d7b546e38e414f7e9822514be443a4800529') { // TEMPORARY fix for WSTETH
110
+ return (await this.getDebankTokenPrice('0x82af49447d8a07e3bd95bd0d56f35241523fbab1')) / 0.92;
111
+ }
112
+ if (tokenAddress.toLowerCase() === '0x3f56e0c36d275367b8c502090edf38289b3dea0d') { // TEMPORARY fix for MAI
113
+ return 1;
114
+ }
115
+ if ([
116
+ "0x9c67ee39e3c4954396b9142010653f17257dd39c",
117
+ "0x7b35ce522cb72e4077baeb96cb923a5529764a00",
118
+ "0xea6887e4a9cda1b77e70129e5fba830cdb5cddef",
119
+ "0x60bb3d364b765c497c8ce50ae0ae3f0882c5bd05",
120
+ "0x900f1ec5819fa087d368877cd03b265bf1802667",
121
+ "0xea38f1ccf77bf43f352636241b05dd8f6f5f52b2",
122
+ ].includes(tokenAddress.toLowerCase())) { // fix for IMX
123
+ return 0;
124
+ }
125
+ if (tokenAddress.toLowerCase() === '0xda0053f0befcbcac208a3f867bb243716734d809') { // TEMPORARY fix for oxSOLID
126
+ return (await this.getDebankTokenPrice('0x888ef71766ca594ded1f0fa3ae64ed2941740a20')) * 0.88;
127
+ }
128
+ if (tokenAddress.toLowerCase() === '0x431d5dff03120afa4bdf332c61a6e1766ef37bdb') { // TEMPORARY fix for JPYCv2
129
+ return (await this.getDebankTokenPrice('0x6ae7dfc73e0dde2aa99ac063dcf7e8a63265108c'));
130
+ }
131
+ if (!this.debankTokenPrice[tokenAddress]) this.debankTokenPrice[tokenAddress] = this.initializeDebankTokenPrice(tokenAddress);
132
+ const tokenPrice = await this.debankTokenPrice[tokenAddress];
133
+ if (tokenPrice === 0) {
134
+ // try fallback on subgraph
135
+ const subgraphTokenPrice = await this.getSubgraphTokenPrice();
136
+ return subgraphTokenPrice[tokenAddress] ? subgraphTokenPrice[tokenAddress] : 0;
137
+ }
138
+ return tokenPrice;
139
+ }
140
+
141
+ async getImxPrice() : Promise<number> {
142
+ const imx = IMX[this.subgraph.network];
143
+ if (!imx) return 0;
144
+ const imxPrice = await this.getDebankTokenPrice(imx);
145
+ if (imxPrice != 0) return imxPrice;
146
+ const subgraphTokenPrice = await this.getSubgraphTokenPrice();
147
+ if (subgraphTokenPrice[imx]) return subgraphTokenPrice[imx]
148
+ return 0;
149
+ }
150
+ }
@@ -0,0 +1,54 @@
1
+ import Subgraph from ".";
2
+ import { Address } from "../config/types";
3
+
4
+ export type SolidexLPDetails = {
5
+ [key in Address]: Array<{
6
+ APR: number,
7
+ symbol: string,
8
+ }>
9
+ }
10
+
11
+ export default class SolidexHelper {
12
+ subgraph: Subgraph;
13
+ solidexLPDetails: Promise<SolidexLPDetails>;
14
+
15
+ constructor(subgraph: Subgraph) {
16
+ this.subgraph = subgraph;
17
+ }
18
+
19
+ cleanCache() {
20
+ this.solidexLPDetails = null;
21
+ }
22
+
23
+ private async initializeSolidexLPDetails() : Promise<SolidexLPDetails> {
24
+ try {
25
+ const response = await fetch("https://api.solidexfinance.com/api/getLPDetails?v=fantom");
26
+ if (response.status != 200) return {};
27
+ const data = await response.json();
28
+ if (!data || !data.success) return {};
29
+ const solidexLPDetails: SolidexLPDetails = {};
30
+ for (const pool of data.data.poolDetailsAll) {
31
+ if (!pool.solidexTVL) continue;
32
+ solidexLPDetails[pool.poolAddress.toLowerCase()] = [
33
+ {
34
+ APR: pool.solidexTVL.realsolidAPR / 100,
35
+ symbol: "SOLID",
36
+ },
37
+ {
38
+ APR: pool.solidexTVL.realsexAPR / 100,
39
+ symbol: "SEX",
40
+ },
41
+ ]
42
+ }
43
+ return solidexLPDetails;
44
+ }
45
+ catch (e) {
46
+ return {};
47
+ }
48
+ }
49
+
50
+ async getSolidexLPDetails() : Promise<SolidexLPDetails> {
51
+ if (!this.solidexLPDetails) this.solidexLPDetails = this.initializeSolidexLPDetails();
52
+ return this.solidexLPDetails;
53
+ }
54
+ }