diff --git a/lib/modules/swap/SwapDetails.tsx b/lib/modules/swap/SwapDetails.tsx deleted file mode 100644 index 91cf48a9c..000000000 --- a/lib/modules/swap/SwapDetails.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import { NumberText } from '@/lib/shared/components/typography/NumberText' -import { useCurrency } from '@/lib/shared/hooks/useCurrency' -import { bn, fNum } from '@/lib/shared/utils/numbers' -import { HStack, VStack, Text, Tooltip, Box } from '@chakra-ui/react' -import { useSwap } from './SwapProvider' -import { GqlSorSwapType } from '@/lib/shared/services/api/generated/graphql' -import { useUserSettings } from '../user/settings/UserSettingsProvider' -import { usePriceImpact } from '@/lib/modules/price-impact/PriceImpactProvider' -import { SdkSimulateSwapResponse } from './swap.types' -import { DefaultSwapHandler } from './handlers/DefaultSwap.handler' -import { useTokens } from '../tokens/TokensProvider' -import { NativeWrapHandler } from './handlers/NativeWrap.handler' -import { InfoIcon } from '@/lib/shared/components/icons/InfoIcon' -import pluralize from 'pluralize' - -export function OrderRoute() { - const { simulationQuery } = useSwap() - - const queryData = simulationQuery.data as SdkSimulateSwapResponse - const orderRouteVersion = queryData ? queryData.protocolVersion : 2 - const hopCount = queryData.routes[0]?.hops?.length ?? 0 - - return ( - - Order route - - - BV{orderRouteVersion}: {hopCount} {pluralize('hop', hopCount)} - - - - - - - ) -} - -export function SwapDetails() { - const { toCurrency } = useCurrency() - const { slippage, slippageDecimal } = useUserSettings() - const { usdValueForToken } = useTokens() - const { tokenInInfo, tokenOutInfo, swapType, tokenIn, tokenOut, handler } = useSwap() - - const { priceImpactLevel, priceImpactColor, PriceImpactIcon, priceImpact } = usePriceImpact() - - const isDefaultSwap = handler instanceof DefaultSwapHandler - const isNativeWrapOrUnwrap = handler instanceof NativeWrapHandler - - const _slippage = isNativeWrapOrUnwrap ? 0 : slippage - const _slippageDecimal = isNativeWrapOrUnwrap ? 0 : slippageDecimal - - const returnAmountUsd = - swapType === GqlSorSwapType.ExactIn - ? usdValueForToken(tokenOutInfo, tokenOut.amount) - : usdValueForToken(tokenInInfo, tokenIn.amount) - - const priceImpactLabel = priceImpact ? fNum('priceImpact', priceImpact) : '-' - const priceImpacUsd = bn(priceImpact || 0).times(returnAmountUsd) - const maxSlippageUsd = bn(_slippage).div(100).times(returnAmountUsd) - - const isExactIn = swapType === GqlSorSwapType.ExactIn - - const limitLabel = isExactIn ? "You'll get at least" : "You'll pay at most" - const limitToken = isExactIn ? tokenOutInfo : tokenInInfo - const limitValue = isExactIn - ? bn(tokenOut.amount).minus(bn(tokenOut.amount).times(_slippageDecimal)).toString() - : bn(tokenIn.amount).plus(bn(tokenIn.amount).times(_slippageDecimal)).toString() - const limitTooltip = isExactIn - ? 'You will get at least this amount of token out.' - : 'You will pay at most this amount of token in.' - - const slippageLabel = isExactIn - ? `This is the maximum slippage that the swap will allow. - It is based on the quoted amount out minus your slippage tolerance, using current market prices. - You can change your slippage tolerance in your settings.` - : `This is the maximum slippage that the swap will allow. - It is based on the quoted amount in plus your slippage tolerance, using current market prices. - You can change your slippage tolerance in your settings.` - - return ( - - - Price impact - - {priceImpactLevel === 'unknown' ? ( - Unknown - ) : ( - - -{toCurrency(priceImpacUsd, { abbreviated: false })} (-{priceImpactLabel}) - - )} - - {priceImpactLevel === 'low' ? ( - - ) : ( - - - - )} - - - - - Max slippage - - - -{toCurrency(maxSlippageUsd, { abbreviated: false })} (-{fNum('slippage', _slippage)}) - - - - - - - - {limitLabel} - - - {fNum('token', limitValue, { abbreviated: false })} {limitToken?.symbol} - - - - - - - - {isDefaultSwap && } - - ) -} diff --git a/lib/modules/swap/SwapForm.tsx b/lib/modules/swap/SwapForm.tsx index e2f0018ca..68a4c97dc 100644 --- a/lib/modules/swap/SwapForm.tsx +++ b/lib/modules/swap/SwapForm.tsx @@ -1,110 +1,11 @@ 'use client' -import { TokenInput } from '@/lib/modules/tokens/TokenInput/TokenInput' -import { GqlChain, GqlToken } from '@/lib/shared/services/api/generated/graphql' -import { HumanAmount } from '@balancer/sdk' -import { - Card, - Center, - HStack, - VStack, - Tooltip, - useDisclosure, - IconButton, - Button, - Box, - CardHeader, - CardFooter, - CardBody, -} from '@chakra-ui/react' -import { useRef, useState } from 'react' -import { useSwap } from './SwapProvider' -import { TokenSelectModal } from '../tokens/TokenSelectModal/TokenSelectModal' -import { Address } from 'viem' -import { SwapPreviewModal } from './modal/SwapModal' -import { TransactionSettings } from '../user/settings/TransactionSettings' -import { PriceImpactAccordion } from '../price-impact/PriceImpactAccordion' -import { ChainSelect } from '../chains/ChainSelect' -import { CheckCircle, Link, Repeat } from 'react-feather' -import { SwapRate } from './SwapRate' -import { SwapDetails } from './SwapDetails' -import { capitalize } from 'lodash' -import { motion, easeOut } from 'framer-motion' import FadeInOnView from '@/lib/shared/components/containers/FadeInOnView' -import { ErrorAlert } from '@/lib/shared/components/errors/ErrorAlert' -import { useIsMounted } from '@/lib/shared/hooks/useIsMounted' -import { parseSwapError } from './swap.helpers' -import { useUserAccount } from '../web3/UserAccountProvider' -import { ConnectWallet } from '../web3/ConnectWallet' -import { SafeAppAlert } from '@/lib/shared/components/alerts/SafeAppAlert' +import { Card, CardBody, Center, VStack } from '@chakra-ui/react' +import { useSwap } from './SwapProvider' export function SwapForm() { - const { - tokenIn, - tokenOut, - selectedChain, - tokens, - tokenSelectKey, - isDisabled, - disabledReason, - previewModalDisclosure, - simulationQuery, - swapAction, - swapTxHash, - transactionSteps, - setSelectedChain, - setTokenInAmount, - setTokenOutAmount, - setTokenSelectKey, - setTokenIn, - setTokenOut, - switchTokens, - setNeedsToAcceptHighPI, - resetSwapAmounts, - replaceUrlPath, - } = useSwap() - const [copiedDeepLink, setCopiedDeepLink] = useState(false) - const tokenSelectDisclosure = useDisclosure() - const nextBtn = useRef(null) - const finalRefTokenIn = useRef(null) - const finalRefTokenOut = useRef(null) - const isMounted = useIsMounted() - const { isConnected } = useUserAccount() - - const isLoadingSwaps = simulationQuery.isLoading - const isLoading = isLoadingSwaps || !isMounted - const loadingText = isLoading ? 'Fetching swap...' : undefined - - function copyDeepLink() { - navigator.clipboard.writeText(window.location.href) - setCopiedDeepLink(true) - setTimeout(() => setCopiedDeepLink(false), 2000) - } - - function handleTokenSelect(token: GqlToken) { - if (!token) return - if (tokenSelectKey === 'tokenIn') { - setTokenIn(token.address as Address) - } else if (tokenSelectKey === 'tokenOut') { - setTokenOut(token.address as Address) - } else { - console.error('Unhandled token select key', tokenSelectKey) - } - } - - function openTokenSelectModal(tokenSelectKey: 'tokenIn' | 'tokenOut') { - setTokenSelectKey(tokenSelectKey) - tokenSelectDisclosure.onOpen() - } - - function onModalClose() { - previewModalDisclosure.onClose() - if (swapTxHash) { - resetSwapAmounts() - replaceUrlPath() - transactionSteps.resetTransactionSteps() - } - } + const { tokenIn, tokenOut, selectedChain } = useSwap() return ( @@ -117,134 +18,17 @@ export function SwapForm() { left={['-12px', '0']} > - - {capitalize(swapAction)} - - - - - - - - - - { - setSelectedChain(newValue as GqlChain) - setTokenInAmount('') - }} - /> - setTokenInAmount(e.currentTarget.value as HumanAmount)} - toggleTokenSelect={() => openTokenSelectModal('tokenIn')} - /> - - } - onClick={switchTokens} - /> - - setTokenOutAmount(e.currentTarget.value as HumanAmount)} - toggleTokenSelect={() => openTokenSelectModal('tokenOut')} - hasPriceImpact - disableBalanceValidation - isLoadingPriceImpact={ - simulationQuery.isLoading || !simulationQuery.data || !tokenIn.amount - } - /> + {selectedChain &&
selectedChain {selectedChain}
} + {tokenIn &&
tokenIn.address {tokenIn.address}
} + {tokenOut &&
tokenOut.address {tokenOut.address}
}
- {!!simulationQuery.data && ( - - } - accordionPanelComponent={} - isDisabled={!simulationQuery.data} - /> - - )} - - {simulationQuery.isError && ( - - {parseSwapError(simulationQuery.error?.message)} - - )}
- - {isConnected ? ( - - - - ) : ( - - )} -
- -
) } diff --git a/lib/modules/swap/SwapProvider.tsx b/lib/modules/swap/SwapProvider.tsx index 5a28b4ff6..87f06a055 100644 --- a/lib/modules/swap/SwapProvider.tsx +++ b/lib/modules/swap/SwapProvider.tsx @@ -1,53 +1,15 @@ 'use client' /* eslint-disable react-hooks/exhaustive-deps */ -import { getNetworkConfig } from '@/lib/config/app.config' -import { GqlChain, GqlSorSwapType, GqlToken } from '@/lib/shared/services/api/generated/graphql' +import { GqlChain, GqlSorSwapType } from '@/lib/shared/services/api/generated/graphql' import { useMandatoryContext } from '@/lib/shared/utils/contexts' -import { ApolloClient, useApolloClient, useReactiveVar } from '@apollo/client' -import { PropsWithChildren, createContext, useEffect, useMemo, useState } from 'react' -import { Address, Hash, isAddress, parseUnits } from 'viem' -import { emptyAddress } from '../web3/contracts/wagmi-helpers' -import { useUserAccount } from '../web3/UserAccountProvider' -import { LABELS } from '@/lib/shared/labels' -import { isDisabledWithReason } from '@/lib/shared/utils/functions/isDisabledWithReason' -import { DefaultSwapHandler } from './handlers/DefaultSwap.handler' -import { bn } from '@/lib/shared/utils/numbers' -import { useSimulateSwapQuery } from './queries/useSimulateSwapQuery' -import { useTokens } from '../tokens/TokensProvider' import { useDisclosure } from '@chakra-ui/react' -import { useSwapSteps } from './useSwapSteps' -import { - OSwapAction, - SdkSimulateSwapResponse, - SimulateSwapResponse, - SwapAction, - SwapState, -} from './swap.types' -import { SwapHandler } from './handlers/Swap.handler' -import { isSameAddress, selectByAddress } from '@/lib/shared/utils/addresses' -import { useVault } from '@/lib/shared/hooks/useVault' -import { NativeWrapHandler } from './handlers/NativeWrap.handler' -import { - getWrapHandlerClass, - getWrapType, - getWrapperForBaseToken, - isNativeWrap, - isSupportedWrap, - isWrapOrUnwrap, -} from './wrap.helpers' -import { useTokenInputsValidation } from '../tokens/TokenInputsValidationProvider' -import { useMakeVarPersisted } from '@/lib/shared/hooks/useMakeVarPersisted' -import { HumanAmount } from '@balancer/sdk' -import { ChainSlug, chainToSlugMap, slugToChainMap } from '../pool/pool.utils' -import { invert } from 'lodash' -import { useTransactionSteps } from '../transactions/transaction-steps/useTransactionSteps' +import { PropsWithChildren, createContext, useEffect, useState } from 'react' +import { Hash } from 'viem' import { useTokenBalances } from '../tokens/TokenBalancesProvider' -import { useNetworkConfig } from '@/lib/config/useNetworkConfig' -import { usePriceImpact } from '../price-impact/PriceImpactProvider' -import { calcMarketPriceImpact } from '../price-impact/price-impact.utils' -import { isAuraBalSwap } from './swap.helpers' -import { AuraBalSwapHandler } from './handlers/AuraBalSwap.handler' +import { useTokens } from '../tokens/TokensProvider' +import { emptyAddress } from '../web3/contracts/wagmi-helpers' +import { SwapState } from './swap.types' export type UseSwapResponse = ReturnType export const SwapContext = createContext(null) @@ -62,510 +24,59 @@ export type PathParams = { urlTxHash?: Hash } -function selectSwapHandler( - tokenInAddress: Address, - tokenOutAddress: Address, - chain: GqlChain, - swapType: GqlSorSwapType, - apolloClient: ApolloClient, - tokens: GqlToken[] -): SwapHandler { - if (isNativeWrap(tokenInAddress, tokenOutAddress, chain)) { - return new NativeWrapHandler(apolloClient) - } else if (isSupportedWrap(tokenInAddress, tokenOutAddress, chain)) { - const WrapHandler = getWrapHandlerClass(tokenInAddress, tokenOutAddress, chain) - return new WrapHandler() - } else if (isAuraBalSwap(tokenInAddress, tokenOutAddress, chain, swapType)) { - return new AuraBalSwapHandler(tokens) - } - - return new DefaultSwapHandler(apolloClient) -} - export function _useSwap({ urlTxHash, ...pathParams }: PathParams) { - const swapStateVar = useMakeVarPersisted( - { - tokenIn: { - address: emptyAddress, - amount: '', - scaledAmount: BigInt(0), - }, - tokenOut: { - address: emptyAddress, - amount: '', - scaledAmount: BigInt(0), - }, - swapType: GqlSorSwapType.ExactIn, - selectedChain: GqlChain.Mainnet, + const initialSwapState = { + tokenIn: { + address: emptyAddress, + amount: '', + scaledAmount: BigInt(0), + }, + tokenOut: { + address: emptyAddress, + amount: '', + scaledAmount: BigInt(0), }, - 'swapState' - ) + swapType: GqlSorSwapType.ExactIn, + selectedChain: GqlChain.Mainnet, + } + + const [swapState] = useState(initialSwapState) - const swapState = useReactiveVar(swapStateVar) - const [needsToAcceptHighPI, setNeedsToAcceptHighPI] = useState(false) const [tokenSelectKey, setTokenSelectKey] = useState<'tokenIn' | 'tokenOut'>('tokenIn') - const [initUserChain, setInitUserChain] = useState(undefined) - const { isConnected } = useUserAccount() - const { chain: walletChain } = useNetworkConfig() - const { getToken, getTokensByChain, usdValueForToken } = useTokens() - const { tokens, setTokens } = useTokenBalances() - const { hasValidationErrors } = useTokenInputsValidation() - const { setPriceImpact, setPriceImpactLevel } = usePriceImpact() + const { getToken } = useTokens() + const { tokens } = useTokenBalances() - const networkConfig = getNetworkConfig(swapState.selectedChain) const previewModalDisclosure = useDisclosure() - const client = useApolloClient() - const handler = useMemo( - () => - selectSwapHandler( - swapState.tokenIn.address, - swapState.tokenOut.address, - swapState.selectedChain, - swapState.swapType, - client, - tokens - ), - [swapState.tokenIn.address, swapState.tokenOut.address, swapState.selectedChain] - ) - - const isTokenInSet = swapState.tokenIn.address !== emptyAddress - const isTokenOutSet = swapState.tokenOut.address !== emptyAddress - const tokenInInfo = getToken(swapState.tokenIn.address, swapState.selectedChain) const tokenOutInfo = getToken(swapState.tokenOut.address, swapState.selectedChain) - if ((isTokenInSet && !tokenInInfo) || (isTokenOutSet && !tokenOutInfo)) { - try { - setDefaultTokens() - } catch (error) { - throw new Error('Token metadata not found') - } - } - - const tokenInUsd = usdValueForToken(tokenInInfo, swapState.tokenIn.amount) - const tokenOutUsd = usdValueForToken(tokenOutInfo, swapState.tokenOut.amount) - - const shouldFetchSwap = (state: SwapState, urlTxHash?: Hash) => { - if (urlTxHash) return false - return ( - isAddress(state.tokenIn.address) && - isAddress(state.tokenOut.address) && - !!state.swapType && - bn(getSwapAmount(swapState)).gt(0) - ) - } - - const getSwapAmount = (state: SwapState) => - (state.swapType === GqlSorSwapType.ExactIn ? state.tokenIn.amount : state.tokenOut.amount) || - '0' - - const simulationQuery = useSimulateSwapQuery({ - handler, - swapInputs: { - chain: swapState.selectedChain, - tokenIn: swapState.tokenIn.address, - tokenOut: swapState.tokenOut.address, - swapType: swapState.swapType, - swapAmount: getSwapAmount(swapState), - }, - enabled: shouldFetchSwap(swapState, urlTxHash), - }) - - function handleSimulationResponse({ returnAmount, swapType }: SimulateSwapResponse) { - swapStateVar({ - ...swapState, - swapType, - }) - - if (swapType === GqlSorSwapType.ExactIn) { - setTokenOutAmount(returnAmount, { userTriggered: false }) - } else { - setTokenInAmount(returnAmount, { userTriggered: false }) - } - } - - function setSelectedChain(_selectedChain: GqlChain) { - const defaultTokenState = getDefaultTokenState(_selectedChain) - swapStateVar(defaultTokenState) - } - - function setTokenIn(tokenAddress: Address) { - const isSameAsTokenOut = isSameAddress(tokenAddress, swapState.tokenOut.address) - - swapStateVar({ - ...swapState, - tokenIn: { - ...swapState.tokenIn, - address: tokenAddress, - }, - tokenOut: isSameAsTokenOut - ? { ...swapState.tokenOut, address: emptyAddress } - : swapState.tokenOut, - }) - } - - function setTokenOut(tokenAddress: Address) { - const isSameAsTokenIn = isSameAddress(tokenAddress, swapState.tokenIn.address) - - swapStateVar({ - ...swapState, - tokenOut: { - ...swapState.tokenOut, - address: tokenAddress, - }, - tokenIn: isSameAsTokenIn - ? { ...swapState.tokenIn, address: emptyAddress } - : swapState.tokenIn, - }) - } - - function switchTokens() { - swapStateVar({ - ...swapState, - tokenIn: swapState.tokenOut, - tokenOut: swapState.tokenIn, - swapType: GqlSorSwapType.ExactIn, - }) - setTokenInAmount('', { userTriggered: false }) - setTokenOutAmount('', { userTriggered: false }) - } - - function setTokenInAmount( - amount: string, - { userTriggered = true }: { userTriggered?: boolean } = {} - ) { - const state = swapStateVar() - const newState = { - ...state, - tokenIn: { - ...state.tokenIn, - amount, - scaledAmount: scaleTokenAmount(amount, tokenInInfo), - }, - } - - if (userTriggered) { - swapStateVar({ - ...newState, - swapType: GqlSorSwapType.ExactIn, - }) - setTokenOutAmount('', { userTriggered: false }) - } else { - // Sometimes we want to set the amount without triggering a fetch or - // swapType change, like when we populate the amount after a change from the other input. - swapStateVar(newState) - } - } - - function setTokenOutAmount( - amount: string, - { userTriggered = true }: { userTriggered?: boolean } = {} - ) { - const state = swapStateVar() - const newState = { - ...state, - tokenOut: { - ...state.tokenOut, - amount, - scaledAmount: scaleTokenAmount(amount, tokenOutInfo), - }, - } - - if (userTriggered) { - swapStateVar({ - ...newState, - swapType: GqlSorSwapType.ExactOut, - }) - setTokenInAmount('', { userTriggered: false }) - } else { - // Sometimes we want to set the amount without triggering a fetch or - // swapType change, like when we populate the amount after a change from - // the other input. - swapStateVar(newState) - } - } - - function getDefaultTokenState(chain: GqlChain) { - const { - tokens: { defaultSwapTokens }, - } = getNetworkConfig(chain) - const { tokenIn, tokenOut } = defaultSwapTokens || {} - - return { - swapType: GqlSorSwapType.ExactIn, - selectedChain: chain, - tokenIn: { - ...swapState.tokenIn, - address: tokenIn ? tokenIn : emptyAddress, - }, - tokenOut: { - ...swapState.tokenOut, - address: tokenOut ? tokenOut : emptyAddress, - }, - } - } - - function resetSwapAmounts() { - const state = swapStateVar() - - swapStateVar({ - ...state, - tokenIn: { - ...state.tokenIn, - amount: '', - scaledAmount: BigInt(0), - }, - tokenOut: { - ...state.tokenOut, - amount: '', - scaledAmount: BigInt(0), - }, - }) - } - - function setDefaultTokens() { - swapStateVar(getDefaultTokenState(swapState.selectedChain)) - } - - function replaceUrlPath() { - const { selectedChain, tokenIn, tokenOut, swapType } = swapState - const { popularTokens } = networkConfig.tokens - const chainSlug = chainToSlugMap[selectedChain] - const newPath = ['/swap'] - - const _tokenIn = selectByAddress(popularTokens || {}, tokenIn.address) || tokenIn.address - const _tokenOut = selectByAddress(popularTokens || {}, tokenOut.address) || tokenOut.address - - if (chainSlug) newPath.push(`/${chainSlug}`) - if (_tokenIn) newPath.push(`/${_tokenIn}`) - if (_tokenIn && _tokenOut) newPath.push(`/${_tokenOut}`) - if (_tokenIn && _tokenOut && tokenIn.amount && swapType === GqlSorSwapType.ExactIn) { - newPath.push(`/${tokenIn.amount}`) - } - if (_tokenIn && _tokenOut && tokenOut.amount && swapType === GqlSorSwapType.ExactOut) { - newPath.push(`/0/${tokenOut.amount}`) - } - - window.history.replaceState({}, '', newPath.join('')) - } - - function scaleTokenAmount(amount: string, token: GqlToken | undefined): bigint { - if (amount === '') return parseUnits('0', 18) - if (!token) throw new Error('Cant scale amount without token metadata') - return parseUnits(amount, token.decimals) - } - - function calcPriceImpact() { - if (!bn(tokenInUsd).isZero() && !bn(tokenOutUsd).isZero()) { - setPriceImpact(calcMarketPriceImpact(tokenInUsd, tokenOutUsd)) - } else if (simulationQuery.data) { - setPriceImpact(undefined) - setPriceImpactLevel('unknown') - } - } - - const wethIsEth = - isSameAddress(swapState.tokenIn.address, networkConfig.tokens.nativeAsset.address) || - isSameAddress(swapState.tokenOut.address, networkConfig.tokens.nativeAsset.address) - const validAmountOut = bn(swapState.tokenOut.amount).gt(0) - - const protocolVersion = (simulationQuery.data as SdkSimulateSwapResponse)?.protocolVersion || 2 - const { vaultAddress } = useVault(protocolVersion) - - const swapAction: SwapAction = useMemo(() => { - if ( - isWrapOrUnwrap(swapState.tokenIn.address, swapState.tokenOut.address, swapState.selectedChain) - ) { - const wrapType = getWrapType( - swapState.tokenIn.address, - swapState.tokenOut.address, - swapState.selectedChain - ) - return wrapType ? wrapType : OSwapAction.SWAP - } - - return OSwapAction.SWAP - }, [swapState.tokenIn.address, swapState.tokenOut.address, swapState.selectedChain]) - - const isWrap = swapAction === 'wrap' || swapAction === 'unwrap' - - /** - * Step construction - */ - const { steps, isLoadingSteps } = useSwapSteps({ - vaultAddress, - swapState, - handler, - simulationQuery, - wethIsEth, - swapAction, - tokenInInfo, - tokenOutInfo, - }) - - const transactionSteps = useTransactionSteps(steps, isLoadingSteps) - - const swapTxHash = urlTxHash || transactionSteps.lastTransaction?.result?.data?.transactionHash - const swapTxConfirmed = transactionSteps.lastTransactionConfirmed - - const hasQuoteContext = !!simulationQuery.data - - function setInitialTokenIn(slugTokenIn?: string) { - const { popularTokens } = networkConfig.tokens - const symbolToAddressMap = invert(popularTokens || {}) as Record - if (slugTokenIn) { - if (isAddress(slugTokenIn)) setTokenIn(slugTokenIn as Address) - else if (symbolToAddressMap[slugTokenIn] && isAddress(symbolToAddressMap[slugTokenIn])) { - setTokenIn(symbolToAddressMap[slugTokenIn]) - } - } - } - - function setInitialTokenOut(slugTokenOut?: string) { - const { popularTokens } = networkConfig.tokens - const symbolToAddressMap = invert(popularTokens || {}) as Record - if (slugTokenOut) { - if (isAddress(slugTokenOut)) setTokenOut(slugTokenOut as Address) - else if (symbolToAddressMap[slugTokenOut] && isAddress(symbolToAddressMap[slugTokenOut])) { - setTokenOut(symbolToAddressMap[slugTokenOut]) - } - } - } - - function setInitialChain(slugChain?: string) { - const _chain = - slugChain && slugToChainMap[slugChain as ChainSlug] - ? slugToChainMap[slugChain as ChainSlug] - : walletChain - - setSelectedChain(_chain) - } - - function setInitialAmounts(slugAmountIn?: string, slugAmountOut?: string) { - if (slugAmountIn && !slugAmountOut && bn(slugAmountIn).gt(0)) { - setTokenInAmount(slugAmountIn as HumanAmount) - } else if (slugAmountOut && bn(slugAmountOut).gt(0)) { - setTokenOutAmount(slugAmountOut as HumanAmount) - } else resetSwapAmounts() - } - // Set state on initial load useEffect(() => { if (urlTxHash) return - const { chain, tokenIn, tokenOut, amountIn, amountOut } = pathParams - - setInitialChain(chain) - setInitialTokenIn(tokenIn) - setInitialTokenOut(tokenOut) - setInitialAmounts(amountIn, amountOut) - - if (!swapState.tokenIn.address && !swapState.tokenOut.address) setDefaultTokens() + const { chain, tokenIn, tokenOut } = pathParams + console.log({ chain, tokenIn, tokenOut }) }, []) - // When wallet chain changes, update the swap form chain - useEffect(() => { - if (isConnected && initUserChain && walletChain !== swapState.selectedChain) { - setSelectedChain(walletChain) - } else if (isConnected) { - setInitUserChain(walletChain) - } - }, [walletChain]) - - // When a new simulation is triggered, update the state - useEffect(() => { - if (simulationQuery.data) { - handleSimulationResponse(simulationQuery.data) - } - }, [simulationQuery.data]) - - // Check if tokenIn is a base wrap token and set tokenOut as the wrapped token. - useEffect(() => { - const wrapper = getWrapperForBaseToken(swapState.tokenIn.address, swapState.selectedChain) - if (wrapper) setTokenOut(wrapper.wrappedToken) - - // If the token in address changes we should reset tx step index because - // the first approval will be different. - transactionSteps.setCurrentStepIndex(0) - }, [swapState.tokenIn.address]) - - // Check if tokenOut is a base wrap token and set tokenIn as the wrapped token. - useEffect(() => { - const wrapper = getWrapperForBaseToken(swapState.tokenOut.address, swapState.selectedChain) - if (wrapper) setTokenIn(wrapper.wrappedToken) - }, [swapState.tokenOut.address]) - - // Update the URL path when the tokens change - useEffect(() => { - if (!swapTxHash) replaceUrlPath() - }, [swapState.selectedChain, swapState.tokenIn, swapState.tokenOut, swapState.tokenIn.amount]) - - // Update selecteable tokens when the chain changes - useEffect(() => { - setTokens(getTokensByChain(swapState.selectedChain)) - }, [swapState.selectedChain]) - - // Open the preview modal when a swap tx hash is present - useEffect(() => { - if (swapTxHash) { - previewModalDisclosure.onOpen() - } - }, [swapTxHash]) - - // If token out value changes when swapping exact in, recalculate price impact. - useEffect(() => { - if (swapState.swapType === GqlSorSwapType.ExactIn) { - calcPriceImpact() - } - }, [tokenOutUsd]) - - // If token in value changes when swapping exact out, recalculate price impact. - useEffect(() => { - if (swapState.swapType === GqlSorSwapType.ExactOut) { - calcPriceImpact() - } - }, [tokenInUsd]) - - const { isDisabled, disabledReason } = isDisabledWithReason( - [!isConnected, LABELS.walletNotConnected], - [!validAmountOut, 'Invalid amount out'], - [needsToAcceptHighPI, 'Accept high price impact first'], - [hasValidationErrors, 'Invalid input'], - [simulationQuery.isError, 'Error fetching swap'], - [simulationQuery.isLoading, 'Fetching swap...'] - ) + // // When wallet chain changes, update the swap form chain + // useEffect(() => { + // if (isConnected && initUserChain && walletChain !== swapState.selectedChain) { + // setSelectedChain(walletChain) + // } else if (isConnected) { + // setInitUserChain(walletChain) + // } + // }, [walletChain]) return { ...swapState, - transactionSteps, tokens, tokenInInfo, tokenOutInfo, tokenSelectKey, - simulationQuery, - isDisabled, - disabledReason, previewModalDisclosure, - handler, - wethIsEth, - swapAction, - urlTxHash, - swapTxHash, - hasQuoteContext, - isWrap, - swapTxConfirmed, - replaceUrlPath, - resetSwapAmounts, setTokenSelectKey, - setSelectedChain, - setTokenInAmount, - setTokenOutAmount, - setTokenIn, - setTokenOut, - switchTokens, - setNeedsToAcceptHighPI, } } diff --git a/lib/modules/swap/SwapRate.tsx b/lib/modules/swap/SwapRate.tsx deleted file mode 100644 index 143f5f59c..000000000 --- a/lib/modules/swap/SwapRate.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Text } from '@chakra-ui/react' -import { useState } from 'react' -import { useSwap } from './SwapProvider' -import { useCurrency } from '@/lib/shared/hooks/useCurrency' -import { useTokens } from '../tokens/TokensProvider' -import { fNum } from '@/lib/shared/utils/numbers' - -export function SwapRate() { - const [priceDirection, setPriceDirection] = useState<'givenIn' | 'givenOut'>('givenIn') - const { simulationQuery, tokenInInfo, tokenOutInfo } = useSwap() - const { toCurrency } = useCurrency() - const { usdValueForToken } = useTokens() - - const effectivePrice = fNum('token', simulationQuery.data?.effectivePrice || '0', { - abbreviated: false, - }) - const effectivePriceReversed = fNum( - 'token', - simulationQuery.data?.effectivePriceReversed || '0', - { abbreviated: false } - ) - - const tokenInUsdValue = usdValueForToken(tokenInInfo, 1) - const tokenOutUsdValue = usdValueForToken(tokenOutInfo, 1) - - const priceLabel = - priceDirection === 'givenIn' - ? `1 ${tokenInInfo?.symbol} = ${effectivePriceReversed} ${tokenOutInfo?.symbol} (${toCurrency( - tokenInUsdValue, - { abbreviated: false } - )})` - : `1 ${tokenOutInfo?.symbol} = ${effectivePrice} ${tokenInInfo?.symbol} (${toCurrency( - tokenOutUsdValue, - { abbreviated: false } - )})` - - const togglePriceDirection = (e: React.MouseEvent) => { - e.preventDefault() - setPriceDirection(priceDirection === 'givenIn' ? 'givenOut' : 'givenIn') - } - - return ( - - {simulationQuery.data && priceLabel} - - ) -} diff --git a/lib/modules/swap/modal/SwapModal.tsx b/lib/modules/swap/modal/SwapModal.tsx deleted file mode 100644 index b015863fb..000000000 --- a/lib/modules/swap/modal/SwapModal.tsx +++ /dev/null @@ -1,95 +0,0 @@ -'use client' - -import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalProps } from '@chakra-ui/react' -import { RefObject, useEffect, useRef } from 'react' -import { DesktopStepTracker } from '../../transactions/transaction-steps/step-tracker/DesktopStepTracker' -import { useSwap } from '../SwapProvider' -import { SwapTimeout } from './SwapTimeout' -import { useBreakpoints } from '@/lib/shared/hooks/useBreakpoints' -import { capitalize } from 'lodash' -import { ActionModalFooter } from '../../../shared/components/modals/ActionModalFooter' -import { TransactionModalHeader } from '../../../shared/components/modals/TransactionModalHeader' -import { chainToSlugMap } from '../../pool/pool.utils' -// eslint-disable-next-line max-len -import { getStylesForModalContentWithStepTracker } from '../../transactions/transaction-steps/step-tracker/step-tracker.utils' -import { SuccessOverlay } from '@/lib/shared/components/modals/SuccessOverlay' -import { useResetStepIndexOnOpen } from '../../pool/actions/useResetStepIndexOnOpen' -import { useOnUserAccountChanged } from '../../web3/useOnUserAccountChanged' -import { SwapSummary } from './SwapSummary' -import { useSwapReceipt } from '../../transactions/transaction-steps/receipts/receipt.hooks' -import { useUserAccount } from '../../web3/UserAccountProvider' - -type Props = { - isOpen: boolean - onClose(): void - onOpen(): void - finalFocusRef?: RefObject -} - -export function SwapPreviewModal({ - isOpen, - onClose, - finalFocusRef, - ...rest -}: Props & Omit) { - const { isDesktop } = useBreakpoints() - const initialFocusRef = useRef(null) - const { userAddress } = useUserAccount() - - const { transactionSteps, swapAction, isWrap, selectedChain, swapTxHash, hasQuoteContext } = - useSwap() - - const swapReceipt = useSwapReceipt({ - txHash: swapTxHash, - userAddress, - chain: selectedChain, - }) - - useResetStepIndexOnOpen(isOpen, transactionSteps) - - useEffect(() => { - if (!isWrap && swapTxHash && !window.location.pathname.includes(swapTxHash)) { - window.history.pushState({}, '', `/swap/${chainToSlugMap[selectedChain]}/${swapTxHash}`) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [swapTxHash]) - - useOnUserAccountChanged(onClose) - - return ( - - - - - {isDesktop && hasQuoteContext && ( - - )} - } - txHash={swapTxHash} - chain={selectedChain} - isReceiptLoading={swapReceipt.isLoading} - /> - - - - - - - - ) -} diff --git a/lib/modules/swap/modal/SwapSummary.tsx b/lib/modules/swap/modal/SwapSummary.tsx deleted file mode 100644 index 8abc9fe88..000000000 --- a/lib/modules/swap/modal/SwapSummary.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { useBreakpoints } from '@/lib/shared/hooks/useBreakpoints' -import { Card, HStack, Text } from '@chakra-ui/react' -import { SwapTokenRow } from '../../tokens/TokenRow/SwapTokenRow' -import { MobileStepTracker } from '../../transactions/transaction-steps/step-tracker/MobileStepTracker' -import { SwapDetails } from '../SwapDetails' -import { SwapRate } from '../SwapRate' -import { useSwap } from '../SwapProvider' -import { SwapReceiptResult } from '../../transactions/transaction-steps/receipts/receipt.hooks' -import { useUserAccount } from '../../web3/UserAccountProvider' -import { BalAlert } from '@/lib/shared/components/alerts/BalAlert' -import { HumanAmount } from '@balancer/sdk' -import { slippageDiffLabel } from '@/lib/shared/utils/slippage' -import { AnimateHeightChange } from '@/lib/shared/components/modals/AnimatedModalBody' -import { CardPopAnim } from '@/lib/shared/components/animations/CardPopAnim' - -export function SwapSummary({ - isLoading: isLoadingReceipt, - receivedToken, - sentToken, - error, -}: SwapReceiptResult) { - const { isMobile } = useBreakpoints() - const { userAddress, isLoading: isUserAddressLoading } = useUserAccount() - const { - tokenIn, - tokenOut, - transactionSteps, - selectedChain, - isWrap, - swapTxHash, - swapTxConfirmed, - simulationQuery, - hasQuoteContext, - } = useSwap() - - const expectedTokenOut = simulationQuery?.data?.returnAmount as HumanAmount - - const shouldShowReceipt = - !isWrap && !!swapTxHash && !isLoadingReceipt && !!receivedToken && !!sentToken - const shouldShowErrors = hasQuoteContext ? swapTxConfirmed : swapTxHash - const isWrapComplete = isWrap && swapTxHash && swapTxConfirmed - - function tokenOutLabel() { - if (shouldShowReceipt || isWrapComplete) return 'You got' - if (isWrap) return "You'll get" - return "You'll get (if no slippage)" - } - - if (!isUserAddressLoading && !userAddress) { - return - } - if (shouldShowErrors && error) { - return - } - if (shouldShowErrors && !isLoadingReceipt && (!receivedToken || !sentToken)) { - return ( - - ) - } - - return ( - - {isMobile && } - - - - - - - - - - {!shouldShowReceipt && !isWrapComplete && ( - <> - - {!swapTxHash && ( - - - - )} - - - - - Exchange rate - - - - - - )} - - ) -} diff --git a/lib/modules/swap/modal/SwapTimeout.tsx b/lib/modules/swap/modal/SwapTimeout.tsx deleted file mode 100644 index c5ee19b47..000000000 --- a/lib/modules/swap/modal/SwapTimeout.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import { HStack, Text } from '@chakra-ui/react' -import { useEffect } from 'react' -import { useCountdown } from 'usehooks-ts' -import { useSwap } from '../SwapProvider' -import { NumberText } from '@/lib/shared/components/typography/NumberText' -import { useShouldFreezeQuote } from '../../transactions/transaction-steps/useShouldFreezeQuote' -import { swapStepId } from '../useSwapStep' - -function useSwapTimeout() { - // This countdown needs to be nested here and not at a higher level, like in - // useAddLiquidity, because otherwise it causes re-renders of the entire - // add-liquidity flow component tree every second. - const [secondsToRefetch, { startCountdown, stopCountdown, resetCountdown }] = useCountdown({ - countStart: 30, - intervalMs: 1000, - }) - - const { simulationQuery, previewModalDisclosure } = useSwap() - - // Disable query refetches: - // if the flow is complete - // if the swap transaction is confirming - const { shouldFreezeQuote } = useShouldFreezeQuote(swapStepId) - - // When the countdown timer reaches 0, refetch all add liquidity queries. - useEffect(() => { - const refetchQueries = async () => { - stopCountdown() - resetCountdown() - await simulationQuery.refetch() - startCountdown() - } - if (secondsToRefetch === 0 && !shouldFreezeQuote) refetchQueries() - }, [secondsToRefetch]) - - // If the transaction flow is complete or confirming, stop the countdown timer. - // Else start the timer. - useEffect(() => { - if (shouldFreezeQuote) { - stopCountdown() - resetCountdown() - } else { - startCountdown() - } - }, [shouldFreezeQuote]) - - // When the modal is closed the timeout should be stopped and reset. - useEffect(() => { - if (!previewModalDisclosure.isOpen) { - stopCountdown() - resetCountdown() - } - }, [previewModalDisclosure.isOpen]) - - // On first render, start the countdown. - useEffect(() => { - stopCountdown() - resetCountdown() - startCountdown() - }, []) - - return { secondsToRefetch, shouldFreezeQuote } -} - -export function SwapTimeout() { - const { secondsToRefetch, shouldFreezeQuote } = useSwapTimeout() - - return ( - !shouldFreezeQuote && ( - - Quote refresh in - - - {secondsToRefetch} - - - s - - - - ) - ) -} diff --git a/lib/modules/swap/queries/swapQueryKeys.ts b/lib/modules/swap/queries/swapQueryKeys.ts deleted file mode 100644 index 02c208ca8..000000000 --- a/lib/modules/swap/queries/swapQueryKeys.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { BuildSwapInputs, SimulateSwapInputs } from '../swap.types' - -const baseKey = 'swap' - -function simulateInputKey({ swapAmount, swapType, tokenIn, tokenOut, chain }: SimulateSwapInputs) { - return `${swapAmount}:${swapType}:${tokenIn}:${tokenOut}:${chain}` -} - -type BuildKeyParams = Pick< - BuildSwapInputs, - 'account' | 'selectedChain' | 'slippagePercent' | 'simulateResponse' -> -function buildInputKey({ - account, - selectedChain, - slippagePercent, - simulateResponse, -}: BuildKeyParams) { - return `${account}:${selectedChain}:${slippagePercent}:${JSON.stringify(simulateResponse)}` -} - -export const swapQueryKeys = { - simulation: (inputs: SimulateSwapInputs) => - [baseKey, 'simulation', simulateInputKey(inputs)] as const, - build: (inputs: BuildKeyParams) => [baseKey, 'build', buildInputKey(inputs)] as const, -} diff --git a/lib/modules/swap/queries/useBuildSwapQuery.ts b/lib/modules/swap/queries/useBuildSwapQuery.ts deleted file mode 100644 index 5c1a9d027..000000000 --- a/lib/modules/swap/queries/useBuildSwapQuery.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { useUserSettings } from '@/lib/modules/user/settings/UserSettingsProvider' -import { useUserAccount } from '@/lib/modules/web3/UserAccountProvider' -import { onlyExplicitRefetch } from '@/lib/shared/utils/queries' -import { useQuery } from '@tanstack/react-query' -import { ensureLastQueryResponse } from '../../pool/actions/LiquidityActionHelpers' -import { SwapHandler } from '../handlers/Swap.handler' -import { SimulateSwapResponse, SwapState } from '../swap.types' -import { swapQueryKeys } from './swapQueryKeys' -import { SwapSimulationQueryResult } from './useSimulateSwapQuery' -import { useRelayerSignature } from '../../relayer/RelayerSignatureProvider' -import { SwapBuildCallExtras, sentryMetaForSwapHandler } from '@/lib/shared/utils/query-errors' - -export type BuildSwapQueryResponse = ReturnType - -export type BuildSwapQueryParams = { - handler: SwapHandler - simulationQuery: SwapSimulationQueryResult - wethIsEth: boolean - swapState: SwapState -} - -// Uses the SDK to build a transaction config to be used by wagmi's useManagedSendTransaction -export function useBuildSwapQuery({ - handler, - simulationQuery, - wethIsEth, - swapState, - enabled, -}: BuildSwapQueryParams & { - enabled: boolean -}) { - const { userAddress, isConnected } = useUserAccount() - const { slippage } = useUserSettings() - const { relayerApprovalSignature } = useRelayerSignature() - - const { selectedChain, tokenIn, tokenOut, swapType } = swapState - - const queryKey = swapQueryKeys.build({ - selectedChain, - account: userAddress, - slippagePercent: slippage, - simulateResponse: simulationQuery.data || ({} as SimulateSwapResponse), - }) - - const queryFn = async () => { - const simulateResponse = ensureLastQueryResponse('Swap query', simulationQuery.data) - - const response = handler.build({ - tokenIn, - tokenOut, - swapType, - account: userAddress, - slippagePercent: slippage, - selectedChain, - simulateResponse, - wethIsEth, - relayerApprovalSignature, - }) - console.log('Swap callData built:', response) - - return response - } - - return useQuery({ - queryKey, - queryFn, - enabled: enabled && isConnected && !!simulationQuery.data, - gcTime: 0, - meta: sentryMetaForSwapHandler('Error in swap buildCallData query', { - handler, - swapState, - slippage, - wethIsEth, - } as SwapBuildCallExtras), - ...onlyExplicitRefetch, - }) -} diff --git a/lib/modules/swap/queries/useSimulateSwapQuery.ts b/lib/modules/swap/queries/useSimulateSwapQuery.ts deleted file mode 100644 index 1f2368561..000000000 --- a/lib/modules/swap/queries/useSimulateSwapQuery.ts +++ /dev/null @@ -1,51 +0,0 @@ -'use client' - -import { defaultDebounceMs, onlyExplicitRefetch } from '@/lib/shared/utils/queries' -import { useDebounce } from 'use-debounce' -import { useQuery } from '@tanstack/react-query' -import { SwapHandler } from '../handlers/Swap.handler' -import { swapQueryKeys } from './swapQueryKeys' -import { SimulateSwapInputs, SimulateSwapResponse } from '../swap.types' -import { sentryMetaForSwapHandler } from '@/lib/shared/utils/query-errors' -import { isZero } from '@/lib/shared/utils/numbers' - -export type SwapSimulationQueryResult = ReturnType - -export type SimulateSwapParams = { - handler: SwapHandler - swapInputs: SimulateSwapInputs - enabled: boolean -} - -export function useSimulateSwapQuery({ - handler, - swapInputs: { swapAmount, chain, tokenIn, tokenOut, swapType }, - enabled = true, -}: SimulateSwapParams) { - const debouncedSwapAmount = useDebounce(swapAmount, defaultDebounceMs)[0] - - const inputs = { - swapAmount: debouncedSwapAmount, - swapType, - tokenIn, - tokenOut, - chain, - } - - const queryKey = swapQueryKeys.simulation(inputs) - - const queryFn = async () => handler.simulate(inputs) - - return useQuery({ - queryKey, - queryFn, - enabled: enabled && !isZero(debouncedSwapAmount), - gcTime: 0, - meta: sentryMetaForSwapHandler('Error in swap simulation query', { - handler, - swapInputs: inputs, - enabled, - }), - ...onlyExplicitRefetch, - }) -} diff --git a/lib/modules/swap/useSwapStep.tsx b/lib/modules/swap/useSwapStep.tsx deleted file mode 100644 index f65aafb6d..000000000 --- a/lib/modules/swap/useSwapStep.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import { ManagedSendTransactionButton } from '@/lib/modules/transactions/transaction-steps/TransactionButton' -import { - TransactionLabels, - TransactionStep, -} from '@/lib/modules/transactions/transaction-steps/lib' -import { GqlToken } from '@/lib/shared/services/api/generated/graphql' -import { sentryMetaForWagmiSimulation } from '@/lib/shared/utils/query-errors' -import { VStack } from '@chakra-ui/react' -import { capitalize } from 'lodash' -import { useEffect, useMemo, useState } from 'react' -import { useTransactionState } from '../transactions/transaction-steps/TransactionStateProvider' -import { BuildSwapQueryParams, useBuildSwapQuery } from './queries/useBuildSwapQuery' -import { swapActionPastTense } from './swap.helpers' -import { SwapAction } from './swap.types' -import { useTokenBalances } from '../tokens/TokenBalancesProvider' -import { useUserAccount } from '../web3/UserAccountProvider' - -export const swapStepId = 'swap' - -export type SwapStepParams = BuildSwapQueryParams & { - swapAction: SwapAction - tokenInInfo: GqlToken | undefined - tokenOutInfo: GqlToken | undefined -} - -export function useSwapStep({ - handler, - simulationQuery, - swapState, - swapAction, - wethIsEth, - tokenInInfo, - tokenOutInfo, -}: SwapStepParams): TransactionStep { - const { isConnected } = useUserAccount() - const [isBuildQueryEnabled, setIsBuildQueryEnabled] = useState(false) - const { getTransaction } = useTransactionState() - const { refetchBalances } = useTokenBalances() - - const buildSwapQuery = useBuildSwapQuery({ - handler, - simulationQuery, - wethIsEth, - swapState, - enabled: isBuildQueryEnabled && !!simulationQuery.data, - }) - - const tokenInSymbol = tokenInInfo?.symbol || 'Unknown' - const tokenOutSymbol = tokenOutInfo?.symbol || 'Unknown' - - const labels: TransactionLabels = { - init: capitalize(swapAction), - title: capitalize(swapAction), - confirming: 'Confirming swap...', - confirmed: `${swapActionPastTense(swapAction)}!`, - tooltip: `${capitalize(swapAction)} ${tokenInSymbol} for ${tokenOutSymbol}`, - description: `${capitalize(swapAction)} ${tokenInSymbol} for ${tokenOutSymbol}`, - } - - useEffect(() => { - // simulationQuery is refetched every 30 seconds by SwapTimeout - if (simulationQuery.data && isConnected) { - buildSwapQuery.refetch() - } - }, [simulationQuery.data]) - - const gasEstimationMeta = sentryMetaForWagmiSimulation( - 'Error in swap gas estimation', - buildSwapQuery.data || {} - ) - - const transaction = getTransaction(swapStepId) - - const isComplete = () => transaction?.result.isSuccess || false - - return useMemo( - () => ({ - id: swapStepId, - stepType: 'swap', - labels, - isComplete, - onActivated: () => setIsBuildQueryEnabled(true), - onDeactivated: () => setIsBuildQueryEnabled(false), - onSuccess: () => refetchBalances(), - renderAction: () => ( - - - - ), - }), - [transaction, simulationQuery.data, buildSwapQuery.data] - ) -} diff --git a/lib/modules/swap/useSwapSteps.tsx b/lib/modules/swap/useSwapSteps.tsx deleted file mode 100644 index ff34f6f89..000000000 --- a/lib/modules/swap/useSwapSteps.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { useMemo } from 'react' -import { Address, parseUnits } from 'viem' -import { ApprovalAction } from '../tokens/approvals/approval-labels' -import { RawAmount } from '../tokens/approvals/approval-rules' -import { useTokenApprovalSteps } from '../tokens/approvals/useTokenApprovalSteps' -import { OSwapAction } from './swap.types' -import { SwapStepParams, useSwapStep } from './useSwapStep' -import { useRelayerMode } from '../relayer/useRelayerMode' -import { useShouldSignRelayerApproval } from '../relayer/signRelayerApproval.hooks' -import { getChainId } from '@/lib/config/app.config' -import { useApproveRelayerStep } from '../relayer/useApproveRelayerStep' -import { useSignRelayerStep } from '../transactions/transaction-steps/useSignRelayerStep' - -type Params = SwapStepParams & { - vaultAddress: Address -} - -export function useSwapSteps({ - swapState, - vaultAddress, - handler, - wethIsEth, - simulationQuery, - swapAction, - tokenInInfo, - tokenOutInfo, -}: Params) { - const chainId = getChainId(swapState.selectedChain) - - const relayerMode = useRelayerMode() - const shouldSignRelayerApproval = useShouldSignRelayerApproval(chainId, relayerMode) - const { step: approveRelayerStep, isLoading: isLoadingRelayerApproval } = - useApproveRelayerStep(chainId) - const signRelayerStep = useSignRelayerStep(swapState.selectedChain) - - const swapRequiresRelayer = handler.constructor.name === 'AuraBalSwapHandler' - - const humanAmountIn = swapState.tokenIn.amount - const tokenInAmounts = useMemo(() => { - if (!tokenInInfo) return [] as RawAmount[] - return [ - { - address: tokenInInfo.address as Address, - rawAmount: parseUnits(humanAmountIn, tokenInInfo.decimals), - }, - ] - }, [humanAmountIn, tokenInInfo]) - - const approvalActionType: ApprovalAction = - swapAction === OSwapAction.UNWRAP ? 'Unwrapping' : 'Swapping' - - const { isLoading: isLoadingTokenApprovalSteps, steps: tokenApprovalSteps } = - useTokenApprovalSteps({ - spenderAddress: vaultAddress, - chain: swapState.selectedChain, - approvalAmounts: tokenInAmounts, - actionType: approvalActionType, - }) - - const swapStep = useSwapStep({ - handler, - wethIsEth, - swapState, - simulationQuery, - swapAction, - tokenInInfo, - tokenOutInfo, - }) - - const steps = useMemo(() => { - if (swapRequiresRelayer) { - if (relayerMode === 'approveRelayer') { - return [approveRelayerStep, ...tokenApprovalSteps, swapStep] - } else if (shouldSignRelayerApproval) { - return [signRelayerStep, ...tokenApprovalSteps, swapStep] - } - } - return [...tokenApprovalSteps, swapStep] - }, [ - swapRequiresRelayer, - tokenApprovalSteps, - swapStep, - relayerMode, - shouldSignRelayerApproval, - approveRelayerStep, - signRelayerStep, - ]) - - return { - isLoadingSteps: isLoadingTokenApprovalSteps || isLoadingRelayerApproval, - steps, - } -} diff --git a/lib/modules/tokens/TokenRow/SwapTokenRow.tsx b/lib/modules/tokens/TokenRow/SwapTokenRow.tsx deleted file mode 100644 index 1fb028daf..000000000 --- a/lib/modules/tokens/TokenRow/SwapTokenRow.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { VStack, HStack, Text } from '@chakra-ui/react' -import { Address } from 'viem' -import TokenRow from './TokenRow' -import { GqlChain } from '@/lib/shared/services/api/generated/graphql' -import { HumanAmount } from '@balancer/sdk' -import { useSwap } from '../../swap/SwapProvider' -import { slippageDiffLabel } from '@/lib/shared/utils/slippage' - -export function ReceiptTokenOutRow({ - chain, - actualReceivedTokenAmount, - tokenAddress, -}: { - chain: GqlChain - actualReceivedTokenAmount: HumanAmount - tokenAddress: string -}) { - const { simulationQuery } = useSwap() - const expectedTokenOut = simulationQuery?.data?.returnAmount as HumanAmount - return ( - - ) -} - -export function SwapTokenRow({ - label, - rightLabel, - chain, - tokenAmount, - tokenAddress, -}: { - label: string - chain: GqlChain - tokenAmount: string - tokenAddress: string - rightLabel?: string -}) { - return ( - - - - {label} - - {rightLabel && {rightLabel}} - - - - - ) -} diff --git a/lib/shared/utils/query-errors.ts b/lib/shared/utils/query-errors.ts index 739a3fd0c..14e9e8ff7 100644 --- a/lib/shared/utils/query-errors.ts +++ b/lib/shared/utils/query-errors.ts @@ -7,7 +7,6 @@ import { stringifyHumanAmountsIn, } from '@/lib/modules/pool/actions/add-liquidity/queries/add-liquidity-keys' import { RemoveLiquidityParams } from '@/lib/modules/pool/actions/remove-liquidity/queries/remove-liquidity-keys' -import { SimulateSwapParams } from '@/lib/modules/swap/queries/useSimulateSwapQuery' import { isProd } from '@/lib/config/app.config' import { SwapState } from '@/lib/modules/swap/swap.types' import { SwapHandler } from '@/lib/modules/swap/handlers/Swap.handler' @@ -40,10 +39,7 @@ export type SwapBuildCallExtras = { slippage: string wethIsEth: boolean } -export function sentryMetaForSwapHandler( - errorMessage: string, - params: SimulateSwapParams | SwapBuildCallExtras -) { +export function sentryMetaForSwapHandler(errorMessage: string, params: SwapBuildCallExtras) { return createSwapHandlerMetadata('HandlerQueryError', errorMessage, params) } @@ -141,7 +137,7 @@ function createRemoveHandlerMetadata( function createSwapHandlerMetadata( errorName: string, errorMessage: string, - params: SimulateSwapParams | SwapBuildCallExtras + params: SwapBuildCallExtras ) { const { handler, ...rest } = params const extra: Extras = {