@evaafi/sdk 0.7.0 → 0.9.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/dist/api/feeds.d.ts +30 -0
- package/dist/api/feeds.js +73 -0
- package/dist/api/liquidation.js +1 -1
- package/dist/api/math.js +1 -1
- package/dist/api/parser.d.ts +4 -2
- package/dist/api/parser.js +39 -18
- package/dist/api/parsers/AbstractOracleParser.d.ts +11 -0
- package/dist/api/parsers/AbstractOracleParser.js +9 -0
- package/dist/api/parsers/ClassicOracleParser.d.ts +10 -0
- package/dist/api/parsers/ClassicOracleParser.js +16 -0
- package/dist/api/parsers/PythOracleParser.d.ts +17 -0
- package/dist/api/parsers/PythOracleParser.js +22 -0
- package/dist/api/parsers/index.d.ts +3 -0
- package/dist/api/parsers/index.js +19 -0
- package/dist/api/prices.d.ts +6 -6
- package/dist/api/prices.js +37 -46
- package/dist/api/pyth.d.ts +16 -0
- package/dist/api/pyth.js +35 -0
- package/dist/constants/assets/assetId.d.ts +22 -0
- package/dist/constants/assets/assetId.js +29 -0
- package/dist/constants/assets/index.d.ts +3 -0
- package/dist/constants/assets/index.js +19 -0
- package/dist/constants/assets/mainnet.d.ts +19 -0
- package/dist/constants/assets/mainnet.js +114 -0
- package/dist/constants/assets/testnet.d.ts +14 -0
- package/dist/constants/assets/testnet.js +54 -0
- package/dist/constants/general/index.d.ts +65 -0
- package/dist/constants/general/index.js +93 -0
- package/dist/constants/general/mainnet.d.ts +24 -0
- package/dist/constants/general/mainnet.js +53 -0
- package/dist/constants/general/testnet.d.ts +12 -0
- package/dist/constants/general/testnet.js +15 -0
- package/dist/constants/general.d.ts +2 -2
- package/dist/constants/general.js +4 -4
- package/dist/constants/index.d.ts +3 -0
- package/dist/constants/index.js +19 -0
- package/dist/constants/pools/index.d.ts +2 -0
- package/dist/constants/pools/index.js +18 -0
- package/dist/constants/pools/mainnet.d.ts +14 -0
- package/dist/constants/pools/mainnet.js +145 -0
- package/dist/constants/pools/testnet.d.ts +9 -0
- package/dist/constants/pools/testnet.js +57 -0
- package/dist/constants/pools.js +7 -7
- package/dist/contracts/AbstractMaster.d.ts +185 -0
- package/dist/contracts/AbstractMaster.js +179 -0
- package/dist/contracts/ClassicMaster.d.ts +34 -0
- package/dist/contracts/ClassicMaster.js +87 -0
- package/dist/contracts/PythMaster.d.ts +61 -0
- package/dist/contracts/PythMaster.js +179 -0
- package/dist/contracts/UserContract.d.ts +1 -7
- package/dist/contracts/UserContract.js +1 -19
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +21 -0
- package/dist/index.d.ts +14 -14
- package/dist/index.js +20 -60
- package/dist/prices/Oracle.interface.d.ts +9 -0
- package/dist/prices/Oracle.interface.js +2 -0
- package/dist/prices/Prices.d.ts +5 -3
- package/dist/prices/Prices.js +13 -3
- package/dist/prices/PricesCollector.d.ts +17 -7
- package/dist/prices/PricesCollector.js +67 -51
- package/dist/prices/PythCollector.d.ts +22 -0
- package/dist/prices/PythCollector.js +217 -0
- package/dist/prices/Types.d.ts +17 -1
- package/dist/prices/Types.js +8 -1
- package/dist/prices/index.d.ts +4 -3
- package/dist/prices/index.js +4 -3
- package/dist/prices/sources/Backend.d.ts +5 -4
- package/dist/prices/sources/Backend.js +16 -13
- package/dist/prices/sources/Icp.d.ts +2 -1
- package/dist/prices/sources/Icp.js +12 -9
- package/dist/prices/sources/PriceSource.d.ts +7 -6
- package/dist/prices/utils.d.ts +10 -8
- package/dist/prices/utils.js +32 -46
- package/dist/types/Master.d.ts +10 -30
- package/dist/types/Master.js +3 -0
- package/dist/utils/userJettonWallet.js +0 -8
- package/dist/utils/utils.d.ts +8 -1
- package/dist/utils/utils.js +31 -2
- package/package.json +3 -2
- package/src/api/feeds.ts +90 -0
- package/src/api/liquidation.ts +1 -1
- package/src/api/math.ts +1 -1
- package/src/api/parser.ts +100 -38
- package/src/api/parsers/AbstractOracleParser.ts +16 -0
- package/src/api/parsers/ClassicOracleParser.ts +20 -0
- package/src/api/parsers/PythOracleParser.ts +34 -0
- package/src/api/parsers/index.ts +3 -0
- package/src/api/prices.ts +32 -41
- package/src/constants/assets/assetId.ts +30 -0
- package/src/constants/assets/index.ts +3 -0
- package/src/constants/{assets.ts → assets/mainnet.ts} +3 -96
- package/src/constants/assets/testnet.ts +74 -0
- package/src/constants/general/index.ts +91 -0
- package/src/constants/{general.ts → general/mainnet.ts} +48 -72
- package/src/constants/general/testnet.ts +25 -0
- package/src/constants/index.ts +3 -0
- package/src/constants/pools/index.ts +2 -0
- package/src/constants/pools/mainnet.ts +218 -0
- package/src/constants/pools/testnet.ts +75 -0
- package/src/contracts/AbstractMaster.ts +450 -0
- package/src/contracts/ClassicMaster.ts +149 -0
- package/src/contracts/PythMaster.ts +313 -0
- package/src/contracts/UserContract.ts +7 -28
- package/src/contracts/index.ts +7 -0
- package/src/index.ts +18 -85
- package/src/prices/Oracle.interface.ts +18 -0
- package/src/prices/Prices.ts +17 -4
- package/src/prices/PricesCollector.ts +91 -68
- package/src/prices/PythCollector.ts +294 -0
- package/src/prices/Types.ts +28 -6
- package/src/prices/index.ts +4 -3
- package/src/prices/sources/Backend.ts +21 -19
- package/src/prices/sources/Icp.ts +13 -10
- package/src/prices/sources/PriceSource.ts +6 -5
- package/src/prices/utils.ts +65 -68
- package/src/types/Master.ts +29 -52
- package/src/types/User.ts +15 -7
- package/src/utils/userJettonWallet.ts +0 -8
- package/src/utils/utils.ts +41 -2
- package/src/constants/pools.ts +0 -177
- package/src/contracts/MasterContract.ts +0 -410
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { BackendPriceSource } from ".";
|
|
2
|
+
import { FetchConfig, proxyFetchRetries, DefaultFetchConfig } from "../../utils/utils";
|
|
2
3
|
|
|
3
4
|
export class IcpPriceSource extends BackendPriceSource {
|
|
4
5
|
protected priceSourceName: string = 'IcpPriceSource';
|
|
5
6
|
|
|
6
|
-
async loadOracleData(): Promise<OutputData[]> {
|
|
7
|
-
|
|
7
|
+
async loadOracleData(fetchConfig: FetchConfig = DefaultFetchConfig): Promise<OutputData[]> {
|
|
8
|
+
const fetchPromise = fetch(`https://${this._endpoint}/prices`, {
|
|
8
9
|
headers: { accept: 'application/json' },
|
|
9
|
-
signal: AbortSignal.timeout(
|
|
10
|
-
})
|
|
10
|
+
signal: AbortSignal.timeout(fetchConfig.timeout)
|
|
11
|
+
}).then(async (response) => {
|
|
12
|
+
const data = (await response.json()) as Record<string, string>;
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
let outputData: OutputData[] = [];
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
for (const nft of this._nfts) {
|
|
17
|
+
outputData.push({oracleId: nft.id, data: data[nft.address] })
|
|
18
|
+
}
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
20
|
+
return outputData;
|
|
21
|
+
});
|
|
19
22
|
|
|
20
|
-
return
|
|
23
|
+
return await proxyFetchRetries(fetchPromise, fetchConfig);
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { RawPriceData } from "..";
|
|
2
|
-
import {
|
|
2
|
+
import { ExtendedEvaaOracle } from "../../types/Master";
|
|
3
|
+
import { FetchConfig } from "../../utils/utils";
|
|
3
4
|
|
|
4
5
|
export abstract class PriceSource {
|
|
5
6
|
protected priceSourceName: string = 'BackendPriceSource';
|
|
6
7
|
protected _endpoint: string;
|
|
7
|
-
protected _nfts:
|
|
8
|
+
protected _nfts: ExtendedEvaaOracle[];
|
|
8
9
|
|
|
9
|
-
constructor(endpoint: string, nfts:
|
|
10
|
+
constructor(endpoint: string, nfts: ExtendedEvaaOracle[]) {
|
|
10
11
|
this._endpoint = endpoint;
|
|
11
12
|
this._nfts = nfts;
|
|
12
13
|
}
|
|
@@ -27,9 +28,9 @@ export abstract class PriceSource {
|
|
|
27
28
|
this._endpoint = endpoint;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
set nfts(nfts:
|
|
31
|
+
set nfts(nfts: ExtendedEvaaOracle[]) {
|
|
31
32
|
this._nfts = nfts;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
abstract getPrices(): Promise<RawPriceData[]>;
|
|
35
|
+
abstract getPrices(fetchConfig?: FetchConfig): Promise<RawPriceData[]>;
|
|
35
36
|
}
|
package/src/prices/utils.ts
CHANGED
|
@@ -1,46 +1,28 @@
|
|
|
1
|
-
import { beginCell, Cell, Dictionary, Slice } from
|
|
2
|
-
import { signVerify } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { beginCell, Cell, Dictionary, Slice } from '@ton/core';
|
|
2
|
+
import { signVerify } from '@ton/crypto';
|
|
3
|
+
import { EvaaOracle, ExtendedEvaaOracle } from '../types/Master';
|
|
4
|
+
import { convertToMerkleProof, generateMerkleProofDirect } from '../utils/merkleProof';
|
|
5
|
+
import { FetchConfig } from '../utils/utils';
|
|
6
|
+
import { TTL_ORACLE_DATA_SEC } from './constants';
|
|
7
|
+
import { BackendPriceSource } from './sources/Backend';
|
|
8
|
+
import { IcpPriceSource } from './sources/Icp';
|
|
9
|
+
import { PriceSource } from './sources/PriceSource';
|
|
10
|
+
import { OraclePricesData, PriceData, PriceSourcesConfig, RawPriceData } from './Types';
|
|
6
11
|
|
|
7
12
|
export function verifyPricesTimestamp() {
|
|
8
|
-
return function(priceData: RawPriceData): boolean {
|
|
13
|
+
return function (priceData: RawPriceData): boolean {
|
|
9
14
|
const timestamp = Date.now() / 1000;
|
|
10
15
|
const pricesTime = priceData.timestamp;
|
|
11
16
|
|
|
12
|
-
//console.debug('timestamp - pricesTime, pricesTime', timestamp - pricesTime, pricesTime);
|
|
13
17
|
return timestamp - pricesTime < TTL_ORACLE_DATA_SEC;
|
|
14
|
-
}
|
|
18
|
+
};
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
export function verifyPricesSign(nfts: OracleNFT[]) {
|
|
18
|
-
return function(priceData: RawPriceData): boolean {
|
|
19
|
-
if (nfts.findIndex(x => x.pubkey.equals(priceData.pubkey)) == -1) {
|
|
20
|
-
//console.debug('[verifyPricesSign] nft not found');
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return verifyRawPriceDataSign(priceData)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* export function verifyPricesAssets(assets: PoolAssetsConfig) {
|
|
29
|
-
return function(priceData: RawPriceData): boolean {
|
|
30
|
-
for (const asset of assets) {
|
|
31
|
-
if(!priceData.dict.has(asset.assetId)) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
} */
|
|
38
|
-
|
|
39
21
|
export function getMedianPrice(pricesData: PriceData[], asset: bigint): bigint | null {
|
|
40
22
|
try {
|
|
41
|
-
const usingPrices = pricesData.filter(x => x.dict.has(asset));
|
|
42
|
-
const sorted = usingPrices.map(x => x.dict.get(asset)!).sort((a, b) => Number(a) - Number(b));
|
|
43
|
-
|
|
23
|
+
const usingPrices = pricesData.filter((x) => x.dict.has(asset));
|
|
24
|
+
const sorted = usingPrices.map((x) => x.dict.get(asset)!).sort((a, b) => Number(a) - Number(b));
|
|
25
|
+
|
|
44
26
|
if (sorted.length == 0) {
|
|
45
27
|
return null;
|
|
46
28
|
}
|
|
@@ -51,38 +33,33 @@ export function getMedianPrice(pricesData: PriceData[], asset: bigint): bigint |
|
|
|
51
33
|
} else {
|
|
52
34
|
return sorted[mid];
|
|
53
35
|
}
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
36
|
+
} catch {
|
|
56
37
|
return null;
|
|
57
38
|
}
|
|
58
39
|
}
|
|
59
40
|
|
|
60
|
-
export function packAssetsData(assetsData: {assetId: bigint
|
|
41
|
+
export function packAssetsData(assetsData: { assetId: bigint; medianPrice: bigint }[]): Cell {
|
|
61
42
|
if (assetsData.length == 0) {
|
|
62
|
-
throw new Error(
|
|
43
|
+
throw new Error('No assets data to pack');
|
|
63
44
|
}
|
|
64
45
|
return assetsData.reduceRight(
|
|
65
|
-
(acc: Cell | null, {assetId, medianPrice}) =>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.storeMaybeRef(acc)
|
|
69
|
-
.endCell(),
|
|
70
|
-
null
|
|
46
|
+
(acc: Cell | null, { assetId, medianPrice }) =>
|
|
47
|
+
beginCell().storeUint(assetId, 256).storeCoins(medianPrice).storeMaybeRef(acc).endCell(),
|
|
48
|
+
null,
|
|
71
49
|
)!;
|
|
72
50
|
}
|
|
73
51
|
|
|
74
52
|
export function packPrices(assetsDataCell: Cell, oraclesDataCell: Cell): Cell {
|
|
75
|
-
let pricesCell = beginCell()
|
|
76
|
-
.storeRef(assetsDataCell)
|
|
77
|
-
.storeRef(oraclesDataCell)
|
|
78
|
-
.endCell();
|
|
53
|
+
let pricesCell = beginCell().storeRef(assetsDataCell).storeRef(oraclesDataCell).endCell();
|
|
79
54
|
return pricesCell;
|
|
80
55
|
}
|
|
81
56
|
|
|
82
|
-
export function createOracleDataProof(
|
|
83
|
-
|
|
57
|
+
export function createOracleDataProof(
|
|
58
|
+
oracle: EvaaOracle,
|
|
59
|
+
data: OraclePricesData,
|
|
84
60
|
signature: Buffer,
|
|
85
|
-
assets: Array<bigint
|
|
61
|
+
assets: Array<bigint>,
|
|
62
|
+
): Slice {
|
|
86
63
|
let prunedDict = generateMerkleProofDirect(data.prices, assets, Dictionary.Keys.BigUint(256));
|
|
87
64
|
let prunedData = beginCell().storeUint(data.timestamp, 32).storeMaybeRef(prunedDict).endCell();
|
|
88
65
|
let merkleProof = convertToMerkleProof(prunedData);
|
|
@@ -90,15 +67,20 @@ export function createOracleDataProof(oracle: Oracle,
|
|
|
90
67
|
return oracleDataProof;
|
|
91
68
|
}
|
|
92
69
|
|
|
93
|
-
export function packOraclesData(
|
|
94
|
-
|
|
70
|
+
export function packOraclesData(
|
|
71
|
+
oraclesData: { oracle: EvaaOracle; data: OraclePricesData; signature: Buffer }[],
|
|
72
|
+
assets: Array<bigint>,
|
|
73
|
+
): Cell {
|
|
95
74
|
if (oraclesData.length == 0) {
|
|
96
|
-
throw new Error(
|
|
75
|
+
throw new Error('no oracles data to pack');
|
|
97
76
|
}
|
|
98
|
-
let proofs = oraclesData
|
|
99
|
-
(
|
|
100
|
-
|
|
101
|
-
return proofs.reduceRight(
|
|
77
|
+
let proofs = oraclesData
|
|
78
|
+
.sort((d1, d2) => d1.oracle.id - d2.oracle.id)
|
|
79
|
+
.map(({ oracle, data, signature }) => createOracleDataProof(oracle, data, signature, assets));
|
|
80
|
+
return proofs.reduceRight(
|
|
81
|
+
(acc: Cell | null, val) => beginCell().storeSlice(val).storeMaybeRef(acc).endCell(),
|
|
82
|
+
null,
|
|
83
|
+
)!;
|
|
102
84
|
}
|
|
103
85
|
|
|
104
86
|
export function sumDicts(result: Dictionary<bigint, bigint>, addendum: Dictionary<bigint, bigint>) {
|
|
@@ -115,27 +97,31 @@ export function sumDicts(result: Dictionary<bigint, bigint>, addendum: Dictionar
|
|
|
115
97
|
}
|
|
116
98
|
}
|
|
117
99
|
|
|
118
|
-
export function generatePriceSources(config: PriceSourcesConfig
|
|
119
|
-
let result: PriceSource[] = config.backendEndpoints.map(x => new BackendPriceSource(x, nfts));
|
|
100
|
+
export function generatePriceSources(config: PriceSourcesConfig, nfts: ExtendedEvaaOracle[]) {
|
|
101
|
+
let result: PriceSource[] = config.backendEndpoints.map((x) => new BackendPriceSource(x, nfts));
|
|
120
102
|
|
|
121
|
-
result.push(...config.icpEndpoints.map(x => new IcpPriceSource(x, nfts)));
|
|
103
|
+
result.push(...config.icpEndpoints.map((x) => new IcpPriceSource(x, nfts)));
|
|
122
104
|
|
|
123
105
|
return result;
|
|
124
106
|
}
|
|
125
107
|
|
|
126
|
-
export async function collectAndFilterPrices(
|
|
127
|
-
|
|
128
|
-
|
|
108
|
+
export async function collectAndFilterPrices(
|
|
109
|
+
priceSource: PriceSource,
|
|
110
|
+
minimalOracles: number,
|
|
111
|
+
fetchConfig?: FetchConfig,
|
|
112
|
+
): Promise<RawPriceData[]> {
|
|
113
|
+
const prices = await priceSource.getPrices(fetchConfig);
|
|
114
|
+
|
|
129
115
|
//console.debug('[FILTERING] before filtering prices len ', priceSource.sourceName, prices.length);
|
|
130
116
|
return (async () => {
|
|
131
|
-
|
|
132
|
-
price => verifyPricesTimestamp()(price) && verifyPricesSign(
|
|
117
|
+
const acceptedPrices: RawPriceData[] = prices.filter(
|
|
118
|
+
(price) => verifyPricesTimestamp()(price) && verifyPricesSign(priceSource.nfts)(price),
|
|
133
119
|
);
|
|
134
120
|
|
|
135
121
|
//console.debug('[FILTERING] after filtering prices len ', priceSource.sourceName, acceptedPrices.length);
|
|
136
122
|
|
|
137
|
-
if (acceptedPrices.length <
|
|
138
|
-
throw new Error(
|
|
123
|
+
if (acceptedPrices.length < minimalOracles) {
|
|
124
|
+
throw new Error('Prices are outdated');
|
|
139
125
|
}
|
|
140
126
|
|
|
141
127
|
return acceptedPrices;
|
|
@@ -157,8 +143,19 @@ export function unpackMedianPrices(pricesCell: Cell): Dictionary<bigint, bigint>
|
|
|
157
143
|
return res;
|
|
158
144
|
}
|
|
159
145
|
|
|
146
|
+
export function verifyPricesSign(nfts: ExtendedEvaaOracle[]) {
|
|
147
|
+
return function (priceData: RawPriceData): boolean {
|
|
148
|
+
if (nfts.findIndex((x) => x.pubkey.equals(priceData.pubkey as Uint8Array)) == -1) {
|
|
149
|
+
//console.debug('[verifyPricesSign] nft not found');
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return verifyRawPriceDataSign(priceData);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
160
157
|
export function verifyRawPriceDataSign(priceData: RawPriceData): boolean {
|
|
161
|
-
const message = priceData.dataCell.refs[0].hash()
|
|
158
|
+
const message = priceData.dataCell.refs[0].hash();
|
|
162
159
|
const signature = priceData.signature;
|
|
163
160
|
const publicKey = priceData.pubkey;
|
|
164
161
|
|
package/src/types/Master.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { Address, Cell, Dictionary } from '@ton/core'
|
|
1
|
+
import { Address, Cell, Dictionary } from '@ton/core';
|
|
2
|
+
import { Oracle } from '../prices/Oracle.interface';
|
|
3
|
+
export { FeedMapItem, parseFeedsMapDict } from '../api/feeds';
|
|
2
4
|
|
|
3
5
|
export type MasterConstants = {
|
|
4
|
-
FACTOR_SCALE: bigint
|
|
5
|
-
ASSET_COEFFICIENT_SCALE: bigint
|
|
6
|
-
ASSET_PRICE_SCALE: bigint
|
|
7
|
-
ASSET_RESERVE_FACTOR_SCALE: bigint
|
|
8
|
-
ASSET_LIQUIDATION_RESERVE_FACTOR_SCALE: bigint
|
|
9
|
-
ASSET_LIQUIDATION_THRESHOLD_SCALE: bigint
|
|
10
|
-
ASSET_LIQUIDATION_BONUS_SCALE: bigint
|
|
11
|
-
ASSET_ORIGINATION_FEE_SCALE: bigint
|
|
12
|
-
ASSET_SRATE_SCALE: bigint
|
|
13
|
-
ASSET_BRATE_SCALE: bigint
|
|
14
|
-
COLLATERAL_WORTH_THRESHOLD: bigint
|
|
6
|
+
FACTOR_SCALE: bigint;
|
|
7
|
+
ASSET_COEFFICIENT_SCALE: bigint;
|
|
8
|
+
ASSET_PRICE_SCALE: bigint;
|
|
9
|
+
ASSET_RESERVE_FACTOR_SCALE: bigint;
|
|
10
|
+
ASSET_LIQUIDATION_RESERVE_FACTOR_SCALE: bigint;
|
|
11
|
+
ASSET_LIQUIDATION_THRESHOLD_SCALE: bigint;
|
|
12
|
+
ASSET_LIQUIDATION_BONUS_SCALE: bigint;
|
|
13
|
+
ASSET_ORIGINATION_FEE_SCALE: bigint;
|
|
14
|
+
ASSET_SRATE_SCALE: bigint;
|
|
15
|
+
ASSET_BRATE_SCALE: bigint;
|
|
16
|
+
COLLATERAL_WORTH_THRESHOLD: bigint;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export type PoolAssetsConfig = PoolAssetConfig[];
|
|
@@ -21,16 +23,15 @@ export type PoolAssetConfig = {
|
|
|
21
23
|
assetId: bigint;
|
|
22
24
|
jettonMasterAddress: Address;
|
|
23
25
|
jettonWalletCode: Cell;
|
|
24
|
-
}
|
|
26
|
+
};
|
|
25
27
|
|
|
26
28
|
export type PoolConfig = {
|
|
27
29
|
masterAddress: Address;
|
|
28
30
|
masterVersion: number;
|
|
29
31
|
masterConstants: MasterConstants;
|
|
30
|
-
oracles: OracleNFT[];
|
|
31
|
-
minimalOracles: number;
|
|
32
32
|
poolAssetsConfig: PoolAssetsConfig;
|
|
33
33
|
lendingCode: Cell;
|
|
34
|
+
oracles: Oracle;
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export type UpgradeConfig = {
|
|
@@ -46,7 +47,7 @@ export type UpgradeConfig = {
|
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
export type AssetConfig = {
|
|
49
|
-
|
|
50
|
+
jwAddress: bigint;
|
|
50
51
|
decimals: bigint;
|
|
51
52
|
collateralFactor: bigint;
|
|
52
53
|
liquidationThreshold: bigint;
|
|
@@ -65,19 +66,10 @@ export type AssetConfig = {
|
|
|
65
66
|
minPrincipalForRewards: bigint;
|
|
66
67
|
baseTrackingSupplySpeed: bigint;
|
|
67
68
|
baseTrackingBorrowSpeed: bigint;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
admin: Address;
|
|
73
|
-
oraclesInfo: OraclesInfo
|
|
74
|
-
tokenKeys: Cell | null;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export type OraclesInfo = {
|
|
78
|
-
numOracles: number;
|
|
79
|
-
threshold: number;
|
|
80
|
-
oracles: Cell | null;
|
|
69
|
+
borrowCap: number | bigint;
|
|
70
|
+
heCategory: number;
|
|
71
|
+
heCollateralFactor: number;
|
|
72
|
+
heLiquidationThreshold: number;
|
|
81
73
|
};
|
|
82
74
|
|
|
83
75
|
export type AssetData = {
|
|
@@ -106,31 +98,16 @@ export type ExtendedAssetData = AssetData & AssetInterest & AssetApy;
|
|
|
106
98
|
export type ExtendedAssetsData = Dictionary<bigint, ExtendedAssetData>;
|
|
107
99
|
export type ExtendedAssetsConfig = Dictionary<bigint, AssetConfig>;
|
|
108
100
|
|
|
109
|
-
export type MasterData = {
|
|
110
|
-
meta: string;
|
|
111
|
-
upgradeConfig: UpgradeConfig;
|
|
112
|
-
masterConfig: MasterConfig;
|
|
113
|
-
assetsConfig: ExtendedAssetsConfig;
|
|
114
|
-
assetsData: ExtendedAssetsData;
|
|
115
|
-
assetsReserves: Dictionary<bigint, bigint>;
|
|
116
|
-
apy: {
|
|
117
|
-
supply: Dictionary<bigint, number>;
|
|
118
|
-
borrow: Dictionary<bigint, number>;
|
|
119
|
-
};
|
|
120
|
-
};
|
|
121
|
-
|
|
122
101
|
export type AgregatedBalances = {
|
|
123
102
|
totalBorrow: bigint;
|
|
124
103
|
totalSupply: bigint;
|
|
125
|
-
}
|
|
104
|
+
};
|
|
126
105
|
|
|
127
|
-
export type
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
pubkey: Buffer
|
|
131
|
-
}
|
|
106
|
+
export type ExtendedEvaaOracle = EvaaOracle & {
|
|
107
|
+
address: string;
|
|
108
|
+
};
|
|
132
109
|
|
|
133
|
-
export type
|
|
134
|
-
id: number
|
|
135
|
-
pubkey: Buffer
|
|
136
|
-
}
|
|
110
|
+
export type EvaaOracle = {
|
|
111
|
+
id: number;
|
|
112
|
+
pubkey: Buffer;
|
|
113
|
+
};
|
package/src/types/User.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { Address,
|
|
2
|
-
import {
|
|
1
|
+
import { Address, Cell, Dictionary } from '@ton/core';
|
|
2
|
+
import {
|
|
3
|
+
AssetConfig,
|
|
4
|
+
AssetData,
|
|
5
|
+
ExtendedAssetsConfig,
|
|
6
|
+
ExtendedAssetsData,
|
|
7
|
+
MasterConstants,
|
|
8
|
+
PoolAssetConfig,
|
|
9
|
+
PoolConfig,
|
|
10
|
+
} from './Master';
|
|
3
11
|
|
|
4
12
|
export enum BalanceType {
|
|
5
13
|
supply = 'supply',
|
|
@@ -38,7 +46,7 @@ export type UserLiteData = {
|
|
|
38
46
|
masterAddress: Address;
|
|
39
47
|
ownerAddress: Address;
|
|
40
48
|
principals: Dictionary<bigint, bigint>;
|
|
41
|
-
realPrincipals: Dictionary<bigint, bigint>;
|
|
49
|
+
realPrincipals: Dictionary<bigint, bigint>; // principals before applying dusts
|
|
42
50
|
state: number;
|
|
43
51
|
balances: Dictionary<bigint, UserBalance>;
|
|
44
52
|
trackingSupplyIndex: bigint;
|
|
@@ -82,18 +90,18 @@ export type HealthParamsArgs = {
|
|
|
82
90
|
principals: Dictionary<bigint, bigint>;
|
|
83
91
|
prices: Dictionary<bigint, bigint>;
|
|
84
92
|
poolConfig: PoolConfig;
|
|
85
|
-
}
|
|
93
|
+
};
|
|
86
94
|
|
|
87
95
|
export enum BalanceChangeType {
|
|
88
96
|
Borrow = 0,
|
|
89
97
|
Repay = 1,
|
|
90
98
|
Supply = 2,
|
|
91
|
-
Withdraw = 3
|
|
99
|
+
Withdraw = 3,
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
export type PredictHealthFactorArgs = {
|
|
95
103
|
balanceChangeType: BalanceChangeType;
|
|
96
|
-
amount: bigint;
|
|
104
|
+
amount: bigint; // always positive
|
|
97
105
|
asset: PoolAssetConfig;
|
|
98
106
|
principals: Dictionary<bigint, bigint>;
|
|
99
107
|
prices: Dictionary<bigint, bigint>;
|
|
@@ -104,7 +112,7 @@ export type PredictHealthFactorArgs = {
|
|
|
104
112
|
|
|
105
113
|
export type PredictAPYArgs = {
|
|
106
114
|
balanceChangeType: BalanceChangeType;
|
|
107
|
-
amount: bigint;
|
|
115
|
+
amount: bigint; // always positive
|
|
108
116
|
assetData: AssetData;
|
|
109
117
|
assetConfig: AssetConfig;
|
|
110
118
|
masterConstants: MasterConstants;
|
|
@@ -4,14 +4,6 @@ import { UNDEFINED_ASSET } from '../constants/assets';
|
|
|
4
4
|
|
|
5
5
|
function getUserJettonData(ownerAddress: Address, assetName: string, jettonWalletCode: Cell, jettonMasterAddress: Address) {
|
|
6
6
|
switch (assetName) {
|
|
7
|
-
case 'uTON':
|
|
8
|
-
return beginCell()
|
|
9
|
-
.storeCoins(0)
|
|
10
|
-
.storeUint(0, 64)
|
|
11
|
-
.storeAddress(ownerAddress)
|
|
12
|
-
.storeAddress(jettonMasterAddress)
|
|
13
|
-
.storeRef(jettonWalletCode)
|
|
14
|
-
.endCell();
|
|
15
7
|
case 'DOGS':
|
|
16
8
|
case 'NOT':
|
|
17
9
|
case 'USDT':
|
package/src/utils/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PoolAssetConfig } from "../types/Master";
|
|
2
1
|
import { ASSET_ID } from '../constants/assets';
|
|
2
|
+
import { PoolAssetConfig } from '../types/Master';
|
|
3
3
|
|
|
4
4
|
export function isTonAsset(asset: PoolAssetConfig) {
|
|
5
5
|
return asset.name === 'TON';
|
|
@@ -10,5 +10,44 @@ export function isTonAssetId(assetId: bigint) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function delay(ms: number) {
|
|
13
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FetchConfig {
|
|
17
|
+
retries: number;
|
|
18
|
+
timeout: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const DefaultFetchConfig: FetchConfig = {
|
|
22
|
+
retries: 3,
|
|
23
|
+
timeout: 1000,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function proxyFetchRetries<T>(fetch: Promise<T>, config: FetchConfig = DefaultFetchConfig) {
|
|
27
|
+
let lastError: Error | null = null;
|
|
28
|
+
for (let attempt = 0; attempt <= config.retries; attempt++) {
|
|
29
|
+
try {
|
|
30
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
31
|
+
setTimeout(() => reject(new Error('Request timeout')), config.timeout);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return await Promise.race([fetch, timeoutPromise]);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
37
|
+
|
|
38
|
+
if (attempt < config.retries) {
|
|
39
|
+
// Exponential backoff: wait 1s, 2s, 4s, etc.
|
|
40
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Failed to fetch after ${config.retries + 1} attempts. Last error: ${lastError instanceof Error ? lastError.message : JSON.stringify(lastError, null, 2)}`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isValidSubaccountId(subaccountId: number) {
|
|
52
|
+
return (subaccountId << 16) >> 16 === subaccountId && subaccountId !== -0x8000;
|
|
14
53
|
}
|