Skip to content

Commit

Permalink
feat: remove max apr, add hover card on avg apr in pools table
Browse files Browse the repository at this point in the history
  • Loading branch information
damnnou committed May 21, 2024
1 parent 2f0d047 commit a6b1777
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 38 deletions.
17 changes: 3 additions & 14 deletions src/components/common/Table/myPositionsColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,13 @@ export const myPositionsColumns: ColumnDef<MyPosition>[] = [
},
{
accessorKey: 'outOfRange',
header: ({ column }) => <HeaderItem sort={() => column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}>Status</HeaderItem>,
header: ({ column }) => <HeaderItem className='min-w-[100px]' sort={() => column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}>Status</HeaderItem>,
cell: ({ getValue }) => getValue() ? <span className="text-yellow-400">Out of range</span> : <span className="text-green-400">In range</span>
},
{
accessorKey: 'range',
header: () => <HeaderItem>Range</HeaderItem>,
cell: ({ getValue }) => {
const range = getValue() as string;
const minRange = "0.0000";
const maxRange = "338492131855223783712001310944818317035.9647"
const splittedRange = range.split(" — ");

if(splittedRange[0] === minRange && splittedRange[1] === maxRange) return "Full Range";
if(splittedRange[0] === minRange) splittedRange[0] = "0";
if(splittedRange[1] === maxRange) splittedRange[1] = "∞";

return splittedRange.join(" — ");
}
header: () => <HeaderItem className='min-w-[180px]'>Range</HeaderItem>,
cell: ({ getValue }) => getValue() as string,
},
{
accessorKey: 'apr',
Expand Down
41 changes: 30 additions & 11 deletions src/components/common/Table/poolsColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { usePoolPlugins } from "@/hooks/pools/usePoolPlugins";
import { Skeleton } from "@/components/ui/skeleton";
import { FarmingPluginIcon } from "../PluginIcons";
import { useCurrency } from "@/hooks/common/useCurrency";
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card";
import { formatPercent } from "@/utils/common/formatPercent";
import { ReactNode } from "react";

interface Pair {
token0: TokenFieldsFragment;
Expand All @@ -21,8 +24,10 @@ interface Pool {
fee: number;
tvlUSD: number;
volume24USD: number;
maxApr: number;
poolMaxApr: number;
poolAvgApr: number;
avgApr: number;
farmApr: number;
isMyPool: boolean;
hasActiveFarming: boolean;
}
Expand Down Expand Up @@ -63,6 +68,19 @@ const Plugins = ({ poolId }: { poolId: Address }) => {
);
};

const AvgAPR = ({ children, avgApr, farmApr, maxApr }: { children: ReactNode; avgApr: string; farmApr: string; maxApr: string }) => {
return (
<HoverCard>
<HoverCardTrigger>{children}</HoverCardTrigger>
<HoverCardContent>
<p>Avg. APR - {avgApr}</p>
<p>Farm APR - {farmApr}</p>
<p>Max APR - {maxApr}</p>
</HoverCardContent>
</HoverCard>
);
};

export const poolsColumns: ColumnDef<Pool>[] = [
{
accessorKey: "pair",
Expand Down Expand Up @@ -98,22 +116,23 @@ export const poolsColumns: ColumnDef<Pool>[] = [
),
cell: ({ getValue }) => formatUSD.format(getValue() as number),
},
{
accessorKey: "maxApr",
header: ({ column }) => (
<HeaderItem sort={() => column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}>
Max. APR
</HeaderItem>
),
cell: ({ getValue }) => `${getValue()} %`,
},
{
accessorKey: "avgApr",
header: ({ column }) => (
<HeaderItem sort={() => column.toggleSorting(column.getIsSorted() === "asc")} isAsc={column.getIsSorted() === "asc"}>
Avg. APR
</HeaderItem>
),
cell: ({ getValue }) => `${getValue()} %`,
cell: ({ getValue, row }) => {
return (
<AvgAPR
avgApr={formatPercent.format(row.original.poolAvgApr)}
maxApr={formatPercent.format(row.original.poolMaxApr)}
farmApr={formatPercent.format(row.original.farmApr)}
>
{formatPercent.format(getValue() as number)}
</AvgAPR>
);
},
},
];
7 changes: 7 additions & 0 deletions src/components/common/Table/poolsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ const PoolsTable = <TData, TValue>({
</Table>
{showPagination && (
<div className="flex items-center justify-end space-x-2 px-4 mt-auto">
<p className="mr-2">
{`${table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1} -
${Math.min(
table.getState().pagination.pageSize * (table.getState().pagination.pageIndex + 1),
table.getFilteredRowModel().rows.length
)} of ${table.getFilteredRowModel().rows.length}`}
</p>
<Button variant="outline" size="sm" onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
Previous
</Button>
Expand Down
39 changes: 28 additions & 11 deletions src/components/pools/PoolsList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { poolsColumns } from "@/components/common/Table/poolsColumns";
import { usePoolsListQuery, usePoolsVolumeDataQuery } from "@/graphql/generated/graphql";
import { useActiveFarmingsQuery, usePoolsListQuery, usePoolsVolumeDataQuery } from "@/graphql/generated/graphql";
import { useMemo } from "react";
import { Address } from "viem";
import { POOL_AVG_APR_API, POOL_MAX_APR_API, fetcher } from "@/constants/api";
import { ETERNAL_FARMINGS_API, POOL_AVG_APR_API, POOL_MAX_APR_API, fetcher } from "@/constants/api";
import useSWR from "swr";
import PoolsTable from "@/components/common/Table/poolsTable";
import { usePositions } from "@/hooks/positions/usePositions";
import { usePoolsStore } from "@/state/poolsStore";
import { farmingClient } from "@/graphql/clients";

const PoolsList = () => {
const { data: pools, loading: isPoolsListLoading } = usePoolsListQuery();
Expand All @@ -15,15 +15,24 @@ const PoolsList = () => {

const { data: poolsMaxApr, isLoading: isPoolsMaxAprLoading } = useSWR(POOL_MAX_APR_API, fetcher);
const { data: poolsAvgApr, isLoading: isPoolsAvgAprLoading } = useSWR(POOL_AVG_APR_API, fetcher);
const { data: farmingsAPR } = useSWR(ETERNAL_FARMINGS_API, fetcher);

const { positions, loading: isPositionsLoading } = usePositions();
const { data: activeFarmings, loading: isFarmingsLoading } = useActiveFarmingsQuery({
client: farmingClient,
});

const isLoading = isPoolsListLoading || isPoolsVolumeLoading || isPoolsMaxAprLoading || isPoolsAvgAprLoading || isPositionsLoading;
const { positions, loading: isPositionsLoading } = usePositions();

const { pluginsForPools } = usePoolsStore();
const isLoading =
isPoolsListLoading ||
isPoolsVolumeLoading ||
isPoolsMaxAprLoading ||
isPoolsAvgAprLoading ||
isPositionsLoading ||
isFarmingsLoading;

const formattedPools = useMemo(() => {
if (!pools?.pools || !poolsMaxApr || !poolsAvgApr || !poolsVolume?.poolDayDatas || !positions) return [];
if (isLoading || !pools || !poolsVolume || !positions) return [];

return pools.pools.map(({ id, token0, token1, fee, totalValueLockedUSD }) => {
const currentPool = poolsVolume.poolDayDatas.find((currPool) => currPool.pool.id === id);
Expand All @@ -34,8 +43,14 @@ const PoolsList = () => {
const msIn24Hours = 24 * 60 * 60 * 1000;

const openPositions = positions.filter((position) => position.pool.toLowerCase() === id.toLowerCase());
const activeFarming = activeFarmings?.eternalFarmings.find((farming) => farming.pool === id);
const hasActiveFarming = Boolean(activeFarming);

const poolMaxApr = poolsMaxApr[id] ? Number(poolsMaxApr[id].toFixed(2)) : 0;
const poolAvgApr = poolsAvgApr[id] ? Number(poolsAvgApr[id].toFixed(2)) : 0;
const farmApr = activeFarming ? farmingsAPR[activeFarming.id] : 0;

const hasActiveFarming = pluginsForPools[id as Address]?.farmingPlugin;
const avgApr = farmApr + poolAvgApr;

return {
id: id as Address,
Expand All @@ -46,13 +61,15 @@ const PoolsList = () => {
fee: Number(fee) / 10_000,
tvlUSD: Number(totalValueLockedUSD),
volume24USD: timeDifference <= msIn24Hours && currentPool ? currentPool.volumeUSD : 0,
maxApr: poolsMaxApr[id] ? poolsMaxApr[id].toFixed(2) : 0,
avgApr: poolsAvgApr[id] ? poolsAvgApr[id].toFixed(2) : 0,
poolMaxApr,
poolAvgApr,
farmApr,
avgApr,
isMyPool: openPositions?.length > 0,
hasActiveFarming,
};
});
}, [pools, poolsMaxApr, poolsAvgApr, poolsVolume, positions]);
}, [isLoading, pools, poolsVolume, positions, activeFarmings, poolsMaxApr, poolsAvgApr, farmingsAPR]);

return (
<div className="flex flex-col gap-4">
Expand Down
11 changes: 10 additions & 1 deletion src/graphql/queries/farmings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { gql } from '@apollo/client';
import { gql } from "@apollo/client";

export const ETERNAL_FARMINGS = gql`
query EternalFarmings($pool: Bytes) {
Expand Down Expand Up @@ -31,3 +31,12 @@ export const DEPOSITS = gql`
}
}
`;

export const ACTIVE_FARMINGS = gql`
query ActiveFarmings {
eternalFarmings(where: { isDeactivated: false }) {
pool
id
}
}
`;
3 changes: 2 additions & 1 deletion src/pages/Pool/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { usePositions } from '@/hooks/positions/usePositions';
import { FormattedPosition } from '@/types/formatted-position';
import { getPositionAPR } from '@/utils/positions/getPositionAPR';
import { getPositionFees } from '@/utils/positions/getPositionFees';
import { formatAmount } from '@/utils/common/formatAmount';
import { Position, ZERO } from '@cryptoalgebra/integral-sdk';
import { useWeb3Modal } from '@web3modal/wagmi/react';
import { MoveRightIcon } from 'lucide-react';
Expand Down Expand Up @@ -169,7 +170,7 @@ const PoolPage = () => {
outOfRange:
poolEntity.tickCurrent < position.tickLower ||
poolEntity.tickCurrent > position.tickUpper,
range: `${position.token0PriceLower.toFixed()}${position.token0PriceUpper.toFixed()}`,
range: `${formatAmount(position.token0PriceLower.toFixed(6), 6)}${formatAmount(position.token0PriceUpper.toFixed(6), 6)}`,
liquidityUSD: formatLiquidityUSD(position),
feesUSD: formatFeesUSD(idx),
apr: formatAPR(idx),
Expand Down
39 changes: 39 additions & 0 deletions src/utils/common/formatAmount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { formatCurrency } from "./formatCurrency";

export function formatAmount(amount: string, decimals = 3): string {
const amountNum = Number(amount);
const minAmount = 1 / 10 ** (decimals || 3);

if (amountNum === 0) return "0";
if (amountNum < minAmount) return `< ${minAmount}`;
if (amountNum < 1) return (Math.floor(amountNum / minAmount) * minAmount).toFixed(decimals);
if (amountNum < 100) return (Math.floor(amountNum * 100) / 100).toString();
if (amountNum < 10000) return Math.floor(amountNum).toString();

if (amountNum < 1000000000000000) return formatCurrency.format(Math.floor(amountNum * 100) / 100);

return "∞";
}

export function reverseFormatAmount(formattedNumber: string): number {
const suffixes: { [key: string]: number } = {
K: 1e3,
M: 1e6,
B: 1e9,
T: 1e12,
};

const suffix = formattedNumber.slice(-1);
const value = parseFloat(formattedNumber.slice(0, -1));

if (formattedNumber.startsWith("< ") || formattedNumber.startsWith("> ")) {
const value = parseFloat(formattedNumber.slice(2));
return value > 0 ? value : 0;
}

if (suffixes[suffix]) {
return value * suffixes[suffix];
} else {
return parseFloat(formattedNumber);
}
}

0 comments on commit a6b1777

Please sign in to comment.