diff --git a/src/pages/api/lp/positionsByPrice/[...params].ts b/src/pages/api/lp/positionsByPrice/[...params].ts new file mode 100644 index 00000000..760f9258 --- /dev/null +++ b/src/pages/api/lp/positionsByPrice/[...params].ts @@ -0,0 +1,58 @@ +// pages/api/lp/positionsByPrice/[...params].ts +import { testnetConstants } from "../../../../constants/configConstants"; +import { tokenConfigMapOnSymbol } from "@/constants/tokenConstants"; +import { NextApiRequest, NextApiResponse } from "next"; +import { LiquidityPositionQuerier } from "@/utils/protos/services/dex/liquidity-positions"; +import { + DirectedTradingPair, + Position, +} from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb"; +import { base64ToUint8Array } from "@/utils/math/base64"; + +export default async function positionsByPriceHandler( + req: NextApiRequest, + res: NextApiResponse +) { + const params = req.query.params as string[]; + + const token1 = params[0] || null; + const token2 = params[1] || null; + const limit = params[2] || null; + + try { + if (!token1 || !token2 || !limit) { + return res.status(400).json({ error: "Invalid query parameters" }); + } + + // Get token 1 & 2 + const asset1Token = tokenConfigMapOnSymbol[token1]; + const asset2Token = tokenConfigMapOnSymbol[token2]; + + const lp_querier = new LiquidityPositionQuerier({ + grpcEndpoint: testnetConstants.grpcEndpoint, + }); + + const tradingPair = new DirectedTradingPair({ + start: { + inner: base64ToUint8Array(asset1Token.inner), + }, + end: { + inner: base64ToUint8Array(asset2Token.inner), + }, + }); + + const data = await lp_querier.liquidityPositionsByPrice( + tradingPair, + Number(limit) + ); + + res.status(200).json(data as Position[]); + } catch (error) { + console.error("Error getting liquidty positions by price grpc data:", error); + res + .status(500) + .json({ + error: `Error getting liquidty positions by price grpc data: ${error}`, + }); + } +} diff --git a/src/utils/protos/services/dex/liquidity-positions.ts b/src/utils/protos/services/dex/liquidity-positions.ts index c473a87c..ca1297b2 100644 --- a/src/utils/protos/services/dex/liquidity-positions.ts +++ b/src/utils/protos/services/dex/liquidity-positions.ts @@ -4,8 +4,10 @@ import { QueryService } from "@buf/penumbra-zone_penumbra.connectrpc_es/penumbra import { PositionId, Position, + DirectedTradingPair, } from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb"; import { LiquidityPositionQuerierInterface } from "../../types/LiquidityPositionQuerier"; +import { Readable } from "stream"; export class LiquidityPositionQuerier implements LiquidityPositionQuerierInterface { private readonly client: PromiseClient; @@ -21,4 +23,29 @@ export class LiquidityPositionQuerier implements LiquidityPositionQuerierInterfa const res = await this.client.liquidityPositionById({ positionId }); return res.data; } + + async liquidityPositionsByPrice( + tradingPair: DirectedTradingPair, + limit: number + ): Promise { + const res = await this.client.liquidityPositionsByPrice({ + tradingPair, + limit: BigInt(limit), + }); + + if (!res[Symbol.asyncIterator]) { + console.error("Received:", res); + throw new Error( + "Received an unexpected response type from the server, expected an async iterable." + ); + } + + const positions: Position[] = []; + console.log("res:", res); + // Res is Symbol(Symbol.asyncIterator)]: [Function: [Symbol.asyncIterator]] + for await (const position of res as Readable) { + positions.push(position); + } + return positions; + } } diff --git a/src/utils/protos/types/LiquidityPositionQuerier.ts b/src/utils/protos/types/LiquidityPositionQuerier.ts index af8951dc..7bf13cb9 100644 --- a/src/utils/protos/types/LiquidityPositionQuerier.ts +++ b/src/utils/protos/types/LiquidityPositionQuerier.ts @@ -1,5 +1,6 @@ -import { PositionId, Position } from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb"; +import { PositionId, Position, DirectedTradingPair } from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb"; export interface LiquidityPositionQuerierInterface { liquidityPositionById(id: PositionId): Promise; + liquidityPositionsByPrice(directedTradingPair: DirectedTradingPair, limit: number): Promise; }