diff --git a/packages/oraidex-server/package.json b/packages/oraidex-server/package.json index 536b33db..7107e032 100644 --- a/packages/oraidex-server/package.json +++ b/packages/oraidex-server/package.json @@ -1,6 +1,6 @@ { "name": "@oraichain/oraidex-server", - "version": "1.0.11", + "version": "1.0.12", "main": "dist/index.js", "bin": "dist/index.js", "license": "MIT", diff --git a/packages/oraidex-server/package.staging.json b/packages/oraidex-server/package.staging.json index 9e2b5fe6..5acc7100 100644 --- a/packages/oraidex-server/package.staging.json +++ b/packages/oraidex-server/package.staging.json @@ -1,6 +1,6 @@ { "name": "@oraichain/oraidex-server-staging", - "version": "1.0.3", + "version": "1.0.4", "main": "dist/index.js", "bin": "dist/index.js", "license": "MIT", diff --git a/packages/oraidex-server/src/index.ts b/packages/oraidex-server/src/index.ts index 4bae65c4..90248a53 100644 --- a/packages/oraidex-server/src/index.ts +++ b/packages/oraidex-server/src/index.ts @@ -13,13 +13,17 @@ import { findPairAddress, getAllFees, getAllVolume24h, + getOraiPrice, getPairLiquidity, + getVolumePairByUsdt, + oraiInfo, oraiUsdtPairOnlyDenom, pairs, pairsOnlyDenom, parseAssetInfoOnlyDenom, simulateSwapPrice, - toDisplay + toDisplay, + usdtInfo } from "@oraichain/oraidex-sync"; import cors from "cors"; import "dotenv/config"; @@ -85,7 +89,6 @@ app.get("/tickers", async (req, res) => { const tickerId = parseSymbolsToTickerId(symbols); const baseIndex = 0; const targetIndex = 1; - console.log(latestTimestamp, then); const baseInfo = parseAssetInfoOnlyDenom(pair.asset_infos[baseIndex]); const targetInfo = parseAssetInfoOnlyDenom(pair.asset_infos[targetIndex]); const volume = await duckDb.queryAllVolumeRange(baseInfo, targetInfo, then, latestTimestamp); @@ -114,7 +117,6 @@ app.get("/tickers", async (req, res) => { if (result.status === "fulfilled") return result.value; else console.log("result: ", result.reason); }); - console.table(data); res.status(200).send(data); } catch (error) { console.log("error: ", error); @@ -265,6 +267,37 @@ app.get("/v1/pools/", async (_req, res) => { } }); +// get price & volume ORAI in latest 24h +app.get("/orai-info", async (req, res) => { + try { + // query tf is in minute unit. + const SECONDS_PER_DAY = 24 * 60 * 60; + let tf = req.query.tf ? Number(req.query.tf) * 60 : SECONDS_PER_DAY; + const currentDate = new Date(); + const dateBeforeNow = getSpecificDateBeforeNow(new Date(), tf); + const oneDayBeforeNow = getSpecificDateBeforeNow(new Date(), SECONDS_PER_DAY); + const volume24h = await getVolumePairByUsdt([oraiInfo, usdtInfo], oneDayBeforeNow, currentDate); + + const timestamp = Math.round(dateBeforeNow.getTime() / 1000); + const oraiPriceByTime = await getOraiPrice(timestamp); + const currenOraiPrice = await getOraiPrice(); + + let percentPriceChange = 0; + if (oraiPriceByTime !== 0) { + percentPriceChange = ((currenOraiPrice - oraiPriceByTime) / oraiPriceByTime) * 100; + } + + res.status(200).send({ + price: currenOraiPrice, + volume_24h: toDisplay(volume24h), + price_change: percentPriceChange + }); + } catch (error) { + console.log({ error }); + res.status(500).send(`Error: ${JSON.stringify(error)}`); + } +}); + app.listen(port, hostname, async () => { // sync data for the service to read duckDb = await DuckDb.create(process.env.DUCKDB_PROD_FILENAME); diff --git a/packages/oraidex-sync/src/db.ts b/packages/oraidex-sync/src/db.ts index a25fb421..6f323fb2 100644 --- a/packages/oraidex-sync/src/db.ts +++ b/packages/oraidex-sync/src/db.ts @@ -506,6 +506,20 @@ export class DuckDb { return result[0] as PoolAmountHistory; } + async getLpAmountWithTime(pairAddr: string, timestamp: number) { + const result = await this.conn.all( + ` + SELECT * FROM lp_amount_history + WHERE pairAddr = ? AND timestamp >= ? + ORDER BY timestamp ASC + LIMIT 1 + `, + pairAddr, + timestamp + ); + return result[0] as PoolAmountHistory; + } + async insertPoolAmountHistory(ops: PoolAmountHistory[]) { await this.insertBulkData(ops, "lp_amount_history"); } diff --git a/packages/oraidex-sync/src/helper.ts b/packages/oraidex-sync/src/helper.ts index 8635a720..14d3835a 100644 --- a/packages/oraidex-sync/src/helper.ts +++ b/packages/oraidex-sync/src/helper.ts @@ -364,7 +364,7 @@ export function getSwapDirection(offerDenom: string, askDenom: string): SwapDire return pair.asset_infos.some((info) => info === offerDenom) && pair.asset_infos.some((info) => info === askDenom); }); if (!pair) { - console.error("Cannot find asset infos in list of pairs"); + console.error("getSwapDirection: Cannot find asset infos in list of pairs"); return; } const assetInfos = pair.asset_infos; diff --git a/packages/oraidex-sync/src/pool-helper.ts b/packages/oraidex-sync/src/pool-helper.ts index a04fcb3b..930d8ffa 100644 --- a/packages/oraidex-sync/src/pool-helper.ts +++ b/packages/oraidex-sync/src/pool-helper.ts @@ -28,7 +28,7 @@ import { queryPoolInfos } from "./query"; import { processEventApr } from "./tx-parsing"; -import { PairInfoData, PairMapping, ProvideLiquidityOperationData } from "./types"; +import { PairInfoData, PairMapping, PoolAmountHistory, ProvideLiquidityOperationData } from "./types"; // use this type to determine the ratio of price of base to the quote or vice versa export type RatioDirection = "base_in_quote" | "quote_in_base"; @@ -71,22 +71,35 @@ export const getPairByAssetInfos = (assetInfos: [AssetInfo, AssetInfo]): PairMap }; // get price ORAI in USDT base on ORAI/USDT pool. -// async function getOraiPrice(): Promise { -export const getOraiPrice = async (): Promise => { +export const getOraiPrice = async (timestamp?: number): Promise => { const oraiUsdtPair = getPairByAssetInfos([oraiInfo, usdtInfo]); const ratioDirection: RatioDirection = parseAssetInfoOnlyDenom(oraiUsdtPair.asset_infos[0]) === ORAI ? "base_in_quote" : "quote_in_base"; - return getPriceByAsset([oraiInfo, usdtInfo], ratioDirection); + return getPriceByAsset([oraiInfo, usdtInfo], ratioDirection, timestamp); }; +/** + * Get price of asset via askPoolAmount & offerPoolAmount in specific timestamp + * @param assetInfos + * @param ratioDirection + * @param timestamp + * @returns price of asset in specific time. + */ export const getPriceByAsset = async ( assetInfos: [AssetInfo, AssetInfo], - ratioDirection: RatioDirection + ratioDirection: RatioDirection, + timestamp?: number ): Promise => { const duckDb = DuckDb.instances; const poolInfo = await duckDb.getPoolByAssetInfos(assetInfos); if (!poolInfo) return 0; - const poolAmount = await duckDb.getLatestLpPoolAmount(poolInfo.pairAddr); + + let poolAmount: PoolAmountHistory; + if (timestamp) { + poolAmount = await duckDb.getLpAmountWithTime(poolInfo.pairAddr, timestamp); + } else { + poolAmount = await duckDb.getLatestLpPoolAmount(poolInfo.pairAddr); + } if (!poolAmount || !poolAmount.askPoolAmount || !poolAmount.offerPoolAmount) return 0; // offer: orai, ask: usdt -> price offer in ask = calculatePriceByPool([ask, offer]) // offer: orai, ask: atom -> price ask in offer = calculatePriceByPool([offer, ask]) @@ -292,7 +305,6 @@ export const triggerCalculateApr = async (assetInfos: [AssetInfo, AssetInfo][], const allRewardPerSecs = poolAprInfos.map((info) => (info.rewardPerSec ? JSON.parse(info.rewardPerSec) : null)); const APRs = await calculateAprResult(allLiquidities, allTotalSupplies, allBondAmounts, allRewardPerSecs); - console.dir({ APRs }, { depth: null }); const newPoolAprs = poolAprInfos.map((poolApr, index) => { return { ...poolApr,