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.
- package/.idea/impermax-sdk.iml +12 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/workspace.xml +642 -0
- package/abis/ImpermaxABI.ts +3 -0
- package/abis/contracts/BAllowance.json +4735 -0
- package/abis/contracts/BDeployer.json +1195 -0
- package/abis/contracts/BInterestRateModel.json +10796 -0
- package/abis/contracts/BSetter.json +6219 -0
- package/abis/contracts/BStorage.json +2613 -0
- package/abis/contracts/Borrowable.json +19937 -0
- package/abis/contracts/CDeployer.json +1104 -0
- package/abis/contracts/CSetter.json +5094 -0
- package/abis/contracts/CStorage.json +516 -0
- package/abis/contracts/ClaimAggregator.json +2015 -0
- package/abis/contracts/Collateral.json +21615 -0
- package/abis/contracts/ERC20.json +819 -0
- package/abis/contracts/Factory.json +21986 -0
- package/abis/contracts/FarmingPool.json +8601 -0
- package/abis/contracts/IBDeployer.json +351 -0
- package/abis/contracts/IBorrowTracker.json +346 -0
- package/abis/contracts/IBorrowable.json +13207 -0
- package/abis/contracts/ICDeployer.json +294 -0
- package/abis/contracts/IClaimable.json +406 -0
- package/abis/contracts/ICollateral.json +8952 -0
- package/abis/contracts/IERC20.json +2376 -0
- package/abis/contracts/IFactory.json +3660 -0
- package/abis/contracts/IFarmingPool.json +3584 -0
- package/abis/contracts/IImpermaxCallee.json +679 -0
- package/abis/contracts/IMerkleDistributor.json +1134 -0
- package/abis/contracts/IPoolToken.json +5343 -0
- package/abis/contracts/IRouter01.json +6891 -0
- package/abis/contracts/IRouter02.json +7283 -0
- package/abis/contracts/ISimpleUniswapOracle.json +1469 -0
- package/abis/contracts/IStakedLPToken.json +7309 -0
- package/abis/contracts/IStakingRewards.json +1036 -0
- package/abis/contracts/IUniswapV2Callee.json +403 -0
- package/abis/contracts/IUniswapV2ERC20.json +3155 -0
- package/abis/contracts/IUniswapV2Factory.json +1690 -0
- package/abis/contracts/IUniswapV2Pair.json +6761 -0
- package/abis/contracts/IWETH.json +561 -0
- package/abis/contracts/ImpermaxChef.json +20945 -0
- package/abis/contracts/ImpermaxERC20.json +12095 -0
- package/abis/contracts/Math.json +1966 -0
- package/abis/contracts/MockERC20.json +8884 -0
- package/abis/contracts/PoolToken.json +10784 -0
- package/abis/contracts/Router01.json +43963 -0
- package/abis/contracts/SafeMath.json +6828 -0
- package/abis/contracts/SimpleUniswapOracle.json +9640 -0
- package/abis/contracts/TransferHelper.json +4875 -0
- package/abis/contracts/UQ112x112.json +1201 -0
- package/abis/contracts/UniswapV2ERC20.json +10969 -0
- package/abis/contracts/UniswapV2Factory.json +5521 -0
- package/abis/contracts/UniswapV2Library.json +13789 -0
- package/abis/contracts/UniswapV2Pair.json +30782 -0
- package/abis/contracts/WETH9.json +6613 -0
- package/config/amms.ts +199 -0
- package/config/contracts/claim-aggregators.ts +16 -0
- package/config/contracts/impermax-chef.ts +16 -0
- package/config/contracts/imxes.ts +16 -0
- package/config/contracts/merkle-distributors.ts +13 -0
- package/config/contracts/routers.ts +36 -0
- package/config/contracts/simple-uniswap-oracles.ts +33 -0
- package/config/contracts/weths.ts +18 -0
- package/config/debank-ids.ts +15 -0
- package/config/endpoints/merkle-distributors.ts +13 -0
- package/config/eth.ts +32 -0
- package/config/factories.ts +26 -0
- package/config/farms.ts +119 -0
- package/config/general.ts +8 -0
- package/config/subgraphs.ts +69 -0
- package/config/types.ts +81 -0
- package/impermax-router/Account.ts +123 -0
- package/impermax-router/AccountBorrowable.ts +110 -0
- package/impermax-router/AccountCollateral.ts +40 -0
- package/impermax-router/AccountLendingPool.ts +231 -0
- package/impermax-router/AccountPoolToken.ts +76 -0
- package/impermax-router/Borrowable.ts +86 -0
- package/impermax-router/Collateral.ts +26 -0
- package/impermax-router/ContractsHelper.ts +64 -0
- package/impermax-router/ImpermaxFactory.ts +47 -0
- package/impermax-router/Interactions.ts +94 -0
- package/impermax-router/InteractionsLendingPool.ts +129 -0
- package/impermax-router/InteractionsPoolToken.ts +187 -0
- package/impermax-router/LendingPool.ts +256 -0
- package/impermax-router/PoolToken.ts +112 -0
- package/impermax-router/index.ts +49 -0
- package/impermax-router/interfaces.ts +233 -0
- package/index.ts +5 -0
- package/package.json +23 -0
- package/subgraph/Account.ts +93 -0
- package/subgraph/AccountLendingPool.ts +60 -0
- package/subgraph/AccountPoolToken.ts +60 -0
- package/subgraph/LendingPool.ts +179 -0
- package/subgraph/PoolToken.ts +381 -0
- package/subgraph/PriceHelper.ts +150 -0
- package/subgraph/SolidexHelper.ts +54 -0
- package/subgraph/index.ts +166 -0
- package/subgraph/initializer.ts +509 -0
- package/subgraph/query.ts +224 -0
- package/tsconfig.json +16 -0
- package/utils/ether-utils.ts +22 -0
- 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
|
+
}
|