Skip to content

Commit

Permalink
Migrate grpc queries server side (#7)
Browse files Browse the repository at this point in the history
* Migrate grpc queries server side

* fix lp view

* Shielded pool -> server side

* fix rendering for if position not found

* Move sim queries server side
  • Loading branch information
philipjames44 authored Mar 25, 2024
1 parent cb08f28 commit e554bf0
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 232 deletions.
74 changes: 31 additions & 43 deletions src/components/liquidityPositions/currentStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import React, { useEffect, useState } from "react";
import {
VStack,
Text,
Badge,
HStack,
Image,
Avatar,
} from "@chakra-ui/react";
import {
Position,
} from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb";
import { VStack, Text, Badge, HStack, Image, Avatar } from "@chakra-ui/react";
import { Position, PositionState } from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb";
import { fromBaseUnit } from "../../utils/math/hiLo";
import { uint8ArrayToBase64 } from "../../utils/math/base64";
import { tokenConfigMapOnInner, Token } from "../../constants/tokenConstants";
Expand All @@ -36,53 +27,50 @@ const CurrentLPStatus = ({ nftId, position }: CurrentLPStatusProps) => {
// First process position to human readable pieces

// Get status
const status = position.state;
const status = (position.state as PositionState).state.toString();

// https://buf.build/penumbra-zone/penumbra/docs/main:penumbra.core.component.dex.v1#penumbra.core.component.dex.v1.PositionState.PositionStateEnum
let statusText = "";
switch (status?.state) {
case 0:

switch (status) {
case "POSITION_STATE_ENUM_UNSPECIFIED":
statusText = "Unspecified";
break;
case 1:
case "POSITION_STATE_ENUM_OPENED":
statusText = "Open";
break;
case 2:
case "POSITION_STATE_ENUM_CLOSED":
statusText = "Closed";
break;
case 3:
case "POSITION_STATE_ENUM_WITHDRAWN":
statusText = "Withdrawn";
break;
case 4:
case "POSITION_STATE_ENUM_CLAIMED":
statusText = "Claimed";
break;
default:
statusText = "Unknown";
}

// Get fee tier
const feeTier = position!.phi!.component!.fee;
const feeTier = Number(position!.phi!.component!.fee);

const asset1 = position!.phi!.pair!.asset1;
const asset2 = position!.phi!.pair!.asset2;

// States for tokens
const [asset1Token, setAsset1Token] = useState<Token>(
{
symbol: "UNKNOWN",
decimals: 0,
inner: "UNKNOWN",
imagePath: "UNKNOWN",
}
);
const [asset2Token, setAsset2Token] = useState<Token>(
{
symbol: "UNKNOWN",
decimals: 0,
inner: "UNKNOWN",
imagePath: "UNKNOWN",
}
);
const [asset1Token, setAsset1Token] = useState<Token>({
symbol: "UNKNOWN",
decimals: 0,
inner: "UNKNOWN",
imagePath: "UNKNOWN",
});
const [asset2Token, setAsset2Token] = useState<Token>({
symbol: "UNKNOWN",
decimals: 0,
inner: "UNKNOWN",
imagePath: "UNKNOWN",
});
const [assetError, setAssetError] = useState<string | undefined>();

useEffect(() => {
Expand Down Expand Up @@ -122,25 +110,25 @@ const CurrentLPStatus = ({ nftId, position }: CurrentLPStatusProps) => {
}

const reserves1 = fromBaseUnit(
position!.reserves!.r1?.lo,
position!.reserves!.r1?.hi,
BigInt(position!.reserves!.r1?.lo || 0),
BigInt(position!.reserves!.r1?.hi || 0),
asset1Token.decimals
);

const reserves2 = fromBaseUnit(
position!.reserves!.r2?.lo,
position!.reserves!.r2?.hi,
BigInt(position!.reserves!.r2?.lo || 0),
BigInt(position!.reserves!.r2?.hi || 0),
asset2Token.decimals
);

const p: BigNumber = fromBaseUnit(
position!.phi!.component!.p!.lo,
position!.phi!.component!.p!.hi,
BigInt(position!.phi!.component!.p!.lo || 0),
BigInt(position!.phi!.component!.p!.hi || 0),
asset2Token.decimals
);
const q: BigNumber = fromBaseUnit(
position!.phi!.component!.q!.lo,
position!.phi!.component!.q!.hi,
BigInt(position!.phi!.component!.q!.lo || 0),
BigInt(position!.phi!.component!.q!.hi || 0),
asset1Token.decimals
);

Expand Down
1 change: 0 additions & 1 deletion src/components/lpAssetView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { FC, useEffect, useState } from "react";
import { CopyIcon } from "@radix-ui/react-icons";
import { Avatar, HStack, VStack } from "@chakra-ui/react";
import { testnetConstants } from "@/constants/configConstants";
import { Text } from "@chakra-ui/react";
import {
LiquidityPositionEvent,
Expand Down
28 changes: 28 additions & 0 deletions src/pages/api/lp/[lp_nft_id]/position.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// pages/api/lp/[lp_nft_id]/position.ts
import { testnetConstants } from "../../../../constants/configConstants";
import { LiquidityPositionQuerier } from "../../../../utils/protos/services/dex/liquidity-positions";
import {
PositionId,
Position,
} from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb";

export default async function liquidityPositionDataHandler(req: any, res: any) {
const { lp_nft_id } = req.query;

const lp_querier = new LiquidityPositionQuerier({
grpcEndpoint: testnetConstants.grpcEndpoint,
});

try {
const positionId = new PositionId({
altBech32m: lp_nft_id,
});

const data = await lp_querier.liquidityPositionById(positionId);

res.status(200).json(data as Position);
} catch (error) {
console.error("Error fetching liquidity position grpc data:", error);
res.status(500).json({"error": "Error fetching liquidity position grpc data"});
}
}
2 changes: 1 addition & 1 deletion src/pages/api/lp/[lp_nft_id]/trades.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// pages/api/lp/[lp_nft_id].js
// pages/api/lp/[lp_nft_id]/trades.js
import { IndexerQuerier } from "../../../../utils/indexer/connector";
import { testnetConstants } from "../../../../constants/configConstants";

Expand Down
31 changes: 31 additions & 0 deletions src/pages/api/shieldedPool/[token_inner].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// pages/api/shieldedPool/[token_inner].ts
import { testnetConstants } from "../../../constants/configConstants";
import { ShieldedPoolQuerier } from "../../../utils/protos/services/app/shielded-pool";
import { base64ToUint8Array } from "../../../utils/math/base64";
import {
AssetId,
Metadata,
} from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb";

export default async function assetMetadataHandler(req: any, res: any) {
const { token_inner } = req.query;

const decodedTokenInner = decodeURIComponent(token_inner);

const pool_querier = new ShieldedPoolQuerier({
grpcEndpoint: testnetConstants.grpcEndpoint,
});

try {
const positionId = new AssetId({
inner: base64ToUint8Array(decodedTokenInner),
});

const data = await pool_querier.assetMetadata(positionId);

res.status(200).json(data as Metadata);
} catch (error) {
console.error("Error fetching asset metadata grpc data:", error);
res.status(500).json({"error": "Error fetching asset metadata grpc data"});
}
}
94 changes: 94 additions & 0 deletions src/pages/api/simulations/[...params].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// pages/api/simulations/[...params].ts
import { testnetConstants } from "../../../constants/configConstants";
import { SimulationQuerier } from "@/utils/protos/services/dex/simulated-trades";
import { base64ToUint8Array } from "../../../utils/math/base64";
import {
SimulateTradeRequest,
SimulateTradeRequest_Routing_SingleHop,
SimulateTradeResponse,
SwapExecution,
} from "@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/dex/v1/dex_pb";
import { tokenConfigMapOnSymbol } from "@/constants/tokenConstants";
import { joinLoHi, splitLoHi } from "@/utils/math/hiLo";
import { NextApiRequest, NextApiResponse } from "next";

export default async function simulationHandler(
req: NextApiRequest,
res: NextApiResponse
) {
const params = req.query.params as string[];

const token1 = params[0] || null;
const token2 = params[1] || null;
const amountIn = params[2] || null;
const singleHop = params[3] || null;

let isSingleHop = false;

try {
if (!token1 || !token2 || !amountIn) {
return res.status(400).json({ error: "Invalid query parameters" });
}

if (String(singleHop).toLocaleLowerCase() === "singlehop") {
isSingleHop = true;
}

// Get token 1 & 2
const asset1Token = tokenConfigMapOnSymbol[token1];
const asset2Token = tokenConfigMapOnSymbol[token2];

const sim_querier = new SimulationQuerier({
grpcEndpoint: testnetConstants.grpcEndpoint,
});

const amtIn = splitLoHi(BigInt(Number(amountIn) * 10 ** asset1Token.decimals));

let simRequest = new SimulateTradeRequest({});
if (!isSingleHop) {
simRequest = new SimulateTradeRequest({
input: {
assetId: {
inner: base64ToUint8Array(asset1Token.inner),
},
amount: {
lo: amtIn.lo,
hi: amtIn.hi,
},
},
output: {
inner: base64ToUint8Array(asset2Token.inner),
},
});
} else {
simRequest = new SimulateTradeRequest({
input: {
assetId: {
inner: base64ToUint8Array(asset1Token.inner),
},
amount: {
lo: amtIn.lo,
hi: amtIn.hi,
},
},
output: {
inner: base64ToUint8Array(asset2Token.inner),
},
routing: {
setting: {
case: "singleHop",
value: SimulateTradeRequest_Routing_SingleHop,
},
},
});
}

const data = await sim_querier.simulateTrade(simRequest);
res.status(200).json(data as SwapExecution);
} catch (error) {
console.error("Error simulation trade grpc data:", error);
res
.status(500)
.json({ error: `Error simualtion trade grpc data: ${error}` });
}
}
26 changes: 11 additions & 15 deletions src/pages/lp/[lp_nft_id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,10 @@ export default function LP() {
useEffect(() => {
setIsLoading(true);
if (lp_nft_id) {
const lp_querier = new LiquidityPositionQuerier({
grpcEndpoint: testnetConstants.grpcEndpoint,
});
const liquidityPositionPromise = fetch(
`/api/lp/${lp_nft_id}/position`
).then((res) => res.json());

const positionId = new PositionId({
altBech32m: lp_nft_id,
});

const liquidityPositionPromise =
lp_querier.liquidityPositionById(positionId);
const lpEventsPromise = fetch(`/api/lp/${lp_nft_id}`).then((res) =>
res.json()
);
Expand All @@ -80,14 +74,13 @@ export default function LP() {

Promise.all([liquidityPositionPromise, lpEventsPromise, lpTradesPromise])
.then(([liquidityPositionResponse, lpEventsData, lpTradesData]) => {
if (!liquidityPositionResponse) {
if (!liquidityPositionResponse || liquidityPositionResponse.error) {
console.error("Error fetching liquidity position: no response");
setError("Error fetching liquidity position: no response");
return;
}

setLiquidityPosition(liquidityPositionResponse);

setLiquidityPosition(liquidityPositionResponse as Position);
if (!lpEventsData) {
console.error(
"Error fetching liquidity position events: no response"
Expand Down Expand Up @@ -115,7 +108,7 @@ export default function LP() {
.finally(() => {
setIsLoading(false);
});
}
}
}, [lp_nft_id]);

useEffect(() => {
Expand Down Expand Up @@ -175,7 +168,7 @@ export default function LP() {
} else {
setTimelineData(allEvents);
setIsTimelineLoading(false);
return
return;
}

setShowExpandButton(true);
Expand Down Expand Up @@ -381,7 +374,10 @@ export default function LP() {
</Text>
<HStack paddingBottom="5em"></HStack>
</>
) : !isLoading && !liquidityPosition && !isLineLoading && !isTimelineLoading ? ( // Explicitly check all loading states
) : !isLoading &&
!liquidityPosition &&
!isLineLoading &&
!isTimelineLoading ? ( // Explicitly check all loading states
<VStack height={"100%"} width={"100%"}>
<Text paddingTop={"20%"}>Liquidity position not found.</Text>
</VStack>
Expand Down
Loading

0 comments on commit e554bf0

Please sign in to comment.