@evaafi/sdk 0.5.4 → 0.5.6-a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/api/math.d.ts +24 -2
  2. package/dist/api/math.js +185 -50
  3. package/dist/api/parser.d.ts +3 -3
  4. package/dist/api/parser.js +32 -19
  5. package/dist/api/prices.d.ts +1 -1
  6. package/dist/api/prices.js +4 -3
  7. package/dist/config.d.ts +1 -0
  8. package/dist/config.js +4 -0
  9. package/dist/constants/assets.d.ts +2 -3
  10. package/dist/constants/assets.js +10 -2
  11. package/dist/constants/general.d.ts +3 -2
  12. package/dist/constants/general.js +6 -5
  13. package/dist/constants/pools.d.ts +0 -1
  14. package/dist/constants/pools.js +1 -14
  15. package/dist/constants.d.ts +4 -4
  16. package/dist/constants.js +15 -7
  17. package/dist/contracts/MasterContract.d.ts +13 -45
  18. package/dist/contracts/MasterContract.js +10 -12
  19. package/dist/contracts/UserContract.js +7 -7
  20. package/dist/index.d.ts +6 -5
  21. package/dist/index.js +5 -3
  22. package/dist/types/Master.d.ts +8 -7
  23. package/dist/types/User.d.ts +5 -5
  24. package/dist/utils/merkleProof.d.ts +4 -0
  25. package/dist/utils/merkleProof.js +108 -0
  26. package/dist/utils/priceUtils.d.ts +55 -0
  27. package/dist/utils/priceUtils.js +117 -0
  28. package/dist/utils/userJettonWallet.d.ts +2 -2
  29. package/dist/utils/userJettonWallet.js +4 -0
  30. package/dist/utils/utils.d.ts +2 -0
  31. package/dist/utils/utils.js +7 -0
  32. package/package.json +2 -2
  33. package/src/api/math.ts +234 -50
  34. package/src/api/parser.ts +52 -37
  35. package/src/api/prices.ts +2 -1
  36. package/src/constants/assets.ts +11 -3
  37. package/src/constants/general.ts +6 -4
  38. package/src/constants/pools.ts +1 -15
  39. package/src/contracts/MasterContract.ts +25 -67
  40. package/src/contracts/UserContract.ts +8 -10
  41. package/src/index.ts +4 -7
  42. package/src/types/Master.ts +9 -8
  43. package/src/types/User.ts +5 -5
  44. package/src/utils/userJettonWallet.ts +6 -2
  45. package/src/utils/utils.ts +6 -0
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sumDicts = exports.packOraclesData = exports.createOracleDataProof = exports.packPrices = exports.packAssetsData = exports.getMedianPrice = exports.verifyPrices = exports.parsePrices = exports.loadPrices = void 0;
4
+ const core_1 = require("@ton/core");
5
+ const config_1 = require("../config");
6
+ const merkleProof_1 = require("./merkleProof");
7
+ async function loadPrices(oracleNftId, endpoints) {
8
+ return await Promise.any(endpoints.map(x => loadOracleData(oracleNftId, x)));
9
+ }
10
+ exports.loadPrices = loadPrices;
11
+ async function loadOracleData(oracleNftId, endpoint) {
12
+ let result = await fetch(`https://${endpoint}/api/indexer/v1/outputs/nft/${oracleNftId}`, {
13
+ headers: { accept: 'application/json' },
14
+ signal: AbortSignal.timeout(5000)
15
+ });
16
+ let outputId = (await result.json());
17
+ result = await fetch(`https://${endpoint}/api/core/v2/outputs/${outputId.items[0]}`, {
18
+ headers: { accept: 'application/json' },
19
+ signal: AbortSignal.timeout(5000)
20
+ });
21
+ return await result.json();
22
+ }
23
+ async function parsePrices(outputData, oracleId) {
24
+ const data = JSON.parse(decodeURIComponent(outputData.output.features[0].data.replace('0x', '').replace(/[0-9a-f]{2}/g, '%$&')));
25
+ try {
26
+ const pricesCell = core_1.Cell.fromBoc(Buffer.from(data['packedPrices'], 'hex'))[0];
27
+ const signature = Buffer.from(data['signature'], 'hex');
28
+ const publicKey = Buffer.from(data['publicKey'], 'hex');
29
+ const timestamp = Number(data['timestamp']);
30
+ return {
31
+ dict: pricesCell.beginParse().loadRef().beginParse().loadDictDirect(core_1.Dictionary.Keys.BigUint(256), core_1.Dictionary.Values.BigVarUint(4)),
32
+ dataCell: (0, core_1.beginCell)().storeRef(pricesCell).storeBuffer(signature).endCell(),
33
+ oracleId: oracleId,
34
+ signature: signature,
35
+ pubkey: publicKey,
36
+ timestamp: timestamp,
37
+ };
38
+ }
39
+ catch (error) {
40
+ console.log(oracleId, data, error);
41
+ throw Error();
42
+ }
43
+ }
44
+ exports.parsePrices = parsePrices;
45
+ function verifyPrices(assets) {
46
+ return function (priceData) {
47
+ const timestamp = Date.now() / 1000;
48
+ const pricesTime = priceData.timestamp;
49
+ for (const asset of assets) {
50
+ if (!priceData.dict.has(asset.assetId)) {
51
+ return false;
52
+ }
53
+ }
54
+ // console.log('timestamp', timestamp, 'pricestime', pricesTime, timestamp - pricesTime);
55
+ return timestamp - pricesTime < config_1.TTL_ORACLE_DATA_SEC;
56
+ };
57
+ }
58
+ exports.verifyPrices = verifyPrices;
59
+ function getMedianPrice(pricesData, asset) {
60
+ const sorted = pricesData.map(x => x.dict.get(asset)).sort((a, b) => Number(a) - Number(b));
61
+ const mid = Math.floor(sorted.length / 2);
62
+ if (sorted.length % 2 === 0) {
63
+ return (sorted[mid - 1] + sorted[mid]) / 2n;
64
+ }
65
+ else {
66
+ return sorted[mid];
67
+ }
68
+ }
69
+ exports.getMedianPrice = getMedianPrice;
70
+ function packAssetsData(assetsData) {
71
+ if (assetsData.length == 0) {
72
+ throw new Error("No assets data to pack");
73
+ }
74
+ return assetsData.reduceRight((acc, { assetId, medianPrice }) => (0, core_1.beginCell)()
75
+ .storeUint(assetId, 256)
76
+ .storeCoins(medianPrice)
77
+ .storeMaybeRef(acc)
78
+ .endCell(), null);
79
+ }
80
+ exports.packAssetsData = packAssetsData;
81
+ function packPrices(assetsDataCell, oraclesDataCell) {
82
+ let pricesCell = (0, core_1.beginCell)()
83
+ .storeRef(assetsDataCell)
84
+ .storeRef(oraclesDataCell)
85
+ .endCell();
86
+ return pricesCell;
87
+ }
88
+ exports.packPrices = packPrices;
89
+ function createOracleDataProof(oracle, data, signature, assets) {
90
+ let prunedDict = (0, merkleProof_1.generateMerkleProofDirect)(data.prices, assets, core_1.Dictionary.Keys.BigUint(256));
91
+ let prunedData = (0, core_1.beginCell)().storeUint(data.timestamp, 32).storeMaybeRef(prunedDict).endCell();
92
+ let merkleProof = (0, merkleProof_1.convertToMerkleProof)(prunedData);
93
+ let oracleDataProof = (0, core_1.beginCell)().storeUint(oracle.id, 32).storeRef(merkleProof).storeBuffer(signature).asSlice();
94
+ return oracleDataProof;
95
+ }
96
+ exports.createOracleDataProof = createOracleDataProof;
97
+ function packOraclesData(oraclesData, assets) {
98
+ if (oraclesData.length == 0) {
99
+ throw new Error("no oracles data to pack");
100
+ }
101
+ let proofs = oraclesData.sort((d1, d2) => d1.oracle.id - d2.oracle.id).map(({ oracle, data, signature }) => createOracleDataProof(oracle, data, signature, assets));
102
+ return proofs.reduceRight((acc, val) => (0, core_1.beginCell)().storeSlice(val).storeMaybeRef(acc).endCell(), null);
103
+ }
104
+ exports.packOraclesData = packOraclesData;
105
+ // : String = "api.stardust-mainnet.iotaledger.net"
106
+ function sumDicts(result, addendum) {
107
+ for (const key of addendum.keys()) {
108
+ const current = result.get(key);
109
+ const value = addendum.get(key);
110
+ if (current === undefined) {
111
+ result.set(key, value);
112
+ continue;
113
+ }
114
+ result.set(key, current + value);
115
+ }
116
+ }
117
+ exports.sumDicts = sumDicts;
@@ -1,3 +1,3 @@
1
1
  import { Address } from '@ton/core';
