@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.
- package/LICENSE.md +7 -0
- package/README.md +2 -1
- package/dist/api/liquidation.js +1 -3
- package/dist/api/math.d.ts +10 -1
- package/dist/api/math.js +45 -6
- package/dist/api/parser.js +49 -27
- package/dist/api/prices.d.ts +5 -2
- package/dist/api/prices.js +35 -13
- package/dist/constants/assets.d.ts +8 -0
- package/dist/constants/assets.js +31 -1
- package/dist/constants/general.d.ts +5 -2
- package/dist/constants/general.js +12 -22
- package/dist/constants/pools.d.ts +1 -0
- package/dist/constants/pools.js +19 -3
- package/dist/contracts/MasterContract.d.ts +5 -0
- package/dist/contracts/MasterContract.js +6 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +10 -2
- package/dist/prices/Prices.d.ts +9 -0
- package/dist/prices/Prices.js +43 -0
- package/dist/prices/PricesCollector.d.ts +12 -0
- package/dist/prices/PricesCollector.js +123 -0
- package/dist/prices/Types.d.ts +33 -0
- package/dist/prices/Types.js +11 -0
- package/dist/prices/constants.d.ts +1 -0
- package/dist/prices/constants.js +4 -0
- package/dist/prices/index.d.ts +6 -0
- package/dist/prices/index.js +22 -0
- package/dist/prices/sources/Backend.d.ts +13 -0
- package/dist/prices/sources/Backend.js +52 -0
- package/dist/prices/sources/Icp.d.ts +10 -0
- package/dist/prices/sources/Icp.js +23 -0
- package/dist/prices/sources/Iota.d.ts +39 -0
- package/dist/prices/sources/Iota.js +49 -0
- package/dist/prices/sources/PriceSource.d.ts +14 -0
- package/dist/prices/sources/PriceSource.js +26 -0
- package/dist/prices/sources/index.d.ts +4 -0
- package/dist/prices/sources/index.js +20 -0
- package/dist/prices/utils.d.ts +23 -0
- package/dist/prices/utils.js +148 -0
- package/dist/types/Master.d.ts +2 -1
- package/dist/types/User.d.ts +11 -1
- package/dist/utils/userJettonWallet.js +42 -43
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +5 -1
- package/package.json +11 -9
- package/src/api/liquidation.ts +0 -1
- package/src/api/math.ts +66 -5
- package/src/api/parser.ts +56 -31
- package/src/api/prices.ts +20 -7
- package/src/constants/assets.ts +57 -0
- package/src/constants/general.ts +11 -23
- package/src/constants/pools.ts +21 -5
- package/src/contracts/MasterContract.ts +8 -1
- package/src/index.ts +9 -2
- package/src/prices/Prices.ts +32 -0
- package/src/prices/PricesCollector.ts +139 -0
- package/src/prices/Types.ts +44 -0
- package/src/prices/constants.ts +1 -0
- package/src/prices/index.ts +6 -0
- package/src/prices/sources/Backend.ts +62 -0
- package/src/prices/sources/Icp.ts +27 -0
- package/src/prices/sources/Iota.ts +90 -0
- package/src/prices/sources/PriceSource.ts +35 -0
- package/src/prices/sources/index.ts +4 -0
- package/src/prices/utils.ts +170 -0
- package/src/types/Master.ts +3 -2
- package/src/types/User.ts +13 -3
- package/src/utils/userJettonWallet.ts +43 -53
- package/src/utils/utils.ts +5 -1
- package/src/config.ts +0 -1
- package/src/types/Common.ts +0 -16
- package/src/utils/priceUtils.ts +0 -177
package/src/api/parser.ts
CHANGED
|
@@ -12,8 +12,7 @@ import {
|
|
|
12
12
|
} from './math';
|
|
13
13
|
import { loadMaybeMyRef, loadMyRef } from './helpers';
|
|
14
14
|
import { BalanceType, UserBalance, UserData, UserLiteData, UserRewards } from '../types/User';
|
|
15
|
-
import {
|
|
16
|
-
import { basename } from 'path';
|
|
15
|
+
import { checkNotInDebtAtAll } from "../api/math";
|
|
17
16
|
|
|
18
17
|
export function createUserRewards(): DictionaryValue<UserRewards> {
|
|
19
18
|
return {
|
|
@@ -34,29 +33,24 @@ export function createAssetData(): DictionaryValue<AssetData> {
|
|
|
34
33
|
serialize: (src: any, buidler: any) => {
|
|
35
34
|
buidler.storeUint(src.sRate, 64);
|
|
36
35
|
buidler.storeUint(src.bRate, 64);
|
|
37
|
-
buidler.
|
|
38
|
-
buidler.
|
|
36
|
+
buidler.storeInt(src.totalSupply, 64);
|
|
37
|
+
buidler.storeInt(src.totalBorrow, 64);
|
|
39
38
|
buidler.storeUint(src.lastAccural, 32);
|
|
40
39
|
buidler.storeUint(src.balance, 64);
|
|
41
40
|
buidler.storeUint(src.trackingSupplyIndex, 64);
|
|
42
41
|
buidler.storeUint(src.trackingBorrowIndex, 64);
|
|
43
|
-
|
|
44
|
-
buidler.storeUint(src.awaitedSupply, 64);
|
|
45
|
-
}
|
|
42
|
+
buidler.storeUint(src.awaitedSupply, 64);
|
|
46
43
|
},
|
|
47
44
|
parse: (src: Slice) => {
|
|
48
|
-
const sRate = BigInt(src.
|
|
49
|
-
const bRate = BigInt(src.
|
|
50
|
-
const totalSupply = BigInt(src.
|
|
51
|
-
const totalBorrow = BigInt(src.
|
|
52
|
-
const lastAccural = BigInt(src.
|
|
53
|
-
const balance = BigInt(src.
|
|
54
|
-
const trackingSupplyIndex = BigInt(src.
|
|
55
|
-
const trackingBorrowIndex = BigInt(src.
|
|
56
|
-
|
|
57
|
-
if (src.remainingBits == 64) {
|
|
58
|
-
awaitedSupply = BigInt(src.loadUint(64));
|
|
59
|
-
}
|
|
45
|
+
const sRate = BigInt(src.loadUintBig(64));
|
|
46
|
+
const bRate = BigInt(src.loadUintBig(64));
|
|
47
|
+
const totalSupply = BigInt(src.loadIntBig(64));
|
|
48
|
+
const totalBorrow = BigInt(src.loadIntBig(64));
|
|
49
|
+
const lastAccural = BigInt(src.loadUintBig(32));
|
|
50
|
+
const balance = BigInt(src.loadUintBig(64));
|
|
51
|
+
const trackingSupplyIndex = BigInt(src.loadUintBig(64));
|
|
52
|
+
const trackingBorrowIndex = BigInt(src.loadUintBig(64));
|
|
53
|
+
const awaitedSupply = BigInt(src.loadUintBig(64));
|
|
60
54
|
|
|
61
55
|
return { sRate, bRate, totalSupply, totalBorrow, lastAccural, balance, trackingSupplyIndex, trackingBorrowIndex, awaitedSupply};
|
|
62
56
|
},
|
|
@@ -205,7 +199,7 @@ export function parseUserLiteData(
|
|
|
205
199
|
assetsData: ExtendedAssetsData,
|
|
206
200
|
assetsConfig: ExtendedAssetsConfig,
|
|
207
201
|
poolConfig: PoolConfig,
|
|
208
|
-
applyDust: boolean =
|
|
202
|
+
applyDust: boolean = false
|
|
209
203
|
): UserLiteData {
|
|
210
204
|
const poolAssetsConfig = poolConfig.poolAssetsConfig;
|
|
211
205
|
const masterConstants = poolConfig.masterConstants;
|
|
@@ -215,7 +209,8 @@ export function parseUserLiteData(
|
|
|
215
209
|
const codeVersion = userSlice.loadCoins();
|
|
216
210
|
const masterAddress = userSlice.loadAddress();
|
|
217
211
|
const userAddress = userSlice.loadAddress();
|
|
218
|
-
const
|
|
212
|
+
const realPrincipals = userSlice.loadDict(Dictionary.Keys.BigUint(256), Dictionary.Values.BigInt(64));
|
|
213
|
+
const principalsDict = Dictionary.empty(Dictionary.Keys.BigUint(256), Dictionary.Values.BigInt(64));
|
|
219
214
|
const userState = userSlice.loadInt(64);
|
|
220
215
|
|
|
221
216
|
let trackingSupplyIndex = 0n;
|
|
@@ -244,7 +239,7 @@ export function parseUserLiteData(
|
|
|
244
239
|
const assetData = assetsData.get(asset.assetId) as ExtendedAssetData;
|
|
245
240
|
const assetConfig = assetsConfig.get(asset.assetId) as AssetConfig;
|
|
246
241
|
|
|
247
|
-
let principal =
|
|
242
|
+
let principal = realPrincipals.get(asset.assetId) || 0n;
|
|
248
243
|
let balance = presentValue(assetData.sRate, assetData.bRate, principal, masterConstants);
|
|
249
244
|
|
|
250
245
|
if (applyDust && (principal > 0 && (principal < assetConfig.dust))) {
|
|
@@ -254,6 +249,8 @@ export function parseUserLiteData(
|
|
|
254
249
|
type: BalanceType.supply,
|
|
255
250
|
};
|
|
256
251
|
principalsDict.set(asset.assetId, 0n);
|
|
252
|
+
} else {
|
|
253
|
+
principalsDict.set(asset.assetId, principal);
|
|
257
254
|
}
|
|
258
255
|
userBalances.set(asset.assetId, balance);
|
|
259
256
|
}
|
|
@@ -264,12 +261,14 @@ export function parseUserLiteData(
|
|
|
264
261
|
masterAddress: masterAddress,
|
|
265
262
|
ownerAddress: userAddress,
|
|
266
263
|
principals: principalsDict,
|
|
264
|
+
realPrincipals: realPrincipals,
|
|
267
265
|
state: userState,
|
|
268
266
|
balances: userBalances,
|
|
269
267
|
trackingSupplyIndex: trackingSupplyIndex,
|
|
270
268
|
trackingBorrowIndex: trackingBorrowIndex,
|
|
271
269
|
dutchAuctionStart: dutchAuctionStart,
|
|
272
270
|
backupCell: backupCell,
|
|
271
|
+
fullyParsed: false,
|
|
273
272
|
|
|
274
273
|
rewards: rewards,
|
|
275
274
|
backupCell1: backupCell1,
|
|
@@ -283,8 +282,11 @@ export function parseUserData(
|
|
|
283
282
|
assetsConfig: ExtendedAssetsConfig,
|
|
284
283
|
prices: Dictionary<bigint, bigint>,
|
|
285
284
|
poolConfig: PoolConfig,
|
|
286
|
-
applyDust: boolean =
|
|
285
|
+
applyDust: boolean = false
|
|
287
286
|
): UserData {
|
|
287
|
+
userLiteData.fullyParsed = true;
|
|
288
|
+
let havePrincipalWithoutPrice = false;
|
|
289
|
+
|
|
288
290
|
const poolAssetsConfig = poolConfig.poolAssetsConfig;
|
|
289
291
|
const masterConstants = poolConfig.masterConstants;
|
|
290
292
|
|
|
@@ -294,6 +296,16 @@ export function parseUserData(
|
|
|
294
296
|
let supplyBalance = 0n;
|
|
295
297
|
let borrowBalance = 0n;
|
|
296
298
|
|
|
299
|
+
for (const [assetId, principal] of userLiteData.realPrincipals) {
|
|
300
|
+
if (!prices.has(assetId)) {
|
|
301
|
+
userLiteData.fullyParsed = false;
|
|
302
|
+
|
|
303
|
+
if (principal != 0n) {
|
|
304
|
+
havePrincipalWithoutPrice = true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
297
309
|
for (const [_, asset] of Object.entries(poolAssetsConfig)) {
|
|
298
310
|
const assetData = assetsData.get(asset.assetId) as ExtendedAssetData;
|
|
299
311
|
const assetConfig = assetsConfig.get(asset.assetId) as AssetConfig;
|
|
@@ -310,6 +322,10 @@ export function parseUserData(
|
|
|
310
322
|
}
|
|
311
323
|
|
|
312
324
|
for (const [_, asset] of Object.entries(poolAssetsConfig)) {
|
|
325
|
+
if (!prices.has(asset.assetId)) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
313
329
|
const assetConfig = assetsConfig.get(asset.assetId) as AssetConfig;
|
|
314
330
|
const balance = userLiteData.balances.get(asset.assetId) as UserBalance;
|
|
315
331
|
|
|
@@ -321,19 +337,25 @@ export function parseUserData(
|
|
|
321
337
|
}
|
|
322
338
|
}
|
|
323
339
|
|
|
324
|
-
const availableToBorrow = getAvailableToBorrow(assetsConfig, assetsData, userLiteData.
|
|
340
|
+
const availableToBorrow = getAvailableToBorrow(assetsConfig, assetsData, userLiteData.realPrincipals, prices, masterConstants);
|
|
341
|
+
|
|
325
342
|
for (const [_, asset] of Object.entries(poolAssetsConfig)) {
|
|
343
|
+
const balance = userLiteData.balances.get(asset.assetId) as UserBalance;
|
|
326
344
|
const assetConfig = assetsConfig.get(asset.assetId) as AssetConfig;
|
|
327
345
|
const assetData = assetsData.get(asset.assetId) as ExtendedAssetData;
|
|
328
|
-
const balance = userLiteData.balances.get(asset.assetId) as UserBalance;
|
|
329
346
|
|
|
330
347
|
if (balance.type === BalanceType.supply) {
|
|
331
348
|
withdrawalLimits.set(
|
|
332
349
|
asset.assetId,
|
|
333
|
-
bigIntMin(calculateMaximumWithdrawAmount(assetsConfig, assetsData, userLiteData.
|
|
350
|
+
bigIntMin(calculateMaximumWithdrawAmount(assetsConfig, assetsData, userLiteData.realPrincipals, prices, masterConstants, asset.assetId), assetData.balance)
|
|
334
351
|
);
|
|
335
352
|
}
|
|
336
353
|
|
|
354
|
+
if (!prices.has(asset.assetId)) {
|
|
355
|
+
borrowLimits.set(asset.assetId, 0n);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
|
|
337
359
|
borrowLimits.set(
|
|
338
360
|
asset.assetId,
|
|
339
361
|
bigIntMax(0n, bigIntMin((availableToBorrow * 10n ** assetConfig.decimals) / prices.get(asset.assetId)!, assetData.balance, assetData.totalSupply - assetData.totalBorrow)),
|
|
@@ -346,12 +368,14 @@ export function parseUserData(
|
|
|
346
368
|
? 0
|
|
347
369
|
: Number(BigInt(1e9) - (availableToBorrow * BigInt(1e9)) / (borrowBalance + availableToBorrow)) / 1e7;
|
|
348
370
|
|
|
349
|
-
const liquidationData = calculateLiquidationData(assetsConfig, assetsData, userLiteData.principals, prices, poolConfig);
|
|
350
371
|
let healthFactor = 1;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
372
|
+
let liquidationData;
|
|
373
|
+
if (!havePrincipalWithoutPrice) {
|
|
374
|
+
liquidationData = calculateLiquidationData(assetsConfig, assetsData, userLiteData.realPrincipals, prices, poolConfig);
|
|
375
|
+
if (liquidationData.totalLimit != 0n) {
|
|
376
|
+
healthFactor = 1 - Number(liquidationData.totalDebt) / Number(liquidationData.totalLimit);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
355
379
|
return {
|
|
356
380
|
...userLiteData,
|
|
357
381
|
withdrawalLimits: withdrawalLimits,
|
|
@@ -363,5 +387,6 @@ export function parseUserData(
|
|
|
363
387
|
limitUsed: limitUsed,
|
|
364
388
|
liquidationData: liquidationData,
|
|
365
389
|
healthFactor: healthFactor,
|
|
390
|
+
havePrincipalWithoutPrice: havePrincipalWithoutPrice
|
|
366
391
|
};
|
|
367
392
|
}
|
package/src/api/prices.ts
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PriceData, RawPriceData } from '../types/Common';
|
|
3
|
-
import { getMedianPrice, loadPrices, packAssetsData, packOraclesData, packPrices, parsePrices, verifyPrices } from '../utils/priceUtils';
|
|
4
|
-
import { OracleNFT, PoolConfig } from '../types/Master';
|
|
1
|
+
import { PoolConfig } from '../types/Master';
|
|
5
2
|
import { MAINNET_POOL_CONFIG } from '../constants/pools';
|
|
3
|
+
import { DefaultPriceSourcesConfig, PriceData, PricesCollector, PriceSource, PriceSourcesConfig } from '../prices';
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated Use PriceCollector istead of getPrices
|
|
7
|
+
*/
|
|
8
|
+
export async function getPrices(endpoints: string[] = ["api.stardust-mainnet.iotaledger.net"], poolConfig: PoolConfig = MAINNET_POOL_CONFIG): Promise<PriceData> {
|
|
8
9
|
if (endpoints.length == 0) {
|
|
9
10
|
throw new Error("Empty endpoint list");
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
|
|
13
|
+
const sources: PriceSourcesConfig = {
|
|
14
|
+
iotaEndpoints: endpoints,
|
|
15
|
+
icpEndpoints: DefaultPriceSourcesConfig.icpEndpoints,
|
|
16
|
+
backendEndpoints: DefaultPriceSourcesConfig.backendEndpoints,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const priceCollector = new PricesCollector(poolConfig, sources);
|
|
20
|
+
const prices = await priceCollector.getPrices();
|
|
21
|
+
|
|
22
|
+
return { dict: prices.dict, dataCell: prices.dataCell };
|
|
23
|
+
/*
|
|
24
|
+
Old code
|
|
12
25
|
const prices = await Promise.all(poolConfig.oracles.map(async x => await parsePrices(await loadPrices(x.address, endpoints), x.id)));
|
|
13
26
|
|
|
14
27
|
let acceptedPrices: RawPriceData[] = prices.filter(verifyPrices(poolConfig.poolAssetsConfig));
|
|
@@ -41,5 +54,5 @@ export async function getPrices(endpoints: String[] = ["api.stardust-mainnet.iot
|
|
|
41
54
|
return {
|
|
42
55
|
dict: dict,
|
|
43
56
|
dataCell: packPrices(packedMedianData, packedOracleData)
|
|
44
|
-
}
|
|
57
|
+
};*/
|
|
45
58
|
}
|
package/src/constants/assets.ts
CHANGED
|
@@ -10,10 +10,18 @@ export const ASSET_ID = {
|
|
|
10
10
|
jUSDC: sha256Hash('jUSDC'),
|
|
11
11
|
stTON: sha256Hash('stTON'),
|
|
12
12
|
tsTON: sha256Hash('tsTON'),
|
|
13
|
+
uTON: sha256Hash('uTON'),
|
|
14
|
+
|
|
15
|
+
// LP
|
|
13
16
|
TONUSDT_DEDUST: sha256Hash('TONUSDT_DEDUST'),
|
|
14
17
|
TONUSDT_STONFI: sha256Hash('TONUSDT_STONFI'),
|
|
15
18
|
TON_STORM: sha256Hash('TON_STORM'),
|
|
16
19
|
USDT_STORM: sha256Hash('USDT_STORM'),
|
|
20
|
+
|
|
21
|
+
// ALTS
|
|
22
|
+
NOT: sha256Hash('NOT'),
|
|
23
|
+
DOGS: sha256Hash('DOGS'),
|
|
24
|
+
CATI: sha256Hash('CATI'),
|
|
17
25
|
};
|
|
18
26
|
|
|
19
27
|
export const UNDEFINED_ASSET: PoolAssetConfig = {
|
|
@@ -137,3 +145,52 @@ export const USDT_STORM_MAINNET: PoolAssetConfig = {
|
|
|
137
145
|
),
|
|
138
146
|
)[0],
|
|
139
147
|
}
|
|
148
|
+
|
|
149
|
+
export const CATI_MAINNET: PoolAssetConfig = {
|
|
150
|
+
name: 'CATI',
|
|
151
|
+
assetId: ASSET_ID.CATI,
|
|
152
|
+
jettonMasterAddress: Address.parse('EQD-cvR0Nz6XAyRBvbhz-abTrRC6sI5tvHvvpeQraV9UAAD7'),
|
|
153
|
+
jettonWalletCode: Cell.fromBoc(
|
|
154
|
+
Buffer.from(
|
|
155
|
+
'b5ee9c7241021101000323000114ff00f4a413f4bcf2c80b0102016202030202cc0405001ba0f605da89a1f401f481f481a8610201d40607020120080900c30831c02497c138007434c0c05c6c2544d7c0fc03383e903e900c7e800c5c75c87e800c7e800c1cea6d0000b4c7e08403e29fa954882ea54c4d167c0278208405e3514654882ea58c511100fc02b80d60841657c1ef2ea4d67c02f817c12103fcbc2000113e910c1c2ebcb853600201200a0b0083d40106b90f6a2687d007d207d206a1802698fc1080bc6a28ca9105d41083deecbef09dd0958f97162e99f98fd001809d02811e428027d012c678b00e78b6664f6aa401f1503d33ffa00fa4021f001ed44d0fa00fa40fa40d4305136a1522ac705f2e2c128c2fff2e2c254344270542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c920f9007074c8cb02ca07cbffc9d004fa40f40431fa0020d749c200f2e2c4778018c8cb055008cf1670fa0217cb6b13cc80c0201200d0e009e8210178d4519c8cb1f19cb3f5007fa0222cf165006cf1625fa025003cf16c95005cc2391729171e25008a813a08209c9c380a014bcf2e2c504c98040fb001023c85004fa0258cf1601cf16ccc9ed5402f73b51343e803e903e90350c0234cffe80145468017e903e9014d6f1c1551cdb5c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c0327e401c1d3232c0b281f2fff274140371c1472c7cb8b0c2be80146a2860822625a019ad822860822625a028062849e5c412440e0dd7c138c34975c2c0600f1000d73b51343e803e903e90350c01f4cffe803e900c145468549271c17cb8b049f0bffcb8b08160824c4b402805af3cb8b0e0841ef765f7b232c7c572cfd400fe8088b3c58073c5b25c60063232c14933c59c3e80b2dab33260103ec01004f214013e809633c58073c5b3327b552000705279a018a182107362d09cc8cb1f5230cb3f58fa025007cf165007cf16c9718010c8cb0524cf165006fa0215cb6a14ccc971fb0010241023007cc30023c200b08e218210d53276db708010c8cb055008cf165004fa0216cb6a12cb1f12cb3fc972fb0093356c21e203c85004fa0258cf1601cf16ccc9ed5495eaedd7',
|
|
156
|
+
'hex',
|
|
157
|
+
),
|
|
158
|
+
)[0],
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const DOGS_MAINNET: PoolAssetConfig = {
|
|
162
|
+
name: 'DOGS',
|
|
163
|
+
assetId: ASSET_ID.DOGS,
|
|
164
|
+
jettonMasterAddress: Address.parse('EQCvxJy4eG8hyHBFsZ7eePxrRsUQSFE_jpptRAYBmcG_DOGS'),
|
|
165
|
+
jettonWalletCode: Cell.fromBoc(
|
|
166
|
+
Buffer.from(
|
|
167
|
+
'b5ee9c7241010101002300084202ba2918c8947e9b25af9ac1b883357754173e5812f807a3d6e642a14709595395237ae3c3',
|
|
168
|
+
'hex',
|
|
169
|
+
),
|
|
170
|
+
)[0],
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const NOT_MAINNET: PoolAssetConfig = {
|
|
174
|
+
name: 'NOT',
|
|
175
|
+
assetId: ASSET_ID.NOT,
|
|
176
|
+
jettonMasterAddress: Address.parse('EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT'),
|
|
177
|
+
jettonWalletCode: Cell.fromBoc(
|
|
178
|
+
Buffer.from(
|
|
179
|
+
'b5ee9c7201010101002300084202ba2918c8947e9b25af9ac1b883357754173e5812f807a3d6e642a14709595395',
|
|
180
|
+
'hex',
|
|
181
|
+
),
|
|
182
|
+
)[0],
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export const UTON_MAINNET: PoolAssetConfig = {
|
|
186
|
+
name: 'uTON',
|
|
187
|
+
assetId: ASSET_ID.uTON,
|
|
188
|
+
jettonMasterAddress: Address.parse('EQAfF5j3JMIpZlLmACv7Ub7RH7WmiVMuV4ivcgNYHvNnqHTz'),
|
|
189
|
+
jettonWalletCode: Cell.fromBoc(
|
|
190
|
+
Buffer.from(
|
|
191
|
+
'b5ee9c7201021301000439000114ff00f4a413f4bcf2c80b0102016202030202cc0405020120111200bbd906380492f827000e8698180b8d84a89af81f807707d207d2018fd0018b8eb90fd0018fd001801698f90c10807c53f52dd4a989a2cf805f010c1080bc6a28cdd4b18a22201f8067000c1082caf83de5d4aa22201f806f02f82c207f9784020120060701f7f01e99ffd007d20381140816000fd23182c5d797a76a2687d00699ffd207d206a18027c30817c317c31fc327c32fc2091d0fc30fc21a8036382f97160fc20e17ff971617c227c22b82a300209aa0a82e42802fd0109e59f80e78b00e78b666490e4658089fa00097a00658064907c80383a6465816503e5ffe4e802c080201200a0b01fefa40f40431fa0020d749c200f2e2c4778018c8cb055009cf1670fa0218cb6b13cc8210178d4519c8cb1f15cb3f5003fa02f843cf1658cf1621fa025004cf16c901cc2291729171e25004a812a08208989680a08208989680a08208989680a0bcf2e2c5f841f842f843f844f845c85005fa0213cb3f01cf1601cf16ccc9ed5409000ac98040fb000201200c0d00b948020d721ed44d0fa00d33ffa40fa40d43004f86102f862f863f864f865d31f218210178d4519ba0282107bdd97deba12b1f2e2c5d33f31fa0030f84101a0f861f841f842f843f844f845c85005fa0213cb3f01cf1601cf16ccc9ed54801f53b51343e8034cffe903e90350c013e1840be18be18fe193e194134cffe803e1048a83e187e903e903e113e1149165c15180104d505417214017e8084f2cfc073c58073c5b332487232c044fd0004bd0032c0327e401c1d3232c0b281f2fff2740a31c17e11140271c1462c7cb8b0c1be80145a2860822625a019a00e01f73b51343e8034cffe903e90350c013e1840be18be18fe193e194134cffe803e903d010c1c0060083d03dbe87cb8b13434c7fe80204c0048b0803cbd350c3e10be10a93e18be1049a87e187e10d402b1c17cb8b07e1070bffcb8b0945e6860822625a019ad82284820822625a0281401e820822625a028086814a42f201001f2b608a18208989680a018a1278e355275a014a182107362d09cc8cb1f5230cb3f58fa025003cf165003cf16c9718018c8cb05f843cf165006fa0215cb6a14ccc971fb0094375b6c21e221d70b01c30023c200b08e208210d53276db708010c8cb055004cf165004fa0212cb6a12cb1fcb3fc972fb00925f03e20f0038f841f842f843f844f845c85005fa0213cb3f01cf1601cf16ccc9ed5400c0f2e2c5058208989680a018a1f841f842f843f844f845c85005fa0213cb3f01cf1601cf16ccc9ed5482107bdd97dec8cb1f14cb3ff843cf1616cb3f01fa0215cb1f5003cf1658fa02ccc9718018c8cb05f844cf165003fa0212cb6accc970fb000047bfd8176a2687d00699ffd207d206a18027c30817c317c31fc327c32fc20fc21fc227c22c004bbdd79f6a2687d00699ffd207d206a18027c30817c317c31fc327c32fc20fc217c21fc227c22c',
|
|
192
|
+
'hex',
|
|
193
|
+
),
|
|
194
|
+
)[0],
|
|
195
|
+
}
|
|
196
|
+
|
package/src/constants/general.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Address, Cell, toNano } from '@ton/core';
|
|
2
|
-
import { sha256Hash } from '../utils/sha256BigInt';
|
|
3
2
|
import { OracleNFT } from '../types/Master';
|
|
4
3
|
|
|
5
4
|
|
|
@@ -21,37 +20,26 @@ export const MASTER_CONSTANTS = {
|
|
|
21
20
|
|
|
22
21
|
export const NULL_ADDRESS = Address.parse('UQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJKZ');
|
|
23
22
|
|
|
24
|
-
|
|
25
23
|
export const EVAA_MASTER_MAINNET = Address.parse('EQC8rUZqR_pWV1BylWUlPNBzyiTYVoBEmQkMIQDZXICfnuRr');
|
|
26
24
|
export const MAINNET_VERSION = 6;
|
|
27
25
|
export const EVAA_MASTER_TESTNET = Address.parse('EQDLsg3w-iBj26Gww7neYoJAxiT2t77Zo8ro56b0yuHsPp3C');
|
|
28
|
-
export const TESTNET_VERSION =
|
|
26
|
+
export const TESTNET_VERSION = 1;
|
|
29
27
|
export const EVAA_LP_MAINNET = Address.parse('EQBIlZX2URWkXCSg3QF2MJZU-wC5XkBoLww-hdWk2G37Jc6N');
|
|
30
|
-
export const EVAA_LP_MAINNET_VERSION =
|
|
28
|
+
export const EVAA_LP_MAINNET_VERSION = 3;
|
|
29
|
+
export const EVAA_ALTS_MAINNET = Address.parse('EQANURVS3fhBO9bivig34iyJQi97FhMbpivo1aUEAS2GYSu-');
|
|
30
|
+
export const EVAA_ALTS_MAINNET_VERSION = 0;
|
|
31
31
|
|
|
32
32
|
export const ORACLES_MAINNET: OracleNFT[] = [
|
|
33
|
-
{id: 0, address: '0xd3a8c0b9fd44fd25a49289c631e3ac45689281f2f8cf0744400b4c65bed38e5d'},
|
|
34
|
-
{id: 1, address: '0x2c21cabdaa89739de16bde7bc44e86401fac334a3c7e55305fe5e7563043e191'},
|
|
35
|
-
{id: 2, address: '0x2eb258ce7b5d02466ab8a178ad8b0ba6ffa7b58ef21de3dc3b6dd359a1e16af0'},
|
|
36
|
-
{id: 3, address: '0xf9a0769954b4430bca95149fb3d876deb7799d8f74852e0ad4ccc5778ce68b52'},
|
|
33
|
+
{id: 0, address: '0xd3a8c0b9fd44fd25a49289c631e3ac45689281f2f8cf0744400b4c65bed38e5d', pubkey: Buffer.from('b404f4a2ebb62f2623b370c89189748a0276c071965b1646b996407f10d72eb9', 'hex') },
|
|
34
|
+
{id: 1, address: '0x2c21cabdaa89739de16bde7bc44e86401fac334a3c7e55305fe5e7563043e191', pubkey: Buffer.from('9ad115087520d91b6b45d6a8521eb4616ee6914af07fabdc2e9d1826dbb17078', 'hex') },
|
|
35
|
+
{id: 2, address: '0x2eb258ce7b5d02466ab8a178ad8b0ba6ffa7b58ef21de3dc3b6dd359a1e16af0', pubkey: Buffer.from('e503e02e8a9226b34e7c9deb463cbf7f19bce589362eb448a69a8ee7b2fca631', 'hex') },
|
|
36
|
+
{id: 3, address: '0xf9a0769954b4430bca95149fb3d876deb7799d8f74852e0ad4ccc5778ce68b52', pubkey: Buffer.from('9cbf8374cf1f2cf17110134871d580198416e101683f4a61f54cf2a3e4e32070', 'hex') },
|
|
37
37
|
];
|
|
38
38
|
|
|
39
|
-
export const ORACLES_TESTNET: OracleNFT[] =
|
|
40
|
-
{id: 0, address: '0x3bb147a37b7a7f874c39320440f352bddd2c9337e31a778731910f0266391650'},
|
|
41
|
-
{id: 1, address: '0x676767e93b05a21aec9023a65f73cffe1c725709c3c964a7c3f0fd4229089bfe'},
|
|
42
|
-
{id: 2, address: '0x9c9e65951b0c5920c286bdb3410babcaf21f85bc9c90c13172988630f1244e0f'},
|
|
43
|
-
{id: 3, address: '0x9dcf880229bfb68d7344fd294624b64f1e0b43b9d858f0fdb1bc6434616c08f5'},
|
|
44
|
-
{id: 4, address: '0x4d1afcf7c0426ca61c405c8cfaef0053a0f0d143740ffed04c8716beb99cd614'},
|
|
45
|
-
{id: 5, address: '0x11c6baa608ed10733051fd74134441d384e471722fbc496b43ea4e3c6652485f'},
|
|
46
|
-
{id: 6, address: '0x2b685672f38dc2fce59013bb740bf24c6037049a1c267bb3b5f6f55d5b195f5f'},
|
|
47
|
-
];
|
|
39
|
+
export const ORACLES_TESTNET: OracleNFT[] = ORACLES_MAINNET;
|
|
48
40
|
|
|
49
|
-
export const ORACLES_LP: OracleNFT[] =
|
|
50
|
-
|
|
51
|
-
{id: 1, address: '0x2c21cabdaa89739de16bde7bc44e86401fac334a3c7e55305fe5e7563043e191'},
|
|
52
|
-
{id: 2, address: '0x2eb258ce7b5d02466ab8a178ad8b0ba6ffa7b58ef21de3dc3b6dd359a1e16af0'},
|
|
53
|
-
{id: 3, address: '0xf9a0769954b4430bca95149fb3d876deb7799d8f74852e0ad4ccc5778ce68b52'},
|
|
54
|
-
];
|
|
41
|
+
export const ORACLES_LP: OracleNFT[] = ORACLES_MAINNET;
|
|
42
|
+
export const ORACLES_ALTS: OracleNFT[] = ORACLES_MAINNET;
|
|
55
43
|
|
|
56
44
|
export const LENDING_CODE = Cell.fromBoc(
|
|
57
45
|
Buffer.from(
|
package/src/constants/pools.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { JUSDC_MAINNET, JUSDC_TESTNET, JUSDT_MAINNET, JUSDT_TESTNET, STTON_MAINNET, STTON_TESTNET, TON_MAINNET, TON_STORM_MAINNET, TONUSDT_DEDUST_MAINNET, TSTON_MAINNET, USDT_MAINNET, USDT_STORM_MAINNET } from "./assets";
|
|
1
|
+
import { CATI_MAINNET, DOGS_MAINNET, JUSDC_MAINNET, JUSDC_TESTNET, JUSDT_MAINNET, JUSDT_TESTNET, NOT_MAINNET, STTON_MAINNET, STTON_TESTNET, TON_MAINNET, TON_STORM_MAINNET, TONUSDT_DEDUST_MAINNET, TSTON_MAINNET, USDT_MAINNET, USDT_STORM_MAINNET, UTON_MAINNET } from "./assets";
|
|
3
2
|
import { PoolConfig } from "../types/Master";
|
|
4
|
-
import { EVAA_MASTER_MAINNET, EVAA_MASTER_TESTNET, LENDING_CODE, MAINNET_VERSION, MASTER_CONSTANTS, TESTNET_VERSION, EVAA_LP_MAINNET, EVAA_LP_MAINNET_VERSION, ORACLES_MAINNET, ORACLES_LP, ORACLES_TESTNET } from "./general";
|
|
3
|
+
import { EVAA_MASTER_MAINNET, EVAA_MASTER_TESTNET, LENDING_CODE, MAINNET_VERSION, MASTER_CONSTANTS, TESTNET_VERSION, EVAA_LP_MAINNET, EVAA_LP_MAINNET_VERSION, ORACLES_MAINNET, ORACLES_LP, ORACLES_TESTNET, EVAA_ALTS_MAINNET, EVAA_ALTS_MAINNET_VERSION, ORACLES_ALTS } from "./general";
|
|
5
4
|
|
|
6
5
|
export const MAINNET_POOL_CONFIG: PoolConfig = {
|
|
7
6
|
masterAddress: EVAA_MASTER_MAINNET,
|
|
@@ -15,7 +14,8 @@ export const MAINNET_POOL_CONFIG: PoolConfig = {
|
|
|
15
14
|
JUSDC_MAINNET,
|
|
16
15
|
STTON_MAINNET,
|
|
17
16
|
TSTON_MAINNET,
|
|
18
|
-
USDT_MAINNET
|
|
17
|
+
USDT_MAINNET,
|
|
18
|
+
// UTON_MAINNET // announce
|
|
19
19
|
],
|
|
20
20
|
lendingCode: LENDING_CODE
|
|
21
21
|
};
|
|
@@ -25,7 +25,7 @@ export const TESTNET_POOL_CONFIG: PoolConfig = {
|
|
|
25
25
|
masterVersion: TESTNET_VERSION,
|
|
26
26
|
masterConstants: MASTER_CONSTANTS,
|
|
27
27
|
oracles: ORACLES_TESTNET,
|
|
28
|
-
minimalOracles:
|
|
28
|
+
minimalOracles: 3,
|
|
29
29
|
poolAssetsConfig: [
|
|
30
30
|
TON_MAINNET,
|
|
31
31
|
JUSDT_TESTNET,
|
|
@@ -50,3 +50,19 @@ export const MAINNET_LP_POOL_CONFIG: PoolConfig = {
|
|
|
50
50
|
],
|
|
51
51
|
lendingCode: LENDING_CODE
|
|
52
52
|
};
|
|
53
|
+
|
|
54
|
+
export const MAINNET_ALTS_POOL_CONFIG: PoolConfig = {
|
|
55
|
+
masterAddress: EVAA_ALTS_MAINNET,
|
|
56
|
+
masterVersion: EVAA_ALTS_MAINNET_VERSION,
|
|
57
|
+
masterConstants: MASTER_CONSTANTS,
|
|
58
|
+
oracles: ORACLES_ALTS,
|
|
59
|
+
minimalOracles: 3,
|
|
60
|
+
poolAssetsConfig: [
|
|
61
|
+
TON_MAINNET,
|
|
62
|
+
USDT_MAINNET,
|
|
63
|
+
CATI_MAINNET,
|
|
64
|
+
NOT_MAINNET,
|
|
65
|
+
DOGS_MAINNET
|
|
66
|
+
],
|
|
67
|
+
lendingCode: LENDING_CODE
|
|
68
|
+
};
|
|
@@ -20,7 +20,7 @@ import { parseMasterData } from '../api/parser';
|
|
|
20
20
|
import { MasterData, PoolAssetConfig, PoolConfig} from '../types/Master';
|
|
21
21
|
import { JettonWallet } from './JettonWallet';
|
|
22
22
|
import { getUserJettonWallet } from '../utils/userJettonWallet';
|
|
23
|
-
import { getPrices, isTonAsset, isTonAssetId, MAINNET_POOL_CONFIG } from '..';
|
|
23
|
+
import { DefaultPriceSourcesConfig, getPrices, isTonAsset, isTonAssetId, MAINNET_POOL_CONFIG, PricesCollector, PriceSourcesConfig } from '..';
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Parameters for the Evaa contract
|
|
@@ -393,6 +393,9 @@ export class Evaa implements Contract {
|
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
+
/**
|
|
397
|
+
* @deprecated Use PriceCollector (createPriceCollector) istead of getPrices
|
|
398
|
+
*/
|
|
396
399
|
async getPrices(provider: ContractProvider, endpoints?: string[]) {
|
|
397
400
|
if ((endpoints?.length ?? 0) > 0) {
|
|
398
401
|
return await getPrices(endpoints, this._poolConfig);
|
|
@@ -400,4 +403,8 @@ export class Evaa implements Contract {
|
|
|
400
403
|
return await getPrices(undefined, this._poolConfig);
|
|
401
404
|
}
|
|
402
405
|
}
|
|
406
|
+
|
|
407
|
+
createPriceCollector(priceSourcesConfig: PriceSourcesConfig = DefaultPriceSourcesConfig) : PricesCollector {
|
|
408
|
+
return new PricesCollector(this._poolConfig, priceSourcesConfig);
|
|
409
|
+
}
|
|
403
410
|
}
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,8 @@ export {
|
|
|
14
14
|
calculateLiquidationData,
|
|
15
15
|
predictHealthFactor,
|
|
16
16
|
calculateHealthParams,
|
|
17
|
+
calculateInterestWithSupplyBorrow,
|
|
18
|
+
predictAPY,
|
|
17
19
|
BigMath,
|
|
18
20
|
} from './api/math';
|
|
19
21
|
|
|
@@ -56,7 +58,6 @@ export {
|
|
|
56
58
|
export { EvaaUser } from './contracts/UserContract';
|
|
57
59
|
|
|
58
60
|
// Types
|
|
59
|
-
export { PriceData } from './types/Common';
|
|
60
61
|
export {
|
|
61
62
|
UpgradeConfig,
|
|
62
63
|
AssetConfig,
|
|
@@ -102,7 +103,8 @@ export {
|
|
|
102
103
|
export {
|
|
103
104
|
MAINNET_POOL_CONFIG,
|
|
104
105
|
TESTNET_POOL_CONFIG,
|
|
105
|
-
MAINNET_LP_POOL_CONFIG
|
|
106
|
+
MAINNET_LP_POOL_CONFIG,
|
|
107
|
+
MAINNET_ALTS_POOL_CONFIG
|
|
106
108
|
} from './constants/pools';
|
|
107
109
|
|
|
108
110
|
export {
|
|
@@ -113,6 +115,10 @@ export {
|
|
|
113
115
|
TONUSDT_DEDUST_MAINNET,
|
|
114
116
|
TON_STORM_MAINNET,
|
|
115
117
|
USDT_STORM_MAINNET,
|
|
118
|
+
DOGS_MAINNET,
|
|
119
|
+
CATI_MAINNET,
|
|
120
|
+
UTON_MAINNET,
|
|
121
|
+
NOT_MAINNET,
|
|
116
122
|
JUSDT_MAINNET,
|
|
117
123
|
JUSDC_MAINNET,
|
|
118
124
|
STTON_MAINNET,
|
|
@@ -124,6 +130,7 @@ export {
|
|
|
124
130
|
|
|
125
131
|
export * from './constants/assets';
|
|
126
132
|
export * from './utils/utils';
|
|
133
|
+
export * from './prices';
|
|
127
134
|
|
|
128
135
|
// Utils
|
|
129
136
|
export { getLastSentBoc, getTonConnectSender } from './utils/tonConnectSender';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Cell, Dictionary } from "@ton/core";
|
|
2
|
+
import { PoolAssetConfig } from "../types/Master";
|
|
3
|
+
|
|
4
|
+
export class Prices {
|
|
5
|
+
#dict: Dictionary<bigint, bigint>;
|
|
6
|
+
#dataCell: Cell;
|
|
7
|
+
constructor(dict: Dictionary<bigint, bigint>, dataCell: Cell) {
|
|
8
|
+
this.#dict = dict;
|
|
9
|
+
this.#dataCell = dataCell;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get dict() {
|
|
13
|
+
const dict = Dictionary.empty<bigint, bigint>();
|
|
14
|
+
for (const [key, value] of this.#dict) {
|
|
15
|
+
dict.set(key, value);
|
|
16
|
+
}
|
|
17
|
+
return dict;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get dataCell() {
|
|
21
|
+
return new Cell(this.#dataCell);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getAssetPrice<T extends bigint | PoolAssetConfig>(asset: T): bigint | undefined {
|
|
25
|
+
const assetId = this.#extractAssetId(asset);
|
|
26
|
+
return this.#dict.get(assetId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#extractAssetId(asset: bigint | PoolAssetConfig): bigint {
|
|
30
|
+
return typeof asset === 'bigint' ? asset : asset.assetId;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Cell, Dictionary } from "@ton/core";
|
|
2
|
+
import { MAINNET_POOL_CONFIG } from "../constants/pools";
|
|
3
|
+
import { PoolAssetConfig, PoolAssetsConfig, PoolConfig } from "../types/Master";
|
|
4
|
+
import { PriceSource } from "./sources";
|
|
5
|
+
import { DefaultPriceSourcesConfig, PriceSourcesConfig, RawPriceData } from "./Types";
|
|
6
|
+
import { collectAndFilterPrices, generatePriceSources, getMedianPrice, packAssetsData, packOraclesData, packPrices, verifyPricesSign, verifyPricesTimestamp } from "./utils";
|
|
7
|
+
import { delay } from "../utils/utils";
|
|
8
|
+
import { Prices } from "./Prices";
|
|
9
|
+
import { checkNotInDebtAtAll } from "../api/math";
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export class PricesCollector {
|
|
13
|
+
#prices: RawPriceData[];
|
|
14
|
+
#poolConfig: PoolConfig;
|
|
15
|
+
#sourcesConfig: PriceSourcesConfig;
|
|
16
|
+
#priceSources: PriceSource[];
|
|
17
|
+
|
|
18
|
+
constructor(poolConfig: PoolConfig = MAINNET_POOL_CONFIG, sourcesConfig: PriceSourcesConfig = DefaultPriceSourcesConfig, additionalPriceSources?: PriceSource[]) {
|
|
19
|
+
this.#poolConfig = poolConfig;
|
|
20
|
+
this.#sourcesConfig = sourcesConfig;
|
|
21
|
+
this.#priceSources = generatePriceSources(this.#sourcesConfig, this.#poolConfig.oracles);
|
|
22
|
+
|
|
23
|
+
if (additionalPriceSources) {
|
|
24
|
+
this.#priceSources.push(...additionalPriceSources);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.#prices = [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// TODO Make UserData class and incapsulate raw bigintegers
|
|
31
|
+
|
|
32
|
+
async getPricesForLiquidate(realPrincipals: Dictionary<bigint, bigint>, retries: number = 1, timeout: number = 3000): Promise<Prices> {
|
|
33
|
+
const assets = this.#filterEmptyPrincipalsAndAssets(realPrincipals);
|
|
34
|
+
if (assets.includes(undefined)) {
|
|
35
|
+
throw new Error("User from another pool");
|
|
36
|
+
}
|
|
37
|
+
return await this.getPrices(assets.map(x => x!), retries, timeout);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
async getPricesForWithdraw(realPrincipals: Dictionary<bigint, bigint>, withdrawAsset: PoolAssetConfig, collateralToDebt = false, retries: number = 1, timeout: number = 3000): Promise<Prices> {
|
|
42
|
+
let assets = this.#filterEmptyPrincipalsAndAssets(realPrincipals);
|
|
43
|
+
if (checkNotInDebtAtAll(realPrincipals) && (realPrincipals.get(withdrawAsset.assetId) ?? 0n) > 0n && !collateralToDebt) {
|
|
44
|
+
return new Prices(Dictionary.empty<bigint, bigint>(), Cell.EMPTY);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (assets.includes(undefined)) {
|
|
48
|
+
throw new Error("User from another pool");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!assets.includes(withdrawAsset)) {
|
|
52
|
+
assets.push(withdrawAsset);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (collateralToDebt && assets.length == 1) {
|
|
56
|
+
throw new Error("Cannot debt only one supplied asset");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return await this.getPrices(assets.map(x => x!), retries, timeout);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async getPrices(assets: PoolAssetsConfig = this.#poolConfig.poolAssetsConfig, retries: number = 1, timeout: number = 3000): Promise<Prices> {
|
|
63
|
+
console.debug('[getPrices] Assets length', assets.length);
|
|
64
|
+
|
|
65
|
+
if (assets.length == 0) {
|
|
66
|
+
return new Prices(Dictionary.empty<bigint, bigint>(), Cell.EMPTY);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i <= retries; i++) { // attemts = retries + 1
|
|
70
|
+
if (!this.#prices || this.#filterPrices() < this.#poolConfig.minimalOracles) {
|
|
71
|
+
//console.debug('[getPrices] Load prices attemp', i + 1)
|
|
72
|
+
if (i > 0) {
|
|
73
|
+
await delay(timeout);
|
|
74
|
+
}
|
|
75
|
+
await this.#collectPrices();
|
|
76
|
+
} else {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (this.#prices.length < this.#poolConfig.minimalOracles) {
|
|
82
|
+
throw new Error(`Error per updating prices, valid ${this.#prices.length} of ${this.#poolConfig.minimalOracles}`); // if still not enough data after retries
|
|
83
|
+
}
|
|
84
|
+
const prices = this.#getPricesByAssetList(assets);
|
|
85
|
+
return new Prices(prices.dict, prices.dataCell);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#getPricesByAssetList(assets: PoolAssetsConfig) {
|
|
89
|
+
//console.debug('[getPricesByAssetList] start')
|
|
90
|
+
let pricesFiltered = this.#prices; // for strict check this.#prices.filter(x => assets.every(asset => x.dict.has(asset.assetId)));
|
|
91
|
+
|
|
92
|
+
if (pricesFiltered.length < this.#poolConfig.minimalOracles) {
|
|
93
|
+
throw new Error("Not enough price data");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (pricesFiltered.length > this.#poolConfig.minimalOracles) {
|
|
97
|
+
const sortedByTimestamp = pricesFiltered.slice().sort((a, b) => b.timestamp - a.timestamp);
|
|
98
|
+
const newerPrices = sortedByTimestamp.slice(0, this.#poolConfig.minimalOracles);
|
|
99
|
+
pricesFiltered = newerPrices.sort((a, b) => a.oracleId - b.oracleId);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const medianData = assets.map(asset => ({ assetId: asset.assetId, medianPrice: getMedianPrice(this.#prices, asset.assetId)}));
|
|
103
|
+
|
|
104
|
+
const nonEmptymedianData = medianData.filter(x => x.medianPrice != null) as { assetId: bigint, medianPrice: bigint }[];
|
|
105
|
+
|
|
106
|
+
const packedMedianData = packAssetsData(nonEmptymedianData);
|
|
107
|
+
|
|
108
|
+
const oraclesData = this.#prices.map(x => ({oracle: {id: x.oracleId, pubkey: x.pubkey}, data: {timestamp: x.timestamp, prices: x.dict}, signature: x.signature}));
|
|
109
|
+
const packedOracleData = packOraclesData(oraclesData, nonEmptymedianData.map(x => x.assetId));
|
|
110
|
+
|
|
111
|
+
const dict = Dictionary.empty<bigint, bigint>();
|
|
112
|
+
for (const medianDataAsset of nonEmptymedianData) {
|
|
113
|
+
dict.set(medianDataAsset.assetId, medianDataAsset.medianPrice);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
dict: dict,
|
|
118
|
+
dataCell: packPrices(packedMedianData, packedOracleData)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async #collectPrices(): Promise<boolean> {
|
|
123
|
+
try {
|
|
124
|
+
this.#prices = await Promise.any(this.#priceSources.map(x => collectAndFilterPrices(x, this.#poolConfig)));
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
catch { }
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#filterPrices(): number { // filter again for expire check
|
|
132
|
+
this.#prices = this.#prices.filter(verifyPricesTimestamp());
|
|
133
|
+
return this.#prices.length;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
#filterEmptyPrincipalsAndAssets(principals: Dictionary<bigint, bigint>) {
|
|
137
|
+
return principals.keys().filter(x => principals.get(x)! != 0n).map(x => this.#poolConfig.poolAssetsConfig.find(asset => asset.assetId == x));
|
|
138
|
+
}
|
|
139
|
+
}
|