@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.
@@ -13,6 +13,7 @@ class EvaaUser {
13
13
  /**
14
14
  * Create user contract wrapper from address
15
15
  * @param address user contract address
16
+ * @param poolConfig pool config
16
17
  */
17
18
  static createFromAddress(address, poolConfig = pools_1.MAINNET_POOL_CONFIG) {
18
19
  return new EvaaUser(address, poolConfig);
@@ -22,10 +23,10 @@ class EvaaUser {
22
23
  this.address = address;
23
24
  this.poolConfig = poolConfig;
24
25
  }
25
- async getSyncLite(provider, assetsData, assetsConfig) {
26
+ async getSyncLite(provider, assetsData, assetsConfig, applyDust = false) {
26
27
  const state = (await provider.getState()).state;
27
28
  if (state.type === 'active') {
28
- this._liteData = (0, parser_1.parseUserLiteData)(state.data.toString('base64'), assetsData, assetsConfig, this.poolConfig);
29
+ this._liteData = (0, parser_1.parseUserLiteData)(state.data.toString('base64'), assetsData, assetsConfig, this.poolConfig, applyDust);
29
30
  this.lastSync = Math.floor(Date.now() / 1000);
30
31
  }
31
32
  else {
@@ -62,11 +63,11 @@ class EvaaUser {
62
63
  .endCell(),
63
64
  });
64
65
  }
65
- async getSync(provider, assetsData, assetsConfig, prices) {
66
+ async getSync(provider, assetsData, assetsConfig, prices, applyDust = false) {
66
67
  const state = (await provider.getState()).state;
67
68
  if (state.type === 'active') {
68
- this._liteData = (0, parser_1.parseUserLiteData)(state.data.toString('base64'), assetsData, assetsConfig, this.poolConfig);
69
- this._data = (0, parser_1.parseUserData)(this._liteData, assetsData, assetsConfig, prices, this.poolConfig);
69
+ this._liteData = (0, parser_1.parseUserLiteData)(state.data.toString('base64'), assetsData, assetsConfig, this.poolConfig, applyDust);
70
+ this._data = (0, parser_1.parseUserData)(this._liteData, assetsData, assetsConfig, prices, this.poolConfig, applyDust);
70
71
  this.lastSync = Math.floor(Date.now() / 1000);
71
72
  }
72
73
  else {
package/dist/index.d.ts CHANGED
@@ -1,15 +1,16 @@
1
- export { mulFactor, mulDiv, bigIntMin, bigIntMax, calculatePresentValue, calculateCurrentRates, calculateAssetData, calculateAssetInterest, getAvailableToBorrow, calculateMaximumWithdrawAmount, presentValue, calculateLiquidationData, predictHealthFactor } from './api/math';
1
+ export { mulFactor, mulDiv, bigIntMin, bigIntMax, calculatePresentValue, calculateCurrentRates, calculateAssetData, calculateAssetInterest, getAvailableToBorrow, calculateMaximumWithdrawAmount, presentValue, calculateLiquidationData, predictHealthFactor, calculateHealthParams, BigMath, } from './api/math';
2
+ export { calculateLiquidationAmounts, calculateMinCollateralByTransferredAmount, isLiquidatable, isBadDebt, addReserve, deductReserve, addLiquidationBonus, deductLiquidationBonus, toAssetAmount, toAssetWorth, PreparedAssetInfo, PreparedAssetInfoResult, prepareAssetInfo, findAssetById, selectGreatestAssets, calculateAssetsValues, AssetsValues, SelectedAssets, } from './api/liquidation';
2
3
  export { createAssetData, createAssetConfig, parseMasterData, parseUserData, parseUserLiteData } from './api/parser';
3
4
  export { getPrices } from './api/prices';
4
5
  export { JettonWallet } from './contracts/JettonWallet';
5
- export { EvaaParameters, WithdrawParameters, LiquidationBaseData, LiquidationParameters, Evaa, } from './contracts/MasterContract';
6
+ export { EvaaParameters, WithdrawParameters, LiquidationBaseData, LiquidationParameters, Evaa } from './contracts/MasterContract';
6
7
  export { EvaaUser } from './contracts/UserContract';
7
8
  export { PriceData } from './types/Common';
8
9
  export { UpgradeConfig, AssetConfig, MasterConfig, AssetData, AssetInterest, AssetApy, ExtendedAssetData, MasterData, PoolConfig, ExtendedAssetsData, ExtendedAssetsConfig, PoolAssetConfig, PoolAssetsConfig, MasterConstants } from './types/Master';
9
10
  export { BalanceType, UserBalance, UserLiqudationData, LiquidableData, NonLiquidableData, LiquidationData, UserDataInactive, UserDataActive, UserData, BalanceChangeType } from './types/User';
10
11
  export { EVAA_MASTER_MAINNET, MAINNET_VERSION, EVAA_MASTER_TESTNET, TESTNET_VERSION, LENDING_CODE, OPCODES, FEES, MASTER_CONSTANTS } from './constants/general';
11
- export { MAINNET_POOL_CONFIG, TESTNET_POOL_CONFIG, MAINNET_LP_POOL_CONFIG, } from './constants/pools';
12
- export { UNDEFINED_ASSET, TON_MAINNET, USDT_MAINNET, TONUSDT_DEDUST_MAINNET, TON_STORM_MAINNET, USDT_STORM_MAINNET, JUSDT_MAINNET, JUSDC_MAINNET, STTON_MAINNET, TSTON_MAINNET, JUSDT_TESTNET, JUSDC_TESTNET, STTON_TESTNET, } from './constants/assets';
12
+ export { MAINNET_POOL_CONFIG, TESTNET_POOL_CONFIG, MAINNET_LP_POOL_CONFIG } from './constants/pools';
13
+ export { ASSET_ID, UNDEFINED_ASSET, TON_MAINNET, USDT_MAINNET, TONUSDT_DEDUST_MAINNET, TON_STORM_MAINNET, USDT_STORM_MAINNET, JUSDT_MAINNET, JUSDC_MAINNET, STTON_MAINNET, TSTON_MAINNET, JUSDT_TESTNET, JUSDC_TESTNET, STTON_TESTNET } from './constants/assets';
13
14
  export * from './constants/assets';
14
15
  export * from './utils/utils';
15
16
  export { getLastSentBoc, getTonConnectSender } from './utils/tonConnectSender';
package/dist/index.js CHANGED
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.getTonConnectSender = exports.getLastSentBoc = exports.STTON_TESTNET = exports.JUSDC_TESTNET = exports.JUSDT_TESTNET = exports.TSTON_MAINNET = exports.STTON_MAINNET = exports.JUSDC_MAINNET = exports.JUSDT_MAINNET = exports.USDT_STORM_MAINNET = exports.TON_STORM_MAINNET = exports.TONUSDT_DEDUST_MAINNET = exports.USDT_MAINNET = exports.TON_MAINNET = exports.UNDEFINED_ASSET = exports.MAINNET_LP_POOL_CONFIG = exports.TESTNET_POOL_CONFIG = exports.MAINNET_POOL_CONFIG = exports.MASTER_CONSTANTS = exports.FEES = exports.OPCODES = exports.LENDING_CODE = exports.TESTNET_VERSION = exports.EVAA_MASTER_TESTNET = exports.MAINNET_VERSION = exports.EVAA_MASTER_MAINNET = exports.BalanceChangeType = exports.BalanceType = exports.EvaaUser = exports.Evaa = exports.JettonWallet = exports.getPrices = exports.parseUserLiteData = exports.parseUserData = exports.parseMasterData = exports.createAssetConfig = exports.createAssetData = exports.predictHealthFactor = exports.calculateLiquidationData = exports.presentValue = exports.calculateMaximumWithdrawAmount = exports.getAvailableToBorrow = exports.calculateAssetInterest = exports.calculateAssetData = exports.calculateCurrentRates = exports.calculatePresentValue = exports.bigIntMax = exports.bigIntMin = exports.mulDiv = exports.mulFactor = void 0;
18
- exports.getUserJettonWallet = void 0;
17
+ exports.TESTNET_POOL_CONFIG = exports.MAINNET_POOL_CONFIG = exports.MASTER_CONSTANTS = exports.FEES = exports.OPCODES = exports.LENDING_CODE = exports.TESTNET_VERSION = exports.EVAA_MASTER_TESTNET = exports.MAINNET_VERSION = exports.EVAA_MASTER_MAINNET = exports.BalanceChangeType = exports.BalanceType = exports.EvaaUser = exports.Evaa = exports.JettonWallet = exports.getPrices = exports.parseUserLiteData = exports.parseUserData = exports.parseMasterData = exports.createAssetConfig = exports.createAssetData = exports.calculateAssetsValues = exports.selectGreatestAssets = exports.findAssetById = exports.prepareAssetInfo = exports.toAssetWorth = exports.toAssetAmount = exports.deductLiquidationBonus = exports.addLiquidationBonus = exports.deductReserve = exports.addReserve = exports.isBadDebt = exports.isLiquidatable = exports.calculateMinCollateralByTransferredAmount = exports.calculateLiquidationAmounts = exports.BigMath = exports.calculateHealthParams = exports.predictHealthFactor = exports.calculateLiquidationData = exports.presentValue = exports.calculateMaximumWithdrawAmount = exports.getAvailableToBorrow = exports.calculateAssetInterest = exports.calculateAssetData = exports.calculateCurrentRates = exports.calculatePresentValue = exports.bigIntMax = exports.bigIntMin = exports.mulDiv = exports.mulFactor = void 0;
18
+ exports.getUserJettonWallet = exports.getTonConnectSender = exports.getLastSentBoc = exports.STTON_TESTNET = exports.JUSDC_TESTNET = exports.JUSDT_TESTNET = exports.TSTON_MAINNET = exports.STTON_MAINNET = exports.JUSDC_MAINNET = exports.JUSDT_MAINNET = exports.USDT_STORM_MAINNET = exports.TON_STORM_MAINNET = exports.TONUSDT_DEDUST_MAINNET = exports.USDT_MAINNET = exports.TON_MAINNET = exports.UNDEFINED_ASSET = exports.ASSET_ID = exports.MAINNET_LP_POOL_CONFIG = void 0;
19
19
  // Math
20
20
  var math_1 = require("./api/math");
21
21
  Object.defineProperty(exports, "mulFactor", { enumerable: true, get: function () { return math_1.mulFactor; } });
@@ -31,6 +31,23 @@ Object.defineProperty(exports, "calculateMaximumWithdrawAmount", { enumerable: t
31
31
  Object.defineProperty(exports, "presentValue", { enumerable: true, get: function () { return math_1.presentValue; } });
32
32
  Object.defineProperty(exports, "calculateLiquidationData", { enumerable: true, get: function () { return math_1.calculateLiquidationData; } });
33
33
  Object.defineProperty(exports, "predictHealthFactor", { enumerable: true, get: function () { return math_1.predictHealthFactor; } });
34
+ Object.defineProperty(exports, "calculateHealthParams", { enumerable: true, get: function () { return math_1.calculateHealthParams; } });
35
+ Object.defineProperty(exports, "BigMath", { enumerable: true, get: function () { return math_1.BigMath; } });
36
+ var liquidation_1 = require("./api/liquidation");
37
+ Object.defineProperty(exports, "calculateLiquidationAmounts", { enumerable: true, get: function () { return liquidation_1.calculateLiquidationAmounts; } });
38
+ Object.defineProperty(exports, "calculateMinCollateralByTransferredAmount", { enumerable: true, get: function () { return liquidation_1.calculateMinCollateralByTransferredAmount; } });
39
+ Object.defineProperty(exports, "isLiquidatable", { enumerable: true, get: function () { return liquidation_1.isLiquidatable; } });
40
+ Object.defineProperty(exports, "isBadDebt", { enumerable: true, get: function () { return liquidation_1.isBadDebt; } });
41
+ Object.defineProperty(exports, "addReserve", { enumerable: true, get: function () { return liquidation_1.addReserve; } });
42
+ Object.defineProperty(exports, "deductReserve", { enumerable: true, get: function () { return liquidation_1.deductReserve; } });
43
+ Object.defineProperty(exports, "addLiquidationBonus", { enumerable: true, get: function () { return liquidation_1.addLiquidationBonus; } });
44
+ Object.defineProperty(exports, "deductLiquidationBonus", { enumerable: true, get: function () { return liquidation_1.deductLiquidationBonus; } });
45
+ Object.defineProperty(exports, "toAssetAmount", { enumerable: true, get: function () { return liquidation_1.toAssetAmount; } });
46
+ Object.defineProperty(exports, "toAssetWorth", { enumerable: true, get: function () { return liquidation_1.toAssetWorth; } });
47
+ Object.defineProperty(exports, "prepareAssetInfo", { enumerable: true, get: function () { return liquidation_1.prepareAssetInfo; } });
48
+ Object.defineProperty(exports, "findAssetById", { enumerable: true, get: function () { return liquidation_1.findAssetById; } });
49
+ Object.defineProperty(exports, "selectGreatestAssets", { enumerable: true, get: function () { return liquidation_1.selectGreatestAssets; } });
50
+ Object.defineProperty(exports, "calculateAssetsValues", { enumerable: true, get: function () { return liquidation_1.calculateAssetsValues; } });
34
51
  // Parser
35
52
  var parser_1 = require("./api/parser");
36
53
  Object.defineProperty(exports, "createAssetData", { enumerable: true, get: function () { return parser_1.createAssetData; } });
@@ -66,6 +83,7 @@ Object.defineProperty(exports, "MAINNET_POOL_CONFIG", { enumerable: true, get: f
66
83
  Object.defineProperty(exports, "TESTNET_POOL_CONFIG", { enumerable: true, get: function () { return pools_1.TESTNET_POOL_CONFIG; } });
67
84
  Object.defineProperty(exports, "MAINNET_LP_POOL_CONFIG", { enumerable: true, get: function () { return pools_1.MAINNET_LP_POOL_CONFIG; } });
68
85
  var assets_1 = require("./constants/assets");
86
+ Object.defineProperty(exports, "ASSET_ID", { enumerable: true, get: function () { return assets_1.ASSET_ID; } });
69
87
  Object.defineProperty(exports, "UNDEFINED_ASSET", { enumerable: true, get: function () { return assets_1.UNDEFINED_ASSET; } });
70
88
  Object.defineProperty(exports, "TON_MAINNET", { enumerable: true, get: function () { return assets_1.TON_MAINNET; } });
71
89
  Object.defineProperty(exports, "USDT_MAINNET", { enumerable: true, get: function () { return assets_1.USDT_MAINNET; } });
@@ -9,6 +9,9 @@ export type MasterConstants = {
9
9
  ASSET_LIQUIDATION_THRESHOLD_SCALE: bigint;
10
10
  ASSET_LIQUIDATION_BONUS_SCALE: bigint;
11
11
  ASSET_ORIGINATION_FEE_SCALE: bigint;
12
+ ASSET_SRATE_SCALE: bigint;
13
+ ASSET_BRATE_SCALE: bigint;
14
+ COLLATERAL_WORTH_THRESHOLD: bigint;
12
15
  };
13
16
  export type PoolAssetsConfig = PoolAssetConfig[];
14
17
  export type PoolAssetConfig = {
@@ -61,6 +61,13 @@ export type UserRewards = {
61
61
  trackingIndex: bigint;
62
62
  trackingAccured: bigint;
63
63
  };
64
+ export type HealthParamsArgs = {
65
+ assetsData: ExtendedAssetsData;
66
+ assetsConfig: ExtendedAssetsConfig;
67
+ principals: Dictionary<bigint, bigint>;
68
+ prices: Dictionary<bigint, bigint>;
69
+ poolConfig: PoolConfig;
70
+ };
64
71
  export declare enum BalanceChangeType {
65
72
  Borrow = 0,
66
73
  Repay = 1,
@@ -1,2 +1,3 @@
1
1
  import { PoolAssetConfig } from "../types/Master";
2
2
  export declare function isTonAsset(asset: PoolAssetConfig): boolean;
3
+ export declare function isTonAssetId(assetId: bigint): boolean;
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isTonAsset = void 0;
3
+ exports.isTonAssetId = exports.isTonAsset = void 0;
4
+ const assets_1 = require("../constants/assets");
4
5
  function isTonAsset(asset) {
5
6
  return asset.name === 'TON';
6
7
  }
7
8
  exports.isTonAsset = isTonAsset;
9
+ function isTonAssetId(assetId) {
10
+ return assetId === assets_1.ASSET_ID.TON;
11
+ }
12
+ exports.isTonAssetId = isTonAssetId;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@evaafi/sdk",
3
- "version": "0.6.0",
4
- "description": "SDK for EVAA v6 contracts",
3
+ "version": "0.6.1",
4
+ "description": "The EVAA SDK is designed to easily integrate with the EVAA lending protocol on TON blockchain.",
5
5
  "main": "dist/index.js",
6
6
  "files": [
7
7
  "dist",
@@ -20,6 +20,7 @@
20
20
  "devDependencies": {
21
21
  "@orbs-network/ton-access": "^2.3.3",
22
22
  "@ton/core": "0.56.0",
23
+ "@ton/crypto": "^3.3.0",
23
24
  "@tonconnect/sdk": "^3.0.5",
24
25
  "@types/jest": "^29.5.12",
25
26
  "@types/node": "^20.10.4",
@@ -0,0 +1,346 @@
1
+ import { Dictionary } from '@ton/core';
2
+ import {
3
+ AssetConfig,
4
+ AssetData,
5
+ ExtendedAssetsConfig,
6
+ ExtendedAssetsData,
7
+ MasterConstants,
8
+ PoolAssetConfig,
9
+ PoolConfig
10
+ } from '../types/Master';
11
+ import { BigMath, calculateHealthParams, presentValue } from './math';
12
+ import { BalanceType, UserBalance } from '../types/User';
13
+
14
+ export function findAssetById(assetId: bigint, poolConfig: PoolConfig): PoolAssetConfig | undefined {
15
+ return poolConfig.poolAssetsConfig.find(asset => asset.assetId === assetId);
16
+ }
17
+
18
+ export type AssetsValues = {
19
+ loanAssets: Dictionary<bigint, bigint>,
20
+ collateralAssets: Dictionary<bigint, bigint>
21
+ }
22
+
23
+ export type SelectedAssets = {
24
+ selectedLoanId: bigint,
25
+ selectedCollateralId: bigint,
26
+ selectedLoanValue?: bigint,
27
+ selectedCollateralValue?: bigint,
28
+ }
29
+
30
+ export function calculateAssetsValues(
31
+ principalsDict: Dictionary<bigint, bigint>,
32
+ pricesDict: Dictionary<bigint, bigint>,
33
+ assetsConfigDict: ExtendedAssetsConfig,
34
+ assetsDataDict: ExtendedAssetsData,
35
+ poolConfig: PoolConfig
36
+ ): AssetsValues {
37
+ const loanAssets = Dictionary.empty<bigint, bigint>();
38
+ const collateralAssets = Dictionary.empty<bigint, bigint>();
39
+
40
+ for (const asset of poolConfig.poolAssetsConfig) {
41
+ const assetId = asset.assetId;
42
+ if (!principalsDict.has(assetId)) {
43
+ continue;
44
+ }
45
+ const assetPrincipal: bigint = principalsDict.get(assetId)!;
46
+ if (!pricesDict.has(assetId)) {
47
+ console.warn(`No price for asset ${asset.name}`);
48
+ continue;
49
+ }
50
+ const assetPrice = pricesDict.get(assetId)!;
51
+ if (!assetsDataDict.has(assetId)) {
52
+ console.warn(`Dynamics for assetId ${assetId} is not defined, skipping`);
53
+ continue;
54
+ }
55
+ const assetData = assetsDataDict.get(assetId)!;
56
+
57
+ if (!assetsConfigDict.has(assetId)) {
58
+ console.warn(`Config for assetId ${assetId} is not defined, skipping`);
59
+ continue;
60
+ }
61
+ const assetConfig = assetsConfigDict.get(assetId)!;
62
+ const assetScale = 10n ** assetConfig.decimals;
63
+ const { sRate, bRate } = assetData;
64
+ const assetPresent = presentValue(sRate, bRate, assetPrincipal, poolConfig.masterConstants);
65
+ const assetValue = assetPresent.amount * assetPrice / assetScale;
66
+ if (assetPresent.type === BalanceType.borrow) {
67
+ loanAssets.set(assetId, assetValue);
68
+ } else {
69
+ collateralAssets.set(assetId, assetValue);
70
+ }
71
+ }
72
+
73
+ return { loanAssets, collateralAssets };
74
+ }
75
+
76
+ export function selectGreatestAssets(principalsDict: Dictionary<bigint, bigint>,
77
+ pricesDict: Dictionary<bigint, bigint>,
78
+ assetsConfigDict: ExtendedAssetsConfig,
79
+ assetsDataDict: ExtendedAssetsData,
80
+ poolConfig: PoolConfig): SelectedAssets {
81
+ let maxLoanId = 0n;
82
+ let maxLoanValue = 0n;
83
+ let maxCollateralId = 0n;
84
+ let maxCollateralValue = 0n;
85
+
86
+ const assetsValues = calculateAssetsValues(principalsDict, pricesDict, assetsConfigDict, assetsDataDict, poolConfig);
87
+
88
+ for (const [loanId, loanValue] of assetsValues.loanAssets) {
89
+ if (loanValue > maxLoanValue) {
90
+ maxLoanId = loanId;
91
+ maxLoanValue = loanValue;
92
+ }
93
+ }
94
+
95
+ for (const [collateralId, collateralValue] of assetsValues.collateralAssets) {
96
+ if (collateralValue > maxCollateralValue) {
97
+ maxCollateralValue = collateralValue;
98
+ maxCollateralId = collateralId;
99
+ }
100
+ }
101
+
102
+ return {
103
+ selectedLoanId: maxLoanId,
104
+ selectedLoanValue: maxLoanValue,
105
+ selectedCollateralId: maxCollateralId,
106
+ selectedCollateralValue: maxCollateralValue
107
+ };
108
+ }
109
+
110
+ /**
111
+ * This function shows how to calculate min collateral amount value.
112
+ * when liquidator has not enough of loan asset to cover the full loan.
113
+ * @param transferredAmount amount of loan asset liquidator want to transfer.
114
+ * @param maxLiquidationAmount max liquidation amount value calculated.
115
+ * @param maxCollateralReward max collateral reward amount calculated.
116
+ * @returns minCollateralAmount value for safe liquidation.
117
+ */
118
+ export function calculateMinCollateralByTransferredAmount(
119
+ transferredAmount: bigint, maxLiquidationAmount: bigint, maxCollateralReward: bigint
120
+ ) {
121
+ if (maxLiquidationAmount === 0n) {
122
+ return 0n;
123
+ }
124
+ return maxCollateralReward * transferredAmount / maxLiquidationAmount;
125
+ }
126
+
127
+ /**
128
+ * Calculates liquidation amount and corresponding collateral amount
129
+ * @param supplyAmount user total supply worth amount
130
+ * @param borrowAmount user total borrow worth amount
131
+ * @param masterConstants evaa master contract constants
132
+ * @param loanAsset loan asset pool config
133
+ * @param collateralAsset collateral asset pool config
134
+ * @param principalsDict user principals
135
+ * @param assetsDataDict assets data collection
136
+ * @param assetsConfigDict assets config collection
137
+ * @param pricesDict assets prices
138
+ * @returns maxLiquidationAmount max loan asset amount to transfer
139
+ * @returns maxCollateralRewardAmount max collateral reward amount, which can be obtained
140
+ */
141
+ export function calculateLiquidationAmounts(
142
+ loanAsset: PoolAssetConfig,
143
+ collateralAsset: PoolAssetConfig,
144
+ supplyAmount: bigint,
145
+ borrowAmount: bigint, // from calculate health params
146
+ principalsDict: Dictionary<bigint, bigint>,
147
+ pricesDict: Dictionary<bigint, bigint>,
148
+ assetsDataDict: ExtendedAssetsData,
149
+ assetsConfigDict: ExtendedAssetsConfig,
150
+ masterConstants: MasterConstants
151
+ ): {
152
+ maxLiquidationAmount: bigint, maxCollateralRewardAmount: bigint
153
+ } {
154
+ const loanInfo = prepareAssetInfo(loanAsset.assetId,
155
+ assetsConfigDict, assetsDataDict, pricesDict, principalsDict, masterConstants
156
+ );
157
+ const collateralInfo = prepareAssetInfo(collateralAsset.assetId,
158
+ assetsConfigDict, assetsDataDict, pricesDict, principalsDict, masterConstants
159
+ );
160
+
161
+ if (!loanInfo.ok || !collateralInfo.ok ||
162
+ loanInfo.present.type !== BalanceType.borrow ||
163
+ collateralInfo.present.type !== BalanceType.supply) {
164
+ return { maxLiquidationAmount: 0n, maxCollateralRewardAmount: 0n };
165
+ }
166
+
167
+ const liquidationBonusScale = masterConstants.ASSET_LIQUIDATION_BONUS_SCALE;
168
+ const collateralThreshold = masterConstants.COLLATERAL_WORTH_THRESHOLD; // basically 100$ worth (100*10^9)
169
+ const reserveFactorScale = masterConstants.ASSET_RESERVE_FACTOR_SCALE;
170
+ const reserveFactor = loanInfo.liquidationReserveFactor;
171
+ const liquidationBonus = collateralInfo.liquidationBonus;
172
+
173
+ let allowedCollateralValue = toAssetWorth(collateralInfo.balance, collateralInfo.scale, collateralInfo.price);
174
+
175
+ const _isBadDebt = isBadDebt(supplyAmount, borrowAmount, liquidationBonus, masterConstants);
176
+ if (!_isBadDebt) {
177
+ allowedCollateralValue = BigMath.min(allowedCollateralValue, BigMath.max(allowedCollateralValue / 2n, collateralThreshold));
178
+ }
179
+
180
+ const loanValue = toAssetWorth(loanInfo.balance, loanInfo.scale, loanInfo.price);
181
+ const baseLiquidationValue = BigMath.min(
182
+ // deductReserve(loanValue, reserveFactor, reserveFactorScale),
183
+ loanValue,
184
+ deductLiquidationBonus(allowedCollateralValue, liquidationBonus, liquidationBonusScale)
185
+ );
186
+
187
+ // calculate collateral amount
188
+ let collateralAmount = addLiquidationBonus(baseLiquidationValue, liquidationBonus, liquidationBonusScale);
189
+ collateralAmount = toAssetAmount(collateralAmount, collateralInfo.scale, collateralInfo.price);
190
+
191
+ // calculate loan amount
192
+ let liquidationAmount = addReserve(baseLiquidationValue, reserveFactor, reserveFactorScale);
193
+ liquidationAmount = toAssetAmount(liquidationAmount, loanInfo.scale, loanInfo.price);
194
+
195
+ return {
196
+ maxLiquidationAmount: liquidationAmount,
197
+ maxCollateralRewardAmount: collateralAmount
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Check if the user is subject to liquidation
203
+ * @param args
204
+ */
205
+ export function isLiquidatable(args: {
206
+ assetsData: ExtendedAssetsData, assetsConfig: ExtendedAssetsConfig,
207
+ principals: Dictionary<bigint, bigint>, prices: Dictionary<bigint, bigint>,
208
+ poolConfig: PoolConfig
209
+ }): boolean {
210
+ const { isLiquidatable: res } = calculateHealthParams(args);
211
+ return res;
212
+ }
213
+
214
+ /**
215
+ * Determines if the provided pair of assets forms a bad debt.
216
+ * @param totalSupply total supply worth amount
217
+ * @param totalBorrow total borrow worth amount
218
+ * @param liquidationBonus collateral liquidation bonus value
219
+ * @param masterConstants pool constants
220
+ */
221
+ export function isBadDebt(totalSupply: bigint, totalBorrow: bigint,
222
+ liquidationBonus: bigint, masterConstants: MasterConstants
223
+ ) {
224
+ return totalSupply * masterConstants.ASSET_LIQUIDATION_BONUS_SCALE < totalBorrow * liquidationBonus;
225
+ }
226
+
227
+ /**
228
+ * Adds reserve to liquidation amount
229
+ * @param amount raw liquidation amount
230
+ * @param reserveFactor asset reserve factor
231
+ * @param factorScale asset reserve factor scale
232
+ * @returns liquidation amount with reserve
233
+ */
234
+ export function addReserve(amount: bigint, reserveFactor: bigint, factorScale: bigint): bigint {
235
+ return amount * factorScale / (factorScale - reserveFactor);
236
+ }
237
+
238
+ /**
239
+ * Deducts reserve from liquidation amount
240
+ * @param amount liquidation amount with reserve
241
+ * @param reserveFactor asset reserve factor
242
+ * @param reserveFactorScale asset reserve factor scale
243
+ * @returns liquidation amount without reserve
244
+ */
245
+ export function deductReserve(amount: bigint, reserveFactor: bigint, reserveFactorScale: bigint): bigint {
246
+ return amount * (reserveFactorScale - reserveFactor) / reserveFactorScale;
247
+ }
248
+
249
+ /**
250
+ * Converts worth value to specified asset amount
251
+ * @param worth worth value (decimals = 9)
252
+ * @param scale asset scale (10^asset_decimals)
253
+ * @param price asset price
254
+ */
255
+ export function toAssetAmount(worth: bigint, scale: bigint, price: bigint): bigint {
256
+ return worth * scale / price;
257
+ }
258
+
259
+ /**
260
+ * Converts calculates worth value of specified asset amount
261
+ * @param amount worth value (decimals = 9)
262
+ * @param scale asset scale (10^asset_decimals)
263
+ * @param price asset price
264
+ */
265
+ export function toAssetWorth(amount: bigint, scale: bigint, price: bigint): bigint {
266
+ return amount * price / scale;
267
+ }
268
+
269
+ /**
270
+ * Adds liquidation bonus to reward value.
271
+ * @param value reward asset value
272
+ * @param bonus liquidation bonus factor
273
+ * @param scale liquidation bonus scale
274
+ */
275
+ export function addLiquidationBonus(value: bigint, bonus: bigint, scale: bigint): bigint {
276
+ return value * bonus / scale;
277
+ }
278
+
279
+ /**
280
+ * Deducts liquidation bonus from reward value.
281
+ * @param value reward asset value
282
+ * @param bonus liquidation bonus factor
283
+ * @param scale liquidation bonus scale
284
+ */
285
+ export function deductLiquidationBonus(value: bigint, bonus: bigint, scale: bigint): bigint {
286
+ return value * scale / bonus;
287
+ }
288
+
289
+ export type SuccessType = { ok: true };
290
+ export type FailType = { ok: false };
291
+
292
+ export type PreparedAssetInfo = {
293
+ config: AssetConfig,
294
+ data: AssetData,
295
+ price: bigint,
296
+ principal: bigint,
297
+ scale: bigint,
298
+ liquidationReserveFactor: bigint,
299
+ liquidationBonus: bigint,
300
+ present: UserBalance,
301
+ balance: bigint,
302
+ dust: bigint,
303
+ };
304
+
305
+ export type PreparedAssetInfoResult = (PreparedAssetInfo & SuccessType) | FailType;
306
+
307
+ /**
308
+ * Prepares extended asset info
309
+ * @param assetId
310
+ * @param assetsConfigDict
311
+ * @param assetsDataDict
312
+ * @param pricesDict
313
+ * @param principalsDict
314
+ * @param masterConstants
315
+ */
316
+ export function prepareAssetInfo(assetId: bigint,
317
+ assetsConfigDict: ExtendedAssetsConfig,
318
+ assetsDataDict: ExtendedAssetsData,
319
+ pricesDict: Dictionary<bigint, bigint>,
320
+ principalsDict: Dictionary<bigint, bigint>,
321
+ masterConstants: MasterConstants
322
+ ): PreparedAssetInfoResult {
323
+ if (!assetsConfigDict.has(assetId) ||
324
+ !assetsDataDict.has(assetId) ||
325
+ !pricesDict.has(assetId) ||
326
+ !principalsDict.has(assetId)) {
327
+ return { ok: false };
328
+ }
329
+
330
+ const config = assetsConfigDict.get(assetId)!;
331
+ const data = assetsDataDict.get(assetId)!;
332
+ const base = {
333
+ ok: true,
334
+ config, data,
335
+ price: pricesDict.get(assetId)!,
336
+ principal: principalsDict.get(assetId)!,
337
+ scale: 10n ** config.decimals,
338
+ liquidationReserveFactor: config.liquidationReserveFactor,
339
+ liquidationBonus: config.liquidationBonus
340
+ };
341
+
342
+ const assetPresent = presentValue(data.sRate, data.bRate, base.principal, masterConstants);
343
+ const dustPresent = presentValue(data.sRate, data.bRate, config.dust, masterConstants);
344
+
345
+ return { ...base, present: assetPresent, balance: assetPresent.amount, dust: dustPresent.amount };
346
+ }