Skip to content

Commit

Permalink
Task/odex 384 (#201)
Browse files Browse the repository at this point in the history
* update: fallback get asset price in usd

* test: fixed failed test case

* test: added some testcase
  • Loading branch information
trungbach authored Mar 12, 2024
1 parent 2f571d8 commit b89f519
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 41 deletions.
3 changes: 1 addition & 2 deletions packages/oraidex-common/src/pairs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import {
USDT_CONTRACT,
WETH_CONTRACT,
NEUTARO_ORAICHAIN_DENOM as NEUTARO_ADDRESS,
OCH_CONTRACT,
ORAI_INFO
OCH_CONTRACT
} from "./constant";
import { parseAssetInfo } from "./helper";
import { TokenItemType, assetInfoMap } from "./token";
Expand Down
6 changes: 3 additions & 3 deletions packages/oraidex-common/src/token.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { FeeCurrency } from "@keplr-wallet/types";
import { PairInfo } from "@oraichain/oraidex-contracts-sdk";
import { flatten, uniqBy } from "lodash";
import { INJECTIVE_ORAICHAIN_DENOM, KWTBSC_ORAICHAIN_DENOM, MILKYBSC_ORAICHAIN_DENOM } from "./constant";
import {
CoinGeckoId,
CoinIcon,
Expand All @@ -8,9 +11,6 @@ import {
chainInfos,
oraichainNetwork
} from "./network";
import { flatten, uniqBy } from "lodash";
import { INJECTIVE_ORAICHAIN_DENOM, KWTBSC_ORAICHAIN_DENOM, MILKYBSC_ORAICHAIN_DENOM } from "./constant";
import { FeeCurrency } from "@keplr-wallet/types";

export type EvmDenom = "bep20_orai" | "bep20_airi" | "erc20_orai" | "kawaii_orai";
export type AmountDetails = { [denom: string]: string };
Expand Down
37 changes: 11 additions & 26 deletions packages/oraidex-server/src/db-query.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import {
BigDecimal,
CW20_DECIMALS,
KWT_CONTRACT,
ORAI,
oraichainTokens,
parseTokenInfoRawDenom
} from "@oraichain/oraidex-common";
import { BigDecimal, CW20_DECIMALS, KWT_CONTRACT, ORAI } from "@oraichain/oraidex-common";
import {
DuckDb,
PoolAmountHistory,
SwapOperationData,
getDate24hBeforeNow,
getPairLiquidity,
getPoolLiquidities,
getPoolsFromDuckDb,
parseAssetInfoOnlyDenom
getPoolsFromDuckDb
} from "@oraichain/oraidex-sync";
import { ARRANGED_PAIRS_CHART, AllPairsInfo, getAssetInfosFromPairString } from "./helper";
import "./polyfill";
import { ARRANGED_PAIRS_CHART, AllPairsInfo, getAssetInfosFromPairString, getPriceAssetInUsd } from "./helper";
import { CACHE_KEY, cache } from "./map-cache";
import "./polyfill";

export type LowHighPriceOfPairType = {
low: number;
Expand Down Expand Up @@ -129,6 +121,8 @@ export class DbQuery {

async getSwapVolume(query: GetHistoricalChart): Promise<HistoricalChartResponse[]> {
const { pair, type } = query;
const assetInfos = getAssetInfosFromPairString(pair);
if (!assetInfos) throw new Error(`Cannot find asset infos for pairAddr: ${pair}`);

const sql = `SELECT
ANY_VALUE(timestamp) as timestamp,
Expand All @@ -142,13 +136,9 @@ export class DbQuery {
const params = [pair];
const result = await this.duckDb.conn.all(sql, ...params);

const [baseAssetInfo] = getAssetInfosFromPairString(pair);
const baseTokenInfo = oraichainTokens.find(
(t) => parseTokenInfoRawDenom(t) === parseAssetInfoOnlyDenom(baseAssetInfo)
);
if (!baseTokenInfo) throw new Error(`Cannot find token for assetInfo: ${JSON.stringify(baseAssetInfo)}`);
const prices = cache.get(CACHE_KEY.COINGECKO_PRICES) ?? {};
const basePriceInUsdt = prices[baseTokenInfo.coinGeckoId] ?? 0;
const [baseAssetInfo] = assetInfos;
const basePriceInUsdt = await getPriceAssetInUsd(baseAssetInfo);

const swapVolume = [];
for (const item of result) {
swapVolume.push({
Expand Down Expand Up @@ -205,13 +195,8 @@ export class DbQuery {
const params = [pairObj.pairAddr];
const result = await this.duckDb.conn.all(sql, ...params);

const baseTokenInfo = oraichainTokens.find(
(t) => parseTokenInfoRawDenom(t) === parseAssetInfoOnlyDenom(assetInfos[0])
);
if (!baseTokenInfo) throw new Error(`Cannot find token for assetInfo: ${JSON.stringify(assetInfos[0])}`);

const prices = cache.get(CACHE_KEY.COINGECKO_PRICES) ?? {};
const basePriceInUsdt = prices[baseTokenInfo.coinGeckoId] ?? 0;
const [baseAssetInfo] = assetInfos;
const basePriceInUsdt = await getPriceAssetInUsd(baseAssetInfo);

const liquiditiesAvg = [];
for (const item of result) {
Expand Down
29 changes: 21 additions & 8 deletions packages/oraidex-server/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
ORAIX_CONTRACT,
ORAI_INFO,
ROUTER_V2_CONTRACT,
USDC_CONTRACT
USDC_CONTRACT,
USDT_CONTRACT
} from "@oraichain/oraidex-common/build/constant";
import { fetchRetry } from "@oraichain/oraidex-common/build/helper";
import { fetchRetry, parseTokenInfoRawDenom, parseAssetInfo } from "@oraichain/oraidex-common/build/helper";
import { AssetInfo, OraiswapRouterQueryClient } from "@oraichain/oraidex-contracts-sdk";
import {
DuckDb,
Expand All @@ -16,28 +17,24 @@ import {
PairInfoDataResponse,
PairMapping,
PoolAmountHistory,
RatioDirection,
calculatePriceByPool,
findPairAddress,
getAllFees,
getAllVolume24h,
getAvgPoolLiquidities,
getOraiPrice,
getPairByAssetInfos,
getPoolAmounts,
getPoolAprsFromDuckDb,
getPoolLiquidities,
getPoolsFromDuckDb,
getPriceByAsset,
getPriceAssetByUsdt,
injAddress,
oraiInfo,
oraixCw20Address,
pairs,
pairsWithDenom,
parseAssetInfoOnlyDenom,
simulateSwapPrice,
usdcCw20Address,
usdtInfo
usdcCw20Address
} from "@oraichain/oraidex-sync";
import bech32 from "bech32";
import "dotenv/config";
Expand Down Expand Up @@ -463,3 +460,19 @@ export const getCoingeckoPrices = async <T extends CoinGeckoId>(
}
return prices;
};

/**
* Get asset (in oraichain network) price in usd from coingecko
* otherwise, get price via pool
*/
export async function getPriceAssetInUsd(assetInfo: AssetInfo): Promise<number> {
const tokenInfo = oraichainTokens.find((t) => parseTokenInfoRawDenom(t) === parseAssetInfo(assetInfo));
if (!tokenInfo) throw new Error(`Cannot find token for assetInfo: ${JSON.stringify(assetInfo)}`);

const prices = cache.get(CACHE_KEY.COINGECKO_PRICES) ?? {};
let assetPriceInUsdt = prices[tokenInfo.coinGeckoId] ?? 0;
if (!assetPriceInUsdt) {
assetPriceInUsdt = await getPriceAssetByUsdt(assetInfo);
}
return assetPriceInUsdt;
}
47 changes: 46 additions & 1 deletion packages/oraidex-server/tests/db-query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DuckDb, PairInfoData } from "@oraichain/oraidex-sync";
import * as oraidexSyncPoolHelper from "@oraichain/oraidex-sync/build/pool-helper";
import * as oraidexSyncHelper from "@oraichain/oraidex-sync/build/helper";
import { CACHE_KEY, cache } from "../src/map-cache";
import { DbQuery } from "./../src/db-query";
import { DbQuery, GetHistoricalChart } from "./../src/db-query";
import {
ORAI,
ORAIX_CONTRACT,
Expand All @@ -17,6 +17,19 @@ import { AllPairsInfo } from "../src/helper";
describe("test-db-query", () => {
afterEach(jest.restoreAllMocks);

it("test-getSwapVolume-should-throw-error-when-input-pair-invalid", async () => {
// arrange
const input: GetHistoricalChart = {
pair: "invalid-pair",
type: "day"
};
const duckdb = await DuckDb.create(":memory:");
const dbQuery = new DbQuery(duckdb);

// act & assertion
await expect(dbQuery.getSwapVolume(input)).rejects.toThrow(`Cannot find asset infos for pairAddr: ${input.pair}`);
});

it.each<["day" | "week" | "month", bigint, bigint, number[]]>([
["day", 1000000n, 2000000n, [1, 2, 2]],
["week", 1000000n, 2000000n, [3, 2]],
Expand Down Expand Up @@ -92,6 +105,7 @@ describe("test-db-query", () => {
const duckdb = await DuckDb.create(":memory:");
const dbQuery = new DbQuery(duckdb);

await duckdb.createPairInfosTable();
await duckdb.createSwapOhlcv();
await duckdb.insertOhlcv([
{
Expand Down Expand Up @@ -154,6 +168,37 @@ describe("test-db-query", () => {
});
});

it("test-getLiquidityChart-should-throw-error-when-input-pair-invalid", async () => {
// arrange
const input: GetHistoricalChart = {
pair: "invalid-pair",
type: "day"
};
const duckdb = await DuckDb.create(":memory:");
const dbQuery = new DbQuery(duckdb);

// act & assertion
await expect(dbQuery.getLiquidityChart(input)).rejects.toThrow(
`Cannot find asset infos for pairAddr: ${input.pair}`
);
});

it("test-getLiquidityChart-should-throw-error-when-db-dont-have-pair-for-assetInfos", async () => {
// arrange
const input: GetHistoricalChart = {
pair: `${ORAI}-${USDT_CONTRACT}`,
type: "day"
};
const duckdb = await DuckDb.create(":memory:");
const dbQuery = new DbQuery(duckdb);
jest.spyOn(duckdb, "getPoolByAssetInfos").mockResolvedValue(undefined as any);

// act & assertion
await expect(dbQuery.getLiquidityChart(input)).rejects.toThrow(
`Cannot find pair for assetInfos: ${JSON.stringify([ORAI_INFO, { token: { contract_addr: USDT_CONTRACT } }])}`
);
});

it.each<["day" | "week" | "month", number[]]>([
["day", [4, 6, 5]],
["week", [6, 5]],
Expand Down
49 changes: 48 additions & 1 deletion packages/oraidex-server/tests/helper.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { getAssetInfosFromPairString, getDate24hBeforeNow, validateOraiAddress } from "../src/helper";
import { ORAIX_INFO } from "@oraichain/oraidex-common";
import {
getAssetInfosFromPairString,
getDate24hBeforeNow,
getPriceAssetInUsd,
validateOraiAddress
} from "../src/helper";
import { CACHE_KEY, cache } from "../src/map-cache";
import * as poolHelper from "@oraichain/oraidex-sync/build/pool-helper";

describe("test-helper", () => {
it("test-getDate24hBeforeNow", () => {
Expand Down Expand Up @@ -57,4 +65,43 @@ describe("test-helper", () => {
// assert
expect(result).toEqual(expected);
});

describe("test-getPriceAssetInUsd", () => {
it("should-throw-error-when-input-is-not-a-valid-asset", async () => {
const assetInfo = {
token: {
contract_addr: "invalid-asset"
}
};
await expect(getPriceAssetInUsd(assetInfo)).rejects.toThrow(
`Cannot find token for assetInfo: ${JSON.stringify(assetInfo)}`
);
});

it("should-return-price-from-cache", async () => {
// arrange
cache.set(CACHE_KEY.COINGECKO_PRICES, {
oraidex: 1
});

// act
const res = await getPriceAssetInUsd(ORAIX_INFO);

// assertion
expect(res).toEqual(1);

cache.set(CACHE_KEY.COINGECKO_PRICES, undefined);
});

it("should-return-price-from-pool-if-cache-is-not-available", async () => {
// arrange
jest.spyOn(poolHelper, "getPriceAssetByUsdt").mockResolvedValue(2);

// act
const res = await getPriceAssetInUsd(ORAIX_INFO);

// assertion
expect(res).toEqual(2);
});
});
});

0 comments on commit b89f519

Please sign in to comment.