diff --git a/src/oracles/utils.ts b/src/oracles/utils.ts index ad263944..bf8f1f4a 100644 --- a/src/oracles/utils.ts +++ b/src/oracles/utils.ts @@ -10,16 +10,6 @@ import { IcpPriceSource } from './sources/Icp'; import { PriceSource } from './sources/PriceSource'; import { OraclePricesData, PriceSourcesConfig, RawPriceData } from './Types'; -export const UPDATE_PRICE_FEEDS_BASE_GAS = 300000n; -export const UPDATE_PRICE_FEEDS_PER_UPDATE_GAS = 90000n; -// Current settings in basechain are as follows: 1 unit of gas costs 400 nanotons -export const GAS_PRICE_FACTOR = 400n; - -// TODO: use PythContract for dynamic fee calc -export function calcPythUpdateFee(numUpdates: number) { - return (UPDATE_PRICE_FEEDS_BASE_GAS + UPDATE_PRICE_FEEDS_PER_UPDATE_GAS * BigInt(numUpdates)) * GAS_PRICE_FACTOR; -} - export function verifyPricesTimestamp() { return function (priceData: RawPriceData): boolean { const timestamp = Date.now() / 1000; @@ -65,6 +55,13 @@ export function packPrices(assetsDataCell: Cell, oraclesDataCell: Cell): Cell { return pricesCell; } +export function unpackPrices(pricesCell: Cell): { assetsDataCell: Cell; oraclesDataCell: Cell } { + let slice = pricesCell.beginParse(); + let assetsDataCell = slice.loadRef(); + let oraclesDataCell = slice.loadRef(); + return { assetsDataCell, oraclesDataCell }; +} + export function createOracleDataProof( oracle: EvaaOracle, data: OraclePricesData, @@ -94,6 +91,26 @@ export function packOraclesData( )!; } +export function unpackOraclesData( + oraclesDataCell: Cell, +): { oracleId: number; merkleProof: Cell; signature: Buffer }[] | undefined { + if (Cell.EMPTY.hash() == oraclesDataCell.hash()) return []; + + const result: { oracleId: number; merkleProof: Cell; signature: Buffer }[] = []; + let oracleCell: Cell | null = oraclesDataCell; + + while (oracleCell != Cell.EMPTY && oracleCell !== null) { + const slice = oracleCell.beginParse(); + const oracleId = slice.loadUint(32); + const merkleProof = slice.loadRef(); + const signature = slice.loadBuffer(64); + result.push({ oracleId, merkleProof, signature }); + oracleCell = slice.loadMaybeRef(); + } + + return result; +} + export function sumDicts(result: Dictionary, addendum: Dictionary) { for (const key of addendum.keys()) { const current = result.get(key)!; diff --git a/tests/prices/PriceCollector.test.ts b/tests/prices/PriceCollector.test.ts index c2620045..eab222cf 100644 --- a/tests/prices/PriceCollector.test.ts +++ b/tests/prices/PriceCollector.test.ts @@ -7,18 +7,20 @@ import { ClassicPricesOffset, DefaultPriceSourcesConfig, generatePriceSources, - MAINNET_POOL_ASSETS_CONFIG, + MAINNET_LP_POOL_ASSETS_CONFIG, PriceSourcesConfig, RawPriceData, STTON_MAINNET, TON_MAINNET, + unpackOraclesData, + unpackPrices, USDT_MAINNET, } from '../../src'; import { ORACLES_MAINNET } from '../../src/constants/general'; import { DefaultFetchConfig } from '../../src/utils/utils'; const PRICE_COLLTECTOR_CONFIG = { - poolAssetsConfig: MAINNET_POOL_ASSETS_CONFIG, + poolAssetsConfig: MAINNET_LP_POOL_ASSETS_CONFIG, minimalOracles: 3, evaaOracles: ORACLES_MAINNET, }; @@ -190,4 +192,95 @@ describe('PriceCollector tests', () => { USDT_MAINNET.assetId - ClassicPricesOffset[ClassicPricesMode.SPOT], ]); }); + + test('test oracles prune getPricesForWithdraw, collateralToDebt true', async () => { + expect.assertions(3); + + const pc = new ClassicCollector(PRICE_COLLTECTOR_CONFIG); + + const principals = Dictionary.empty(); + principals.set(TON_MAINNET.assetId, 5n); + principals.set(USDT_MAINNET.assetId, -5n); + + const prices = await pc.getPricesForWithdraw(principals, USDT_MAINNET, true, DefaultFetchConfig); + const { assetsDataCell, oraclesDataCell } = unpackPrices(prices.dataCell); + + expect(prices.dict.values().length).toEqual(2); + expect(prices.dataCell.hash()).not.toEqual(Cell.EMPTY.hash()); + expect(unpackOraclesData(oraclesDataCell)?.length).toEqual(3); + }); + + test('test oracles prune getPricesForWithdraw, collateralToDebt false', async () => { + expect.assertions(3); + + const pc = new ClassicCollector(PRICE_COLLTECTOR_CONFIG); + + const principals = Dictionary.empty(); + principals.set(TON_MAINNET.assetId, 5n); + principals.set(USDT_MAINNET.assetId, 5n); + + const prices = await pc.getPricesForWithdraw(principals, USDT_MAINNET, true, DefaultFetchConfig); + const { oraclesDataCell } = unpackPrices(prices.dataCell); + + expect(prices.dict.values().length).toEqual(2); + expect(prices.dataCell.hash()).not.toEqual(Cell.EMPTY.hash()); + expect(unpackOraclesData(oraclesDataCell)?.length).toEqual(3); + }); + + test('test oracles prune getPrices', async () => { + expect.assertions(3); + + const pc = new ClassicCollector(PRICE_COLLTECTOR_CONFIG); + + const principals = Dictionary.empty(); + principals.set(TON_MAINNET.assetId, 5n); + principals.set(USDT_MAINNET.assetId, 5n); + + const prices = await pc.getPrices(); + const { oraclesDataCell } = unpackPrices(prices.dataCell); + + expect(prices.dict.values().length).toEqual(PRICE_COLLTECTOR_CONFIG.poolAssetsConfig.length); + expect(prices.dataCell.hash()).not.toEqual(Cell.EMPTY.hash()); + expect(unpackOraclesData(oraclesDataCell)?.length).toEqual(3); + }); + + test('test oracles prune getPricesForLiquidate', async () => { + expect.assertions(3); + + const pc = new ClassicCollector(PRICE_COLLTECTOR_CONFIG); + + const principals = Dictionary.empty(); + principals.set(TON_MAINNET.assetId, -5n); + principals.set(USDT_MAINNET.assetId, 5n); + + const prices = await pc.getPricesForLiquidate(principals, DefaultFetchConfig); + const { oraclesDataCell } = unpackPrices(prices.dataCell); + + expect(prices.dict.values().length).toEqual(2); + expect(prices.dataCell.hash()).not.toEqual(Cell.EMPTY.hash()); + expect(unpackOraclesData(oraclesDataCell)?.length).toEqual(3); + }); + + test('test oracles prune getPricesForSupplyWithdraw', async () => { + expect.assertions(3); + + const pc = new ClassicCollector(PRICE_COLLTECTOR_CONFIG); + + const principals = Dictionary.empty(); + principals.set(TON_MAINNET.assetId, -5n); + principals.set(USDT_MAINNET.assetId, 5n); + + const prices = await pc.getPricesForSupplyWithdraw( + principals, + TON_MAINNET, + USDT_MAINNET, + true, + DefaultFetchConfig, + ); + const { oraclesDataCell } = unpackPrices(prices.dataCell); + + expect(prices.dict.values().length).toEqual(2); + expect(prices.dataCell.hash()).not.toEqual(Cell.EMPTY.hash()); + expect(unpackOraclesData(oraclesDataCell)?.length).toEqual(3); + }); });