@evaafi/sdk 0.9.0-a → 0.9.1
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/dist/api/feeds.d.ts +15 -24
- package/dist/api/feeds.js +22 -49
- package/dist/api/math.d.ts +1 -1
- package/dist/api/math.js +55 -38
- package/dist/api/parser.d.ts +2 -2
- package/dist/api/parser.js +3 -3
- package/dist/api/parsers/PythOracleParser.d.ts +3 -3
- package/dist/api/parsers/PythOracleParser.js +2 -1
- package/dist/api/prices.js +2 -1
- package/dist/constants/general/index.d.ts +25 -11
- package/dist/constants/general/index.js +15 -1
- package/dist/constants/pools/mainnet.js +20 -18
- package/dist/constants/pools/testnet.js +14 -6
- package/dist/contracts/AbstractMaster.d.ts +239 -127
- package/dist/contracts/AbstractMaster.js +101 -16
- package/dist/contracts/ClassicMaster.d.ts +12 -12
- package/dist/contracts/PythMaster.d.ts +40 -24
- package/dist/contracts/PythMaster.js +61 -76
- package/dist/contracts/PythOracle.d.ts +16 -0
- package/dist/contracts/PythOracle.js +19 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{prices → oracles}/Types.d.ts +0 -4
- package/dist/oracles/collectors/AbstractCollector.d.ts +10 -0
- package/dist/oracles/collectors/AbstractCollector.js +6 -0
- package/dist/oracles/collectors/ClassicCollector.d.ts +22 -0
- package/dist/oracles/collectors/ClassicCollector.js +192 -0
- package/dist/oracles/collectors/PythCollector.d.ts +27 -0
- package/dist/oracles/collectors/PythCollector.js +252 -0
- package/dist/oracles/collectors/index.d.ts +3 -0
- package/dist/oracles/collectors/index.js +19 -0
- package/dist/{prices → oracles}/index.d.ts +2 -3
- package/dist/{prices → oracles}/index.js +2 -3
- package/dist/oracles/prices/AbstractPrices.d.ts +33 -0
- package/dist/oracles/prices/AbstractPrices.js +40 -0
- package/dist/oracles/prices/ClassicPrices.d.ts +19 -0
- package/dist/oracles/prices/ClassicPrices.js +48 -0
- package/dist/oracles/prices/PythPrices.d.ts +18 -0
- package/dist/oracles/prices/PythPrices.js +32 -0
- package/dist/oracles/prices/index.d.ts +3 -0
- package/dist/oracles/prices/index.js +19 -0
- package/dist/{prices → oracles}/utils.d.ts +6 -1
- package/dist/{prices → oracles}/utils.js +10 -1
- package/dist/types/Master.d.ts +4 -5
- package/package.json +2 -3
- package/src/api/feeds.ts +24 -60
- package/src/api/math.ts +118 -90
- package/src/api/parser.ts +5 -5
- package/src/api/parsers/PythOracleParser.ts +6 -2
- package/src/api/prices.ts +2 -1
- package/src/constants/general/index.ts +16 -1
- package/src/constants/pools/mainnet.ts +20 -35
- package/src/constants/pools/testnet.ts +17 -8
- package/src/contracts/AbstractMaster.ts +272 -144
- package/src/contracts/ClassicMaster.ts +12 -12
- package/src/contracts/PythMaster.ts +130 -123
- package/src/contracts/PythOracle.ts +20 -0
- package/src/contracts/index.ts +2 -0
- package/src/index.ts +1 -1
- package/src/{prices → oracles}/Types.ts +0 -5
- package/src/oracles/collectors/AbstractCollector.ts +22 -0
- package/src/oracles/collectors/ClassicCollector.ts +263 -0
- package/src/oracles/collectors/PythCollector.ts +358 -0
- package/src/oracles/collectors/index.ts +3 -0
- package/src/{prices → oracles}/index.ts +2 -3
- package/src/oracles/prices/AbstractPrices.ts +59 -0
- package/src/oracles/prices/ClassicPrices.ts +52 -0
- package/src/oracles/prices/PythPrices.ts +40 -0
- package/src/oracles/prices/index.ts +3 -0
- package/src/{prices → oracles}/utils.ts +12 -1
- package/src/types/Master.ts +4 -6
- package/dist/prices/Oracle.interface.d.ts +0 -9
- package/dist/prices/Oracle.interface.js +0 -2
- package/dist/prices/Prices.d.ts +0 -11
- package/dist/prices/Prices.js +0 -53
- package/dist/prices/PricesCollector.d.ts +0 -22
- package/dist/prices/PricesCollector.js +0 -146
- package/dist/prices/PythCollector.d.ts +0 -22
- package/dist/prices/PythCollector.js +0 -217
- package/src/prices/Oracle.interface.ts +0 -18
- package/src/prices/Prices.ts +0 -45
- package/src/prices/PricesCollector.ts +0 -169
- package/src/prices/PythCollector.ts +0 -294
- /package/dist/{prices → oracles}/Types.js +0 -0
- /package/dist/{prices → oracles}/constants.d.ts +0 -0
- /package/dist/{prices → oracles}/constants.js +0 -0
- /package/dist/{prices → oracles}/sources/Backend.d.ts +0 -0
- /package/dist/{prices → oracles}/sources/Backend.js +0 -0
- /package/dist/{prices → oracles}/sources/Icp.d.ts +0 -0
- /package/dist/{prices → oracles}/sources/Icp.js +0 -0
- /package/dist/{prices → oracles}/sources/PriceSource.d.ts +0 -0
- /package/dist/{prices → oracles}/sources/PriceSource.js +0 -0
- /package/dist/{prices → oracles}/sources/index.d.ts +0 -0
- /package/dist/{prices → oracles}/sources/index.js +0 -0
- /package/src/{prices → oracles}/constants.ts +0 -0
- /package/src/{prices → oracles}/sources/Backend.ts +0 -0
- /package/src/{prices → oracles}/sources/Icp.ts +0 -0
- /package/src/{prices → oracles}/sources/PriceSource.ts +0 -0
- /package/src/{prices → oracles}/sources/index.ts +0 -0
package/src/api/math.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Dictionary } from '@ton/core';
|
|
2
|
+
import { UNDEFINED_ASSET } from '../constants/assets';
|
|
1
3
|
import {
|
|
2
4
|
AgregatedBalances,
|
|
3
5
|
AssetApy,
|
|
@@ -8,9 +10,8 @@ import {
|
|
|
8
10
|
ExtendedAssetsConfig,
|
|
9
11
|
ExtendedAssetsData,
|
|
10
12
|
MasterConstants,
|
|
11
|
-
PoolConfig
|
|
13
|
+
PoolConfig,
|
|
12
14
|
} from '../types/Master';
|
|
13
|
-
import { Dictionary } from '@ton/core';
|
|
14
15
|
import {
|
|
15
16
|
BalanceChangeType,
|
|
16
17
|
BalanceType,
|
|
@@ -18,9 +19,8 @@ import {
|
|
|
18
19
|
LiquidationData,
|
|
19
20
|
PredictAPYArgs,
|
|
20
21
|
PredictHealthFactorArgs,
|
|
21
|
-
UserBalance
|
|
22
|
+
UserBalance,
|
|
22
23
|
} from '../types/User';
|
|
23
|
-
import { UNDEFINED_ASSET } from '../constants/assets';
|
|
24
24
|
import { addReserve, isBadDebt } from './liquidation';
|
|
25
25
|
|
|
26
26
|
export function mulFactor(decimal: bigint, a: bigint, b: bigint): bigint {
|
|
@@ -61,9 +61,13 @@ export function getAssetLiquidityMinusReserves(assetData: AssetData, masterConst
|
|
|
61
61
|
return bigIntMin(total_supply - total_borrow, assetData.balance);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export function calculateCurrentRates(
|
|
64
|
+
export function calculateCurrentRates(
|
|
65
|
+
assetConfig: AssetConfig,
|
|
66
|
+
assetData: AssetData,
|
|
67
|
+
masterConstants: MasterConstants,
|
|
68
|
+
) {
|
|
65
69
|
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
66
|
-
const timeElapsed = now - assetData.
|
|
70
|
+
const timeElapsed = now - assetData.lastAccrual;
|
|
67
71
|
const { supplyInterest, borrowInterest } = calculateAssetInterest(assetConfig, assetData, masterConstants);
|
|
68
72
|
|
|
69
73
|
if (timeElapsed > 0) {
|
|
@@ -76,7 +80,7 @@ export function calculateCurrentRates(assetConfig: AssetConfig, assetData: Asset
|
|
|
76
80
|
bRate: updatedBRate,
|
|
77
81
|
supplyInterest,
|
|
78
82
|
borrowInterest,
|
|
79
|
-
now
|
|
83
|
+
now,
|
|
80
84
|
};
|
|
81
85
|
}
|
|
82
86
|
|
|
@@ -85,7 +89,7 @@ export function calculateCurrentRates(assetConfig: AssetConfig, assetData: Asset
|
|
|
85
89
|
bRate: assetData.bRate,
|
|
86
90
|
supplyInterest,
|
|
87
91
|
borrowInterest,
|
|
88
|
-
now
|
|
92
|
+
now,
|
|
89
93
|
};
|
|
90
94
|
}
|
|
91
95
|
|
|
@@ -93,7 +97,7 @@ export function calculateAssetData(
|
|
|
93
97
|
assetsConfigDict: ExtendedAssetsConfig,
|
|
94
98
|
assetsDataDict: Dictionary<bigint, AssetData>,
|
|
95
99
|
assetId: bigint,
|
|
96
|
-
masterConstants: MasterConstants
|
|
100
|
+
masterConstants: MasterConstants,
|
|
97
101
|
): ExtendedAssetData {
|
|
98
102
|
const config = assetsConfigDict.get(assetId);
|
|
99
103
|
const data = assetsDataDict.get(assetId);
|
|
@@ -105,7 +109,7 @@ export function calculateAssetData(
|
|
|
105
109
|
const { sRate, bRate, supplyInterest, borrowInterest, now } = calculateCurrentRates(config, data, masterConstants);
|
|
106
110
|
data.sRate = sRate || 0n;
|
|
107
111
|
data.bRate = bRate || 0n;
|
|
108
|
-
data.
|
|
112
|
+
data.lastAccrual = now;
|
|
109
113
|
|
|
110
114
|
const supplyApy = (1 + (Number(supplyInterest) / 1e12) * 24 * 3600) ** 365 - 1;
|
|
111
115
|
const borrowApy = (1 + (Number(borrowInterest) / 1e12) * 24 * 3600) ** 365 - 1;
|
|
@@ -113,31 +117,26 @@ export function calculateAssetData(
|
|
|
113
117
|
return {
|
|
114
118
|
...data,
|
|
115
119
|
...{ supplyInterest, borrowInterest },
|
|
116
|
-
...{ supplyApy, borrowApy }
|
|
120
|
+
...{ supplyApy, borrowApy },
|
|
117
121
|
};
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
export function calculateAssetInterest(
|
|
121
125
|
assetConfig: AssetConfig,
|
|
122
126
|
assetData: AssetData,
|
|
123
|
-
masterConstants: MasterConstants
|
|
127
|
+
masterConstants: MasterConstants,
|
|
124
128
|
): AssetInterest {
|
|
125
129
|
const totalSupply = calculatePresentValue(assetData.sRate, assetData.totalSupply, masterConstants);
|
|
126
130
|
const totalBorrow = calculatePresentValue(assetData.bRate, assetData.totalBorrow, masterConstants);
|
|
127
131
|
|
|
128
|
-
return calculateInterestWithSupplyBorrow(
|
|
129
|
-
totalSupply,
|
|
130
|
-
totalBorrow,
|
|
131
|
-
assetConfig,
|
|
132
|
-
masterConstants
|
|
133
|
-
);
|
|
132
|
+
return calculateInterestWithSupplyBorrow(totalSupply, totalBorrow, assetConfig, masterConstants);
|
|
134
133
|
}
|
|
135
134
|
|
|
136
135
|
export function calculateInterestWithSupplyBorrow(
|
|
137
136
|
totalSupply: bigint,
|
|
138
137
|
totalBorrow: bigint,
|
|
139
138
|
assetConfig: AssetConfig,
|
|
140
|
-
masterConstants: MasterConstants
|
|
139
|
+
masterConstants: MasterConstants,
|
|
141
140
|
): AssetInterest {
|
|
142
141
|
let utilization = 0n;
|
|
143
142
|
let supplyInterest = 0n;
|
|
@@ -158,25 +157,24 @@ export function calculateInterestWithSupplyBorrow(
|
|
|
158
157
|
mulFactor(
|
|
159
158
|
masterConstants.FACTOR_SCALE,
|
|
160
159
|
assetConfig.borrowRateSlopeHigh,
|
|
161
|
-
utilization - assetConfig.targetUtilization
|
|
160
|
+
utilization - assetConfig.targetUtilization,
|
|
162
161
|
);
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
supplyInterest = mulDiv(
|
|
166
165
|
mulDiv(borrowInterest, utilization, masterConstants.FACTOR_SCALE),
|
|
167
166
|
masterConstants.ASSET_RESERVE_FACTOR_SCALE - assetConfig.reserveFactor,
|
|
168
|
-
masterConstants.ASSET_RESERVE_FACTOR_SCALE
|
|
167
|
+
masterConstants.ASSET_RESERVE_FACTOR_SCALE,
|
|
169
168
|
);
|
|
170
169
|
|
|
171
170
|
return {
|
|
172
171
|
supplyInterest,
|
|
173
|
-
borrowInterest
|
|
172
|
+
borrowInterest,
|
|
174
173
|
};
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
|
|
178
176
|
export function checkNotInDebtAtAll(principals: Dictionary<bigint, bigint>): boolean {
|
|
179
|
-
return principals.values().every(x => x >= 0n);
|
|
177
|
+
return principals.values().every((x) => x >= 0n);
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
export function getAgregatedBalances(
|
|
@@ -184,14 +182,13 @@ export function getAgregatedBalances(
|
|
|
184
182
|
assetsConfig: ExtendedAssetsConfig,
|
|
185
183
|
principals: Dictionary<bigint, bigint>,
|
|
186
184
|
prices: Dictionary<bigint, bigint>,
|
|
187
|
-
masterConstants: MasterConstants
|
|
185
|
+
masterConstants: MasterConstants,
|
|
188
186
|
): AgregatedBalances {
|
|
189
187
|
let user_total_supply = 0n;
|
|
190
188
|
let user_total_borrow = 0n;
|
|
191
189
|
|
|
192
190
|
for (const [assetId, principal] of principals) {
|
|
193
191
|
if (principal) {
|
|
194
|
-
|
|
195
192
|
if (!prices.has(assetId)) {
|
|
196
193
|
return { totalSupply: 0n, totalBorrow: 0n };
|
|
197
194
|
}
|
|
@@ -200,9 +197,13 @@ export function getAgregatedBalances(
|
|
|
200
197
|
const assetConfig = assetsConfig.get(assetId)!;
|
|
201
198
|
|
|
202
199
|
if (principal < 0) {
|
|
203
|
-
user_total_borrow +=
|
|
200
|
+
user_total_borrow +=
|
|
201
|
+
(presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price) /
|
|
202
|
+
10n ** assetConfig.decimals;
|
|
204
203
|
} else {
|
|
205
|
-
user_total_supply +=
|
|
204
|
+
user_total_supply +=
|
|
205
|
+
(presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price) /
|
|
206
|
+
10n ** assetConfig.decimals;
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
}
|
|
@@ -215,7 +216,7 @@ export function calculateMaximumWithdrawAmount(
|
|
|
215
216
|
principals: Dictionary<bigint, bigint>,
|
|
216
217
|
prices: Dictionary<bigint, bigint>,
|
|
217
218
|
masterConstants: MasterConstants,
|
|
218
|
-
assetId: bigint
|
|
219
|
+
assetId: bigint,
|
|
219
220
|
): bigint {
|
|
220
221
|
let withdrawAmountMax = 0n;
|
|
221
222
|
|
|
@@ -240,19 +241,18 @@ export function calculateMaximumWithdrawAmount(
|
|
|
240
241
|
if (assetConfig.collateralFactor == 0n) {
|
|
241
242
|
maxAmountToReclaim = oldPresentValue.amount;
|
|
242
243
|
} else if (price > 0) {
|
|
243
|
-
maxAmountToReclaim =
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
244
|
+
maxAmountToReclaim = bigIntMax(
|
|
245
|
+
0n,
|
|
246
|
+
mulDiv(
|
|
247
|
+
mulDiv(borrowable, masterConstants.ASSET_COEFFICIENT_SCALE, assetConfig.collateralFactor),
|
|
248
|
+
10n ** assetConfig.decimals,
|
|
249
|
+
price,
|
|
250
|
+
) -
|
|
251
|
+
calculatePresentValue(assetData.sRate, assetConfig.dust, masterConstants) / 2n,
|
|
252
|
+
);
|
|
250
253
|
}
|
|
251
254
|
|
|
252
|
-
withdrawAmountMax = bigIntMin(
|
|
253
|
-
maxAmountToReclaim,
|
|
254
|
-
oldPresentValue.amount
|
|
255
|
-
);
|
|
255
|
+
withdrawAmountMax = bigIntMin(maxAmountToReclaim, oldPresentValue.amount);
|
|
256
256
|
}
|
|
257
257
|
} else {
|
|
258
258
|
if (!prices.has(assetId)) {
|
|
@@ -261,7 +261,11 @@ export function calculateMaximumWithdrawAmount(
|
|
|
261
261
|
|
|
262
262
|
const price = prices.get(assetId) as bigint;
|
|
263
263
|
|
|
264
|
-
return
|
|
264
|
+
return (
|
|
265
|
+
(getAvailableToBorrow(assetsConfig, assetsData, principals, prices, masterConstants) *
|
|
266
|
+
10n ** assetConfig.decimals) /
|
|
267
|
+
price
|
|
268
|
+
);
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
return withdrawAmountMax;
|
|
@@ -272,14 +276,14 @@ export function getAvailableToBorrow(
|
|
|
272
276
|
assetsData: ExtendedAssetsData,
|
|
273
277
|
principals: Dictionary<bigint, bigint>,
|
|
274
278
|
prices: Dictionary<bigint, bigint>,
|
|
275
|
-
masterConstants: MasterConstants
|
|
279
|
+
masterConstants: MasterConstants,
|
|
276
280
|
): bigint {
|
|
277
281
|
let borrowLimit = 0n;
|
|
278
282
|
let borrowAmount = 0n;
|
|
279
283
|
|
|
280
284
|
for (const assetID of principals.keys()) {
|
|
281
285
|
const principal = principals.get(assetID) as bigint;
|
|
282
|
-
|
|
286
|
+
|
|
283
287
|
if (principal == 0n) {
|
|
284
288
|
continue;
|
|
285
289
|
}
|
|
@@ -293,13 +297,21 @@ export function getAvailableToBorrow(
|
|
|
293
297
|
const price = prices.get(assetID) as bigint;
|
|
294
298
|
|
|
295
299
|
if (principal < 0n) {
|
|
296
|
-
borrowAmount += mulDiv(
|
|
300
|
+
borrowAmount += mulDiv(
|
|
301
|
+
calculatePresentValue(assetData.bRate, -principal, masterConstants),
|
|
302
|
+
price,
|
|
303
|
+
10n ** assetConfig.decimals,
|
|
304
|
+
);
|
|
297
305
|
} else if (principal > 0n) {
|
|
298
|
-
borrowLimit +=
|
|
306
|
+
borrowLimit += mulDiv(
|
|
299
307
|
mulDiv(
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
308
|
+
calculatePresentValue(assetData.sRate, principal, masterConstants),
|
|
309
|
+
price,
|
|
310
|
+
10n ** assetConfig.decimals,
|
|
311
|
+
),
|
|
312
|
+
assetConfig.collateralFactor,
|
|
313
|
+
masterConstants.ASSET_COEFFICIENT_SCALE,
|
|
314
|
+
);
|
|
303
315
|
}
|
|
304
316
|
}
|
|
305
317
|
|
|
@@ -313,21 +325,26 @@ export function getAvailableToBorrow(
|
|
|
313
325
|
* @param principalValue asset principal value
|
|
314
326
|
* @param masterConstants pool constants
|
|
315
327
|
*/
|
|
316
|
-
export function presentValue(
|
|
328
|
+
export function presentValue(
|
|
329
|
+
sRate: bigint,
|
|
330
|
+
bRate: bigint,
|
|
331
|
+
principalValue: bigint,
|
|
332
|
+
masterConstants: MasterConstants,
|
|
333
|
+
): UserBalance {
|
|
317
334
|
if (principalValue > 0) {
|
|
318
335
|
return {
|
|
319
336
|
amount: calculatePresentValue(sRate, principalValue, masterConstants),
|
|
320
|
-
type: BalanceType.supply
|
|
337
|
+
type: BalanceType.supply,
|
|
321
338
|
};
|
|
322
339
|
} else if (principalValue < 0) {
|
|
323
340
|
return {
|
|
324
341
|
amount: calculatePresentValue(bRate, -principalValue, masterConstants),
|
|
325
|
-
type: BalanceType.borrow
|
|
342
|
+
type: BalanceType.borrow,
|
|
326
343
|
};
|
|
327
344
|
} else {
|
|
328
345
|
return {
|
|
329
346
|
amount: 0n,
|
|
330
|
-
type: undefined
|
|
347
|
+
type: undefined,
|
|
331
348
|
};
|
|
332
349
|
}
|
|
333
350
|
}
|
|
@@ -337,11 +354,7 @@ export function presentValue(sRate: bigint, bRate: bigint, principalValue: bigin
|
|
|
337
354
|
* @param parameters
|
|
338
355
|
*/
|
|
339
356
|
export function calculateHealthParams(parameters: HealthParamsArgs) {
|
|
340
|
-
const {
|
|
341
|
-
principals, prices,
|
|
342
|
-
assetsData, assetsConfig,
|
|
343
|
-
poolConfig
|
|
344
|
-
} = parameters;
|
|
357
|
+
const { principals, prices, assetsData, assetsConfig, poolConfig } = parameters;
|
|
345
358
|
|
|
346
359
|
const { ASSET_LIQUIDATION_THRESHOLD_SCALE } = poolConfig.masterConstants;
|
|
347
360
|
|
|
@@ -353,22 +366,22 @@ export function calculateHealthParams(parameters: HealthParamsArgs) {
|
|
|
353
366
|
if (!principals.has(asset.assetId)) continue;
|
|
354
367
|
const assetPrincipal = principals.get(asset.assetId)!;
|
|
355
368
|
|
|
356
|
-
if (!assetsConfig.has(asset.assetId)) throw
|
|
369
|
+
if (!assetsConfig.has(asset.assetId)) throw `No config for ${asset.name}:${asset.assetId}`;
|
|
357
370
|
const assetConfig = assetsConfig.get(asset.assetId)!;
|
|
358
371
|
|
|
359
|
-
if (!assetsData.has(asset.assetId)) throw
|
|
372
|
+
if (!assetsData.has(asset.assetId)) throw `No data for asset ${asset.name}:${asset.assetId}`;
|
|
360
373
|
const assetData = assetsData.get(asset.assetId)!;
|
|
361
374
|
|
|
362
|
-
if (!prices.has(asset.assetId)) throw
|
|
375
|
+
if (!prices.has(asset.assetId)) throw `No price for asset ${asset.name}:${asset.assetId}`;
|
|
363
376
|
const assetPrice = prices.get(asset.assetId)! as bigint;
|
|
364
377
|
const assetScale = 10n ** assetConfig.decimals;
|
|
365
378
|
|
|
366
379
|
const { sRate, bRate } = assetData;
|
|
367
380
|
const assetBalance = presentValue(sRate, bRate, assetPrincipal, poolConfig.masterConstants);
|
|
368
|
-
const assetWorth = assetBalance.amount * assetPrice / assetScale;
|
|
381
|
+
const assetWorth = (assetBalance.amount * assetPrice) / assetScale;
|
|
369
382
|
if (assetBalance.type === BalanceType.supply) {
|
|
370
383
|
totalSupply += assetWorth;
|
|
371
|
-
totalLimit += assetWorth * assetConfig.liquidationThreshold / ASSET_LIQUIDATION_THRESHOLD_SCALE;
|
|
384
|
+
totalLimit += (assetWorth * assetConfig.liquidationThreshold) / ASSET_LIQUIDATION_THRESHOLD_SCALE;
|
|
372
385
|
} else if (assetBalance.type === BalanceType.borrow && assetConfig.dust < assetBalance.amount) {
|
|
373
386
|
totalDebt += assetWorth;
|
|
374
387
|
}
|
|
@@ -383,9 +396,11 @@ export function calculateHealthParams(parameters: HealthParamsArgs) {
|
|
|
383
396
|
};
|
|
384
397
|
|
|
385
398
|
return {
|
|
386
|
-
totalDebt,
|
|
399
|
+
totalDebt,
|
|
400
|
+
totalLimit,
|
|
401
|
+
totalSupply,
|
|
387
402
|
isLiquidatable: _isLiquidable,
|
|
388
|
-
isBadDebt: _isBadDebt
|
|
403
|
+
isBadDebt: _isBadDebt,
|
|
389
404
|
};
|
|
390
405
|
}
|
|
391
406
|
|
|
@@ -403,7 +418,7 @@ export function calculateLiquidationData(
|
|
|
403
418
|
assetsData: ExtendedAssetsData,
|
|
404
419
|
principals: Dictionary<bigint, bigint>,
|
|
405
420
|
prices: Dictionary<bigint, bigint>,
|
|
406
|
-
poolConfig: PoolConfig
|
|
421
|
+
poolConfig: PoolConfig,
|
|
407
422
|
): LiquidationData {
|
|
408
423
|
let collateralValue = 0n;
|
|
409
424
|
let collateralAsset = UNDEFINED_ASSET;
|
|
@@ -412,23 +427,22 @@ export function calculateLiquidationData(
|
|
|
412
427
|
let totalDebt = 0n;
|
|
413
428
|
let totalLimit = 0n;
|
|
414
429
|
|
|
415
|
-
const {
|
|
416
|
-
ASSET_SRATE_SCALE, ASSET_BRATE_SCALE,
|
|
417
|
-
COLLATERAL_WORTH_THRESHOLD
|
|
418
|
-
} = poolConfig.masterConstants;
|
|
430
|
+
const { ASSET_SRATE_SCALE, ASSET_BRATE_SCALE, COLLATERAL_WORTH_THRESHOLD } = poolConfig.masterConstants;
|
|
419
431
|
|
|
420
432
|
for (const asset of poolConfig.poolAssetsConfig) {
|
|
421
433
|
const principal = principals.get(asset.assetId)!;
|
|
422
434
|
if (!principal) continue;
|
|
423
435
|
const assetConfig = assetsConfig.get(asset.assetId)!;
|
|
424
436
|
const assetData = assetsData.get(asset.assetId)!;
|
|
425
|
-
const balance =
|
|
426
|
-
|
|
427
|
-
|
|
437
|
+
const balance =
|
|
438
|
+
principal > 0
|
|
439
|
+
? (principal * assetData.sRate) / ASSET_SRATE_SCALE
|
|
440
|
+
: (principal * assetData.bRate) / ASSET_BRATE_SCALE;
|
|
428
441
|
|
|
429
442
|
const assetWorth = (bigAbs(balance) * prices.get(asset.assetId)!) / 10n ** assetConfig.decimals;
|
|
430
443
|
if (balance > 0) {
|
|
431
|
-
totalLimit +=
|
|
444
|
+
totalLimit +=
|
|
445
|
+
(assetWorth * assetConfig.liquidationThreshold) / poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE;
|
|
432
446
|
// get the greatest collateral
|
|
433
447
|
if (assetWorth > collateralValue) {
|
|
434
448
|
collateralValue = assetWorth;
|
|
@@ -455,8 +469,8 @@ export function calculateLiquidationData(
|
|
|
455
469
|
(bigIntMax(collateralValue / 3n, bigIntMin(collateralValue, COLLATERAL_WORTH_THRESHOLD)) *
|
|
456
470
|
loanScale *
|
|
457
471
|
poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE) /
|
|
458
|
-
|
|
459
|
-
|
|
472
|
+
liquidationBonus /
|
|
473
|
+
loanAssetPrice,
|
|
460
474
|
);
|
|
461
475
|
values.push((loanValue * loanScale) / loanAssetPrice);
|
|
462
476
|
|
|
@@ -464,9 +478,11 @@ export function calculateLiquidationData(
|
|
|
464
478
|
const collateralAssetPrice: bigint = prices.get(collateralAsset.assetId)!;
|
|
465
479
|
const collateralDecimal = 10n ** collateralAssetConfig.decimals;
|
|
466
480
|
let minCollateralAmount =
|
|
467
|
-
(((liquidationAmount * loanAssetPrice * liquidationBonus) /
|
|
468
|
-
|
|
469
|
-
|
|
481
|
+
(((liquidationAmount * loanAssetPrice * liquidationBonus) /
|
|
482
|
+
poolConfig.masterConstants.ASSET_LIQUIDATION_BONUS_SCALE) *
|
|
483
|
+
collateralDecimal) /
|
|
484
|
+
collateralAssetPrice /
|
|
485
|
+
loanScale -
|
|
470
486
|
10n;
|
|
471
487
|
minCollateralAmount = (minCollateralAmount * 97n) / 100n;
|
|
472
488
|
if (minCollateralAmount > 0n) {
|
|
@@ -478,8 +494,12 @@ export function calculateLiquidationData(
|
|
|
478
494
|
totalDebt,
|
|
479
495
|
totalLimit,
|
|
480
496
|
liquidable: true,
|
|
481
|
-
liquidationAmount: addReserve(
|
|
482
|
-
|
|
497
|
+
liquidationAmount: addReserve(
|
|
498
|
+
liquidationAmount,
|
|
499
|
+
loanAssetConfig.liquidationReserveFactor,
|
|
500
|
+
poolConfig.masterConstants.ASSET_RESERVE_FACTOR_SCALE,
|
|
501
|
+
),
|
|
502
|
+
minCollateralAmount,
|
|
483
503
|
};
|
|
484
504
|
}
|
|
485
505
|
}
|
|
@@ -491,7 +511,7 @@ export function calculateLiquidationData(
|
|
|
491
511
|
greatestLoanValue: loanValue,
|
|
492
512
|
totalDebt,
|
|
493
513
|
totalLimit,
|
|
494
|
-
liquidable: false
|
|
514
|
+
liquidable: false,
|
|
495
515
|
};
|
|
496
516
|
}
|
|
497
517
|
|
|
@@ -509,31 +529,39 @@ export function predictHealthFactor(args: PredictHealthFactorArgs): number {
|
|
|
509
529
|
|
|
510
530
|
const decimals = Number(assetConfig.decimals);
|
|
511
531
|
|
|
512
|
-
const currentBalance = assetPrice * Number(currentAmount) / Math.pow(10, decimals);
|
|
532
|
+
const currentBalance = (assetPrice * Number(currentAmount)) / Math.pow(10, decimals);
|
|
513
533
|
const changeType = args.balanceChangeType;
|
|
514
534
|
|
|
515
535
|
if (currentAmount != null && currentAmount != 0n) {
|
|
516
536
|
if (changeType == BalanceChangeType.Borrow) {
|
|
517
|
-
totalBorrow +=
|
|
537
|
+
totalBorrow +=
|
|
538
|
+
currentBalance *
|
|
539
|
+
(1 +
|
|
540
|
+
Number(assetConfig.originationFee) /
|
|
541
|
+
Number(args.poolConfig.masterConstants.ASSET_ORIGINATION_FEE_SCALE));
|
|
518
542
|
} else if (changeType == BalanceChangeType.Repay) {
|
|
519
543
|
totalBorrow -= currentBalance;
|
|
520
544
|
} else if (changeType == BalanceChangeType.Withdraw) {
|
|
521
|
-
totalLimit -=
|
|
545
|
+
totalLimit -=
|
|
546
|
+
(currentBalance * Number(assetConfig.liquidationThreshold)) /
|
|
547
|
+
Number(args.poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE);
|
|
522
548
|
} else if (changeType == BalanceChangeType.Supply) {
|
|
523
|
-
totalLimit +=
|
|
549
|
+
totalLimit +=
|
|
550
|
+
(currentBalance * Number(assetConfig.liquidationThreshold)) /
|
|
551
|
+
Number(args.poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE);
|
|
524
552
|
}
|
|
525
553
|
}
|
|
526
554
|
if (Number(totalLimit) == 0) {
|
|
527
555
|
return 1;
|
|
528
556
|
}
|
|
529
557
|
|
|
530
|
-
return Math.min(Math.max(1 - totalBorrow / totalLimit, 0), 1);
|
|
558
|
+
return Math.min(Math.max(1 - totalBorrow / totalLimit, 0), 1); // let's limit a result to zero below and one above
|
|
531
559
|
}
|
|
532
560
|
|
|
533
561
|
/**
|
|
534
|
-
* Predicts how APY will change as a result of one of the actions Borrow, Supply, Withdraw or Repay.
|
|
562
|
+
* Predicts how APY will change as a result of one of the actions Borrow, Supply, Withdraw or Repay.
|
|
535
563
|
*
|
|
536
|
-
* Used on the front-end.
|
|
564
|
+
* Used on the front-end.
|
|
537
565
|
*
|
|
538
566
|
* @returns Estimated APYs for Supply and Borrow
|
|
539
567
|
*/
|
|
@@ -565,6 +593,6 @@ export function predictAPY(args: PredictAPYArgs): AssetInterest & AssetApy {
|
|
|
565
593
|
return {
|
|
566
594
|
...interest,
|
|
567
595
|
supplyApy: (1 + (Number(interest.supplyInterest) / 1e12) * 24 * 3600) ** 365 - 1,
|
|
568
|
-
borrowApy: (1 + (Number(interest.borrowInterest) / 1e12) * 24 * 3600) ** 365 - 1
|
|
569
|
-
}
|
|
596
|
+
borrowApy: (1 + (Number(interest.borrowInterest) / 1e12) * 24 * 3600) ** 365 - 1,
|
|
597
|
+
};
|
|
570
598
|
}
|
package/src/api/parser.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ExtendedAssetsConfig,
|
|
8
8
|
ExtendedAssetsData,
|
|
9
9
|
MasterConstants,
|
|
10
|
-
|
|
10
|
+
PoolAssetConfig,
|
|
11
11
|
PoolConfig,
|
|
12
12
|
} from '../types/Master';
|
|
13
13
|
import { BalanceType, UserBalance, UserData, UserLiteData, UserRewards } from '../types/User';
|
|
@@ -46,7 +46,7 @@ export function createAssetData(): DictionaryValue<AssetData> {
|
|
|
46
46
|
buidler.storeUint(src.bRate, 64);
|
|
47
47
|
buidler.storeInt(src.totalSupply, 64);
|
|
48
48
|
buidler.storeInt(src.totalBorrow, 64);
|
|
49
|
-
buidler.storeUint(src.
|
|
49
|
+
buidler.storeUint(src.lastAccrual, 32);
|
|
50
50
|
buidler.storeUint(src.balance, 64);
|
|
51
51
|
buidler.storeUint(src.trackingSupplyIndex, 64);
|
|
52
52
|
buidler.storeUint(src.trackingBorrowIndex, 64);
|
|
@@ -57,7 +57,7 @@ export function createAssetData(): DictionaryValue<AssetData> {
|
|
|
57
57
|
const bRate = BigInt(src.loadUintBig(64));
|
|
58
58
|
const totalSupply = BigInt(src.loadIntBig(64));
|
|
59
59
|
const totalBorrow = BigInt(src.loadIntBig(64));
|
|
60
|
-
const
|
|
60
|
+
const lastAccrual = BigInt(src.loadUintBig(32));
|
|
61
61
|
const balance = BigInt(src.loadUintBig(64));
|
|
62
62
|
const trackingSupplyIndex = BigInt(src.loadUintBig(64));
|
|
63
63
|
const trackingBorrowIndex = BigInt(src.loadUintBig(64));
|
|
@@ -68,7 +68,7 @@ export function createAssetData(): DictionaryValue<AssetData> {
|
|
|
68
68
|
bRate,
|
|
69
69
|
totalSupply,
|
|
70
70
|
totalBorrow,
|
|
71
|
-
|
|
71
|
+
lastAccrual,
|
|
72
72
|
balance,
|
|
73
73
|
trackingSupplyIndex,
|
|
74
74
|
trackingBorrowIndex,
|
|
@@ -164,7 +164,7 @@ export function createAssetConfig(): DictionaryValue<AssetConfig> {
|
|
|
164
164
|
|
|
165
165
|
export function parseMasterData(
|
|
166
166
|
masterDataBOC: string,
|
|
167
|
-
poolAssetsConfig:
|
|
167
|
+
poolAssetsConfig: PoolAssetConfig[],
|
|
168
168
|
masterConstants: MasterConstants,
|
|
169
169
|
oracleParser: OracleParser,
|
|
170
170
|
): MasterData<MasterConfig<OracleInfo>> {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { HexString } from '@pythnetwork/hermes-client';
|
|
1
2
|
import { Address, Dictionary, Slice } from '@ton/core';
|
|
3
|
+
import { FeedMapItem, parseFeedsMapDict } from '../feeds';
|
|
2
4
|
import { AbstractOracleParser } from './AbstractOracleParser';
|
|
3
5
|
|
|
4
6
|
export type OracleConfig = {
|
|
5
7
|
pythAddress: Address;
|
|
6
8
|
// FYI: The Pyth max feeds count is 7, but it can add more in the future
|
|
7
|
-
feedsMap:
|
|
9
|
+
feedsMap: Map<HexString, FeedMapItem>;
|
|
8
10
|
allowedRefTokens: Dictionary<bigint, bigint>;
|
|
9
11
|
};
|
|
10
12
|
|
|
@@ -23,7 +25,9 @@ export class PythOracleParser extends AbstractOracleParser {
|
|
|
23
25
|
|
|
24
26
|
return {
|
|
25
27
|
pythAddress: oraclesSlice.loadAddress(),
|
|
26
|
-
feedsMap:
|
|
28
|
+
feedsMap: parseFeedsMapDict(
|
|
29
|
+
feedDataSlice.loadDict(Dictionary.Keys.BigUint(256), Dictionary.Values.Buffer(64)),
|
|
30
|
+
),
|
|
27
31
|
allowedRefTokens: feedDataSlice.loadDict(Dictionary.Keys.BigUint(256), Dictionary.Values.BigUint(256)),
|
|
28
32
|
pricesTtl: oraclesSlice.loadUint(32),
|
|
29
33
|
pythComputeBaseGas: oraclesSlice.loadUintBig(64),
|
package/src/api/prices.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Cell } from '@ton/core';
|
|
|
4
4
|
import { beginCell } from '@ton/ton';
|
|
5
5
|
import { Buffer } from 'buffer';
|
|
6
6
|
|
|
7
|
+
// TODO: move to PythCollector
|
|
7
8
|
export function composeFeedsCell(feeds: HexString[]): Cell {
|
|
8
9
|
if (feeds.length === 0) {
|
|
9
10
|
return beginCell().storeUint(0, 8).endCell();
|
|
@@ -40,7 +41,7 @@ export async function getPrices(endpoints: string[] = ["api.stardust-mainnet.iot
|
|
|
40
41
|
backendEndpoints: DefaultPriceSourcesConfig.backendEndpoints,
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
const priceCollector = new
|
|
44
|
+
const priceCollector = new ClassicCollector(poolConfig, sources);
|
|
44
45
|
const prices = await priceCollector.getPrices();
|
|
45
46
|
|
|
46
47
|
return { dict: prices.dict, dataCell: prices.dataCell };
|
|
@@ -88,4 +88,19 @@ export const FEES = {
|
|
|
88
88
|
REWARD_MASTER_WITHDRAW: toNano('0.1'),
|
|
89
89
|
REWARD_USER_DEPLOY: toNano('0.05'),
|
|
90
90
|
REWARD_USER_CLAIM: toNano('0.1'),
|
|
91
|
-
};
|
|
91
|
+
} as const;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Common validation constants and error messages
|
|
95
|
+
*/
|
|
96
|
+
export const VALIDATION = {
|
|
97
|
+
ERRORS: {
|
|
98
|
+
INVALID_AMOUNT: 'Amount must be positive',
|
|
99
|
+
INVALID_SUBACCOUNT_ID: 'Subaccount ID must be between 0 and 255',
|
|
100
|
+
MISSING_JETTON_AMOUNT: 'Either amount, liquidationAmount, or supplyAmount must be provided',
|
|
101
|
+
MISSING_RESPONSE_ADDRESS: 'responseAddress, userAddress, or liquidatorAddress must be provided',
|
|
102
|
+
INVALID_ASSET_CONFIG: 'Invalid asset configuration provided',
|
|
103
|
+
MASTER_CONTRACT_INACTIVE: 'Master contract is not active',
|
|
104
|
+
OUTDATED_SDK_VERSION: 'Outdated SDK pool version',
|
|
105
|
+
} as const,
|
|
106
|
+
} as const;
|