Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 27 additions & 10 deletions src/oracles/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<bigint, bigint>, addendum: Dictionary<bigint, bigint>) {
for (const key of addendum.keys()) {
const current = result.get(key)!;
Expand Down
97 changes: 95 additions & 2 deletions tests/prices/PriceCollector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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<bigint, bigint>();
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<bigint, bigint>();
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<bigint, bigint>();
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<bigint, bigint>();
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<bigint, bigint>();
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);
});
});