diff --git a/packages/oraidex-common/src/helper.ts b/packages/oraidex-common/src/helper.ts index 30461fb7..cf442ed7 100644 --- a/packages/oraidex-common/src/helper.ts +++ b/packages/oraidex-common/src/helper.ts @@ -121,10 +121,10 @@ export const toTokenInfo = (token: TokenItemType, info?: TokenInfoResponse): Tok export const toAssetInfo = (token: TokenInfo): AssetInfo => { return token.contractAddress ? { - token: { - contract_addr: token.contractAddress + token: { + contract_addr: token.contractAddress + } } - } : { native_token: { denom: token.denom } }; }; @@ -426,6 +426,9 @@ export const fetchRetry = async (url: RequestInfo | URL, options: RequestInit & } }; +/** + * @deprecated since version 1.0.76. Use `parseAssetInfo` instead. + */ export function parseAssetInfoOnlyDenom(info: AssetInfo): string { if ("native_token" in info) return info.native_token.denom; return info.token.contract_addr; diff --git a/packages/oraidex-common/src/pairs.ts b/packages/oraidex-common/src/pairs.ts index f29f7e0a..d5ad4d03 100644 --- a/packages/oraidex-common/src/pairs.ts +++ b/packages/oraidex-common/src/pairs.ts @@ -19,7 +19,7 @@ import { OCH_CONTRACT, ORAI_INFO } from "./constant"; -import { parseAssetInfo, parseAssetInfoOnlyDenom } from "./helper"; +import { parseAssetInfo } from "./helper"; import { TokenItemType, assetInfoMap } from "./token"; import uniq from "lodash/uniq"; import flatten from "lodash/flatten"; diff --git a/packages/oraidex-server/src/db-query.ts b/packages/oraidex-server/src/db-query.ts index a065a13d..91e28152 100644 --- a/packages/oraidex-server/src/db-query.ts +++ b/packages/oraidex-server/src/db-query.ts @@ -11,6 +11,9 @@ import { PoolAmountHistory, SwapOperationData, getDate24hBeforeNow, + getPairLiquidity, + getPoolLiquidities, + getPoolsFromDuckDb, parseAssetInfoOnlyDenom } from "@oraichain/oraidex-sync"; import { ARRANGED_PAIRS_CHART, AllPairsInfo, getAssetInfosFromPairString } from "./helper"; @@ -171,6 +174,17 @@ export class DbQuery { return swapVolume; } + async getLatestLiquidityPools() { + const pools = await getPoolsFromDuckDb(); + const allLiquidities = await getPoolLiquidities(pools); + const totalLiquiditesInUsdt = allLiquidities.reduce((acc, cur) => { + acc += cur; + return acc; + }, 0); + + return totalLiquiditesInUsdt; + } + async getLiquidityChart(query: GetHistoricalChart): Promise { const { pair, type } = query; const assetInfos = getAssetInfosFromPairString(pair); @@ -182,7 +196,7 @@ export class DbQuery { const sql = `SELECT ANY_VALUE(timestamp) as timestamp, DATE_TRUNC('${type}', to_timestamp(timestamp)) AS time, - AVG(offerPoolAmount) AS value + MAX(offerPoolAmount) AS value FROM lp_amount_history WHERE pairAddr = ? GROUP BY DATE_TRUNC('${type}', to_timestamp(timestamp)) @@ -201,7 +215,7 @@ export class DbQuery { const liquiditiesAvg = []; for (const item of result) { - const liquidityInUsdt = new BigDecimal(Math.trunc(basePriceInUsdt * item.value)) + const liquidityInUsdt = new BigDecimal(Math.trunc(basePriceInUsdt * Number(item.value))) .div(10 ** CW20_DECIMALS) .mul(2) .toNumber(); @@ -210,6 +224,22 @@ export class DbQuery { value: liquidityInUsdt }); } + + let latestLiquidityPool = 0; + const poolsInfo = cache.get(CACHE_KEY.POOLS_INFO); + if (poolsInfo) { + const currentPool = poolsInfo.find((p) => p.pairAddr === pairObj.pairAddr); + if (currentPool) latestLiquidityPool = currentPool.totalLiquidity; + } else { + latestLiquidityPool = await getPairLiquidity(pairObj); + } + + if (latestLiquidityPool) + liquiditiesAvg[liquiditiesAvg.length - 1] = { + ...liquiditiesAvg[liquiditiesAvg.length - 1], + value: new BigDecimal(latestLiquidityPool).div(10 ** 6).toNumber() + }; + const KWT_ORAI_PAIR = `${KWT_CONTRACT}-${ORAI}`; // TODO: current harcode filter data for kwt-orai pair @@ -249,6 +279,23 @@ export class DbQuery { }); } + let latestLiquidityPools = 0; + const poolsInfo = cache.get(CACHE_KEY.POOLS_INFO); + if (poolsInfo) { + poolsInfo.reduce((acc, cur) => { + acc += cur.totalLiquidity; + return acc; + }, latestLiquidityPools); + } else { + latestLiquidityPools = await this.getLatestLiquidityPools(); + } + + if (latestLiquidityPools) + totalLiquiditiesChart[totalLiquiditiesChart.length - 1] = { + ...totalLiquiditiesChart[totalLiquiditiesChart.length - 1], + value: new BigDecimal(latestLiquidityPools).div(10 ** 6).toNumber() + }; + return totalLiquiditiesChart.sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime()); } } diff --git a/packages/oraidex-server/tests/db-query.spec.ts b/packages/oraidex-server/tests/db-query.spec.ts index de144af4..2c4b5897 100644 --- a/packages/oraidex-server/tests/db-query.spec.ts +++ b/packages/oraidex-server/tests/db-query.spec.ts @@ -1,4 +1,6 @@ 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 { @@ -153,9 +155,9 @@ describe("test-db-query", () => { }); it.each<["day" | "week" | "month", number[]]>([ - ["day", [3, 6, 9]], - ["week", [4, 9]], - ["month", [4, 9]] + ["day", [4, 6, 5]], + ["week", [6, 5]], + ["month", [6, 5]] ])("test-getLiquidityChart", async (type, expectedResult) => { // setup const pair = "orai-orai12hzjxfh77wl572gdzct2fxv2arxcwh6gykc7qh"; @@ -194,7 +196,7 @@ describe("test-db-query", () => { uniqueKey: "3" }, { - offerPoolAmount: 4000000n, + offerPoolAmount: 5000000n, askPoolAmount: 1n, height: 4, timestamp: 1710906613, // Wednesday, 20 March 2024 03:50:13 @@ -203,7 +205,7 @@ describe("test-db-query", () => { uniqueKey: "4" }, { - offerPoolAmount: 5000000n, + offerPoolAmount: 4000000n, askPoolAmount: 1n, height: 5, timestamp: 1710906614, // Wednesday, 20 March 2024 03:50:14 @@ -214,6 +216,7 @@ describe("test-db-query", () => { ]); jest.spyOn(duckdb, "getPoolByAssetInfos").mockResolvedValue({ pairAddr } as PairInfoData); + jest.spyOn(oraidexSyncPoolHelper, "getPriceAssetByUsdt").mockResolvedValue(1); // mock price orai = 1 usdt const coingeckoPrices = { @@ -221,6 +224,14 @@ describe("test-db-query", () => { }; cache.set(CACHE_KEY.COINGECKO_PRICES, coingeckoPrices); + // mock cached pools info to get latest lp in usdt + cache.set(CACHE_KEY.POOLS_INFO, [ + { + pairAddr, + totalLiquidity: 5e6 + } + ]); + // act const result = await dbQuery.getLiquidityChart({ pair, type }); @@ -231,9 +242,9 @@ describe("test-db-query", () => { }); it.each<["day" | "week" | "month", number[]]>([ - ["day", [7, 6, 17]], - ["week", [8, 17]], - ["month", [8, 17]] + ["day", [8, 6, 11]], + ["week", [10, 11]], + ["month", [10, 11]] ])("test-getLiquidityChartAllPools", async (type, expectedResult) => { // setup const pairAddr = "orai1c5s03c3l336dgesne7dylnmhszw8554tsyy9yt"; // ORAI/USDT @@ -344,6 +355,18 @@ describe("test-db-query", () => { }; cache.set(CACHE_KEY.COINGECKO_PRICES, coingeckoPrices); + // mock cached pools info to get latest lp in usdt + cache.set(CACHE_KEY.POOLS_INFO, [ + { + pairAddr, + totalLiquidity: 5e6 + }, + { + pairAddr: pairAddrOraixUsdc, + totalLiquidity: 6e6 + } + ]); + const pairs: AllPairsInfo[] = [ { symbol: "orai/usdt", @@ -411,8 +434,24 @@ describe("test-db-query", () => { // act const result = await dbQuery.getSwapVolumeForPairByRangeTime(pair, then, now, basePriceInUsdt); + // assert expect(result).toEqual(expectedResult); } ); + + it("test-getLatestLiquidityPools", async () => { + // setup + const duckdb = await DuckDb.create(":memory:"); + const dbQuery = new DbQuery(duckdb); + + jest.spyOn(oraidexSyncHelper, "getPoolsFromDuckDb").mockResolvedValue([]); + jest.spyOn(oraidexSyncPoolHelper, "getPoolLiquidities").mockResolvedValue([1, 2, 3, 4, 5]); + + // act + const result = await dbQuery.getLatestLiquidityPools(); + + // assert + expect(result).toEqual(15); + }); });