2
- import { PoolAssetConfig, PoolJettonAssetConfig } from '../types/Master';
3
- export declare function getUserJettonWallet(ownerAddress: Address, poolAssetConfig: PoolAssetConfig & PoolJettonAssetConfig): Address;
2
+ import { PoolAssetConfig } from '../types/Master';
3
+ export declare function getUserJettonWallet(ownerAddress: Address, poolAssetConfig: PoolAssetConfig): Address;
@@ -2,7 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getUserJettonWallet = void 0;
4
4
  const core_1 = require("@ton/core");
5
+ const assets_1 = require("../constants/assets");
5
6
  function getUserJettonWallet(ownerAddress, poolAssetConfig) {
7
+ if (poolAssetConfig.name == 'TON' || poolAssetConfig.assetId === assets_1.UNDEFINED_ASSET.assetId) {
8
+ throw new Error(`Cant getUserJettonWallet for ${poolAssetConfig.name} asset`);
9
+ }
6
10
  const jettonMasterAddress = poolAssetConfig.jettonMasterAddress;
7
11
  const jettonWalletCode = poolAssetConfig.jettonWalletCode;
8
12
  if (poolAssetConfig.name === 'USDT') {
@@ -0,0 +1,2 @@
1
+ import { PoolAssetConfig } from "../types/Master";
2
+ export declare function isTonAsset(asset: PoolAssetConfig): boolean;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isTonAsset = void 0;
4
+ function isTonAsset(asset) {
5
+ return asset.name === 'TON';
6
+ }
7
+ exports.isTonAsset = isTonAsset;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evaafi/sdk",
3
- "version": "0.5.4",
3
+ "version": "0.5.6a",
4
4
  "description": "SDK for EVAA contracts",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -20,7 +20,7 @@
20
20
  "devDependencies": {
21
21
  "@orbs-network/ton-access": "^2.3.3",
22
22
  "@ton/core": "0.56.0",
23
- "@tonconnect/sdk": "^3.0.0",
23
+ "@tonconnect/sdk": "^3.0.5",
24
24
  "@types/jest": "^29.5.12",
25
25
  "@types/node": "^20.10.4",
26
26
  "crypto-js": "^4.2.0",
package/src/api/math.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { AssetConfig, AssetData, AssetInterest, ExtendedAssetData, ExtendedAssetsConfig, ExtendedAssetsData, MasterConstants } from '../types/Master';
1
+ import { AgregatedBalances, AssetConfig, AssetData, AssetInterest, ExtendedAssetData, ExtendedAssetsConfig, ExtendedAssetsData, MasterConstants, PoolConfig } from '../types/Master';
2
2
  import { Dictionary } from '@ton/core';
3
3
  import { BalanceChangeType, BalanceType, LiquidationData, PredictHealthFactorArgs, UserBalance } from '../types/User';
4
4
  import { sha256Hash } from '../utils/sha256BigInt';
5
+ import { TON_MAINNET, UNDEFINED_ASSET } from '../constants/assets';
6
+ import { MAINNET_POOL_CONFIG, TESTNET_POOL_CONFIG } from '..';
5
7
 
6
8
  export function mulFactor(decimal: bigint, a: bigint, b: bigint): bigint {
7
9
  return (a * b) / decimal;
@@ -11,6 +13,12 @@ export function mulDiv(x: bigint, y: bigint, z: bigint): bigint {
11
13
  return (x * y) / z;
12
14
  }
13
15
 
16
+ export function mulDivC(x: bigint, y: bigint, z: bigint): bigint {
17
+ //const mul = x * y;
18
+ //return mul / z + (mul % z ? 1n : 0n);
19
+ return BigInt(Math.ceil(Number(x * y) / Number(z)));
20
+ }
21
+
14
22
  export function bigIntMax(...args: bigint[]): bigint {
15
23
  return args.reduce((m, e) => (e > m ? e : m));
16
24
  }
@@ -116,6 +124,169 @@ export function calculateAssetInterest(assetConfig: AssetConfig, assetData: Asse
116
124
  };
117
125
  }
118
126
 
127
+ export function checkNotInDebtAtAll(principals: Dictionary<bigint, bigint>): boolean {
128
+ return principals.values().every(x => x >= 0n);
129
+ }
130
+
131
+ export function getAgregatedBalances (
132
+ assetsData: ExtendedAssetsData,
133
+ assetsConfig: ExtendedAssetsConfig,
134
+ principals: Dictionary<bigint, bigint>,
135
+ prices: Dictionary<bigint, bigint>,
136
+ masterConstants: MasterConstants,
137
+ ): AgregatedBalances {
138
+ let user_total_supply = 0n;
139
+ let user_total_borrow = 0n;
140
+
141
+ for (const [assetId, principal] of principals) {
142
+
143
+ if (principal) {
144
+
145
+ if (!prices.has(assetId)) {
146
+ return {totalSupply: 0n, totalBorrow: 0n};
147
+ }
148
+ const price = prices.get(assetId)!;
149
+ const assetData = assetsData.get(assetId)!;
150
+ const assetConfig = assetsConfig.get(assetId)!;
151
+ // console.log('price', price);
152
+ if (principal < 0) {
153
+ user_total_borrow += presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals;
154
+ } else {
155
+ user_total_supply += presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals;
156
+ }
157
+ // console.log('aggregated', assetId, presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).type, presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals)
158
+ }
159
+ }
160
+ return {totalSupply: user_total_supply, totalBorrow: user_total_borrow};
161
+ }
162
+
163
+ /**
164
+ * @deprecated The method should be used only for main contract v5
165
+ */
166
+ export function isV5MainPoolContract(poolConfig: PoolConfig): boolean {
167
+ if ((poolConfig.masterAddress == MAINNET_POOL_CONFIG.masterAddress && poolConfig.masterVersion == 5) ||
168
+ (poolConfig.masterAddress == TESTNET_POOL_CONFIG.masterAddress && poolConfig.masterVersion == 5)) {
169
+ return true;
170
+ } else {
171
+ return false;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * @deprecated The method should be used only for main contract v5
177
+ */
178
+ export function calculateMaximumWithdrawAmountOld(
179
+ assetsConfig: ExtendedAssetsConfig,
180
+ assetsData: ExtendedAssetsData,
181
+ principals: Dictionary<bigint, bigint>,
182
+ prices: Dictionary<bigint, bigint>,
183
+ masterConstants: MasterConstants,
184
+ assetId: bigint,
185
+ ): bigint {
186
+ let withdrawAmountMax = 0n;
187
+
188
+ const assetConfig = assetsConfig.get(assetId) as AssetConfig;
189
+ const assetData = assetsData.get(assetId) as ExtendedAssetData;
190
+ const oldPrincipal = principals.get(assetId) as bigint;
191
+ const oldPresentValue = presentValue(assetData.sRate, assetData.bRate, oldPrincipal, masterConstants);
192
+
193
+ if (oldPresentValue.amount > assetConfig.dust) {
194
+ if(checkNotInDebtAtAll(principals)) {
195
+ withdrawAmountMax = oldPresentValue.amount;
196
+ } else {
197
+ if (!prices.has(assetId)) {
198
+ return 0n;
199
+ }
200
+
201
+ //const borrowable = getAvailableToBorrow(assetsConfig, assetsData, principals, prices, masterConstants);
202
+ const price = prices.get(assetId) as bigint;
203
+ const agregatedBalances = getAgregatedBalances(assetsData, assetsConfig, principals, prices, masterConstants);
204
+ let maxAmountToReclaim =
205
+ mulDiv(
206
+ agregatedBalances.totalSupply - mulDivC(agregatedBalances.totalBorrow, masterConstants.ASSET_COEFFICIENT_SCALE, assetConfig.collateralFactor),
207
+ 10n**assetConfig.decimals,
208
+ price
209
+ );
210
+
211
+ withdrawAmountMax = bigIntMin(
212
+ maxAmountToReclaim,
213
+ oldPresentValue.amount
214
+ );
215
+ //console.log('agregatedBalances', agregatedBalances);
216
+ //console.log('masterConstants.ASSET_COEFFICIENT_SCALE', masterConstants.ASSET_COEFFICIENT_SCALE);
217
+ //console.log('assetConfig.collateralFactor', assetConfig.collateralFactor);
218
+ //console.log('sekay', maxAmountToReclaim, oldPresentValue.amount);
219
+ }
220
+ } else {
221
+ if (!prices.has(assetId)) {
222
+ return 0n;
223
+ }
224
+
225
+ const price = prices.get(assetId) as bigint;
226
+
227
+ return getAvailableToBorrow(assetsConfig, assetsData, principals, prices, masterConstants) * (10n ** assetConfig.decimals) / price;
228
+ }
229
+
230
+ return withdrawAmountMax;
231
+ }
232
+
233
+ export function calculateMaximumWithdrawAmount( // todo v6 ifelse dust not debt at all is fixed?
234
+ assetsConfig: ExtendedAssetsConfig,
235
+ assetsData: ExtendedAssetsData,
236
+ principals: Dictionary<bigint, bigint>,
237
+ prices: Dictionary<bigint, bigint>,
238
+ masterConstants: MasterConstants,
239
+ assetId: bigint,
240
+ ): bigint {
241
+ let withdrawAmountMax = 0n;
242
+
243
+ const assetConfig = assetsConfig.get(assetId) as AssetConfig;
244
+ const assetData = assetsData.get(assetId) as ExtendedAssetData;
245
+ const oldPrincipal = principals.get(assetId) as bigint;
246
+
247
+ if (oldPrincipal > assetConfig.dust) {
248
+ const oldPresentValue = presentValue(assetData.sRate, assetData.bRate, oldPrincipal, masterConstants);
249
+ if(checkNotInDebtAtAll(principals)) {
250
+ withdrawAmountMax = oldPresentValue.amount;
251
+ } else {
252
+ if (!prices.has(assetId)) {
253
+ return 0n;
254
+ }
255
+
256
+ const borrowable = getAvailableToBorrow(assetsConfig, assetsData, principals, prices, masterConstants);
257
+ const price = prices.get(assetId) as bigint;
258
+
259
+ let maxAmountToReclaim = 0n;
260
+
261
+ if (assetConfig.collateralFactor == 0n) {
262
+ maxAmountToReclaim = oldPresentValue.amount;
263
+ }
264
+ else if (price > 0) {
265
+ maxAmountToReclaim =
266
+ mulDiv(
267
+ mulDivC(borrowable, masterConstants.ASSET_COEFFICIENT_SCALE, assetConfig.collateralFactor),
268
+ 10n ** assetConfig.decimals, price
269
+ );
270
+ }
271
+
272
+ withdrawAmountMax = bigIntMin(
273
+ maxAmountToReclaim,
274
+ oldPresentValue.amount
275
+ );
276
+ }
277
+ } else {
278
+ if (!prices.has(assetId)) {
279
+ return 0n;
280
+ }
281
+
282
+ const price = prices.get(assetId) as bigint;
283
+
284
+ return getAvailableToBorrow(assetsConfig, assetsData, principals, prices, masterConstants) * (10n ** assetConfig.decimals) / price;
285
+ }
286
+
287
+ return withdrawAmountMax;
288
+ }
289
+
119
290
  export function getAvailableToBorrow(
120
291
  assetsConfig: ExtendedAssetsConfig,
121
292
  assetsData: ExtendedAssetsData,
@@ -136,9 +307,10 @@ export function getAvailableToBorrow(
136
307
  borrowAmount += (calculatePresentValue(assetData.bRate, -principal, masterConstants) * price) / 10n ** assetConfig.decimals;
137
308
  } else if (principal > 0) {
138
309
  borrowLimit +=
139
- (calculatePresentValue(assetData.sRate, principal, masterConstants) * price * assetConfig.collateralFactor) /
140
- 10n ** assetConfig.decimals /
141
- masterConstants.ASSET_COEFFICIENT_SCALE;
310
+ mulDivC(
311
+ mulDivC(calculatePresentValue(assetData.sRate, principal, masterConstants), price, 10n ** assetConfig.decimals),
312
+ assetConfig.collateralFactor,
313
+ masterConstants.ASSET_COEFFICIENT_SCALE);
142
314
  }
143
315
  }
144
316
 
@@ -164,74 +336,86 @@ export function presentValue(sRate: bigint, bRate: bigint, principalValue: bigin
164
336
  }
165
337
  }
166
338
 
339
+ /**
340
+ *
341
+ * @param assetsConfig
342
+ * @param assetsData
343
+ * @param principals
344
+ * @param prices
345
+ * @param poolConfig
346
+ * @returns can return UNDEFINED_ASSET if there are no assets
347
+ */
167
348
  export function calculateLiquidationData(
168
349
  assetsConfig: ExtendedAssetsConfig,
169
350
  assetsData: ExtendedAssetsData,
170
351
  principals: Dictionary<bigint, bigint>,
171
352
  prices: Dictionary<bigint, bigint>,
172
- masterConstants: MasterConstants,
353
+ poolConfig: PoolConfig,
173
354
  ): LiquidationData {
174
- let gCollateralValue = 0n;
175
- let gCollateralAsset = 0n;
176
- let gLoanValue = 0n;
177
- let gLoanAsset = 0n;
355
+ let collateralValue = 0n;
356
+ let collateralAsset = UNDEFINED_ASSET;
357
+ let loanValue = 0n;
358
+ let loanAsset = UNDEFINED_ASSET;
178
359
  let totalDebt = 0n;
179
360
  let totalLimit = 0n;
180
361
 
181
- for (const key of principals.keys()) {
182
- const principal = principals.get(key)!;
183
- const assetConfig = assetsConfig.get(key)!;
184
- const assetData = assetsData.get(key)!;
362
+ for (const asset of poolConfig.poolAssetsConfig) {
363
+ if (!principals.has(asset.assetId)) {
364
+ continue;
365
+ }
366
+ const principal = principals.get(asset.assetId)!;
367
+ const assetConfig = assetsConfig.get(asset.assetId)!;
368
+ const assetData = assetsData.get(asset.assetId)!;
185
369
  const balance =
186
370
  principal > 0 ? (principal * assetData.sRate) / BigInt(1e12) : (principal * assetData.bRate) / BigInt(1e12);
187
371
  if (balance > 0) {
188
- const assetWorth = (balance * prices.get(key)!) / 10n ** assetConfig.decimals;
189
- totalLimit += (assetWorth * assetConfig.liquidationThreshold) / masterConstants.ASSET_COEFFICIENT_SCALE;
190
- if (assetWorth > gCollateralValue) {
191
- gCollateralValue = assetWorth;
192
- gCollateralAsset = key;
372
+ const assetWorth = (balance * prices.get(asset.assetId)!) / 10n ** assetConfig.decimals;
373
+ totalLimit += (assetWorth * assetConfig.liquidationThreshold) / poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE;
374
+ if (assetWorth > collateralValue) {
375
+ collateralValue = assetWorth;
376
+ collateralAsset = asset;
193
377
  }
194
378
  } else if (balance < 0) {
195
- const assetWorth = (-balance * prices.get(key)!) / 10n ** assetConfig.decimals;
379
+ const assetWorth = (-balance * prices.get(asset.assetId)!) / 10n ** assetConfig.decimals;
196
380
  totalDebt += assetWorth;
197
- if (assetWorth > gLoanValue) {
198
- gLoanValue = assetWorth;
199
- gLoanAsset = key;
381
+ if (assetWorth > loanValue) {
382
+ loanValue = assetWorth;
383
+ loanAsset = asset;
200
384
  }
201
385
  }
202
386
  }
203
387
 
204
- if (totalLimit < totalDebt) {
205
- const gLoanAssetPrice = prices.get(gLoanAsset)!;
388
+ if (collateralAsset.assetId !== UNDEFINED_ASSET.assetId && totalLimit < totalDebt) {
389
+ const loanAssetPrice = prices.get(loanAsset.assetId)!;
206
390
  const values: bigint[] = [];
207
- const gCollateralAssetConfig = assetsConfig.get(gCollateralAsset)!;
208
- const gLoanAssetConfig = assetsConfig.get(gLoanAsset)!;
209
- const liquidationBonus = gCollateralAssetConfig.liquidationBonus;
210
- const loanDecimal = 10n ** gLoanAssetConfig.decimals;
391
+ const collateralAssetConfig = assetsConfig.get(collateralAsset.assetId)!;
392
+ const loanAssetConfig = assetsConfig.get(loanAsset.assetId)!;
393
+ const liquidationBonus = collateralAssetConfig.liquidationBonus;
394
+ const loanScale = 10n ** loanAssetConfig.decimals;
211
395
  values.push(
212
- (bigIntMax(gCollateralValue / 2n, bigIntMin(gCollateralValue, 10_000_000_000n)) *
213
- loanDecimal *
214
- masterConstants.ASSET_COEFFICIENT_SCALE) /
396
+ (bigIntMax(collateralValue / 2n, bigIntMin(collateralValue, 100_000_000_000n)) *
397
+ loanScale *
398
+ poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE) /
215
399
  liquidationBonus /
216
- gLoanAssetPrice,
400
+ loanAssetPrice,
217
401
  );
218
- values.push((gLoanValue * loanDecimal) / gLoanAssetPrice);
402
+ values.push((loanValue * loanScale) / loanAssetPrice);
219
403
 
220
404
  const liquidationAmount = (bigIntMin(...values) as bigint) - 5n;
221
- const gCollateralAssetPrice: bigint = prices.get(gCollateralAsset)!;
222
- const collateralDecimal = 10n ** gCollateralAssetConfig.decimals;
405
+ const collateralAssetPrice: bigint = prices.get(collateralAsset.assetId)!;
406
+ const collateralDecimal = 10n ** collateralAssetConfig.decimals;
223
407
  let minCollateralAmount =
224
- (((liquidationAmount * gLoanAssetPrice * liquidationBonus) / 10000n) * collateralDecimal) /
225
- gCollateralAssetPrice /
226
- loanDecimal -
408
+ (((liquidationAmount * loanAssetPrice * liquidationBonus) / poolConfig.masterConstants.ASSET_LIQUIDATION_BONUS_SCALE) * collateralDecimal) /
409
+ collateralAssetPrice /
410
+ loanScale -
227
411
  10n;
228
412
  minCollateralAmount = (minCollateralAmount * 97n) / 100n;
229
413
  if (minCollateralAmount / collateralDecimal >= 1n) {
230
414
  return {
231
- greatestCollateralAsset: gCollateralAsset,
232
- greatestCollateralValue: gCollateralValue,
233
- greatestLoanAsset: gLoanAsset,
234
- greatestLoanValue: gLoanValue,
415
+ greatestCollateralAsset: collateralAsset,
416
+ greatestCollateralValue: collateralValue,
417
+ greatestLoanAsset: loanAsset,
418
+ greatestLoanValue: loanValue,
235
419
  totalDebt,
236
420
  totalLimit,
237
421
  liquidable: true,
@@ -242,10 +426,10 @@ export function calculateLiquidationData(
242
426
  }
243
427
 
244
428
  return {
245
- greatestCollateralAsset: gCollateralAsset,
246
- greatestCollateralValue: gCollateralValue,
247
- greatestLoanAsset: gLoanAsset,
248
- greatestLoanValue: gLoanValue,
429
+ greatestCollateralAsset: collateralAsset,
430
+ greatestCollateralValue: collateralValue,
431
+ greatestLoanAsset: loanAsset,
432
+ greatestLoanValue: loanValue,
249
433
  totalDebt,
250
434
  totalLimit,
251
435
  liquidable: false,
@@ -253,7 +437,7 @@ export function calculateLiquidationData(
253
437
  }
254
438
 
255
439
  export function predictHealthFactor(args: PredictHealthFactorArgs): number {
256
- const liquidationData = calculateLiquidationData(args.assetsConfig, args.assetsData, args.balances, args.prices, args.masterConstants);
440
+ const liquidationData = calculateLiquidationData(args.assetsConfig, args.assetsData, args.principals, args.prices, args.poolConfig);
257
441
  const tokenHash = sha256Hash(args.tokenSymbol);
258
442
 
259
443
  const assetConfig = args.assetsConfig.get(tokenHash)!;
@@ -271,13 +455,13 @@ export function predictHealthFactor(args: PredictHealthFactorArgs): number {
271
455
 
272
456
  if (currentAmount != null && currentAmount != 0n) {
273
457
  if (changeType == BalanceChangeType.Borrow) {
274
- totalBorrow += currentBalance * (1 + Number(assetConfig.originationFee) / Number(args.masterConstants.ASSET_ORIGINATION_FEE_SCALE));
458
+ totalBorrow += currentBalance * (1 + Number(assetConfig.originationFee) / Number(args.poolConfig.masterConstants.ASSET_ORIGINATION_FEE_SCALE));
275
459
  } else if (changeType == BalanceChangeType.Repay) {
276
460
  totalBorrow -= currentBalance;
277
461
  } else if (changeType == BalanceChangeType.Withdraw) {
278
- totalLimit -= currentBalance * Number(assetConfig.liquidationThreshold) / Number(args.masterConstants.ASSET_COEFFICIENT_SCALE);
462
+ totalLimit -= currentBalance * Number(assetConfig.liquidationThreshold) / Number(args.poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE);
279
463
  } else if (changeType == BalanceChangeType.Supply) {
280
- totalLimit += currentBalance * Number(assetConfig.liquidationThreshold) / Number(args.masterConstants.ASSET_COEFFICIENT_SCALE);
464
+ totalLimit += currentBalance * Number(assetConfig.liquidationThreshold) / Number(args.poolConfig.masterConstants.ASSET_COEFFICIENT_SCALE);
281
465
  }
282
466
  }
283
467
  if (Number(totalLimit) == 0) {