@evaafi/sdk 0.6.1 → 0.6.2-b

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 (73) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +2 -1
  3. package/dist/api/liquidation.js +1 -3
  4. package/dist/api/math.d.ts +10 -1
  5. package/dist/api/math.js +45 -6
  6. package/dist/api/parser.js +49 -27
  7. package/dist/api/prices.d.ts +5 -2
  8. package/dist/api/prices.js +35 -13
  9. package/dist/constants/assets.d.ts +8 -0
  10. package/dist/constants/assets.js +31 -1
  11. package/dist/constants/general.d.ts +5 -2
  12. package/dist/constants/general.js +12 -22
  13. package/dist/constants/pools.d.ts +1 -0
  14. package/dist/constants/pools.js +19 -3
  15. package/dist/contracts/MasterContract.d.ts +5 -0
  16. package/dist/contracts/MasterContract.js +6 -0
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.js +10 -2
  19. package/dist/prices/Prices.d.ts +9 -0
  20. package/dist/prices/Prices.js +43 -0
  21. package/dist/prices/PricesCollector.d.ts +12 -0
  22. package/dist/prices/PricesCollector.js +123 -0
  23. package/dist/prices/Types.d.ts +33 -0
  24. package/dist/prices/Types.js +11 -0
  25. package/dist/prices/constants.d.ts +1 -0
  26. package/dist/prices/constants.js +4 -0
  27. package/dist/prices/index.d.ts +6 -0
  28. package/dist/prices/index.js +22 -0
  29. package/dist/prices/sources/Backend.d.ts +13 -0
  30. package/dist/prices/sources/Backend.js +52 -0
  31. package/dist/prices/sources/Icp.d.ts +10 -0
  32. package/dist/prices/sources/Icp.js +23 -0
  33. package/dist/prices/sources/Iota.d.ts +39 -0
  34. package/dist/prices/sources/Iota.js +49 -0
  35. package/dist/prices/sources/PriceSource.d.ts +14 -0
  36. package/dist/prices/sources/PriceSource.js +26 -0
  37. package/dist/prices/sources/index.d.ts +4 -0
  38. package/dist/prices/sources/index.js +20 -0
  39. package/dist/prices/utils.d.ts +23 -0
  40. package/dist/prices/utils.js +148 -0
  41. package/dist/types/Master.d.ts +2 -1
  42. package/dist/types/User.d.ts +11 -1
  43. package/dist/utils/userJettonWallet.js +42 -43
  44. package/dist/utils/utils.d.ts +1 -0
  45. package/dist/utils/utils.js +5 -1
  46. package/package.json +11 -9
  47. package/src/api/liquidation.ts +0 -1
  48. package/src/api/math.ts +66 -5
  49. package/src/api/parser.ts +56 -31
  50. package/src/api/prices.ts +20 -7
  51. package/src/constants/assets.ts +57 -0
  52. package/src/constants/general.ts +11 -23
  53. package/src/constants/pools.ts +21 -5
  54. package/src/contracts/MasterContract.ts +8 -1
  55. package/src/index.ts +9 -2
  56. package/src/prices/Prices.ts +32 -0
  57. package/src/prices/PricesCollector.ts +139 -0
  58. package/src/prices/Types.ts +44 -0
  59. package/src/prices/constants.ts +1 -0
  60. package/src/prices/index.ts +6 -0
  61. package/src/prices/sources/Backend.ts +62 -0
  62. package/src/prices/sources/Icp.ts +27 -0
  63. package/src/prices/sources/Iota.ts +90 -0
  64. package/src/prices/sources/PriceSource.ts +35 -0
  65. package/src/prices/sources/index.ts +4 -0
  66. package/src/prices/utils.ts +170 -0
  67. package/src/types/Master.ts +3 -2
  68. package/src/types/User.ts +13 -3
  69. package/src/utils/userJettonWallet.ts +43 -53
  70. package/src/utils/utils.ts +5 -1
  71. package/src/config.ts +0 -1
  72. package/src/types/Common.ts +0 -16
  73. package/src/utils/priceUtils.ts +0 -177
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./Backend"), exports);
18
+ __exportStar(require("./Iota"), exports);
19
+ __exportStar(require("./Icp"), exports);
20
+ __exportStar(require("./PriceSource"), exports);
@@ -0,0 +1,23 @@
1
+ /// <reference types="node" />
2
+ import { Cell, Dictionary, Slice } from "@ton/core";
3
+ import { OraclePricesData, PriceData, PriceSource, PriceSourcesConfig, RawPriceData } from "..";
4
+ import { Oracle, OracleNFT, PoolConfig } from "../types/Master";
5
+ export declare function verifyPricesTimestamp(): (priceData: RawPriceData) => boolean;
6
+ export declare function verifyPricesSign(nfts: OracleNFT[]): (priceData: RawPriceData) => boolean;
7
+ export declare function getMedianPrice(pricesData: PriceData[], asset: bigint): bigint | null;
8
+ export declare function packAssetsData(assetsData: {
9
+ assetId: bigint;
10
+ medianPrice: bigint;
11
+ }[]): Cell;
12
+ export declare function packPrices(assetsDataCell: Cell, oraclesDataCell: Cell): Cell;
13
+ export declare function createOracleDataProof(oracle: Oracle, data: OraclePricesData, signature: Buffer, assets: Array<bigint>): Slice;
14
+ export declare function packOraclesData(oraclesData: {
15
+ oracle: Oracle;
16
+ data: OraclePricesData;
17
+ signature: Buffer;
18
+ }[], assets: Array<bigint>): Cell;
19
+ export declare function sumDicts(result: Dictionary<bigint, bigint>, addendum: Dictionary<bigint, bigint>): void;
20
+ export declare function generatePriceSources(config?: PriceSourcesConfig, nfts?: OracleNFT[]): PriceSource[];
21
+ export declare function collectAndFilterPrices(priceSource: PriceSource, poolConfig: PoolConfig): Promise<RawPriceData[]>;
22
+ export declare function unpackMedianPrices(pricesCell: Cell): Dictionary<bigint, bigint> | undefined;
23
+ export declare function verifyRawPriceDataSign(priceData: RawPriceData): boolean;
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyRawPriceDataSign = exports.unpackMedianPrices = exports.collectAndFilterPrices = exports.generatePriceSources = exports.sumDicts = exports.packOraclesData = exports.createOracleDataProof = exports.packPrices = exports.packAssetsData = exports.getMedianPrice = exports.verifyPricesSign = exports.verifyPricesTimestamp = void 0;
4
+ const core_1 = require("@ton/core");
5
+ const __1 = require("..");
6
+ const merkleProof_1 = require("../utils/merkleProof");
7
+ const crypto_1 = require("@ton/crypto");
8
+ function verifyPricesTimestamp() {
9
+ return function (priceData) {
10
+ const timestamp = Date.now() / 1000;
11
+ const pricesTime = priceData.timestamp;
12
+ //console.debug('timestamp - pricesTime, pricesTime', timestamp - pricesTime, pricesTime);
13
+ return timestamp - pricesTime < __1.TTL_ORACLE_DATA_SEC;
14
+ };
15
+ }
16
+ exports.verifyPricesTimestamp = verifyPricesTimestamp;
17
+ function verifyPricesSign(nfts) {
18
+ return function (priceData) {
19
+ if (nfts.findIndex(x => x.pubkey.equals(priceData.pubkey)) == -1) {
20
+ //console.debug('[verifyPricesSign] nft not found');
21
+ return false;
22
+ }
23
+ return verifyRawPriceDataSign(priceData);
24
+ };
25
+ }
26
+ exports.verifyPricesSign = verifyPricesSign;
27
+ /* export function verifyPricesAssets(assets: PoolAssetsConfig) {
28
+ return function(priceData: RawPriceData): boolean {
29
+ for (const asset of assets) {
30
+ if(!priceData.dict.has(asset.assetId)) {
31
+ return false;
32
+ }
33
+ }
34
+ return true;
35
+ }
36
+ } */
37
+ function getMedianPrice(pricesData, asset) {
38
+ try {
39
+ const usingPrices = pricesData.filter(x => x.dict.has(asset));
40
+ const sorted = usingPrices.map(x => x.dict.get(asset)).sort((a, b) => Number(a) - Number(b));
41
+ if (sorted.length == 0) {
42
+ return null;
43
+ }
44
+ const mid = Math.floor(sorted.length / 2);
45
+ if (sorted.length % 2 === 0) {
46
+ return (sorted[mid - 1] + sorted[mid]) / 2n;
47
+ }
48
+ else {
49
+ return sorted[mid];
50
+ }
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ exports.getMedianPrice = getMedianPrice;
57
+ function packAssetsData(assetsData) {
58
+ if (assetsData.length == 0) {
59
+ throw new Error("No assets data to pack");
60
+ }
61
+ return assetsData.reduceRight((acc, { assetId, medianPrice }) => (0, core_1.beginCell)()
62
+ .storeUint(assetId, 256)
63
+ .storeCoins(medianPrice)
64
+ .storeMaybeRef(acc)
65
+ .endCell(), null);
66
+ }
67
+ exports.packAssetsData = packAssetsData;
68
+ function packPrices(assetsDataCell, oraclesDataCell) {
69
+ let pricesCell = (0, core_1.beginCell)()
70
+ .storeRef(assetsDataCell)
71
+ .storeRef(oraclesDataCell)
72
+ .endCell();
73
+ return pricesCell;
74
+ }
75
+ exports.packPrices = packPrices;
76
+ function createOracleDataProof(oracle, data, signature, assets) {
77
+ let prunedDict = (0, merkleProof_1.generateMerkleProofDirect)(data.prices, assets, core_1.Dictionary.Keys.BigUint(256));
78
+ let prunedData = (0, core_1.beginCell)().storeUint(data.timestamp, 32).storeMaybeRef(prunedDict).endCell();
79
+ let merkleProof = (0, merkleProof_1.convertToMerkleProof)(prunedData);
80
+ let oracleDataProof = (0, core_1.beginCell)().storeUint(oracle.id, 32).storeRef(merkleProof).storeBuffer(signature).asSlice();
81
+ return oracleDataProof;
82
+ }
83
+ exports.createOracleDataProof = createOracleDataProof;
84
+ function packOraclesData(oraclesData, assets) {
85
+ if (oraclesData.length == 0) {
86
+ throw new Error("no oracles data to pack");
87
+ }
88
+ let proofs = oraclesData.sort((d1, d2) => d1.oracle.id - d2.oracle.id).map(({ oracle, data, signature }) => createOracleDataProof(oracle, data, signature, assets));
89
+ return proofs.reduceRight((acc, val) => (0, core_1.beginCell)().storeSlice(val).storeMaybeRef(acc).endCell(), null);
90
+ }
91
+ exports.packOraclesData = packOraclesData;
92
+ function sumDicts(result, addendum) {
93
+ for (const key of addendum.keys()) {
94
+ const current = result.get(key);
95
+ const value = addendum.get(key);
96
+ if (current === undefined) {
97
+ result.set(key, value);
98
+ continue;
99
+ }
100
+ result.set(key, current + value);
101
+ }
102
+ }
103
+ exports.sumDicts = sumDicts;
104
+ function generatePriceSources(config = __1.DefaultPriceSourcesConfig, nfts = __1.MAINNET_POOL_CONFIG.oracles) {
105
+ let result = config.backendEndpoints.map(x => new __1.BackendPriceSource(x, nfts));
106
+ result.push(...config.icpEndpoints.map(x => new __1.IcpPriceSource(x, nfts)));
107
+ result.push(...config.iotaEndpoints.map(x => new __1.IotaPriceSource(x, nfts)));
108
+ return result;
109
+ }
110
+ exports.generatePriceSources = generatePriceSources;
111
+ async function collectAndFilterPrices(priceSource, poolConfig) {
112
+ const prices = await priceSource.getPrices();
113
+ //console.debug('[FILTERING] before filtering prices len ', priceSource.sourceName, prices.length);
114
+ return await (async () => {
115
+ const acceptedPrices = prices.filter(price => verifyPricesTimestamp()(price) && verifyPricesSign(poolConfig.oracles)(price));
116
+ //console.debug('[FILTERING] after filtering prices len ', priceSource.sourceName, acceptedPrices.length);
117
+ if (acceptedPrices.length < poolConfig.minimalOracles) {
118
+ throw new Error("Prices are outdated");
119
+ }
120
+ return acceptedPrices;
121
+ })();
122
+ }
123
+ exports.collectAndFilterPrices = collectAndFilterPrices;
124
+ function unpackMedianPrices(pricesCell) {
125
+ if (!pricesCell)
126
+ return undefined;
127
+ const slice = pricesCell.beginParse();
128
+ let assetCell = slice.loadRef();
129
+ const res = core_1.Dictionary.empty();
130
+ while (assetCell != core_1.Cell.EMPTY && assetCell !== null) {
131
+ const slice = assetCell.beginParse();
132
+ const assetId = slice.loadUintBig(256);
133
+ const medianPrice = slice.loadCoins();
134
+ res.set(assetId, medianPrice);
135
+ assetCell = slice.loadMaybeRef();
136
+ }
137
+ return res;
138
+ }
139
+ exports.unpackMedianPrices = unpackMedianPrices;
140
+ function verifyRawPriceDataSign(priceData) {
141
+ const message = priceData.dataCell.refs[0].hash();
142
+ const signature = priceData.signature;
143
+ const publicKey = priceData.pubkey;
144
+ const valid = (0, crypto_1.signVerify)(message, signature, publicKey);
145
+ //console.debug('[verifyRawPriceDataSign] sign is valid:', valid);
146
+ return valid;
147
+ }
148
+ exports.verifyRawPriceDataSign = verifyRawPriceDataSign;
@@ -80,7 +80,7 @@ export type AssetData = {
80
80
  balance: bigint;
81
81
  trackingSupplyIndex: bigint;
82
82
  trackingBorrowIndex: bigint;
83
- awaitedSupply?: bigint;
83
+ awaitedSupply: bigint;
84
84
  };
85
85
  export type AssetInterest = {
86
86
  supplyInterest: bigint;
@@ -112,6 +112,7 @@ export type AgregatedBalances = {
112
112
  export type OracleNFT = {
113
113
  id: number;
114
114
  address: string;
115
+ pubkey: Buffer;
115
116
  };
116
117
  export type Oracle = {
117
118
  id: number;
@@ -1,5 +1,5 @@
1
1
  import { Address, Cell, Dictionary } from '@ton/core';
2
- import { ExtendedAssetsConfig, ExtendedAssetsData, PoolAssetConfig, PoolConfig } from './Master';
2
+ import { AssetConfig, AssetData, ExtendedAssetsConfig, ExtendedAssetsData, MasterConstants, PoolAssetConfig, PoolConfig } from './Master';
3
3
  export declare enum BalanceType {
4
4
  supply = "supply",
5
5
  borrow = "borrow"
@@ -31,6 +31,7 @@ export type UserLiteData = {
31
31
  masterAddress: Address;
32
32
  ownerAddress: Address;
33
33
  principals: Dictionary<bigint, bigint>;
34
+ realPrincipals: Dictionary<bigint, bigint>;
34
35
  state: number;
35
36
  balances: Dictionary<bigint, UserBalance>;
36
37
  trackingSupplyIndex: bigint;
@@ -40,6 +41,7 @@ export type UserLiteData = {
40
41
  rewards: Dictionary<bigint, UserRewards>;
41
42
  backupCell1: Cell | null;
42
43
  backupCell2: Cell | null;
44
+ fullyParsed: boolean;
43
45
  };
44
46
  export type UserDataActive = UserLiteData & {
45
47
  withdrawalLimits: Dictionary<bigint, bigint>;
@@ -52,6 +54,7 @@ export type UserDataActive = UserLiteData & {
52
54
  limitUsed: bigint;
53
55
  healthFactor: number;
54
56
  liquidationData: LiquidationData;
57
+ havePrincipalWithoutPrice: boolean;
55
58
  };
56
59
  export type UserDataInactive = {
57
60
  type: 'inactive';
@@ -84,3 +87,10 @@ export type PredictHealthFactorArgs = {
84
87
  assetsConfig: ExtendedAssetsConfig;
85
88
  poolConfig: PoolConfig;
86
89
  };
90
+ export type PredictAPYArgs = {
91
+ balanceChangeType: BalanceChangeType;
92
+ amount: bigint;
93
+ assetData: AssetData;
94
+ assetConfig: AssetConfig;
95
+ masterConstants: MasterConstants;
96
+ };
@@ -3,54 +3,53 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getUserJettonWallet = void 0;
4
4
  const core_1 = require("@ton/core");
5
5
  const assets_1 = require("../constants/assets");
6
+ function getUserJettonData(ownerAddress, assetName, jettonWalletCode, jettonMasterAddress) {
7
+ switch (assetName) {
8
+ case 'uTON':
9
+ return (0, core_1.beginCell)()
10
+ .storeCoins(0)
11
+ .storeUint(0, 64)
12
+ .storeAddress(ownerAddress)
13
+ .storeAddress(jettonMasterAddress)
14
+ .storeRef(jettonWalletCode)
15
+ .endCell();
16
+ case 'DOGS':
17
+ case 'NOT':
18
+ case 'USDT':
19
+ return (0, core_1.beginCell)()
20
+ .storeUint(0, 4)
21
+ .storeCoins(0)
22
+ .storeAddress(ownerAddress)
23
+ .storeAddress(jettonMasterAddress)
24
+ .endCell();
25
+ case 'tsTON':
26
+ return (0, core_1.beginCell)()
27
+ .storeCoins(0)
28
+ .storeAddress(ownerAddress)
29
+ .storeAddress(jettonMasterAddress)
30
+ .storeRef(jettonWalletCode)
31
+ .storeCoins(0)
32
+ .storeUint(0, 48)
33
+ .endCell();
34
+ default:
35
+ return (0, core_1.beginCell)().storeCoins(0)
36
+ .storeAddress(ownerAddress)
37
+ .storeAddress(jettonMasterAddress)
38
+ .storeRef(jettonWalletCode)
39
+ .endCell();
40
+ }
41
+ }
6
42
  function getUserJettonWallet(ownerAddress, poolAssetConfig) {
7
- if (poolAssetConfig.name == 'TON' || poolAssetConfig.assetId === assets_1.UNDEFINED_ASSET.assetId) {
43
+ const assetName = poolAssetConfig.name;
44
+ if (assetName == 'TON' || poolAssetConfig.assetId === assets_1.UNDEFINED_ASSET.assetId) {
8
45
  throw new Error(`Cant getUserJettonWallet for ${poolAssetConfig.name} asset`);
9
46
  }
10
- const jettonMasterAddress = poolAssetConfig.jettonMasterAddress;
11
- const jettonWalletCode = poolAssetConfig.jettonWalletCode;
12
- if (poolAssetConfig.name === 'USDT') {
47
+ let jettonWalletCode = poolAssetConfig.jettonWalletCode;
48
+ if (assetName === 'USDT' || assetName === 'tsTON') {
13
49
  const lib_prep = (0, core_1.beginCell)().storeUint(2, 8).storeBuffer(jettonWalletCode.hash()).endCell();
14
- const jwallet_code = new core_1.Cell({ exotic: true, bits: lib_prep.bits, refs: lib_prep.refs });
15
- const jettonData = (0, core_1.beginCell)()
16
- .storeUint(0, 4)
17
- .storeCoins(0)
18
- .storeAddress(ownerAddress)
19
- .storeAddress(jettonMasterAddress)
20
- .endCell();
21
- const stateInit = (0, core_1.beginCell)()
22
- .store((0, core_1.storeStateInit)({
23
- code: jwallet_code,
24
- data: jettonData
25
- }))
26
- .endCell();
27
- return new core_1.Address(0, stateInit.hash());
50
+ jettonWalletCode = new core_1.Cell({ exotic: true, bits: lib_prep.bits, refs: lib_prep.refs });
28
51
  }
29
- if (poolAssetConfig.name === 'tsTON') {
30
- const lib_prep = (0, core_1.beginCell)().storeUint(2, 8).storeBuffer(jettonWalletCode.hash()).endCell();
31
- const jwallet_code = new core_1.Cell({ exotic: true, bits: lib_prep.bits, refs: lib_prep.refs });
32
- const jettonData = (0, core_1.beginCell)()
33
- .storeCoins(0)
34
- .storeAddress(ownerAddress)
35
- .storeAddress(jettonMasterAddress)
36
- .storeRef(jwallet_code)
37
- .storeCoins(0)
38
- .storeUint(0, 48)
39
- .endCell();
40
- const stateInit = (0, core_1.beginCell)()
41
- .store((0, core_1.storeStateInit)({
42
- code: jwallet_code,
43
- data: jettonData
44
- }))
45
- .endCell();
46
- return new core_1.Address(0, stateInit.hash());
47
- }
48
- const jettonData = (0, core_1.beginCell)()
49
- .storeCoins(0)
50
- .storeAddress(ownerAddress)
51
- .storeAddress(jettonMasterAddress)
52
- .storeRef(jettonWalletCode)
53
- .endCell();
52
+ const jettonData = getUserJettonData(ownerAddress, assetName, jettonWalletCode, poolAssetConfig.jettonMasterAddress);
54
53
  const stateInit = (0, core_1.beginCell)()
55
54
  .store((0, core_1.storeStateInit)({
56
55
  code: jettonWalletCode,
@@ -1,3 +1,4 @@
1
1
  import { PoolAssetConfig } from "../types/Master";
2
2
  export declare function isTonAsset(asset: PoolAssetConfig): boolean;
3
3
  export declare function isTonAssetId(assetId: bigint): boolean;
4
+ export declare function delay(ms: number): Promise<unknown>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isTonAssetId = exports.isTonAsset = void 0;
3
+ exports.delay = exports.isTonAssetId = exports.isTonAsset = void 0;
4
4
  const assets_1 = require("../constants/assets");
5
5
  function isTonAsset(asset) {
6
6
  return asset.name === 'TON';
@@ -10,3 +10,7 @@ function isTonAssetId(assetId) {
10
10
  return assetId === assets_1.ASSET_ID.TON;
11
11
  }
12
12
  exports.isTonAssetId = isTonAssetId;
13
+ function delay(ms) {
14
+ return new Promise(resolve => setTimeout(resolve, ms));
15
+ }
16
+ exports.delay = delay;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evaafi/sdk",
3
- "version": "0.6.1",
3
+ "version": "0.6.2-b",
4
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": [
@@ -8,7 +8,8 @@
8
8
  "src"
9
9
  ],
10
10
  "scripts": {
11
- "build": "tsc --declaration"
11
+ "build": "tsc --declaration",
12
+ "test": "jest"
12
13
  },
13
14
  "repository": {
14
15
  "type": "git",
@@ -20,15 +21,16 @@
20
21
  "devDependencies": {
21
22
  "@orbs-network/ton-access": "^2.3.3",
22
23
  "@ton/core": "0.56.0",
23
- "@ton/crypto": "^3.3.0",
24
- "@tonconnect/sdk": "^3.0.5",
24
+ "@ton/crypto": "3.3.0",
25
+ "@tonconnect/sdk": "3.0.5",
25
26
  "@types/jest": "^29.5.12",
26
27
  "@types/node": "^20.10.4",
27
- "crypto-js": "^4.2.0",
28
- "prettier": "^3.2.4",
28
+ "crypto-js": "4.2.0",
29
+ "prettier": "3.2.4",
29
30
  "ts-jest": "^29.2.4",
30
31
  "ts-node": "^10.9.1",
31
- "typescript": "^5.3.3"
32
+ "typedoc": "0.27.4",
33
+ "typescript": "5.3.3"
32
34
  },
33
35
  "peerDependencies": {
34
36
  "@ton/core": ">=0.56.0",
@@ -36,7 +38,7 @@
36
38
  "crypto-js": ">=4.2.0"
37
39
  },
38
40
  "dependencies": {
39
- "@ton/ton": "^14.0.0",
40
- "dotenv": "^16.4.5"
41
+ "@ton/ton": "14.0.0",
42
+ "dotenv": "16.4.5"
41
43
  }
42
44
  }
@@ -179,7 +179,6 @@ export function calculateLiquidationAmounts(
179
179
 
180
180
  const loanValue = toAssetWorth(loanInfo.balance, loanInfo.scale, loanInfo.price);
181
181
  const baseLiquidationValue = BigMath.min(
182
- // deductReserve(loanValue, reserveFactor, reserveFactorScale),
183
182
  loanValue,
184
183
  deductLiquidationBonus(allowedCollateralValue, liquidationBonus, liquidationBonusScale)
185
184
  );
package/src/api/math.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  BalanceType,
16
16
  HealthParamsArgs,
17
17
  LiquidationData,
18
+ PredictAPYArgs,
18
19
  PredictHealthFactorArgs,
19
20
  UserBalance
20
21
  } from '../types/User';
@@ -109,9 +110,28 @@ export function calculateAssetData(
109
110
  };
110
111
  }
111
112
 
112
- export function calculateAssetInterest(assetConfig: AssetConfig, assetData: AssetData, masterConstants: MasterConstants): AssetInterest {
113
+ export function calculateAssetInterest(
114
+ assetConfig: AssetConfig,
115
+ assetData: AssetData,
116
+ masterConstants: MasterConstants
117
+ ): AssetInterest {
113
118
  const totalSupply = calculatePresentValue(assetData.sRate, assetData.totalSupply, masterConstants);
114
119
  const totalBorrow = calculatePresentValue(assetData.bRate, assetData.totalBorrow, masterConstants);
120
+
121
+ return calculateInterestWithSupplyBorrow(
122
+ totalSupply,
123
+ totalBorrow,
124
+ assetConfig,
125
+ masterConstants
126
+ );
127
+ }
128
+
129
+ export function calculateInterestWithSupplyBorrow(
130
+ totalSupply: bigint,
131
+ totalBorrow: bigint,
132
+ assetConfig: AssetConfig,
133
+ masterConstants: MasterConstants
134
+ ): AssetInterest {
115
135
  let utilization = 0n;
116
136
  let supplyInterest = 0n;
117
137
  let borrowInterest = 0n;
@@ -147,6 +167,7 @@ export function calculateAssetInterest(assetConfig: AssetConfig, assetData: Asse
147
167
  };
148
168
  }
149
169
 
170
+
150
171
  export function checkNotInDebtAtAll(principals: Dictionary<bigint, bigint>): boolean {
151
172
  return principals.values().every(x => x >= 0n);
152
173
  }
@@ -170,13 +191,12 @@ export function getAgregatedBalances(
170
191
  const price = prices.get(assetId)!;
171
192
  const assetData = assetsData.get(assetId)!;
172
193
  const assetConfig = assetsConfig.get(assetId)!;
173
- // console.log('price', price);
194
+
174
195
  if (principal < 0) {
175
196
  user_total_borrow += presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals;
176
197
  } else {
177
198
  user_total_supply += presentValue(assetData.sRate, assetData.bRate, principal, masterConstants).amount * price / 10n ** assetConfig.decimals;
178
199
  }
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)
180
200
  }
181
201
  }
182
202
  return { totalSupply: user_total_supply, totalBorrow: user_total_borrow };
@@ -251,10 +271,19 @@ export function getAvailableToBorrow(
251
271
  let borrowAmount = 0n;
252
272
 
253
273
  for (const assetID of principals.keys()) {
274
+ const principal = principals.get(assetID) as bigint;
275
+
276
+ if (principal == 0n) {
277
+ continue;
278
+ }
279
+
280
+ if (!prices.has(assetID)) {
281
+ return 0n;
282
+ }
283
+
254
284
  const assetConfig = assetsConfig.get(assetID) as AssetConfig;
255
285
  const assetData = assetsData.get(assetID) as ExtendedAssetData;
256
286
  const price = prices.get(assetID) as bigint;
257
- const principal = principals.get(assetID) as bigint;
258
287
 
259
288
  if (principal < 0n) {
260
289
  borrowAmount += mulDiv(calculatePresentValue(assetData.bRate, -principal, masterConstants), price, 10n ** assetConfig.decimals);
@@ -465,7 +494,6 @@ export function predictHealthFactor(args: PredictHealthFactorArgs): number {
465
494
 
466
495
  const assetConfig = args.assetsConfig.get(assetId)!;
467
496
  const assetPrice = Number(args.prices.get(assetId)!);
468
- const assetData = args.assetsData.get(assetId)!;
469
497
 
470
498
  let totalLimit = Number(healthParams.totalLimit);
471
499
  let totalBorrow = Number(healthParams.totalDebt);
@@ -494,3 +522,36 @@ const assetData = args.assetsData.get(assetId)!;
494
522
 
495
523
  return Math.min(Math.max(1 - totalBorrow / totalLimit, 0), 1); // let's limit a result to zero below and one above
496
524
  }
525
+
526
+ /**
527
+ * Predicts how APY will change as a result of one of the actions Borrow, Supply, Withdraw or Repay.
528
+ *
529
+ * Used on the front-end.
530
+ *
531
+ * @returns Estimated APYs for Supply and Borrow
532
+ */
533
+ export function predictAPY(args: PredictAPYArgs): AssetInterest {
534
+ const assetConfig = args.assetConfig;
535
+ const assetData = args.assetData;
536
+ const masterConstants = args.masterConstants;
537
+
538
+ let totalSupply = calculatePresentValue(assetData.sRate, assetData.totalSupply, masterConstants);
539
+ let totalBorrow = calculatePresentValue(assetData.bRate, assetData.totalBorrow, masterConstants);
540
+
541
+ const currentAmount = args.amount;
542
+ const changeType = args.balanceChangeType;
543
+
544
+ if (currentAmount != null && currentAmount != 0n) {
545
+ if (changeType == BalanceChangeType.Borrow) {
546
+ totalBorrow += currentAmount;
547
+ } else if (changeType == BalanceChangeType.Repay) {
548
+ totalBorrow -= currentAmount;
549
+ } else if (changeType == BalanceChangeType.Withdraw) {
550
+ totalSupply -= currentAmount;
551
+ } else if (changeType == BalanceChangeType.Supply) {
552
+ totalSupply += currentAmount;
553
+ }
554
+ }
555
+
556
+ return calculateInterestWithSupplyBorrow(totalSupply, totalBorrow, assetConfig, masterConstants);
557
+ }