@evaafi/sdk 0.6.0 → 0.6.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/liquidation.d.ts +136 -0
- package/dist/api/liquidation.js +252 -0
- package/dist/api/math.d.ts +34 -7
- package/dist/api/math.js +100 -32
- package/dist/api/parser.js +4 -1
- package/dist/constants/assets.d.ts +12 -0
- package/dist/constants/assets.js +25 -13
- package/dist/constants/general.d.ts +3 -0
- package/dist/constants/general.js +5 -1
- package/dist/constants/pools.js +1 -1
- package/dist/contracts/MasterContract.d.ts +6 -1
- package/dist/contracts/MasterContract.js +17 -11
- package/dist/contracts/UserContract.d.ts +3 -2
- package/dist/contracts/UserContract.js +6 -5
- package/dist/index.d.ts +5 -4
- package/dist/index.js +20 -2
- package/dist/types/Master.d.ts +3 -0
- package/dist/types/User.d.ts +7 -0
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +6 -1
- package/package.json +3 -2
- package/src/api/liquidation.ts +346 -0
- package/src/api/math.ts +169 -76
- package/src/api/parser.ts +4 -1
- package/src/constants/assets.ts +26 -12
- package/src/constants/general.ts +7 -1
- package/src/constants/pools.ts +1 -1
- package/src/contracts/MasterContract.ts +21 -13
- package/src/contracts/UserContract.ts +8 -3
- package/src/index.ts +30 -6
- package/src/types/Master.ts +4 -1
- package/src/types/User.ts +8 -0
- package/src/utils/utils.ts +4 -0
package/src/api/math.ts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AgregatedBalances,
|
|
3
|
+
AssetConfig,
|
|
4
|
+
AssetData,
|
|
5
|
+
AssetInterest,
|
|
6
|
+
ExtendedAssetData,
|
|
7
|
+
ExtendedAssetsConfig,
|
|
8
|
+
ExtendedAssetsData,
|
|
9
|
+
MasterConstants,
|
|
10
|
+
PoolConfig
|
|
11
|
+
} from '../types/Master';
|
|
2
12
|
import { Dictionary } from '@ton/core';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
import {
|
|
14
|
+
BalanceChangeType,
|
|
15
|
+
BalanceType,
|
|
16
|
+
HealthParamsArgs,
|
|
17
|
+
LiquidationData,
|
|
18
|
+
PredictHealthFactorArgs,
|
|
19
|
+
UserBalance
|
|
20
|
+
} from '../types/User';
|
|
21
|
+
import { UNDEFINED_ASSET } from '../constants/assets';
|
|
22
|
+
import { addReserve, isBadDebt } from './liquidation';
|
|
7
23
|
|
|
8
24
|
export function mulFactor(decimal: bigint, a: bigint, b: bigint): bigint {
|
|
9
25
|
return (a * b) / decimal;
|
|
@@ -14,17 +30,25 @@ export function mulDiv(x: bigint, y: bigint, z: bigint): bigint {
|
|
|
14
30
|
}
|
|
15
31
|
|
|
16
32
|
export function mulDivC(x: bigint, y: bigint, z: bigint): bigint {
|
|
17
|
-
const mul = x * y;
|
|
18
|
-
return mul / z + (mul % z ? 1n : 0n);
|
|
33
|
+
//const mul = x * y;
|
|
34
|
+
//return mul / z + (mul % z ? 1n : 0n);
|
|
35
|
+
return BigInt(Math.ceil(Number(x * y) / Number(z)));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function bigAbs(value: bigint) {
|
|
39
|
+
return value > 0n ? value : -value;
|
|
19
40
|
}
|
|
20
41
|
|
|
21
42
|
export function bigIntMax(...args: bigint[]): bigint {
|
|
22
43
|
return args.reduce((m, e) => (e > m ? e : m));
|
|
23
44
|
}
|
|
45
|
+
|
|
24
46
|
export function bigIntMin(...args: bigint[]): bigint {
|
|
25
47
|
return args.reduce((m, e) => (e < m ? e : m));
|
|
26
48
|
}
|
|
27
49
|
|
|
50
|
+
export const BigMath = { mulFactor, mulDiv, mulDivC, abs: bigAbs, min: bigIntMin, max: bigIntMax };
|
|
51
|
+
|
|
28
52
|
export function calculatePresentValue(index: bigint, principalValue: bigint, masterConstants: MasterConstants): bigint {
|
|
29
53
|
return (principalValue * index) / masterConstants.FACTOR_SCALE;
|
|
30
54
|
}
|
|
@@ -44,7 +68,7 @@ export function calculateCurrentRates(assetConfig: AssetConfig, assetData: Asset
|
|
|
44
68
|
bRate: updatedBRate,
|
|
45
69
|
supplyInterest,
|
|
46
70
|
borrowInterest,
|
|
47
|
-
now
|
|
71
|
+
now
|
|
48
72
|
};
|
|
49
73
|
}
|
|
50
74
|
|
|
@@ -53,7 +77,7 @@ export function calculateCurrentRates(assetConfig: AssetConfig, assetData: Asset
|
|
|
53
77
|
bRate: assetData.bRate,
|
|
54
78
|
supplyInterest,
|
|
55
79
|
borrowInterest,
|
|
56
|
-
now
|
|
80
|
+
now
|
|
57
81
|
};
|
|
58
82
|
}
|
|
59
83
|
|
|
@@ -81,7 +105,7 @@ export function calculateAssetData(
|
|
|
81
105
|
return {
|
|
82
106
|
...data,
|
|
83
107
|
...{ supplyInterest, borrowInterest },
|
|
84
|
-
...{ supplyApy, borrowApy }
|
|
108
|
+
...{ supplyApy, borrowApy }
|
|
85
109
|
};
|
|
86
110
|
}
|
|
87
111
|
|
|
@@ -107,19 +131,19 @@ export function calculateAssetInterest(assetConfig: AssetConfig, assetData: Asse
|
|
|
107
131
|
mulFactor(
|
|
108
132
|
masterConstants.FACTOR_SCALE,
|
|
109
133
|
assetConfig.borrowRateSlopeHigh,
|
|
110
|
-
utilization - assetConfig.targetUtilization
|
|
134
|
+
utilization - assetConfig.targetUtilization
|
|
111
135
|
);
|
|
112
136
|
}
|
|
113
137
|
|
|
114
138
|
supplyInterest = mulDiv(
|
|
115
139
|
mulDiv(borrowInterest, utilization, masterConstants.FACTOR_SCALE),
|
|
116
140
|
masterConstants.ASSET_RESERVE_FACTOR_SCALE - assetConfig.reserveFactor,
|
|
117
|
-
masterConstants.ASSET_RESERVE_FACTOR_SCALE
|
|
141
|
+
masterConstants.ASSET_RESERVE_FACTOR_SCALE
|
|
118
142
|
);
|
|
119
143
|
|
|
120
144
|
return {
|
|
121
145
|
supplyInterest,
|
|
122
|
-
borrowInterest
|
|
146
|
+
borrowInterest
|
|
123
147
|
};
|
|
124
148
|
}
|
|
125
149
|
|
|
@@ -127,37 +151,36 @@ export function checkNotInDebtAtAll(principals: Dictionary<bigint, bigint>): boo
|
|
|
127
151
|
return principals.values().every(x => x >= 0n);
|
|
128
152
|
}
|
|
129
153
|
|
|
130
|
-
export function getAgregatedBalances
|
|
154
|
+
export function getAgregatedBalances(
|
|
131
155
|
assetsData: ExtendedAssetsData,
|
|
132
156
|
assetsConfig: ExtendedAssetsConfig,
|
|
133
157
|
principals: Dictionary<bigint, bigint>,
|
|
134
158
|
prices: Dictionary<bigint, bigint>,
|
|
135
|
-
masterConstants: MasterConstants
|
|
136
|
-
|
|
159
|
+
masterConstants: MasterConstants
|
|
160
|
+
): AgregatedBalances {
|
|
137
161
|
let user_total_supply = 0n;
|
|
138
162
|
let user_total_borrow = 0n;
|
|
139
|
-
|
|
140
|
-
for (const [assetId, principal] of principals) {
|
|
141
163
|
|
|
164
|
+
for (const [assetId, principal] of principals) {
|
|
142
165
|
if (principal) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
|
|
167
|
+
if (!prices.has(assetId)) {
|
|
168
|
+
return { totalSupply: 0n, totalBorrow: 0n };
|
|
169
|
+
}
|
|
170
|
+
const price = prices.get(assetId)!;
|
|
171
|
+
const assetData = assetsData.get(assetId)!;
|
|
172
|
+
const assetConfig = assetsConfig.get(assetId)!;
|
|
173
|
+
// console.log('price', price);
|
|
174
|
+
if (principal < 0) {
|
|
175
|
+
user_total_borrow += presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals;
|
|
176
|
+
} else {
|
|
177
|
+
user_total_supply += presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals;
|
|
178
|
+
}
|
|
179
|
+
// console.log('aggregated', assetId, presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).type, presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals)
|
|
155
180
|
}
|
|
156
|
-
|
|
157
|
-
}
|
|
158
181
|
}
|
|
159
|
-
return {totalSupply: user_total_supply, totalBorrow: user_total_borrow};
|
|
160
|
-
|
|
182
|
+
return { totalSupply: user_total_supply, totalBorrow: user_total_borrow };
|
|
183
|
+
}
|
|
161
184
|
|
|
162
185
|
export function calculateMaximumWithdrawAmount(
|
|
163
186
|
assetsConfig: ExtendedAssetsConfig,
|
|
@@ -165,7 +188,7 @@ export function calculateMaximumWithdrawAmount(
|
|
|
165
188
|
principals: Dictionary<bigint, bigint>,
|
|
166
189
|
prices: Dictionary<bigint, bigint>,
|
|
167
190
|
masterConstants: MasterConstants,
|
|
168
|
-
assetId: bigint
|
|
191
|
+
assetId: bigint
|
|
169
192
|
): bigint {
|
|
170
193
|
let withdrawAmountMax = 0n;
|
|
171
194
|
|
|
@@ -175,8 +198,8 @@ export function calculateMaximumWithdrawAmount(
|
|
|
175
198
|
|
|
176
199
|
if (oldPrincipal > assetConfig.dust) {
|
|
177
200
|
const oldPresentValue = presentValue(assetData.sRate, assetData.bRate, oldPrincipal, masterConstants);
|
|
178
|
-
if(checkNotInDebtAtAll(principals)) {
|
|
179
|
-
withdrawAmountMax = oldPresentValue.amount;
|
|
201
|
+
if (checkNotInDebtAtAll(principals)) {
|
|
202
|
+
withdrawAmountMax = oldPresentValue.amount;
|
|
180
203
|
} else {
|
|
181
204
|
if (!prices.has(assetId)) {
|
|
182
205
|
return 0n;
|
|
@@ -189,17 +212,16 @@ export function calculateMaximumWithdrawAmount(
|
|
|
189
212
|
|
|
190
213
|
if (assetConfig.collateralFactor == 0n) {
|
|
191
214
|
maxAmountToReclaim = oldPresentValue.amount;
|
|
192
|
-
}
|
|
193
|
-
else if (price > 0) {
|
|
215
|
+
} else if (price > 0) {
|
|
194
216
|
maxAmountToReclaim =
|
|
195
|
-
bigIntMax(0n,
|
|
217
|
+
bigIntMax(0n,
|
|
196
218
|
mulDiv(
|
|
197
219
|
mulDiv(borrowable, masterConstants.ASSET_COEFFICIENT_SCALE, assetConfig.collateralFactor),
|
|
198
220
|
10n ** assetConfig.decimals, price)
|
|
199
221
|
- calculatePresentValue(assetData.sRate, assetConfig.dust, masterConstants) / 2n
|
|
200
222
|
);
|
|
201
223
|
}
|
|
202
|
-
|
|
224
|
+
|
|
203
225
|
withdrawAmountMax = bigIntMin(
|
|
204
226
|
maxAmountToReclaim,
|
|
205
227
|
oldPresentValue.amount
|
|
@@ -234,9 +256,9 @@ export function getAvailableToBorrow(
|
|
|
234
256
|
const price = prices.get(assetID) as bigint;
|
|
235
257
|
const principal = principals.get(assetID) as bigint;
|
|
236
258
|
|
|
237
|
-
if (principal <
|
|
259
|
+
if (principal < 0n) {
|
|
238
260
|
borrowAmount += mulDiv(calculatePresentValue(assetData.bRate, -principal, masterConstants), price, 10n ** assetConfig.decimals);
|
|
239
|
-
} else if (principal >
|
|
261
|
+
} else if (principal > 0n) {
|
|
240
262
|
borrowLimit +=
|
|
241
263
|
mulDiv(
|
|
242
264
|
mulDiv(calculatePresentValue(assetData.sRate, principal, masterConstants), price, 10n ** assetConfig.decimals),
|
|
@@ -248,32 +270,96 @@ export function getAvailableToBorrow(
|
|
|
248
270
|
return borrowLimit - borrowAmount;
|
|
249
271
|
}
|
|
250
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Calculates balance value for asset principal.
|
|
275
|
+
* @param sRate asset supply rate
|
|
276
|
+
* @param bRate asset borrow rate
|
|
277
|
+
* @param principalValue asset principal value
|
|
278
|
+
* @param masterConstants pool constants
|
|
279
|
+
*/
|
|
251
280
|
export function presentValue(sRate: bigint, bRate: bigint, principalValue: bigint, masterConstants: MasterConstants): UserBalance {
|
|
252
281
|
if (principalValue > 0) {
|
|
253
282
|
return {
|
|
254
283
|
amount: calculatePresentValue(sRate, principalValue, masterConstants),
|
|
255
|
-
type: BalanceType.supply
|
|
284
|
+
type: BalanceType.supply
|
|
256
285
|
};
|
|
257
286
|
} else if (principalValue < 0) {
|
|
258
287
|
return {
|
|
259
288
|
amount: calculatePresentValue(bRate, -principalValue, masterConstants),
|
|
260
|
-
type: BalanceType.borrow
|
|
289
|
+
type: BalanceType.borrow
|
|
261
290
|
};
|
|
262
291
|
} else {
|
|
263
292
|
return {
|
|
264
293
|
amount: 0n,
|
|
265
|
-
type: undefined
|
|
294
|
+
type: undefined
|
|
266
295
|
};
|
|
267
296
|
}
|
|
268
297
|
}
|
|
269
298
|
|
|
270
299
|
/**
|
|
271
|
-
*
|
|
272
|
-
* @param
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
300
|
+
* Calculates health parameters of the specified user account based on its parameters
|
|
301
|
+
* @param parameters
|
|
302
|
+
*/
|
|
303
|
+
export function calculateHealthParams(parameters: HealthParamsArgs) {
|
|
304
|
+
const {
|
|
305
|
+
principals, prices,
|
|
306
|
+
assetsData, assetsConfig,
|
|
307
|
+
poolConfig
|
|
308
|
+
} = parameters;
|
|
309
|
+
|
|
310
|
+
const { ASSET_LIQUIDATION_THRESHOLD_SCALE } = poolConfig.masterConstants;
|
|
311
|
+
|
|
312
|
+
let totalSupply = 0n;
|
|
313
|
+
let totalDebt = 0n;
|
|
314
|
+
let totalLimit = 0n;
|
|
315
|
+
|
|
316
|
+
for (const asset of poolConfig.poolAssetsConfig) {
|
|
317
|
+
if (!principals.has(asset.assetId)) continue;
|
|
318
|
+
const assetPrincipal = principals.get(asset.assetId)!;
|
|
319
|
+
|
|
320
|
+
if (!assetsConfig.has(asset.assetId)) throw (`No config for ${asset.name}:${asset.assetId}`);
|
|
321
|
+
const assetConfig = assetsConfig.get(asset.assetId)!;
|
|
322
|
+
|
|
323
|
+
if (!assetsData.has(asset.assetId)) throw (`No data for asset ${asset.name}:${asset.assetId}`);
|
|
324
|
+
const assetData = assetsData.get(asset.assetId)!;
|
|
325
|
+
|
|
326
|
+
if (!prices.has(asset.assetId)) throw (`No price for asset ${asset.name}:${asset.assetId}`);
|
|
327
|
+
const assetPrice = prices.get(asset.assetId)! as bigint;
|
|
328
|
+
const assetScale = 10n ** assetConfig.decimals;
|
|
329
|
+
|
|
330
|
+
const { sRate, bRate } = assetData;
|
|
331
|
+
const assetBalance = presentValue(sRate, bRate, assetPrincipal, poolConfig.masterConstants);
|
|
332
|
+
const assetWorth = assetBalance.amount * assetPrice / assetScale;
|
|
333
|
+
if (assetBalance.type === BalanceType.supply) {
|
|
334
|
+
totalSupply += assetWorth;
|
|
335
|
+
totalLimit += assetWorth * assetConfig.liquidationThreshold / ASSET_LIQUIDATION_THRESHOLD_SCALE;
|
|
336
|
+
} else if (assetBalance.type === BalanceType.borrow) {
|
|
337
|
+
totalDebt += assetWorth;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const _isLiquidable = totalLimit < totalDebt;
|
|
342
|
+
|
|
343
|
+
// the `bad debt` condition depends on certain asset's liquidation bonus parameter
|
|
344
|
+
// , so it is not a user constant, but depends on certain asset
|
|
345
|
+
const _isBadDebt = (liquidationBonus: bigint): boolean => {
|
|
346
|
+
return isBadDebt(totalSupply, totalDebt, liquidationBonus, poolConfig.masterConstants) as boolean;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
totalDebt, totalLimit, totalSupply,
|
|
351
|
+
isLiquidatable: _isLiquidable,
|
|
352
|
+
isBadDebt: _isBadDebt
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Calculates liquidation data for greatest loan and collateral assets
|
|
358
|
+
* @param assetsConfig assets config dictionary
|
|
359
|
+
* @param assetsData assets data dictionary
|
|
360
|
+
* @param principals principals dictionary
|
|
361
|
+
* @param prices prices dictionary
|
|
362
|
+
* @param poolConfig pool config
|
|
277
363
|
* @returns can return UNDEFINED_ASSET if there are no assets
|
|
278
364
|
*/
|
|
279
365
|
export function calculateLiquidationData(
|
|
@@ -281,7 +367,7 @@ export function calculateLiquidationData(
|
|
|
281
367
|
assetsData: ExtendedAssetsData,
|
|
282
368
|
principals: Dictionary<bigint, bigint>,
|
|
283
369
|
prices: Dictionary<bigint, bigint>,
|
|
284
|
-
poolConfig: PoolConfig
|
|
370
|
+
poolConfig: PoolConfig
|
|
285
371
|
): LiquidationData {
|
|
286
372
|
let collateralValue = 0n;
|
|
287
373
|
let collateralAsset = UNDEFINED_ASSET;
|
|
@@ -290,25 +376,31 @@ export function calculateLiquidationData(
|
|
|
290
376
|
let totalDebt = 0n;
|
|
291
377
|
let totalLimit = 0n;
|
|
292
378
|
|
|
379
|
+
const {
|
|
380
|
+
ASSET_SRATE_SCALE, ASSET_BRATE_SCALE,
|
|
381
|
+
COLLATERAL_WORTH_THRESHOLD
|
|
382
|
+
} = poolConfig.masterConstants;
|
|
383
|
+
|
|
293
384
|
for (const asset of poolConfig.poolAssetsConfig) {
|
|
294
|
-
if (!principals.has(asset.assetId)) {
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
385
|
const principal = principals.get(asset.assetId)!;
|
|
386
|
+
if (!principal) continue;
|
|
298
387
|
const assetConfig = assetsConfig.get(asset.assetId)!;
|
|
299
388
|
const assetData = assetsData.get(asset.assetId)!;
|
|
300
|
-
const balance =
|
|
301
|
-
|
|
389
|
+
const balance = principal > 0 ?
|
|
390
|
+
(principal * assetData.sRate) / ASSET_SRATE_SCALE :
|
|
391
|
+
(principal * assetData.bRate) / ASSET_BRATE_SCALE;
|
|
392
|
+
|
|
393
|
+
const assetWorth = (bigAbs(balance) * prices.get(asset.assetId)!) / 10n ** assetConfig.decimals;
|
|
302
394
|
if (balance > 0) {
|
|
303
|
-
const assetWorth = (balance * prices.get(asset.assetId)!) / 10n ** assetConfig.decimals;
|
|
304
395
|
totalLimit += (assetWorth * assetConfig.liquidationThreshold) / poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE;
|
|
396
|
+
// get the greatest collateral
|
|
305
397
|
if (assetWorth > collateralValue) {
|
|
306
398
|
collateralValue = assetWorth;
|
|
307
399
|
collateralAsset = asset;
|
|
308
400
|
}
|
|
309
401
|
} else if (balance < 0) {
|
|
310
|
-
const assetWorth = (-balance * prices.get(asset.assetId)!) / 10n ** assetConfig.decimals;
|
|
311
402
|
totalDebt += assetWorth;
|
|
403
|
+
// get the greatest loan
|
|
312
404
|
if (assetWorth > loanValue) {
|
|
313
405
|
loanValue = assetWorth;
|
|
314
406
|
loanAsset = asset;
|
|
@@ -324,11 +416,11 @@ export function calculateLiquidationData(
|
|
|
324
416
|
const liquidationBonus = collateralAssetConfig.liquidationBonus;
|
|
325
417
|
const loanScale = 10n ** loanAssetConfig.decimals;
|
|
326
418
|
values.push(
|
|
327
|
-
(bigIntMax(collateralValue / 2n, bigIntMin(collateralValue,
|
|
419
|
+
(bigIntMax(collateralValue / 2n, bigIntMin(collateralValue, COLLATERAL_WORTH_THRESHOLD)) *
|
|
328
420
|
loanScale *
|
|
329
421
|
poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE) /
|
|
330
|
-
|
|
331
|
-
|
|
422
|
+
liquidationBonus /
|
|
423
|
+
loanAssetPrice
|
|
332
424
|
);
|
|
333
425
|
values.push((loanValue * loanScale) / loanAssetPrice);
|
|
334
426
|
|
|
@@ -337,11 +429,11 @@ export function calculateLiquidationData(
|
|
|
337
429
|
const collateralDecimal = 10n ** collateralAssetConfig.decimals;
|
|
338
430
|
let minCollateralAmount =
|
|
339
431
|
(((liquidationAmount * loanAssetPrice * liquidationBonus) / poolConfig.masterConstants.ASSET_LIQUIDATION_BONUS_SCALE) * collateralDecimal) /
|
|
340
|
-
|
|
341
|
-
|
|
432
|
+
collateralAssetPrice /
|
|
433
|
+
loanScale -
|
|
342
434
|
10n;
|
|
343
435
|
minCollateralAmount = (minCollateralAmount * 97n) / 100n;
|
|
344
|
-
if (minCollateralAmount
|
|
436
|
+
if (minCollateralAmount > 0n) {
|
|
345
437
|
return {
|
|
346
438
|
greatestCollateralAsset: collateralAsset,
|
|
347
439
|
greatestCollateralValue: collateralValue,
|
|
@@ -350,8 +442,8 @@ export function calculateLiquidationData(
|
|
|
350
442
|
totalDebt,
|
|
351
443
|
totalLimit,
|
|
352
444
|
liquidable: true,
|
|
353
|
-
liquidationAmount,
|
|
354
|
-
minCollateralAmount
|
|
445
|
+
liquidationAmount: addReserve(liquidationAmount, loanAssetConfig.liquidationReserveFactor, poolConfig.masterConstants.ASSET_RESERVE_FACTOR_SCALE),
|
|
446
|
+
minCollateralAmount
|
|
355
447
|
};
|
|
356
448
|
}
|
|
357
449
|
}
|
|
@@ -363,28 +455,29 @@ export function calculateLiquidationData(
|
|
|
363
455
|
greatestLoanValue: loanValue,
|
|
364
456
|
totalDebt,
|
|
365
457
|
totalLimit,
|
|
366
|
-
liquidable: false
|
|
458
|
+
liquidable: false
|
|
367
459
|
};
|
|
368
460
|
}
|
|
369
461
|
|
|
370
462
|
export function predictHealthFactor(args: PredictHealthFactorArgs): number {
|
|
371
|
-
const
|
|
463
|
+
const healthParams = calculateHealthParams(args);
|
|
372
464
|
const assetId = args.asset.assetId;
|
|
373
|
-
|
|
465
|
+
|
|
374
466
|
const assetConfig = args.assetsConfig.get(assetId)!;
|
|
375
467
|
const assetPrice = Number(args.prices.get(assetId)!);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
let
|
|
468
|
+
const assetData = args.assetsData.get(assetId)!;
|
|
469
|
+
|
|
470
|
+
let totalLimit = Number(healthParams.totalLimit);
|
|
471
|
+
let totalBorrow = Number(healthParams.totalDebt);
|
|
379
472
|
|
|
380
473
|
const currentAmount = args.amount;
|
|
381
474
|
|
|
382
|
-
const decimals = Number(assetConfig.decimals)
|
|
475
|
+
const decimals = Number(assetConfig.decimals);
|
|
383
476
|
|
|
384
477
|
const currentBalance = assetPrice * Number(currentAmount) / Math.pow(10, decimals);
|
|
385
478
|
const changeType = args.balanceChangeType;
|
|
386
479
|
|
|
387
|
-
if (currentAmount != null && currentAmount != 0n) {
|
|
480
|
+
if (currentAmount != null && currentAmount != 0n) {
|
|
388
481
|
if (changeType == BalanceChangeType.Borrow) {
|
|
389
482
|
totalBorrow += currentBalance * (1 + Number(assetConfig.originationFee) / Number(args.poolConfig.masterConstants.ASSET_ORIGINATION_FEE_SCALE));
|
|
390
483
|
} else if (changeType == BalanceChangeType.Repay) {
|
package/src/api/parser.ts
CHANGED
|
@@ -347,7 +347,10 @@ export function parseUserData(
|
|
|
347
347
|
: Number(BigInt(1e9) - (availableToBorrow * BigInt(1e9)) / (borrowBalance + availableToBorrow)) / 1e7;
|
|
348
348
|
|
|
349
349
|
const liquidationData = calculateLiquidationData(assetsConfig, assetsData, userLiteData.principals, prices, poolConfig);
|
|
350
|
-
|
|
350
|
+
let healthFactor = 1;
|
|
351
|
+
if (liquidationData.totalLimit != 0n) {
|
|
352
|
+
healthFactor = 1 - Number(liquidationData.totalDebt) / Number(liquidationData.totalLimit);
|
|
353
|
+
}
|
|
351
354
|
|
|
352
355
|
return {
|
|
353
356
|
...userLiteData,
|
package/src/constants/assets.ts
CHANGED
|
@@ -3,6 +3,19 @@ import { PoolAssetConfig } from "../types/Master";
|
|
|
3
3
|
import { sha256Hash } from "../utils/sha256BigInt";
|
|
4
4
|
import { JETTON_WALLET_STANDART_CODE, JETTON_WALLET_STANDART_CODE_TESTNET, NULL_ADDRESS } from "./general";
|
|
5
5
|
|
|
6
|
+
export const ASSET_ID = {
|
|
7
|
+
TON: sha256Hash('TON'),
|
|
8
|
+
USDT: sha256Hash('USDT'),
|
|
9
|
+
jUSDT: sha256Hash('jUSDT'),
|
|
10
|
+
jUSDC: sha256Hash('jUSDC'),
|
|
11
|
+
stTON: sha256Hash('stTON'),
|
|
12
|
+
tsTON: sha256Hash('tsTON'),
|
|
13
|
+
TONUSDT_DEDUST: sha256Hash('TONUSDT_DEDUST'),
|
|
14
|
+
TONUSDT_STONFI: sha256Hash('TONUSDT_STONFI'),
|
|
15
|
+
TON_STORM: sha256Hash('TON_STORM'),
|
|
16
|
+
USDT_STORM: sha256Hash('USDT_STORM'),
|
|
17
|
+
};
|
|
18
|
+
|
|
6
19
|
export const UNDEFINED_ASSET: PoolAssetConfig = {
|
|
7
20
|
name: 'undefined_asset',
|
|
8
21
|
assetId: -1n,
|
|
@@ -12,7 +25,7 @@ export const UNDEFINED_ASSET: PoolAssetConfig = {
|
|
|
12
25
|
|
|
13
26
|
export const TON_MAINNET: PoolAssetConfig = {
|
|
14
27
|
name: 'TON',
|
|
15
|
-
assetId:
|
|
28
|
+
assetId: ASSET_ID.TON,
|
|
16
29
|
jettonMasterAddress: NULL_ADDRESS, // fake
|
|
17
30
|
jettonWalletCode: Cell.EMPTY
|
|
18
31
|
}
|
|
@@ -20,21 +33,21 @@ export const TON_TESTNET = TON_MAINNET;
|
|
|
20
33
|
|
|
21
34
|
export const JUSDT_MAINNET: PoolAssetConfig = {
|
|
22
35
|
name: 'jUSDT',
|
|
23
|
-
assetId:
|
|
36
|
+
assetId: ASSET_ID.jUSDT,
|
|
24
37
|
jettonMasterAddress: Address.parse('EQBynBO23ywHy_CgarY9NK9FTz0yDsG82PtcbSTQgGoXwiuA'),
|
|
25
38
|
jettonWalletCode: JETTON_WALLET_STANDART_CODE
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
export const JUSDC_MAINNET: PoolAssetConfig = {
|
|
29
42
|
name: 'jUSDC',
|
|
30
|
-
assetId:
|
|
43
|
+
assetId: ASSET_ID.jUSDC,
|
|
31
44
|
jettonMasterAddress: Address.parse('EQB-MPwrd1G6WKNkLz_VnV6WqBDd142KMQv-g1O-8QUA3728'),
|
|
32
45
|
jettonWalletCode: JETTON_WALLET_STANDART_CODE
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
export const STTON_MAINNET: PoolAssetConfig = {
|
|
36
49
|
name: 'stTON',
|
|
37
|
-
assetId:
|
|
50
|
+
assetId: ASSET_ID.stTON,
|
|
38
51
|
jettonMasterAddress: Address.parse('EQDNhy-nxYFgUqzfUzImBEP67JqsyMIcyk2S5_RwNNEYku0k'),
|
|
39
52
|
jettonWalletCode: Cell.fromBase64(
|
|
40
53
|
'te6cckECEgEAA2IAART/APSkE/S88sgLAQIBYgIDAgLMBAUAG6D2BdqJofQB9IH0gahhAgHUBgcCASAJCgHPCDHAJJfBOAB0NMDAXGwlRNfA/AN4PpA+kAx+gAxcdch+gAx+gAwc6m0AALTHyGCEA+KfqW6lTE0WfAK4CGCEBeNRRm6ljFERAPwC+AhghBZXwe8upUxNFnwDOAUXwTABOMCMIQP8vCAIABE+kQwwADy4U2AAfO1E0PoA+kD6QNQwECNfAwGCCJiWgKFtgBByIm6zIJFxkXDiA8jLBVAGzxZQBPoCy2oDk1jMAZEw4gHJAfsAAgFYCwwCAUgQEQHxAPTP/oA+kAh8AHtRND6APpA+kDUMFE2oVIqxwXy4sEowv/y4sJUNEJwVCATVBQDyFAE+gJYzxYBzxbMySLIywES9AD0AMsAySD5AHB0yMsCygfL/8nQBPpA9AQx+gAg10nCAPLixHeAGMjLBVAIzxZw+gIXy2sTzIA0C9ztRND6APpA+kDUMAjTP/oAUVGgBfpA+kBTW8cFVHNtcFQgE1QUA8hQBPoCWM8WAc8WzMkiyMsBEvQA9ADLAMn5AHB0yMsCygfL/8nQUA3HBRyx8uLDCvoAUaihggiYloBmtgihggjk4cCgGKEnlxBJEDg3XwTjDSXXCwGAODwCeghAXjUUZyMsfGcs/UAf6AiLPFlAGzxYl+gJQA88WyVAFzCORcpFx4lAIqBOgggpiWgCgFLzy4sUEyYBA+wAQI8hQBPoCWM8WAc8WzMntVABwUnmgGKGCEHNi0JzIyx9SMMs/WPoCUAfPFlAHzxbJcYAQyMsFJM8WUAb6AhXLahTMyXH7ABAkECMAfMMAI8IAsI4hghDVMnbbcIAQyMsFUAjPFlAE+gIWy2oSyx8Syz/JcvsAkzVsIeIDyFAE+gJYzxYBzxbMye1UAMkMO1E0PoA+kD6QNQwBtM/+gAwUUShUjfHBfLiwSXC//LiwgSCC5OHAL7y4sWCEHvdl97Iyx8Uyz9Y+gIhzxbJcYAYyMsFJM8WcPoCy2rMyYBA+wBAE8hQBPoCWM8WAc8WzMntVIACBIAg1yHtRND6APpA+kDUMATTHyGCEBeNRRm6AoIQe92X3roSsfLgyNM/MfoAMBOgUCPIUAT6AljPFgHPFszJ7VSBpMmqD'
|
|
@@ -43,7 +56,7 @@ export const STTON_MAINNET: PoolAssetConfig = {
|
|
|
43
56
|
|
|
44
57
|
export const TSTON_MAINNET: PoolAssetConfig = {
|
|
45
58
|
name: 'tsTON',
|
|
46
|
-
assetId:
|
|
59
|
+
assetId: ASSET_ID.tsTON,
|
|
47
60
|
jettonMasterAddress: Address.parse('EQC98_qAmNEptUtPc7W6xdHh_ZHrBUFpw5Ft_IzNU20QAJav'),
|
|
48
61
|
jettonWalletCode: Cell.fromBase64(
|
|
49
62
|
'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'
|
|
@@ -52,7 +65,7 @@ export const TSTON_MAINNET: PoolAssetConfig = {
|
|
|
52
65
|
|
|
53
66
|
export const USDT_MAINNET: PoolAssetConfig = {
|
|
54
67
|
name: 'USDT',
|
|
55
|
-
assetId:
|
|
68
|
+
assetId: ASSET_ID.USDT,
|
|
56
69
|
jettonMasterAddress: Address.parse('EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs'),
|
|
57
70
|
jettonWalletCode: Cell.fromBoc(
|
|
58
71
|
Buffer.from(
|
|
@@ -64,21 +77,21 @@ export const USDT_MAINNET: PoolAssetConfig = {
|
|
|
64
77
|
|
|
65
78
|
export const JUSDT_TESTNET: PoolAssetConfig = {
|
|
66
79
|
name: 'jUSDT',
|
|
67
|
-
assetId:
|
|
80
|
+
assetId: ASSET_ID.jUSDT,
|
|
68
81
|
jettonMasterAddress: Address.parse('kQBe4gtSQMxM5RpMYLr4ydNY72F8JkY-icZXG1NJcsju8XM7'),
|
|
69
82
|
jettonWalletCode: JETTON_WALLET_STANDART_CODE_TESTNET
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
export const JUSDC_TESTNET: PoolAssetConfig = {
|
|
73
86
|
name: 'jUSDC',
|
|
74
|
-
assetId:
|
|
87
|
+
assetId: ASSET_ID.jUSDC,
|
|
75
88
|
jettonMasterAddress: Address.parse('kQDaY5yUatYnHei73HBqRX_Ox9LK2XnR7XuCY9MFC2INbfYI'),
|
|
76
89
|
jettonWalletCode: JETTON_WALLET_STANDART_CODE_TESTNET
|
|
77
90
|
}
|
|
78
91
|
|
|
79
92
|
export const STTON_TESTNET: PoolAssetConfig = {
|
|
80
93
|
name: 'stTON',
|
|
81
|
-
assetId:
|
|
94
|
+
assetId: ASSET_ID.stTON,
|
|
82
95
|
jettonMasterAddress: Address.parse('kQC3Duw3dg8k98xf5S7Bm7YOWVJ5QW8hm3iLqFfJfa_g9h07'),
|
|
83
96
|
jettonWalletCode: Cell.fromBoc(
|
|
84
97
|
Buffer.from(
|
|
@@ -90,7 +103,7 @@ export const STTON_TESTNET: PoolAssetConfig = {
|
|
|
90
103
|
|
|
91
104
|
export const TONUSDT_DEDUST_MAINNET: PoolAssetConfig = {
|
|
92
105
|
name: 'TONUSDT_DEDUST',
|
|
93
|
-
assetId:
|
|
106
|
+
assetId: ASSET_ID.TONUSDT_DEDUST,
|
|
94
107
|
jettonMasterAddress: Address.parse('EQA-X_yo3fzzbDbJ_0bzFWKqtRuZFIRa1sJsveZJ1YpViO3r'),
|
|
95
108
|
jettonWalletCode: Cell.fromBoc(
|
|
96
109
|
Buffer.from(
|
|
@@ -102,7 +115,7 @@ export const TONUSDT_DEDUST_MAINNET: PoolAssetConfig = {
|
|
|
102
115
|
|
|
103
116
|
export const TON_STORM_MAINNET: PoolAssetConfig = {
|
|
104
117
|
name: 'TON_STORM',
|
|
105
|
-
assetId:
|
|
118
|
+
assetId: ASSET_ID.TON_STORM,
|
|
106
119
|
jettonMasterAddress: Address.parse('EQCNY2AQ3ZDYwJAqx_nzl9i9Xhd_Ex7izKJM6JTxXRnO6n1F'),
|
|
107
120
|
jettonWalletCode: Cell.fromBoc(
|
|
108
121
|
Buffer.from(
|
|
@@ -110,11 +123,12 @@ export const TON_STORM_MAINNET: PoolAssetConfig = {
|
|
|
110
123
|
'hex',
|
|
111
124
|
),
|
|
112
125
|
)[0],
|
|
126
|
+
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
export const USDT_STORM_MAINNET: PoolAssetConfig = {
|
|
116
130
|
name: 'USDT_STORM',
|
|
117
|
-
assetId:
|
|
131
|
+
assetId: ASSET_ID.USDT_STORM,
|
|
118
132
|
jettonMasterAddress: Address.parse('EQCup4xxCulCcNwmOocM9HtDYPU8xe0449tQLp6a-5BLEegW'),
|
|
119
133
|
jettonWalletCode: Cell.fromBoc(
|
|
120
134
|
Buffer.from(
|
package/src/constants/general.ts
CHANGED
|
@@ -2,15 +2,21 @@ import { Address, Cell, toNano } from '@ton/core';
|
|
|
2
2
|
import { sha256Hash } from '../utils/sha256BigInt';
|
|
3
3
|
import { OracleNFT } from '../types/Master';
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
const ASSET_PRICE_SCALE = BigInt(1e9);
|
|
7
|
+
|
|
5
8
|
export const MASTER_CONSTANTS = {
|
|
6
9
|
FACTOR_SCALE: BigInt(1e12),
|
|
7
10
|
ASSET_COEFFICIENT_SCALE: 10000n,
|
|
8
|
-
ASSET_PRICE_SCALE
|
|
11
|
+
ASSET_PRICE_SCALE,
|
|
9
12
|
ASSET_RESERVE_FACTOR_SCALE: 10000n,
|
|
10
13
|
ASSET_LIQUIDATION_RESERVE_FACTOR_SCALE: 10000n,
|
|
11
14
|
ASSET_ORIGINATION_FEE_SCALE: BigInt(1e9),
|
|
12
15
|
ASSET_LIQUIDATION_THRESHOLD_SCALE: 10_000n,
|
|
13
16
|
ASSET_LIQUIDATION_BONUS_SCALE: 10_000n,
|
|
17
|
+
ASSET_SRATE_SCALE: BigInt(1e12),
|
|
18
|
+
ASSET_BRATE_SCALE: BigInt(1e12),
|
|
19
|
+
COLLATERAL_WORTH_THRESHOLD: 100n * ASSET_PRICE_SCALE, // literally 100$
|
|
14
20
|
};
|
|
15
21
|
|
|
16
22
|
export const NULL_ADDRESS = Address.parse('UQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJKZ');
|