diff --git a/apps/deposit-pool/src/app/page.tsx b/apps/deposit-pool/src/app/page.tsx index 1dc7916..0d91e26 100644 --- a/apps/deposit-pool/src/app/page.tsx +++ b/apps/deposit-pool/src/app/page.tsx @@ -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"; @@ -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 || @@ -142,7 +154,7 @@ export default function Page() { setValue("poolId", pool.id)} PoolItemInfo={PoolItemInfo} - pools={pools || []} + pools={allPools} selectedPool={selectedPool} isCheckDetailsCentered={false} /> diff --git a/apps/deposit-pool/src/components/PoolItemInfo.tsx b/apps/deposit-pool/src/components/PoolItemInfo.tsx index 8640df4..d3206b2 100644 --- a/apps/deposit-pool/src/components/PoolItemInfo.tsx +++ b/apps/deposit-pool/src/components/PoolItemInfo.tsx @@ -6,7 +6,7 @@ export function PoolItemInfo({ pool }: { pool: IPool }) { pool.dynamicData.aprItems.reduce((acc, { apr }) => acc + apr, 0) * 100; return ( -
+
TVL: ${formatNumber(pool.dynamicData.totalLiquidity, 2)} APR: {formatNumber(aprSumPct, 2)}%
diff --git a/apps/deposit-pool/src/components/TokenAmountInput.tsx b/apps/deposit-pool/src/components/TokenAmountInput.tsx index 19652bb..8a5be42 100644 --- a/apps/deposit-pool/src/components/TokenAmountInput.tsx +++ b/apps/deposit-pool/src/components/TokenAmountInput.tsx @@ -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"; @@ -16,6 +21,7 @@ export function TokenAmountInput({ tokenPrice?: number; updateTokenAmounts: (amount: string, address: Address) => void; }) { + const { context } = useIFrameContext(); const { register, control, setValue } = useFormContext(); const amount = useWatch({ @@ -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 (
@@ -93,18 +102,20 @@ export function TokenAmountInput({
{tokenBalanceAfterSwap && ( - +
+ Balance:{" "} - {Number.parseFloat( - formatNumber( - tokenBalanceAfterSwap, - 4, - "decimal", - "standard", - 0.0001, - ), - ).toString()} + {formatNumber( + tokenBalanceAfterSwap, + 4, + "decimal", + "standard", + 0.0001, + ).replace(/\.?0+$/, "")} {!buttonDisabled && (
)}
diff --git a/apps/deposit-pool/src/hooks/useSelectedPool.ts b/apps/deposit-pool/src/hooks/useSelectedPool.ts index b7f8c76..f7582f2 100644 --- a/apps/deposit-pool/src/hooks/useSelectedPool.ts +++ b/apps/deposit-pool/src/hooks/useSelectedPool.ts @@ -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 => { + if (!id || !chainId) return; + const chainName = BalancerChainName[chainId]; + return await BALANCER_GQL_CLIENT[chainId] + .request(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(); - 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; } diff --git a/packages/cow-hooks-ui/src/ui/TooltipBase.tsx b/packages/cow-hooks-ui/src/ui/TooltipBase.tsx index 303a5be..3af463f 100644 --- a/packages/cow-hooks-ui/src/ui/TooltipBase.tsx +++ b/packages/cow-hooks-ui/src/ui/TooltipBase.tsx @@ -12,12 +12,14 @@ export const InfoTooltip = ({ link, variant = "default", side = "top", + className, }: { // get type from the InfoTooltip component text?: Parameters[0]["content"]; link?: string; variant?: "default" | "question" | "error"; side?: "top" | "right" | "bottom" | "left"; + className?: string; }) => { if (!text) return null; @@ -38,6 +40,7 @@ export const InfoTooltip = ({ onFocusCapture={(e) => { e.stopPropagation(); }} + className={className} > {link ? ( diff --git a/packages/cow-hooks-ui/src/ui/WaitingSignature.tsx b/packages/cow-hooks-ui/src/ui/WaitingSignature.tsx index 81abe5d..c4c85ac 100644 --- a/packages/cow-hooks-ui/src/ui/WaitingSignature.tsx +++ b/packages/cow-hooks-ui/src/ui/WaitingSignature.tsx @@ -43,12 +43,7 @@ export function WaitingSignature({ ?.trim() || "An error occurred"}
-