@evaafi/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/api/helpers.d.ts +8 -0
- package/dist/api/helpers.js +33 -0
- package/dist/api/math.d.ts +20 -0
- package/dist/api/math.js +214 -0
- package/dist/api/parser.d.ts +8 -0
- package/dist/api/parser.js +227 -0
- package/dist/api/prices.d.ts +9 -0
- package/dist/api/prices.js +104 -0
- package/dist/constants.d.ts +38 -0
- package/dist/constants.js +42 -0
- package/dist/contracts/JettonWallet.d.ts +7 -0
- package/dist/contracts/JettonWallet.js +20 -0
- package/dist/contracts/MasterContract.d.ts +166 -0
- package/dist/contracts/MasterContract.js +217 -0
- package/dist/contracts/UserContract.d.ts +49 -0
- package/dist/contracts/UserContract.js +99 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +53 -0
- package/dist/types/Common.d.ts +5 -0
- package/dist/types/Common.js +2 -0
- package/dist/types/Master.d.ts +63 -0
- package/dist/types/Master.js +2 -0
- package/dist/types/Redstone.d.ts +15 -0
- package/dist/types/Redstone.js +2 -0
- package/dist/types/User.d.ts +55 -0
- package/dist/types/User.js +8 -0
- package/dist/utils/sha256BigInt.d.ts +1 -0
- package/dist/utils/sha256BigInt.js +13 -0
- package/dist/utils/tonConnectSender.d.ts +4 -0
- package/dist/utils/tonConnectSender.js +37 -0
- package/dist/utils/userJettonWallet.d.ts +2 -0
- package/dist/utils/userJettonWallet.js +37 -0
- package/package.json +38 -0
- package/src/api/helpers.ts +32 -0
- package/src/api/math.ts +252 -0
- package/src/api/parser.ts +277 -0
- package/src/api/prices.ts +127 -0
- package/src/constants.ts +53 -0
- package/src/contracts/JettonWallet.ts +20 -0
- package/src/contracts/MasterContract.ts +387 -0
- package/src/contracts/UserContract.ts +125 -0
- package/src/index.ts +78 -0
- package/src/types/Common.ts +6 -0
- package/src/types/Master.ts +70 -0
- package/src/types/Redstone.ts +15 -0
- package/src/types/User.ts +66 -0
- package/src/utils/sha256BigInt.ts +7 -0
- package/src/utils/tonConnectSender.ts +37 -0
- package/src/utils/userJettonWallet.ts +34 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Address, Cell, Dictionary } from '@ton/core';
|
|
3
|
+
export type UpgradeConfig = {
|
|
4
|
+
masterCodeVersion: number;
|
|
5
|
+
userCodeVersion: number;
|
|
6
|
+
timeout: number;
|
|
7
|
+
updateTime: number;
|
|
8
|
+
freezeTime: number;
|
|
9
|
+
userCode: Cell;
|
|
10
|
+
blankCode: Cell;
|
|
11
|
+
newMasterCode: Cell | null;
|
|
12
|
+
newUserCode: Cell | null;
|
|
13
|
+
};
|
|
14
|
+
export type AssetConfig = {
|
|
15
|
+
oracle: bigint;
|
|
16
|
+
decimals: bigint;
|
|
17
|
+
collateralFactor: bigint;
|
|
18
|
+
liquidationThreshold: bigint;
|
|
19
|
+
liquidationBonus: bigint;
|
|
20
|
+
baseBorrowRate: bigint;
|
|
21
|
+
borrowRateSlopeLow: bigint;
|
|
22
|
+
borrowRateSlopeHigh: bigint;
|
|
23
|
+
supplyRateSlopeLow: bigint;
|
|
24
|
+
supplyRateSlopeHigh: bigint;
|
|
25
|
+
targetUtilization: bigint;
|
|
26
|
+
originationFee: bigint;
|
|
27
|
+
};
|
|
28
|
+
export type MasterConfig = {
|
|
29
|
+
ifActive: number;
|
|
30
|
+
admin: Address;
|
|
31
|
+
adminPK: Buffer;
|
|
32
|
+
tokenKeys: Cell | null;
|
|
33
|
+
walletToMaster: Cell | null;
|
|
34
|
+
};
|
|
35
|
+
export type AssetData = {
|
|
36
|
+
sRate: bigint;
|
|
37
|
+
bRate: bigint;
|
|
38
|
+
totalSupply: bigint;
|
|
39
|
+
totalBorrow: bigint;
|
|
40
|
+
lastAccural: bigint;
|
|
41
|
+
balance: bigint;
|
|
42
|
+
};
|
|
43
|
+
export type AssetInterest = {
|
|
44
|
+
supplyInterest: bigint;
|
|
45
|
+
borrowInterest: bigint;
|
|
46
|
+
};
|
|
47
|
+
export type AssetApy = {
|
|
48
|
+
supplyApy: number;
|
|
49
|
+
borrowApy: number;
|
|
50
|
+
};
|
|
51
|
+
export type ExtendedAssetData = AssetData & AssetInterest & AssetApy;
|
|
52
|
+
export type MasterData = {
|
|
53
|
+
meta: string;
|
|
54
|
+
upgradeConfig: UpgradeConfig;
|
|
55
|
+
masterConfig: MasterConfig;
|
|
56
|
+
assetsConfig: Dictionary<bigint, AssetConfig>;
|
|
57
|
+
assetsData: Dictionary<bigint, ExtendedAssetData>;
|
|
58
|
+
assetsReserves: Dictionary<bigint, bigint>;
|
|
59
|
+
apy: {
|
|
60
|
+
supply: Dictionary<bigint, number>;
|
|
61
|
+
borrow: Dictionary<bigint, number>;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type CoinData = {
|
|
2
|
+
id: string;
|
|
3
|
+
symbol: string;
|
|
4
|
+
provider: string;
|
|
5
|
+
value: number;
|
|
6
|
+
liteEvmSignature: string;
|
|
7
|
+
permawebTx: string;
|
|
8
|
+
version: string;
|
|
9
|
+
source: {
|
|
10
|
+
coingecko: number;
|
|
11
|
+
};
|
|
12
|
+
timestamp: number;
|
|
13
|
+
minutes: number;
|
|
14
|
+
providerPublicKey: string;
|
|
15
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Address, Cell, Dictionary } from '@ton/core';
|
|
2
|
+
export declare enum BalanceType {
|
|
3
|
+
supply = "supply",
|
|
4
|
+
borrow = "borrow"
|
|
5
|
+
}
|
|
6
|
+
export type UserBalance = {
|
|
7
|
+
amount: bigint;
|
|
8
|
+
type?: BalanceType;
|
|
9
|
+
};
|
|
10
|
+
export type UserLiqudationData = {
|
|
11
|
+
greatestCollateralValue: bigint;
|
|
12
|
+
greatestCollateralAsset: bigint;
|
|
13
|
+
greatestLoanValue: bigint;
|
|
14
|
+
greatestLoanAsset: bigint;
|
|
15
|
+
totalDebt: bigint;
|
|
16
|
+
totalLimit: bigint;
|
|
17
|
+
};
|
|
18
|
+
export type LiquidableData = UserLiqudationData & {
|
|
19
|
+
liquidable: true;
|
|
20
|
+
liquidationAmount: bigint;
|
|
21
|
+
minCollateralAmount: bigint;
|
|
22
|
+
};
|
|
23
|
+
export type NonLiquidableData = UserLiqudationData & {
|
|
24
|
+
liquidable: false;
|
|
25
|
+
};
|
|
26
|
+
export type LiquidationData = LiquidableData | NonLiquidableData;
|
|
27
|
+
export type UserLiteData = {
|
|
28
|
+
type: 'active';
|
|
29
|
+
codeVersion: number;
|
|
30
|
+
masterAddress: Address;
|
|
31
|
+
ownerAddress: Address;
|
|
32
|
+
principals: Dictionary<bigint, bigint>;
|
|
33
|
+
state: number;
|
|
34
|
+
balances: Dictionary<bigint, UserBalance>;
|
|
35
|
+
trackingSupplyIndex: bigint;
|
|
36
|
+
trackingBorrowIndex: bigint;
|
|
37
|
+
dutchAuctionStart: number;
|
|
38
|
+
backupCell: Cell;
|
|
39
|
+
};
|
|
40
|
+
export type UserDataActive = UserLiteData & {
|
|
41
|
+
withdrawalLimits: Dictionary<bigint, bigint>;
|
|
42
|
+
borrowLimits: Dictionary<bigint, bigint>;
|
|
43
|
+
repayLimits?: Dictionary<bigint, bigint>;
|
|
44
|
+
supplyBalance: bigint;
|
|
45
|
+
borrowBalance: bigint;
|
|
46
|
+
availableToBorrow: bigint;
|
|
47
|
+
limitUsedPercent: number;
|
|
48
|
+
limitUsed: bigint;
|
|
49
|
+
healthFactor: number;
|
|
50
|
+
liquidationData: LiquidationData;
|
|
51
|
+
};
|
|
52
|
+
export type UserDataInactive = {
|
|
53
|
+
type: 'inactive';
|
|
54
|
+
};
|
|
55
|
+
export type UserData = UserDataActive | UserDataInactive;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BalanceType = void 0;
|
|
4
|
+
var BalanceType;
|
|
5
|
+
(function (BalanceType) {
|
|
6
|
+
BalanceType["supply"] = "supply";
|
|
7
|
+
BalanceType["borrow"] = "borrow";
|
|
8
|
+
})(BalanceType || (exports.BalanceType = BalanceType = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sha256Hash(input: string): bigint;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sha256Hash = void 0;
|
|
7
|
+
const sha256_1 = __importDefault(require("crypto-js/sha256"));
|
|
8
|
+
function sha256Hash(input) {
|
|
9
|
+
const hash = (0, sha256_1.default)(input);
|
|
10
|
+
const hashHex = hash.toString();
|
|
11
|
+
return BigInt('0x' + hashHex);
|
|
12
|
+
}
|
|
13
|
+
exports.sha256Hash = sha256Hash;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTonConnectSender = exports.getLastSentBoc = void 0;
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
|
+
/*
|
|
6
|
+
This is not the best solution to get the BOC of the sent external message, however the Sender
|
|
7
|
+
interface does not support returning any value from send(), so at the moment you can get it from
|
|
8
|
+
this global variable.
|
|
9
|
+
*/
|
|
10
|
+
let lastSentBoc;
|
|
11
|
+
function getLastSentBoc() {
|
|
12
|
+
return lastSentBoc;
|
|
13
|
+
}
|
|
14
|
+
exports.getLastSentBoc = getLastSentBoc;
|
|
15
|
+
function getTonConnectSender(connector) {
|
|
16
|
+
return {
|
|
17
|
+
get address() {
|
|
18
|
+
return connector.account ? core_1.Address.parse(connector.account.address) : undefined;
|
|
19
|
+
},
|
|
20
|
+
async send(args) {
|
|
21
|
+
lastSentBoc = await connector.sendTransaction({
|
|
22
|
+
validUntil: Date.now() + 2 * 60 * 1000, // 1 minutes
|
|
23
|
+
messages: [
|
|
24
|
+
{
|
|
25
|
+
address: args.to.toString(),
|
|
26
|
+
amount: args.value.toString(),
|
|
27
|
+
payload: args.body?.toBoc().toString('base64'),
|
|
28
|
+
stateInit: args.init
|
|
29
|
+
? (0, core_1.beginCell)().store((0, core_1.storeStateInit)(args.init)).endCell().toBoc().toString('base64')
|
|
30
|
+
: undefined,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
exports.getTonConnectSender = getTonConnectSender;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getUserJettonWallet = void 0;
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
function getUserJettonWallet(ownerAddress, assetID, network) {
|
|
7
|
+
const builder = (0, core_1.beginCell)().storeCoins(0).storeAddress(ownerAddress);
|
|
8
|
+
switch (assetID) {
|
|
9
|
+
case constants_1.ASSET_ID.jUSDT:
|
|
10
|
+
if (network === 'mainnet') {
|
|
11
|
+
builder.storeAddress(constants_1.JETTON_MASTER_ADDRESSES.jUSDT_MAINNET);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
builder.storeAddress(constants_1.JETTON_MASTER_ADDRESSES.jUSDT_TESTNET);
|
|
15
|
+
}
|
|
16
|
+
break;
|
|
17
|
+
case constants_1.ASSET_ID.jUSDC:
|
|
18
|
+
if (network === 'mainnet') {
|
|
19
|
+
builder.storeAddress(constants_1.JETTON_MASTER_ADDRESSES.jUSDC_MAINNET);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
builder.storeAddress(constants_1.JETTON_MASTER_ADDRESSES.jUSDC_TESTNET);
|
|
23
|
+
}
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
throw new Error('Unsupported asset');
|
|
27
|
+
}
|
|
28
|
+
const data = builder.storeRef(constants_1.JETTON_WALLET_CODE).endCell();
|
|
29
|
+
const stateInit = (0, core_1.beginCell)()
|
|
30
|
+
.store((0, core_1.storeStateInit)({
|
|
31
|
+
code: constants_1.JETTON_WALLET_CODE,
|
|
32
|
+
data: data,
|
|
33
|
+
}))
|
|
34
|
+
.endCell();
|
|
35
|
+
return new core_1.Address(0, stateInit.hash());
|
|
36
|
+
}
|
|
37
|
+
exports.getUserJettonWallet = getUserJettonWallet;
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evaafi/sdk",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "SDK for EVAA contracts",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc --declaration"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/evaafi/sdk.git"
|
|
16
|
+
},
|
|
17
|
+
"author": "EVAA Finance",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"homepage": "https://github.com/evaafi/sdk#readme",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^20.10.4",
|
|
22
|
+
"prettier": "^3.2.4",
|
|
23
|
+
"ts-node": "^10.9.1",
|
|
24
|
+
"typescript": "^5.3.3",
|
|
25
|
+
"@ton/core": "0.56.0",
|
|
26
|
+
"@tonconnect/sdk": "^3.0.0",
|
|
27
|
+
"crypto-js": "^4.2.0",
|
|
28
|
+
"ethereumjs-util": "7.0.10",
|
|
29
|
+
"ethers": "5.6.9"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@ton/core": ">=0.56.0",
|
|
33
|
+
"@tonconnect/sdk": ">=3.0.0",
|
|
34
|
+
"crypto-js": ">=4.2.0",
|
|
35
|
+
"ethereumjs-util": "7.0.10",
|
|
36
|
+
"ethers": "5.6.9"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Cell, Slice } from '@ton/core';
|
|
2
|
+
|
|
3
|
+
class MyCell extends Cell {
|
|
4
|
+
toString() {
|
|
5
|
+
return this.hashBigInt().toString();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
hashBigInt() {
|
|
9
|
+
return BigInt('0x' + this.hash().toString('hex'));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function loadMyRef(slice: Slice): MyCell {
|
|
14
|
+
const cell = slice.loadRef();
|
|
15
|
+
return new MyCell({
|
|
16
|
+
exotic: cell.isExotic,
|
|
17
|
+
bits: cell.bits,
|
|
18
|
+
refs: cell.refs,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function loadMaybeMyRef(slice: Slice): Cell | null {
|
|
23
|
+
const cell = slice.loadMaybeRef();
|
|
24
|
+
if (cell === null) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return new MyCell({
|
|
28
|
+
exotic: cell.isExotic,
|
|
29
|
+
bits: cell.bits,
|
|
30
|
+
refs: cell.refs,
|
|
31
|
+
});
|
|
32
|
+
}
|
package/src/api/math.ts
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { AssetConfig, AssetData, AssetInterest, ExtendedAssetData } from '../types/Master';
|
|
2
|
+
import { MASTER_CONSTANTS } from '../constants';
|
|
3
|
+
import { Dictionary } from '@ton/core';
|
|
4
|
+
import { BalanceType, LiquidationData, UserBalance } from '../types/User';
|
|
5
|
+
|
|
6
|
+
export function mulFactor(decimal: bigint, a: bigint, b: bigint): bigint {
|
|
7
|
+
return (a * b) / decimal;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function mulDiv(x: bigint, y: bigint, z: bigint): bigint {
|
|
11
|
+
return (x * y) / z;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function bigIntMax(...args: bigint[]): bigint {
|
|
15
|
+
return args.reduce((m, e) => (e > m ? e : m));
|
|
16
|
+
}
|
|
17
|
+
export function bigIntMin(...args: bigint[]): bigint {
|
|
18
|
+
return args.reduce((m, e) => (e < m ? e : m));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function calculatePresentValue(index: bigint, principalValue: bigint): bigint {
|
|
22
|
+
return (principalValue * index) / MASTER_CONSTANTS.FACTOR_SCALE;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function calculateCurrentRates(assetConfig: AssetConfig, assetData: AssetData) {
|
|
26
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
27
|
+
const timeElapsed = now - assetData.lastAccural;
|
|
28
|
+
const { supplyInterest, borrowInterest } = calculateAssetInterest(assetConfig, assetData);
|
|
29
|
+
|
|
30
|
+
if (timeElapsed > 0) {
|
|
31
|
+
const updatedSRate =
|
|
32
|
+
assetData.sRate + mulFactor(MASTER_CONSTANTS.FACTOR_SCALE, assetData.sRate, supplyInterest * timeElapsed);
|
|
33
|
+
const updatedBRate =
|
|
34
|
+
assetData.bRate + mulFactor(MASTER_CONSTANTS.FACTOR_SCALE, assetData.bRate, borrowInterest * timeElapsed);
|
|
35
|
+
return {
|
|
36
|
+
sRate: updatedSRate,
|
|
37
|
+
bRate: updatedBRate,
|
|
38
|
+
supplyInterest,
|
|
39
|
+
borrowInterest,
|
|
40
|
+
now,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
sRate: assetData.sRate,
|
|
46
|
+
bRate: assetData.bRate,
|
|
47
|
+
supplyInterest,
|
|
48
|
+
borrowInterest,
|
|
49
|
+
now,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function calculateAssetData(
|
|
54
|
+
assetsConfigDict: Dictionary<bigint, AssetConfig>,
|
|
55
|
+
assetsDataDict: Dictionary<bigint, AssetData>,
|
|
56
|
+
assetId: bigint,
|
|
57
|
+
): ExtendedAssetData {
|
|
58
|
+
const config = assetsConfigDict.get(assetId); // maybe it's a huge mistake could be
|
|
59
|
+
const data = assetsDataDict.get(assetId);
|
|
60
|
+
|
|
61
|
+
if (!data || !config) {
|
|
62
|
+
throw new Error('Asset Data or Config is not accessible');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { sRate, bRate, supplyInterest, borrowInterest, now } = calculateCurrentRates(config, data);
|
|
66
|
+
data.sRate = sRate || 0n;
|
|
67
|
+
data.bRate = bRate || 0n;
|
|
68
|
+
data.lastAccural = now;
|
|
69
|
+
|
|
70
|
+
const supplyApy = (1 + (Number(supplyInterest) / 1e12) * 24 * 3600) ** 365 - 1;
|
|
71
|
+
const borrowApy = (1 + (Number(borrowInterest) / 1e12) * 24 * 3600) ** 365 - 1;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
...data,
|
|
75
|
+
...{ supplyInterest, borrowInterest },
|
|
76
|
+
...{ supplyApy, borrowApy },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function calculateAssetInterest(assetConfig: AssetConfig, assetData: AssetData): AssetInterest {
|
|
81
|
+
const totalSupply = calculatePresentValue(assetData.sRate, assetData.totalSupply);
|
|
82
|
+
const totalBorrow = calculatePresentValue(assetData.bRate, assetData.totalBorrow);
|
|
83
|
+
let utilization = 0n;
|
|
84
|
+
let supplyInterest = 0n;
|
|
85
|
+
let borrowInterest = 0n;
|
|
86
|
+
|
|
87
|
+
if (totalSupply !== 0n) {
|
|
88
|
+
utilization = (totalBorrow * MASTER_CONSTANTS.FACTOR_SCALE) / totalSupply;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (utilization <= assetConfig.targetUtilization) {
|
|
92
|
+
borrowInterest =
|
|
93
|
+
assetConfig.baseBorrowRate +
|
|
94
|
+
mulFactor(MASTER_CONSTANTS.FACTOR_SCALE, assetConfig.borrowRateSlopeLow, utilization);
|
|
95
|
+
} else {
|
|
96
|
+
borrowInterest =
|
|
97
|
+
assetConfig.baseBorrowRate +
|
|
98
|
+
mulFactor(MASTER_CONSTANTS.FACTOR_SCALE, assetConfig.borrowRateSlopeLow, assetConfig.targetUtilization) +
|
|
99
|
+
mulFactor(
|
|
100
|
+
MASTER_CONSTANTS.FACTOR_SCALE,
|
|
101
|
+
assetConfig.borrowRateSlopeHigh,
|
|
102
|
+
utilization - assetConfig.targetUtilization,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const reserveFactor = 10n;
|
|
107
|
+
const reserveScale = 100n;
|
|
108
|
+
supplyInterest = mulDiv(
|
|
109
|
+
mulDiv(borrowInterest, utilization, MASTER_CONSTANTS.FACTOR_SCALE),
|
|
110
|
+
reserveScale - reserveFactor,
|
|
111
|
+
reserveScale,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
supplyInterest,
|
|
116
|
+
borrowInterest,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function getAvailableToBorrow(
|
|
121
|
+
assetsConfig: Dictionary<bigint, AssetConfig>,
|
|
122
|
+
assetsData: Dictionary<bigint, ExtendedAssetData>,
|
|
123
|
+
principals: Dictionary<bigint, bigint>,
|
|
124
|
+
prices: Dictionary<bigint, bigint>,
|
|
125
|
+
): bigint {
|
|
126
|
+
let borrowLimit = 0n;
|
|
127
|
+
let borrowAmount = 0n;
|
|
128
|
+
|
|
129
|
+
for (const assetID of principals.keys()) {
|
|
130
|
+
const assetConfig = assetsConfig.get(assetID) as AssetConfig;
|
|
131
|
+
const assetData = assetsData.get(assetID) as ExtendedAssetData;
|
|
132
|
+
const price = prices.get(assetID) as bigint;
|
|
133
|
+
const principal = principals.get(assetID) as bigint;
|
|
134
|
+
|
|
135
|
+
if (principal < 0) {
|
|
136
|
+
borrowAmount += (calculatePresentValue(assetData.bRate, -principal) * price) / 10n ** assetConfig.decimals;
|
|
137
|
+
} else if (principal > 0) {
|
|
138
|
+
borrowLimit +=
|
|
139
|
+
(calculatePresentValue(assetData.sRate, principal) * price * assetConfig.collateralFactor) /
|
|
140
|
+
10n ** assetConfig.decimals /
|
|
141
|
+
MASTER_CONSTANTS.ASSET_COEFFICIENT_SCALE;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return borrowLimit - borrowAmount;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function presentValue(sRate: bigint, bRate: bigint, principalValue: bigint): UserBalance {
|
|
149
|
+
if (principalValue > 0) {
|
|
150
|
+
return {
|
|
151
|
+
amount: calculatePresentValue(sRate, principalValue),
|
|
152
|
+
type: BalanceType.supply,
|
|
153
|
+
};
|
|
154
|
+
} else if (principalValue < 0) {
|
|
155
|
+
return {
|
|
156
|
+
amount: calculatePresentValue(bRate, -principalValue),
|
|
157
|
+
type: BalanceType.borrow,
|
|
158
|
+
};
|
|
159
|
+
} else {
|
|
160
|
+
return {
|
|
161
|
+
amount: 0n,
|
|
162
|
+
type: undefined,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function calculateLiquidationData(
|
|
168
|
+
assetsConfig: Dictionary<bigint, AssetConfig>,
|
|
169
|
+
assetsData: Dictionary<bigint, ExtendedAssetData>,
|
|
170
|
+
principals: Dictionary<bigint, bigint>,
|
|
171
|
+
prices: Dictionary<bigint, bigint>,
|
|
172
|
+
): LiquidationData {
|
|
173
|
+
let gCollateralValue = 0n;
|
|
174
|
+
let gCollateralAsset = 0n;
|
|
175
|
+
let gLoanValue = 0n;
|
|
176
|
+
let gLoanAsset = 0n;
|
|
177
|
+
let totalDebt = 0n;
|
|
178
|
+
let totalLimit = 0n;
|
|
179
|
+
|
|
180
|
+
for (const key of principals.keys()) {
|
|
181
|
+
const principal = principals.get(key)!;
|
|
182
|
+
const assetConfig = assetsConfig.get(key)!;
|
|
183
|
+
const assetData = assetsData.get(key)!;
|
|
184
|
+
const balance =
|
|
185
|
+
principal > 0 ? (principal * assetData.sRate) / BigInt(1e12) : (principal * assetData.bRate) / BigInt(1e12);
|
|
186
|
+
if (balance > 0) {
|
|
187
|
+
const assetWorth = (balance * prices.get(key)!) / 10n ** assetConfig.decimals;
|
|
188
|
+
totalLimit += (assetWorth * assetConfig.liquidationThreshold) / MASTER_CONSTANTS.ASSET_COEFFICIENT_SCALE;
|
|
189
|
+
if (assetWorth > gCollateralValue) {
|
|
190
|
+
gCollateralValue = assetWorth;
|
|
191
|
+
gCollateralAsset = key;
|
|
192
|
+
}
|
|
193
|
+
} else if (balance < 0) {
|
|
194
|
+
const assetWorth = (-balance * prices.get(key)!) / 10n ** assetConfig.decimals;
|
|
195
|
+
totalDebt += assetWorth;
|
|
196
|
+
if (assetWorth > gLoanValue) {
|
|
197
|
+
gLoanValue = assetWorth;
|
|
198
|
+
gLoanAsset = key;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (totalLimit < totalDebt) {
|
|
204
|
+
const gLoanAssetPrice = prices.get(gLoanAsset)!;
|
|
205
|
+
const values: bigint[] = [];
|
|
206
|
+
const gCollateralAssetConfig = assetsConfig.get(gCollateralAsset)!;
|
|
207
|
+
const gLoanAssetConfig = assetsConfig.get(gLoanAsset)!;
|
|
208
|
+
const liquidationBonus = gLoanAssetConfig.liquidationBonus;
|
|
209
|
+
const loanDecimal = 10n ** gLoanAssetConfig.decimals;
|
|
210
|
+
values.push(
|
|
211
|
+
(bigIntMax(gCollateralValue / 2n, bigIntMin(gCollateralValue, 10_000_000_000n)) *
|
|
212
|
+
loanDecimal *
|
|
213
|
+
MASTER_CONSTANTS.ASSET_COEFFICIENT_SCALE) /
|
|
214
|
+
liquidationBonus /
|
|
215
|
+
gLoanAssetPrice,
|
|
216
|
+
);
|
|
217
|
+
values.push((gLoanValue * loanDecimal) / gLoanAssetPrice);
|
|
218
|
+
|
|
219
|
+
const liquidationAmount = (bigIntMin(...values) as bigint) - 5n;
|
|
220
|
+
const gCollateralAssetPrice: bigint = prices.get(gCollateralAsset)!;
|
|
221
|
+
const collateralDecimal = 10n ** gCollateralAssetConfig.decimals;
|
|
222
|
+
let minCollateralAmount =
|
|
223
|
+
(((liquidationAmount * gLoanAssetPrice * liquidationBonus) / 10000n) * collateralDecimal) /
|
|
224
|
+
gCollateralAssetPrice /
|
|
225
|
+
loanDecimal -
|
|
226
|
+
10n;
|
|
227
|
+
minCollateralAmount = (minCollateralAmount * 97n) / 100n;
|
|
228
|
+
if (minCollateralAmount / collateralDecimal >= 1n) {
|
|
229
|
+
return {
|
|
230
|
+
greatestCollateralAsset: gCollateralAsset,
|
|
231
|
+
greatestCollateralValue: gCollateralValue,
|
|
232
|
+
greatestLoanAsset: gLoanAsset,
|
|
233
|
+
greatestLoanValue: gLoanValue,
|
|
234
|
+
totalDebt,
|
|
235
|
+
totalLimit,
|
|
236
|
+
liquidable: true,
|
|
237
|
+
liquidationAmount,
|
|
238
|
+
minCollateralAmount,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
greatestCollateralAsset: gCollateralAsset,
|
|
245
|
+
greatestCollateralValue: gCollateralValue,
|
|
246
|
+
greatestLoanAsset: gLoanAsset,
|
|
247
|
+
greatestLoanValue: gLoanValue,
|
|
248
|
+
totalDebt,
|
|
249
|
+
totalLimit,
|
|
250
|
+
liquidable: false,
|
|
251
|
+
};
|
|
252
|
+
}
|