Skip to content

Commit

Permalink
Merge pull request #59 from bleu/pedro/review-deposit-cow-amm-pt6
Browse files Browse the repository at this point in the history
Pedro/review deposit cow amm pt6
  • Loading branch information
yvesfracari authored Nov 21, 2024
2 parents 75fe968 + 0ed6f52 commit 80c8c84
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 31 deletions.
16 changes: 14 additions & 2 deletions apps/deposit-pool/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from "@bleu/cow-hooks-ui";
import { COW_NATIVE_TOKEN_ADDRESS } from "@bleu/utils";
import { ALL_SUPPORTED_CHAIN_IDS, type Address } from "@cowprotocol/cow-sdk";
import { useCallback, useState } from "react";
import { useCallback, useMemo, useState } from "react";
import { useFormContext, useWatch } from "react-hook-form";
import { PoolForm } from "#/components/PoolForm";
import { PoolItemInfo } from "#/components/PoolItemInfo";
Expand All @@ -34,6 +34,18 @@ export default function Page() {

const selectedPool = useSelectedPool();

const allPools = useMemo(() => {
if (!pools && !selectedPool) return [];
if (!selectedPool) return pools || [];
if (!pools) return [selectedPool];
return [...pools, selectedPool].filter((item, index, array) => {
return (
index ===
array.findIndex((obj) => obj.id.toLowerCase() === item.id.toLowerCase())
);
});
}, [pools, selectedPool]);

const loadHookInfo = useCallback(async () => {
if (
!context?.hookToEdit?.hook.callData ||
Expand Down Expand Up @@ -142,7 +154,7 @@ export default function Page() {
<PoolsDropdownMenu
onSelect={(pool: IPool) => setValue("poolId", pool.id)}
PoolItemInfo={PoolItemInfo}
pools={pools || []}
pools={allPools}
selectedPool={selectedPool}
isCheckDetailsCentered={false}
/>
Expand Down
2 changes: 1 addition & 1 deletion apps/deposit-pool/src/components/PoolItemInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function PoolItemInfo({ pool }: { pool: IPool }) {
pool.dynamicData.aprItems.reduce((acc, { apr }) => acc + apr, 0) * 100;

return (
<div className="flex text-left items-start flex-col gap-1 text-xs">
<div className="flex text-right items-end flex-col gap-1 text-xs">
<i>TVL: ${formatNumber(pool.dynamicData.totalLiquidity, 2)}</i>
<i>APR: {formatNumber(aprSumPct, 2)}%</i>
</div>
Expand Down
37 changes: 24 additions & 13 deletions apps/deposit-pool/src/components/TokenAmountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Button, Input, formatNumber } from "@bleu.builders/ui";
import { type IBalance, TokenLogoWithWeight } from "@bleu/cow-hooks-ui";
import {
type IBalance,
InfoTooltip,
TokenLogoWithWeight,
useIFrameContext,
} from "@bleu/cow-hooks-ui";
import { useCallback, useMemo } from "react";
import { useFormContext, useWatch } from "react-hook-form";
import type { Address } from "viem";
Expand All @@ -16,6 +21,7 @@ export function TokenAmountInput({
tokenPrice?: number;
updateTokenAmounts: (amount: string, address: Address) => void;
}) {
const { context } = useIFrameContext();
const { register, control, setValue } = useFormContext<FormType>();

const amount = useWatch({
Expand Down Expand Up @@ -52,10 +58,13 @@ export function TokenAmountInput({

const disabled = amountType !== "userInput";

const isSellOrder = context?.orderParams?.kind === "sell";

const buttonDisabled =
disabled ||
Number(tokenBalanceAfterSwap) <= 0 ||
amount === tokenBalanceAfterSwap;
amount === tokenBalanceAfterSwap ||
isSellOrder;

return (
<div className="grid grid-cols-2 min-h-24 w-full bg-muted text-muted-foreground rounded-xl p-3">
Expand Down Expand Up @@ -93,18 +102,20 @@ export function TokenAmountInput({
<div className="flex items-center justify-between col-span-2">
<div className="flex items-center justify-start">
{tokenBalanceAfterSwap && (
<span>
<div className="flex items-center">
<InfoTooltip
className="opacity-70"
text="Estimated balance, it might change depending of order and fee update."
/>
<span className="ml-1 text-xs font-normal opacity-70">
Balance:{" "}
{Number.parseFloat(
formatNumber(
tokenBalanceAfterSwap,
4,
"decimal",
"standard",
0.0001,
),
).toString()}
{formatNumber(
tokenBalanceAfterSwap,
4,
"decimal",
"standard",
0.0001,
).replace(/\.?0+$/, "")}
</span>
{!buttonDisabled && (
<Button
Expand All @@ -122,7 +133,7 @@ export function TokenAmountInput({
Max
</Button>
)}
</span>
</div>
)}
</div>
<div className="flex items-center justify-end">
Expand Down
151 changes: 142 additions & 9 deletions apps/deposit-pool/src/hooks/useSelectedPool.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,147 @@
import { useMemo } from "react";
import { useFormContext, useWatch } from "react-hook-form";
import type { FormType } from "#/types";
import { type IPool, useIFrameContext } from "@bleu/cow-hooks-ui";
import { BALANCER_GQL_CLIENT, BalancerChainName } from "@bleu/utils";
import type { SupportedChainId } from "@cowprotocol/cow-sdk";
import { gql } from "graphql-request";
import { useEffect } from "react";
import { useWatch } from "react-hook-form";
import useSWR from "swr";
import { type Address, parseUnits } from "viem";
import { useTokenBuyPools } from "./useTokenBuyPools";

interface IQuery {
pool: {
id: `0x${string}`;
chain: string;
address: Address;
type: string;
decimals: number;
symbol: string;
protocolVersion: 1 | 2 | 3;
dynamicData: {
aprItems: {
apr: number;
id: string;
}[];
totalLiquidity: string;
volume24h: string;
totalShares: string;
};
allTokens: {
address: Address;
symbol: string;
decimals: number;
isNested: boolean;
weight: number;
}[];
userBalance: {
walletBalance: string;
walletBalanceUsd: number;
stakedBalances: {
balance: string;
stakingId: string;
}[];
};
};
}

const POOL_QUERY = gql`
query GetPool($id: String!, $chainName: GqlChain!) {
pool: poolGetPool(id: $id, chain: $chainName) {
id
chain
decimals
symbol
address
type
protocolVersion
dynamicData {
aprItems {
apr
id
}
totalLiquidity
volume24h
totalShares
}
allTokens {
address
symbol
decimals
isNested
weight
}
userBalance {
walletBalance
walletBalanceUsd
stakedBalances {
balance
stakingId
}
}
}
}
`;

export function usePool(id?: string, chainId?: SupportedChainId) {
return useSWR(
[id, chainId],
async ([id, chainId]): Promise<IPool | undefined> => {
if (!id || !chainId) return;
const chainName = BalancerChainName[chainId];
return await BALANCER_GQL_CLIENT[chainId]
.request<IQuery>(POOL_QUERY, {
id,
chainName,
})
.then((result) => {
const pool = result.pool;
return {
...pool,
userBalance: {
...pool.userBalance,
walletBalance: parseUnits(
pool.userBalance.walletBalance,
pool.decimals,
),
stakedBalances: pool.userBalance.stakedBalances.map((staked) => ({
balance: parseUnits(
Number(staked.balance).toFixed(pool.decimals),
pool.decimals,
),
stakingId: staked.stakingId,
})),
},
dynamicData: {
...pool.dynamicData,
totalShares: parseUnits(
Number(pool.dynamicData.totalShares).toFixed(pool.decimals),
pool.decimals,
),
},
};
});
},
{
revalidateOnFocus: false,
},
);
}

export function useSelectedPool() {
const { context } = useIFrameContext();

const { data: pools } = useTokenBuyPools();
const { control } = useFormContext<FormType>();
const poolId = useWatch({ control, name: "poolId" });
return useMemo(
() => pools?.find((pool) => pool.id === poolId),
[pools, poolId],
);
const poolId = useWatch({ name: "poolId" });
const { data, mutate } = usePool(poolId, context?.chainId);

useEffect(() => {
if (!pools || !poolId) return;
const newSelectedPool = pools?.find((pool) => pool.id === poolId);

if (!newSelectedPool) return;

mutate(newSelectedPool);
}, [poolId, pools, mutate]);

return data;
}
3 changes: 3 additions & 0 deletions packages/cow-hooks-ui/src/ui/TooltipBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ export const InfoTooltip = ({
link,
variant = "default",
side = "top",
className,
}: {
// get type from the InfoTooltip component
text?: Parameters<typeof Tooltip>[0]["content"];
link?: string;
variant?: "default" | "question" | "error";
side?: "top" | "right" | "bottom" | "left";
className?: string;
}) => {
if (!text) return null;

Expand All @@ -38,6 +40,7 @@ export const InfoTooltip = ({
onFocusCapture={(e) => {
e.stopPropagation();
}}
className={className}
>
{link ? (
<a href={link} target="_blank" rel="noreferrer">
Expand Down
7 changes: 1 addition & 6 deletions packages/cow-hooks-ui/src/ui/WaitingSignature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,7 @@ export function WaitingSignature({
?.trim() || "An error occurred"}
</span>
<div className="flex gap-2">
<Button
type="button"
variant="destructive"
className="bg-destructive/15 hover:bg-destructive/50"
onClick={() => mutate()}
>
<Button type="button" onClick={() => mutate()}>
Try again
</Button>
<Button
Expand Down

0 comments on commit 80c8c84

Please sign in to comment.