Skip to content

Commit

Permalink
Merge pull request #3411 from osmosis-labs/connor/order-quant-normali…
Browse files Browse the repository at this point in the history
…sation

feat: Placed quantity in denom values
  • Loading branch information
crnbarr93 authored Jun 26, 2024
2 parents ae3dce2 + 2bbb5c8 commit 56cea50
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 45 deletions.
28 changes: 28 additions & 0 deletions packages/server/src/queries/complex/orderbooks/denoms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Chain } from "@osmosis-labs/types";
import cachified, { CacheEntry } from "cachified";
import { LRUCache } from "lru-cache";

import { DEFAULT_LRU_OPTIONS } from "../../../utils/cache";
import { queryOrderbookDenoms } from "../../osmosis";

const orderbookDenomsCache = new LRUCache<string, CacheEntry>(
DEFAULT_LRU_OPTIONS
);

export function getOrderbookDenoms({
orderbookAddress,
chainList,
}: {
orderbookAddress: string;
chainList: Chain[];
}) {
return cachified({
cache: orderbookDenomsCache,
key: `orderbookDenoms-${orderbookAddress}`,
ttl: 1000 * 60 * 60 * 24 * 7, // 7 days
getFreshValue: () =>
queryOrderbookDenoms({ orderbookAddress, chainList }).then(
({ data }) => data
),
});
}
1 change: 1 addition & 0 deletions packages/server/src/queries/complex/orderbooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./active-orders";
export * from "./denoms";
export * from "./maker-fee";
export * from "./spot-price";
export * from "./tick-state";
4 changes: 2 additions & 2 deletions packages/server/src/queries/complex/orderbooks/tick-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function getOrderbookTickState({
key: `orderbookTickInfo-${orderbookAddress}-${tickIds
.sort((a, b) => a - b)
.join(",")}`,
ttl: 1000 * 60 * 2, // 2 minutes
ttl: 1000 * 30, // 30 seconds
getFreshValue: () =>
queryOrderbookTicks({ orderbookAddress, chainList, tickIds }).then(
({ data }) => data.ticks
Expand All @@ -46,7 +46,7 @@ export function getOrderbookTickUnrealizedCancels({
key: `orderbookTickUnrealizedCancels-${orderbookAddress}-${tickIds
.sort((a, b) => a - b)
.join(",")}`,
ttl: 1000 * 60 * 2, // 2 minutes
ttl: 1000 * 30, // 30 seconds
getFreshValue: () =>
queryOrderbookTickUnrealizedCancelsById({
orderbookAddress,
Expand Down
22 changes: 22 additions & 0 deletions packages/server/src/queries/osmosis/orderbooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,25 @@ export const queryOrderbookSpotPrice = createNodeQuery<
return `/cosmwasm/wasm/v1/contract/${orderbookAddress}/smart/${encodedMsg}`;
},
});

interface OrderbookDenomsResponse {
data: {
quote_denom: string;
base_denom: string;
};
}

export const queryOrderbookDenoms = createNodeQuery<
OrderbookDenomsResponse,
{
orderbookAddress: string;
}
>({
path: ({ orderbookAddress }) => {
const msg = JSON.stringify({
denoms: {},
});
const encodedMsg = Buffer.from(msg).toString("base64");
return `/cosmwasm/wasm/v1/contract/${orderbookAddress}/smart/${encodedMsg}`;
},
});
80 changes: 69 additions & 11 deletions packages/trpc/src/orderbook-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { tickToPrice } from "@osmosis-labs/math";
import {
CursorPaginationSchema,
getOrderbookActiveOrders,
getOrderbookDenoms,
getOrderbookMakerFee,
getOrderbookSpotPrice,
getOrderbookTickState,
Expand All @@ -11,6 +12,7 @@ import {
maybeCachePaginatedItems,
} from "@osmosis-labs/server";
import { Chain } from "@osmosis-labs/types";
import { getAssetFromAssetList } from "@osmosis-labs/utils";
import { z } from "zod";

import { createTRPCRouter, publicProcedure } from "./api";
Expand Down Expand Up @@ -41,6 +43,9 @@ export type MappedLimitOrder = Omit<
orderbookAddress: string;
price: Dec;
status: OrderStatus;
output: number;
quoteAsset: ReturnType<typeof getAssetFromAssetList>;
baseAsset: ReturnType<typeof getAssetFromAssetList>;
};

function mapOrderStatus(order: LimitOrder): OrderStatus {
Expand All @@ -56,7 +61,9 @@ function mapOrderStatus(order: LimitOrder): OrderStatus {
async function getTickInfoAndTransformOrders(
orderbookAddress: string,
orders: LimitOrder[],
chainList: Chain[]
chainList: Chain[],
quoteAsset: ReturnType<typeof getAssetFromAssetList>,
baseAsset: ReturnType<typeof getAssetFromAssetList>
): Promise<MappedLimitOrder[]> {
const tickIds = [...new Set(orders.map((o) => o.tick_id))];
const tickStates = await getOrderbookTickState({
Expand All @@ -81,11 +88,20 @@ async function getTickInfoAndTransformOrders(
const { tickState, unrealizedCancels } = fullTickState.find(
({ tickId }) => tickId === o.tick_id
) ?? { tickState: undefined, unrealizedCancels: undefined };
const quantity = parseInt(o.quantity);
const placedQuantity = parseInt(o.placed_quantity);

const [tokenInAsset, tokenOutAsset] =
o.order_direction === "bid"
? [quoteAsset, baseAsset]
: [baseAsset, quoteAsset];

const quantityMin = parseInt(o.quantity);
const placedQuantityMin = parseInt(o.placed_quantity);
const placedQuantity =
placedQuantityMin / 10 ** (tokenInAsset?.decimals ?? 0);
const quantity = quantityMin / 10 ** (tokenInAsset?.decimals ?? 0);

const percentClaimed = new Dec(
(placedQuantity - quantity) / placedQuantity
(placedQuantityMin - quantityMin) / placedQuantityMin
);
const [tickEtas, tickCumulativeCancelled, tickUnrealizedCancelled] =
o.order_direction === "bid"
Expand Down Expand Up @@ -116,12 +132,23 @@ async function getTickInfoAndTransformOrders(
const tickTotalEtas =
tickEtas + (tickUnrealizedCancelled - tickCumulativeCancelled);
const totalFilled = Math.max(
tickTotalEtas - (parseInt(o.etas) - (placedQuantity - quantity)),
tickTotalEtas - (parseInt(o.etas) - (placedQuantityMin - quantityMin)),
0
);
const percentFilled = new Dec(totalFilled / placedQuantity);
const percentFilled = new Dec(totalFilled / placedQuantityMin);
const price = tickToPrice(new Int(o.tick_id));
const status = mapOrderStatus(o);

const outputMin =
o.order_direction === "bid"
? new Dec(placedQuantityMin).quo(price)
: new Dec(placedQuantityMin).mul(price);
const output = parseInt(
outputMin
.quo(new Dec(10 ** (tokenOutAsset?.decimals ?? 0)))
.truncate()
.toString()
);
return {
...o,
price,
Expand All @@ -132,6 +159,9 @@ async function getTickInfoAndTransformOrders(
percentFilled,
orderbookAddress,
status,
output,
quoteAsset,
baseAsset,
};
})
.sort((a, b) => a.order_id - b.order_id);
Expand Down Expand Up @@ -169,11 +199,24 @@ export const orderbookRouter = createTRPCRouter({
});

if (resp.orders.length === 0) return [];

const { quote_denom, base_denom } = await getOrderbookDenoms({
orderbookAddress: contractOsmoAddress,
chainList: ctx.chainList,
});
const quoteAsset = getAssetFromAssetList({
assetLists: ctx.assetLists,
sourceDenom: quote_denom,
});
const baseAsset = getAssetFromAssetList({
assetLists: ctx.assetLists,
sourceDenom: base_denom,
});
return getTickInfoAndTransformOrders(
contractOsmoAddress,
resp.orders,
ctx.chainList
ctx.chainList,
quoteAsset,
baseAsset
);
},
cacheKey: JSON.stringify([
Expand All @@ -195,20 +238,35 @@ export const orderbookRouter = createTRPCRouter({
const { contractAddresses, userOsmoAddress } = input;
if (contractAddresses.length === 0 || userOsmoAddress.length === 0)
return [];

const promises = contractAddresses.map(
async (contractOsmoAddress) => {
async (contractOsmoAddress: string) => {
const resp = await getOrderbookActiveOrders({
orderbookAddress: contractOsmoAddress,
userOsmoAddress: userOsmoAddress,
chainList: ctx.chainList,
});

if (resp.orders.length === 0) return [];

const { base_denom } = await getOrderbookDenoms({
orderbookAddress: contractOsmoAddress,
chainList: ctx.chainList,
});
// TODO: Use actual quote denom here
const quoteAsset = getAssetFromAssetList({
assetLists: ctx.assetLists,
sourceDenom: "uusdc",
});
const baseAsset = getAssetFromAssetList({
assetLists: ctx.assetLists,
sourceDenom: base_denom,
});
const mappedOrders = await getTickInfoAndTransformOrders(
contractOsmoAddress,
resp.orders,
ctx.chainList
ctx.chainList,
quoteAsset,
baseAsset
);
return mappedOrders;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const OrderProgressBar: React.FC<OrderProgressBarProps> = ({
const { percentFilled, status } = order;

const roundedAmountFilled = useMemo(() => {
if (percentFilled.lt(new Dec(1))) {
if (percentFilled.lt(new Dec(1)) && !percentFilled.isZero()) {
return new Dec(1);
}
return percentFilled.round();
Expand Down
30 changes: 23 additions & 7 deletions packages/web/components/complex/orders-history/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { PricePretty } from "@keplr-wallet/unit";
import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server";
import { createColumnHelper } from "@tanstack/react-table";
import classNames from "classnames";
import Image from "next/image";
Expand All @@ -6,6 +8,7 @@ import { Icon } from "~/components/assets";
import { ActionsCell } from "~/components/complex/orders-history/cells/actions";
import { OrderProgressBar } from "~/components/complex/orders-history/cells/filled-progress";
import { DisplayableLimitOrder } from "~/hooks/limit-orders/use-orderbook";
import { formatPretty } from "~/utils/formatter";

const columnHelper = createColumnHelper<DisplayableLimitOrder>();

Expand All @@ -22,7 +25,8 @@ export const tableColumns = [
order_direction,
quoteAsset,
baseAsset,
// placed_quantity,
placed_quantity,
output,
// quantity,
// tick_id,
// percentFilled,
Expand All @@ -35,7 +39,6 @@ export const tableColumns = [
baseAsset?.rawAsset.logoURIs.svg ??
baseAsset?.rawAsset.logoURIs.png ??
"";

return (
<div className="flex items-center gap-4">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-osmoverse-800">
Expand All @@ -56,18 +59,31 @@ export const tableColumns = [
{ "flex-row-reverse": order_direction === "bid" }
)}
>
<span>1000 {baseAsset?.symbol}</span>
<span>
{order_direction === "bid" ? output : placed_quantity}{" "}
{baseAsset?.symbol}
</span>
<Icon
id="arrow-right"
className="h-4 w-4"
width={16}
height={16}
/>
<span>0.123 {quoteAsset?.symbol}</span>
<span>
{order_direction === "bid" ? placed_quantity : output}{" "}
{quoteAsset?.symbol}
</span>
</p>
<div className="inline-flex items-center gap-2">
<span className="subtitle1 font-bold">
{order_direction === "bid" ? "Buy" : "Sell"} $1000 of
{order_direction === "bid" ? "Buy" : "Sell"}{" "}
{formatPretty(
new PricePretty(
DEFAULT_VS_CURRENCY,
order_direction === "bid" ? placed_quantity : output
)
)}{" "}
of
</span>
<Image
src={baseAssetLogo}
Expand All @@ -90,15 +106,15 @@ export const tableColumns = [
},
cell: ({
row: {
original: { baseAsset },
original: { baseAsset, price },
},
}) => {
return (
<div className="flex flex-col gap-1">
<p className="body2 text-osmoverse-300">
{baseAsset?.symbol} · Limit
</p>
<p>$67,890.10</p>
<p>{formatPretty(new PricePretty(DEFAULT_VS_CURRENCY, price))}</p>
</div>
);
},
Expand Down
26 changes: 2 additions & 24 deletions packages/web/hooks/limit-orders/use-orderbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,7 @@ export const useActiveLimitOrdersByOrderbook = ({
};
};

export type DisplayableLimitOrder = MappedLimitOrder & {
baseAsset: ReturnType<typeof getAssetFromAssetList>;
quoteAsset: ReturnType<typeof getAssetFromAssetList>;
};
export type DisplayableLimitOrder = MappedLimitOrder;

export const useOrderbookAllActiveOrders = ({
userAddress,
Expand Down Expand Up @@ -298,27 +295,8 @@ export const useOrderbookAllActiveOrders = ({
const allOrders = useMemo(() => {
return orders?.pages.flatMap((page) => page.items) ?? [];
}, [orders]);
const ordersWithDenoms: DisplayableLimitOrder[] = useMemo(() => {
return allOrders.map((o) => {
const orderbook = orderbooks.find(
(ob) => ob.contractAddress === o.orderbookAddress
);
return {
...o,
baseAsset: getAssetFromAssetList({
coinMinimalDenom: orderbook?.baseDenom ?? "",
assetLists: AssetLists,
}),
quoteAsset: getAssetFromAssetList({
coinMinimalDenom: orderbook?.quoteDenom ?? "",
assetLists: AssetLists,
}),
};
});
}, [allOrders, orderbooks]);

return {
orders: ordersWithDenoms,
orders: allOrders,
isLoading,
fetchNextPage,
isFetching,
Expand Down

0 comments on commit 56cea50

Please sign in to comment.