From ae128e63ff41f938de0a18723f440a87836406e5 Mon Sep 17 00:00:00 2001 From: 0xMasayoshi <0xMasayoshi@protonmail.com> Date: Tue, 19 Nov 2024 20:42:16 +0700 Subject: [PATCH] feat: improve zap flow --- .../(evm)/[chainId]/pool/v2/add/page.tsx | 169 +++++++++++++----- .../src/app/(networks)/(evm)/api/zap/route.ts | 39 ++-- apps/web/src/lib/hooks/useZap.ts | 32 ++-- apps/web/src/ui/pool/AddSectionLegacy.tsx | 29 ++- apps/web/src/ui/pool/AddSectionWidget.tsx | 6 +- .../src/ui/pool/SmartPoolLiquidityWidget.tsx | 11 +- .../Add/SteerPositionZap.tsx | 169 ++++++++++++------ .../SteerStrategies/SteerBaseStrategy.tsx | 11 +- apps/web/src/ui/pool/ZapSectionLegacy.tsx | 160 ++++++++++++----- 9 files changed, 424 insertions(+), 202 deletions(-) diff --git a/apps/web/src/app/(networks)/(evm)/[chainId]/pool/v2/add/page.tsx b/apps/web/src/app/(networks)/(evm)/[chainId]/pool/v2/add/page.tsx index 79fa60f9ed..dd5dfcfb79 100644 --- a/apps/web/src/app/(networks)/(evm)/[chainId]/pool/v2/add/page.tsx +++ b/apps/web/src/app/(networks)/(evm)/[chainId]/pool/v2/add/page.tsx @@ -1,6 +1,8 @@ 'use client' import { PlusIcon } from '@heroicons/react-v1/solid' +import { SlippageToleranceStorageKey } from '@sushiswap/hooks' +import { createToast } from '@sushiswap/notifications' import { Button, Dots, FormSection, Loader } from '@sushiswap/ui' import { useRouter } from 'next/navigation' import { notFound } from 'next/navigation' @@ -22,10 +24,14 @@ import { } from 'src/lib/constants' import { isSushiSwapV2Pool } from 'src/lib/functions' import { useZap } from 'src/lib/hooks' +import { useSlippageTolerance } from 'src/lib/hooks/useSlippageTolerance' import { Web3Input } from 'src/lib/wagmi/components/web3-input' import { SushiSwapV2PoolState } from 'src/lib/wagmi/hooks/pools/hooks/useSushiSwapV2Pools' import { Checker } from 'src/lib/wagmi/systems/Checker' -import { CheckerProvider } from 'src/lib/wagmi/systems/Checker/Provider' +import { + CheckerProvider, + useApproved, +} from 'src/lib/wagmi/systems/Checker/Provider' import { PoolFinder } from 'src/lib/wagmi/systems/PoolFinder/PoolFinder' import { AddSectionPoolShareCardV2 } from 'src/ui/pool/AddSectionPoolShareCardV2' import { AddSectionReviewModalLegacy } from 'src/ui/pool/AddSectionReviewModalLegacy' @@ -46,7 +52,14 @@ import { Amount, Type, tryParseAmount } from 'sushi/currency' import { ZERO } from 'sushi/math' import { SushiSwapV2Pool } from 'sushi/pool/sushiswap-v2' import { SWRConfig } from 'swr' -import { useAccount, useEstimateGas, useSendTransaction } from 'wagmi' +import { SendTransactionReturnType } from 'viem' +import { + useAccount, + useEstimateGas, + usePublicClient, + useSendTransaction, +} from 'wagmi' +import { useRefetchBalances } from '~evm/_common/ui/balance-provider/use-refetch-balances' export default function Page({ params }: { params: { chainId: string } }) { const chainId = +params.chainId as ChainId @@ -54,7 +67,7 @@ export default function Page({ params }: { params: { chainId: string } }) { return notFound() } - const [useZap, setUseZap] = useState(false) + const [isZapModeEnabled, setIsZapModeEnabled] = useState(false) const router = useRouter() const [token0, setToken0] = useState( @@ -132,9 +145,9 @@ export default function Page({ params }: { params: { chainId: string } }) { isZapSupportedChainId(chainId) && poolState === SushiSwapV2PoolState.EXISTS ) { - setUseZap(true) + setIsZapModeEnabled(true) } else { - setUseZap(false) + setIsZapModeEnabled(false) } }, [poolState]) @@ -179,9 +192,12 @@ export default function Page({ params }: { params: { chainId: string } }) { > {isZapSupportedChainId(chainId) && poolState === SushiSwapV2PoolState.EXISTS ? ( - + ) : null} - {useZap ? ( + {isZapModeEnabled ? ( = ({ chainId, pool, poolState, title }) => { - const { address } = useAccount() +const ZapWidget: FC = (props) => { + return ( + + <_ZapWidget {...props} /> + + ) +} + +const _ZapWidget: FC = ({ + chainId, + pool, + poolState, + title, +}) => { + const client = usePublicClient() + + const { address, chain } = useAccount() + + const [slippageTolerance] = useSlippageTolerance( + SlippageToleranceStorageKey.AddLiquidity, + ) const [inputAmount, setInputAmount] = useState('') - const [inputCurrency, setInputCurrency] = useState( + const [inputCurrency, _setInputCurrency] = useState( defaultCurrency[chainId as keyof typeof defaultCurrency], ) + const setInputCurrency = useCallback((currency: Type) => { + _setInputCurrency(currency) + setInputAmount('') + }, []) + const parsedInputAmount = useMemo( () => tryParseAmount(inputAmount, inputCurrency) || @@ -241,8 +281,11 @@ const ZapWidget: FC = ({ chainId, pool, poolState, title }) => { tokenIn: inputCurrency.isNative ? NativeAddress : inputCurrency.address, amountIn: parsedInputAmount?.quotient?.toString(), tokenOut: pool?.liquidityToken.address, + slippage: slippageTolerance, }) + const { approved } = useApproved(APPROVE_TAG_ZAP_LEGACY) + const { data: estGas, isError: isEstGasError } = useEstimateGas({ chainId, account: address, @@ -250,7 +293,7 @@ const ZapWidget: FC = ({ chainId, pool, poolState, title }) => { data: zapResponse?.tx.data, value: zapResponse?.tx.value, query: { - enabled: Boolean(address && zapResponse?.tx), + enabled: Boolean(approved && address && zapResponse?.tx), }, }) @@ -260,7 +303,41 @@ const ZapWidget: FC = ({ chainId, pool, poolState, title }) => { : undefined }, [zapResponse, estGas]) - const { sendTransaction, isPending: isWritePending } = useSendTransaction() + const { refetchChain: refetchBalances } = useRefetchBalances() + + const onSuccess = useCallback( + (hash: SendTransactionReturnType) => { + if (!chain || !pool) return + + setInputAmount('') + + const receipt = client.waitForTransactionReceipt({ hash }) + receipt.then(() => { + refetchBalances(chain.id) + }) + + const ts = new Date().getTime() + void createToast({ + account: address, + type: 'mint', + chainId: chain.id, + txHash: hash, + promise: receipt, + summary: { + pending: `Zapping into the ${pool.token0.symbol}/${pool.token1.symbol} pair`, + completed: `Successfully zapped into the ${pool.token0.symbol}/${pool.token1.symbol} pair`, + failed: `Something went wrong when zapping into the ${pool.token0.symbol}/${pool.token1.symbol} pair`, + }, + timestamp: ts, + groupTimestamp: ts, + }) + }, + [refetchBalances, client, chain, address, pool], + ) + + const { sendTransaction, isPending: isWritePending } = useSendTransaction({ + mutation: { onSuccess }, + }) return ( <> @@ -280,44 +357,42 @@ const ZapWidget: FC = ({ chainId, pool, poolState, title }) => { loading={poolState === SushiSwapV2PoolState.LOADING} allowNative={isWNativeSupported(chainId)} /> - - - - + + + - - - - - - - - - + + + + + + + getAddress(receiver)), - ), - spender: z.optional(z.string().transform((spender) => getAddress(spender))), + receiver: z + .string() + .transform((receiver) => getAddress(receiver)) + .optional(), + spender: z + .string() + .transform((spender) => getAddress(spender)) + .optional(), amountIn: z.union([z.string(), z.array(z.string())]), - amountOut: z.optional(z.union([z.string(), z.array(z.string())])), - minAmountOut: z.optional(z.union([z.string(), z.array(z.string())])), - slippage: z.optional(z.string()), - fee: z.optional(z.union([z.string(), z.array(z.string())])), - feeReceiver: z.optional(z.string()), - disableAggregators: z.optional(z.string()), - ignoreAggregators: z.optional(z.string()), - ignoreStandards: z.optional(z.string()), - tokenIn: z.optional(z.union([z.string(), z.array(z.string())])), - tokenOut: z.optional(z.union([z.string(), z.array(z.string())])), - quote: z.optional(z.boolean()), + amountOut: z.union([z.string(), z.array(z.string())]).optional(), + minAmountOut: z.union([z.string(), z.array(z.string())]).optional(), + slippage: z.string().optional(), // BIPS + fee: z.union([z.string(), z.array(z.string())]).optional(), // BIPS + feeReceiver: z.string().optional(), + disableAggregators: z.string().optional(), + ignoreAggregators: z.string().optional(), + ignoreStandards: z.string().optional(), + tokenIn: z.union([z.string(), z.array(z.string())]).optional(), + tokenOut: z.union([z.string(), z.array(z.string())]).optional(), + quote: z.boolean().optional(), }) export const revalidate = 600 @@ -41,7 +44,7 @@ export async function GET(request: NextRequest) { const { quote, ...parsedParams } = schema.parse(params) const queryParams = new URLSearchParams( - Object.entries(params).reduce( + Object.entries(parsedParams).reduce( (accum: [string, string][], [key, value]) => { if (value !== undefined && value !== null) { if (Array.isArray(value)) { @@ -68,7 +71,7 @@ export async function GET(request: NextRequest) { }, ) - return new Response(response.body, { + return new Response(await response.text(), { status: response.status, headers: { 'Cache-Control': 'max-age=60, stale-while-revalidate=600', diff --git a/apps/web/src/lib/hooks/useZap.ts b/apps/web/src/lib/hooks/useZap.ts index 348104b49a..1b5647d246 100644 --- a/apps/web/src/lib/hooks/useZap.ts +++ b/apps/web/src/lib/hooks/useZap.ts @@ -1,6 +1,8 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query' import { isZapSupportedChainId } from 'src/config' import { ChainId } from 'sushi/chain' +import { TOKEN_CHOMPER_ADDRESS, isTokenChomperChainId } from 'sushi/config' +import { Percent } from 'sushi/math' import { Address, Hex } from 'viem' import { z } from 'zod' @@ -45,20 +47,12 @@ export type ZapResponse = z.infer type UseZapParams = { chainId: ChainId fromAddress?: Address - routingStrategy?: string receiver?: Address - spender?: Address amountIn: string | string[] - amountOut?: string | string[] - minAmountOut?: string | string[] - slippage?: string - fee?: string | string[] - feeReceiver?: string - disableRFQs?: boolean - ignoreAggregators?: string | string[] - ignoreStandards?: string | string[] tokenIn: Address | Address[] tokenOut?: Address | Address[] + slippage?: Percent + enableFee?: boolean query?: Omit, 'queryKey' | 'queryFn'> } @@ -68,7 +62,9 @@ export const useZap = ({ query, ...params }: UseZapParams) => { queryFn: async () => { const url = new URL('/api/zap', window.location.origin) - Object.entries(params).forEach(([key, value]) => { + const { enableFee = true, slippage, ..._params } = params + + Object.entries(_params).forEach(([key, value]) => { if (value !== undefined && value !== null) { if (Array.isArray(value)) { value.forEach((val) => url.searchParams.append(key, val)) @@ -78,6 +74,20 @@ export const useZap = ({ query, ...params }: UseZapParams) => { } }) + if (slippage) { + url.searchParams.set('slippage', slippage.multiply(100n).toFixed(0)) + } + + if (enableFee) { + url.searchParams.set('fee', '25') // 0.25% + url.searchParams.set( + 'feeReceiver', + isTokenChomperChainId(params.chainId) + ? TOKEN_CHOMPER_ADDRESS[params.chainId] + : '0xFF64C2d5e23e9c48e8b42a23dc70055EEC9ea098', + ) + } + const response = await fetch(url.toString(), { method: 'GET', headers: { diff --git a/apps/web/src/ui/pool/AddSectionLegacy.tsx b/apps/web/src/ui/pool/AddSectionLegacy.tsx index 0b6d21f649..a13a5930b2 100644 --- a/apps/web/src/ui/pool/AddSectionLegacy.tsx +++ b/apps/web/src/ui/pool/AddSectionLegacy.tsx @@ -3,7 +3,7 @@ import { V2Pool } from '@sushiswap/graph-client/data-api' import { useIsMounted } from '@sushiswap/hooks' import { Button } from '@sushiswap/ui' -import { FC, useCallback, useEffect, useMemo, useState } from 'react' +import { FC, useCallback, useMemo, useState } from 'react' import { isZapSupportedChainId } from 'src/config' import { APPROVE_TAG_ADD_LEGACY } from 'src/lib/constants' import { getSushiSwapRouterContractConfig } from 'src/lib/wagmi/hooks/contracts/useSushiSwapRouter' @@ -22,7 +22,9 @@ import { AddSectionWidget } from './AddSectionWidget' import { ZapSectionLegacy } from './ZapSectionLegacy' export const AddSectionLegacy: FC<{ pool: V2Pool }> = ({ pool }) => { - const [useZap, setUseZap] = useState(false) + const [isZapModeEnabled, setIsZapModeEnabled] = useState( + isZapSupportedChainId(pool.chainId), + ) const { token0, token1 } = useTokensFromPool(pool) @@ -30,23 +32,12 @@ export const AddSectionLegacy: FC<{ pool: V2Pool }> = ({ pool }) => { data: [poolState, _pool], } = useSushiSwapV2Pool(pool.chainId as SushiSwapV2ChainId, token0, token1) - useEffect(() => { - if ( - isZapSupportedChainId(pool.chainId) && - poolState === SushiSwapV2PoolState.EXISTS - ) { - setUseZap(true) - } else { - setUseZap(false) - } - }, [pool.chainId, poolState]) - - return useZap ? ( + return isZapModeEnabled ? ( ) : ( <_AddSectionLegacy @@ -56,7 +47,7 @@ export const AddSectionLegacy: FC<{ pool: V2Pool }> = ({ pool }) => { token0={token0} token1={token1} isFarm={!!pool.incentives && pool.incentives.length > 0} - setUseZap={setUseZap} + toggleZapMode={setIsZapModeEnabled} /> ) } @@ -68,7 +59,7 @@ interface AddSectionLegacyProps { token1: Type poolState: SushiSwapV2PoolState isFarm: boolean - setUseZap(value: boolean): void + toggleZapMode(value: boolean): void } const _AddSectionLegacy: FC = ({ @@ -78,7 +69,7 @@ const _AddSectionLegacy: FC = ({ token1, poolState, isFarm, - setUseZap, + toggleZapMode, }) => { const isMounted = useIsMounted() @@ -147,7 +138,7 @@ const _AddSectionLegacy: FC = ({ token1={token1} onInput0={onChangeToken0TypedAmount} onInput1={onChangeToken1TypedAmount} - setUseZap={setUseZap} + toggleZapMode={toggleZapMode} > = ({ onSelectToken1, onInput0, onInput1, - setUseZap, + toggleZapMode, children, }) => { return ( @@ -82,7 +82,7 @@ export const AddSectionWidget: FC = ({ {isZapSupportedChainId(chainId) ? (
- +
) : null}
diff --git a/apps/web/src/ui/pool/SmartPoolLiquidityWidget.tsx b/apps/web/src/ui/pool/SmartPoolLiquidityWidget.tsx index e31dead651..c435cdb5f9 100644 --- a/apps/web/src/ui/pool/SmartPoolLiquidityWidget.tsx +++ b/apps/web/src/ui/pool/SmartPoolLiquidityWidget.tsx @@ -19,7 +19,9 @@ interface SmartPoolLiquidityWidgetProps { export const SmartPoolLiquidityWidget: FC = ({ vault, }) => { - const [useZap, setUseZap] = useState(isZapSupportedChainId(vault.chainId)) + const [isZapModeEnabled, setIsZapModeEnabled] = useState( + isZapSupportedChainId(vault.chainId), + ) const { data: prices } = usePrices({ chainId: vault.chainId }) @@ -57,9 +59,12 @@ export const SmartPoolLiquidityWidget: FC = ({ } > {isZapSupportedChainId(vault.chainId) ? ( - + ) : null} - {useZap ? ( + {isZapModeEnabled ? ( ) : ( diff --git a/apps/web/src/ui/pool/Steer/SteerLiquidityManagement/Add/SteerPositionZap.tsx b/apps/web/src/ui/pool/Steer/SteerLiquidityManagement/Add/SteerPositionZap.tsx index cc67a1632b..3a1d6635d3 100644 --- a/apps/web/src/ui/pool/Steer/SteerLiquidityManagement/Add/SteerPositionZap.tsx +++ b/apps/web/src/ui/pool/Steer/SteerLiquidityManagement/Add/SteerPositionZap.tsx @@ -1,33 +1,65 @@ 'use client' import { VaultV1 } from '@sushiswap/graph-client/data-api' +import { SlippageToleranceStorageKey } from '@sushiswap/hooks' +import { createToast } from '@sushiswap/notifications' import { Button, Dots } from '@sushiswap/ui' -import React, { FC, useMemo, useState } from 'react' +import React, { FC, useCallback, useMemo, useState } from 'react' import { APPROVE_TAG_ZAP_STEER, NativeAddress } from 'src/lib/constants' import { useZap } from 'src/lib/hooks' +import { useSlippageTolerance } from 'src/lib/hooks/useSlippageTolerance' import { Web3Input } from 'src/lib/wagmi/components/web3-input' import { Checker } from 'src/lib/wagmi/systems/Checker' -import { CheckerProvider } from 'src/lib/wagmi/systems/Checker/Provider' +import { + CheckerProvider, + useApproved, +} from 'src/lib/wagmi/systems/Checker/Provider' import { ZapInfoCard } from 'src/ui/pool/ZapInfoCard' import { defaultCurrency, isWNativeSupported } from 'sushi/config' import { Amount, Type, tryParseAmount } from 'sushi/currency' -import { useAccount, useEstimateGas, useSendTransaction } from 'wagmi' +import { SendTransactionReturnType } from 'viem' +import { + useAccount, + useEstimateGas, + usePublicClient, + useSendTransaction, +} from 'wagmi' +import { useRefetchBalances } from '~evm/_common/ui/balance-provider/use-refetch-balances' -interface SteerPositionAddProps { +interface SteerPositionZapProps { vault: VaultV1 tokenRatios?: { token0: number; token1: number } } -export const SteerPositionZap: FC = ({ +export const SteerPositionZap: FC = (props) => { + return ( + + <_SteerPositionZap {...props} /> + + ) +} + +const _SteerPositionZap: FC = ({ vault, tokenRatios, }) => { - const { address } = useAccount() + const client = usePublicClient() + + const { address, chain } = useAccount() + + const [slippageTolerance] = useSlippageTolerance( + SlippageToleranceStorageKey.AddSteerLiquidity, + ) const [inputAmount, setInputAmount] = useState('') - const [inputCurrency, setInputCurrency] = useState( + const [inputCurrency, _setInputCurrency] = useState( defaultCurrency[vault.chainId as keyof typeof defaultCurrency], ) + const setInputCurrency = useCallback((currency: Type) => { + _setInputCurrency(currency) + setInputAmount('') + }, []) + const parsedInputAmount = useMemo( () => tryParseAmount(inputAmount, inputCurrency) || @@ -41,8 +73,11 @@ export const SteerPositionZap: FC = ({ tokenIn: inputCurrency.isNative ? NativeAddress : inputCurrency.address, amountIn: parsedInputAmount?.quotient?.toString(), tokenOut: vault.address, + slippage: slippageTolerance, }) + const { approved } = useApproved(APPROVE_TAG_ZAP_STEER) + const { data: estGas, isError: isEstGasError } = useEstimateGas({ chainId: vault.chainId, account: address, @@ -50,7 +85,7 @@ export const SteerPositionZap: FC = ({ data: zapResponse?.tx.data, value: zapResponse?.tx.value, query: { - enabled: Boolean(address && zapResponse?.tx), + enabled: Boolean(approved && address && zapResponse?.tx), }, }) @@ -60,7 +95,43 @@ export const SteerPositionZap: FC = ({ : undefined }, [zapResponse, estGas]) - const { sendTransaction, isPending: isWritePending } = useSendTransaction() + const { refetchChain: refetchBalances } = useRefetchBalances() + + const onSuccess = useCallback( + (hash: SendTransactionReturnType) => { + if (!chain) return + + setInputAmount('') + + const receipt = client.waitForTransactionReceipt({ hash }) + receipt.then(() => { + refetchBalances(chain.id) + }) + + const ts = new Date().getTime() + void createToast({ + account: address, + type: 'mint', + chainId: chain.id, + txHash: hash, + promise: receipt, + summary: { + pending: `Zapping into the ${vault.token0.symbol}/${vault.token1.symbol} smart pool`, + completed: `Successfully zapped into the ${vault.token0.symbol}/${vault.token1.symbol} smart pool`, + failed: `Something went wrong when zapping into the ${vault.token0.symbol}/${vault.token1.symbol} smart pool`, + }, + timestamp: ts, + groupTimestamp: ts, + }) + }, + [refetchBalances, client, chain, address, vault], + ) + + const { sendTransaction, isPending: isWritePending } = useSendTransaction({ + mutation: { + onSuccess, + }, + }) return (
@@ -75,53 +146,51 @@ export const SteerPositionZap: FC = ({ currency={inputCurrency} allowNative={isWNativeSupported(vault.chainId)} /> - - - - + + + - - - - - - - - - - - + + + + + + + + { - const [useZap, setUseZap] = useState(isZapSupportedChainId(vault.chainId)) + const [isZapModeEnabled, setIsZapModeEnabled] = useState( + isZapSupportedChainId(vault.chainId), + ) return (
@@ -92,9 +94,12 @@ export const SteerBaseStrategy: SteerStrategyComponent = ({ {isZapSupportedChainId(vault.chainId) ? ( - + ) : null} - {useZap ? ( + {isZapModeEnabled ? ( ) : ( diff --git a/apps/web/src/ui/pool/ZapSectionLegacy.tsx b/apps/web/src/ui/pool/ZapSectionLegacy.tsx index 79a1749ffa..49b8362745 100644 --- a/apps/web/src/ui/pool/ZapSectionLegacy.tsx +++ b/apps/web/src/ui/pool/ZapSectionLegacy.tsx @@ -2,6 +2,7 @@ import { Cog6ToothIcon } from '@heroicons/react/24/outline' import { SlippageToleranceStorageKey } from '@sushiswap/hooks' +import { createToast } from '@sushiswap/notifications' import { Button, Dots, @@ -15,12 +16,16 @@ import { WidgetHeader, WidgetTitle, } from '@sushiswap/ui' -import { FC, useMemo, useState } from 'react' +import { FC, useCallback, useMemo, useState } from 'react' import { APPROVE_TAG_ZAP_LEGACY, NativeAddress } from 'src/lib/constants' +import { useSlippageTolerance } from 'src/lib/hooks/useSlippageTolerance' import { Web3Input } from 'src/lib/wagmi/components/web3-input' import { SushiSwapV2PoolState } from 'src/lib/wagmi/hooks/pools/hooks/useSushiSwapV2Pools' import { Checker } from 'src/lib/wagmi/systems/Checker' -import { CheckerProvider } from 'src/lib/wagmi/systems/Checker/Provider' +import { + CheckerProvider, + useApproved, +} from 'src/lib/wagmi/systems/Checker/Provider' import { SushiSwapV2ChainId, defaultCurrency, @@ -28,7 +33,14 @@ import { } from 'sushi/config' import { Amount, Type, tryParseAmount } from 'sushi/currency' import { SushiSwapV2Pool } from 'sushi/pool' -import { useAccount, useEstimateGas, useSendTransaction } from 'wagmi' +import { SendTransactionReturnType } from 'viem' +import { + useAccount, + useEstimateGas, + usePublicClient, + useSendTransaction, +} from 'wagmi' +import { useRefetchBalances } from '~evm/_common/ui/balance-provider/use-refetch-balances' import { useZap } from '../../lib/hooks' import { ToggleZapCard } from './ToggleZapCard' import { ZapInfoCard } from './ZapInfoCard' @@ -37,21 +49,40 @@ interface ZapSectionLegacyProps { chainId: SushiSwapV2ChainId pool: SushiSwapV2Pool | null poolState: SushiSwapV2PoolState - setUseZap(value: boolean): void + toggleZapMode(value: boolean): void +} + +export const ZapSectionLegacy: FC = (props) => { + return ( + + <_ZapSectionLegacy {...props} /> + + ) } -export const ZapSectionLegacy: FC = ({ +const _ZapSectionLegacy: FC = ({ chainId, pool, poolState, - setUseZap, + toggleZapMode, }) => { - const { address } = useAccount() + const client = usePublicClient() + + const { address, chain } = useAccount() + + const [slippageTolerance] = useSlippageTolerance( + SlippageToleranceStorageKey.AddLiquidity, + ) const [inputAmount, setInputAmount] = useState('') - const [inputCurrency, setInputCurrency] = useState( + const [inputCurrency, _setInputCurrency] = useState( defaultCurrency[chainId as keyof typeof defaultCurrency], ) + const setInputCurrency = useCallback((currency: Type) => { + _setInputCurrency(currency) + setInputAmount('') + }, []) + const parsedInputAmount = useMemo( () => tryParseAmount(inputAmount, inputCurrency) || @@ -65,8 +96,11 @@ export const ZapSectionLegacy: FC = ({ tokenIn: inputCurrency.isNative ? NativeAddress : inputCurrency.address, amountIn: parsedInputAmount?.quotient?.toString(), tokenOut: pool?.liquidityToken.address, + slippage: slippageTolerance, }) + const { approved } = useApproved(APPROVE_TAG_ZAP_LEGACY) + const { data: estGas, isError: isEstGasError } = useEstimateGas({ chainId, account: address, @@ -74,7 +108,7 @@ export const ZapSectionLegacy: FC = ({ data: zapResponse?.tx.data, value: zapResponse?.tx.value, query: { - enabled: Boolean(address && zapResponse?.tx), + enabled: Boolean(approved && address && zapResponse?.tx), }, }) @@ -84,7 +118,41 @@ export const ZapSectionLegacy: FC = ({ : undefined }, [zapResponse, estGas]) - const { sendTransaction, isPending: isWritePending } = useSendTransaction() + const { refetchChain: refetchBalances } = useRefetchBalances() + + const onSuccess = useCallback( + (hash: SendTransactionReturnType) => { + if (!chain || !pool) return + + setInputAmount('') + + const receipt = client.waitForTransactionReceipt({ hash }) + receipt.then(() => { + refetchBalances(chain.id) + }) + + const ts = new Date().getTime() + void createToast({ + account: address, + type: 'mint', + chainId: chain.id, + txHash: hash, + promise: receipt, + summary: { + pending: `Zapping into the ${pool.token0.symbol}/${pool.token1.symbol} pair`, + completed: `Successfully zapped into the ${pool.token0.symbol}/${pool.token1.symbol} pair`, + failed: `Something went wrong when zapping into the ${pool.token0.symbol}/${pool.token1.symbol} pair`, + }, + timestamp: ts, + groupTimestamp: ts, + }) + }, + [refetchBalances, client, chain, address, pool], + ) + + const { sendTransaction, isPending: isWritePending } = useSendTransaction({ + mutation: { onSuccess }, + }) return ( @@ -116,7 +184,7 @@ export const ZapSectionLegacy: FC = ({
- +
= ({ />
- - - - + + + - - - - - - - - - + + + + + + +