From 8647fd171c362cd3219f8214f397dfb314974800 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Mon, 3 Jul 2023 16:21:29 +0600 Subject: [PATCH 01/10] feat(trade): generalise wrap/unwrap flow for all trade widgets --- .../trade/containers/TradeWidget/index.tsx | 10 ++++--- .../containers/WrapFlowActionButton/index.tsx | 26 +++++++++++++++++++ .../pure/TradeFormButtons/index.tsx | 2 +- .../services/validateTradeForm.ts | 6 ++--- 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 src/modules/trade/containers/WrapFlowActionButton/index.tsx diff --git a/src/modules/trade/containers/TradeWidget/index.tsx b/src/modules/trade/containers/TradeWidget/index.tsx index 22c75d191f..31947fdff6 100644 --- a/src/modules/trade/containers/TradeWidget/index.tsx +++ b/src/modules/trade/containers/TradeWidget/index.tsx @@ -20,6 +20,7 @@ import * as styledEl from './styled' import { TradeWidgetModals } from './TradeWidgetModals' import { PriceImpactUpdater } from '../../updaters/PriceImpactUpdater' +import { WrapFlowActionButton } from '../WrapFlowActionButton' import { WrapNativeModal } from '../WrapNativeModal' export interface TradeWidgetActions { @@ -61,7 +62,6 @@ export interface TradeWidgetProps { export const TradeWidgetContainer = styledEl.Container -// TODO: add ImportTokenModal, TradeApproveWidget export function TradeWidget(props: TradeWidgetProps) { const { id, slots, inputCurrencyInfo, outputCurrencyInfo, actions, params, disableOutput } = props const { settingsWidget, lockScreen, middleContent, bottomContent } = slots @@ -148,7 +148,7 @@ export function TradeWidget(props: TradeWidgetProps) { @@ -169,7 +171,7 @@ export function TradeWidget(props: TradeWidgetProps) { )} - {bottomContent} + {isWrapOrUnwrap ? : bottomContent} )} diff --git a/src/modules/trade/containers/WrapFlowActionButton/index.tsx b/src/modules/trade/containers/WrapFlowActionButton/index.tsx new file mode 100644 index 0000000000..bd1466d89d --- /dev/null +++ b/src/modules/trade/containers/WrapFlowActionButton/index.tsx @@ -0,0 +1,26 @@ +import { TradeFormButtons, useGetTradeFormValidation, useTradeFormButtonContext } from 'modules/tradeFormValidation' + +const doTradeText = '' +const confirmText = '' +const tradeCallbacks = { doTrade() {}, confirmTrade() {} } + +/** + * This component is used only to display a button for Wrap/Unwrap + * because of it, we just stub parameters above + */ +export function WrapFlowActionButton() { + const primaryFormValidation = useGetTradeFormValidation() + const tradeFormButtonContext = useTradeFormButtonContext(doTradeText, tradeCallbacks) + + if (!tradeFormButtonContext) return null + + return ( + + ) +} diff --git a/src/modules/tradeFormValidation/pure/TradeFormButtons/index.tsx b/src/modules/tradeFormValidation/pure/TradeFormButtons/index.tsx index eb63f6e25a..12a79b7aa6 100644 --- a/src/modules/tradeFormValidation/pure/TradeFormButtons/index.tsx +++ b/src/modules/tradeFormValidation/pure/TradeFormButtons/index.tsx @@ -20,7 +20,7 @@ export function TradeFormButtons(props: TradeFormButtonsProps) { const { validation, context, isExpertMode, isDisabled, doTradeText, confirmText } = props // When there are no validation errors - if (!validation) { + if (validation === null) { return ( Date: Mon, 3 Jul 2023 16:34:54 +0600 Subject: [PATCH 02/10] fix(swap): bind swap widget to generic Wrap/Unwrap UI --- .../containers/AdvancedOrdersWidget/index.tsx | 1 + .../limitOrders/containers/LimitOrdersWidget/index.tsx | 1 + src/modules/swap/containers/SwapWidget/index.tsx | 1 + src/modules/swap/state/useSwapDerivedState.ts | 9 +++++---- src/modules/trade/containers/TradeWidget/index.tsx | 4 ++++ src/pages/AdvancedOrders/index.tsx | 4 ---- src/pages/LimitOrders/index.tsx | 5 ----- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx b/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx index e65e2de57c..12f2852548 100644 --- a/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx +++ b/src/modules/advancedOrders/containers/AdvancedOrdersWidget/index.tsx @@ -71,6 +71,7 @@ export function AdvancedOrdersWidget({ children }: { children: JSX.Element }) { showRecipient: false, isTradePriceUpdating, priceImpact, + isExpertMode: false, // TODO: bind value } return ( diff --git a/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx b/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx index 8d99d93a4a..94e0e52c09 100644 --- a/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx +++ b/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx @@ -217,6 +217,7 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { const params = { disableNonToken: false, compactView: false, + isExpertMode, recipient, showRecipient, isTradePriceUpdating, diff --git a/src/modules/swap/containers/SwapWidget/index.tsx b/src/modules/swap/containers/SwapWidget/index.tsx index f7844c504d..98d2a599cc 100644 --- a/src/modules/swap/containers/SwapWidget/index.tsx +++ b/src/modules/swap/containers/SwapWidget/index.tsx @@ -248,6 +248,7 @@ export function SwapWidget() { priceImpact: priceImpactParams, disableQuotePolling: true, canSellAllNative, + isExpertMode, } return ( diff --git a/src/modules/swap/state/useSwapDerivedState.ts b/src/modules/swap/state/useSwapDerivedState.ts index 23707d82b5..33c8b062b2 100644 --- a/src/modules/swap/state/useSwapDerivedState.ts +++ b/src/modules/swap/state/useSwapDerivedState.ts @@ -15,14 +15,15 @@ export function useSwapDerivedState(): SwapDerivedState { export function useFillSwapDerivedState() { const { independentField, recipient } = useSwapState() - const { v2Trade, currencyBalances, currencies, slippageAdjustedSellAmount } = useDerivedSwapInfo() + const { v2Trade, currencyBalances, currencies, slippageAdjustedSellAmount, parsedAmount } = useDerivedSwapInfo() + const isSellTrade = independentField === Field.INPUT const inputCurrency = currencies.INPUT || null const outputCurrency = currencies.OUTPUT || null const inputCurrencyBalance = currencyBalances.INPUT || null const outputCurrencyBalance = currencyBalances.OUTPUT || null - const inputCurrencyAmount = v2Trade?.inputAmount || null - const outputCurrencyAmount = v2Trade?.outputAmount || null + const inputCurrencyAmount = (isSellTrade ? parsedAmount : v2Trade?.inputAmount) || null + const outputCurrencyAmount = (!isSellTrade ? parsedAmount : v2Trade?.outputAmount) || null const inputCurrencyFiatAmount = useHigherUSDValue(inputCurrencyAmount || undefined) const outputCurrencyFiatAmount = useHigherUSDValue(outputCurrencyAmount || undefined) @@ -41,7 +42,7 @@ export function useFillSwapDerivedState() { inputCurrencyFiatAmount, outputCurrencyFiatAmount, recipient, - orderKind: independentField === Field.INPUT ? OrderKind.SELL : OrderKind.BUY, + orderKind: isSellTrade ? OrderKind.SELL : OrderKind.BUY, }) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ diff --git a/src/modules/trade/containers/TradeWidget/index.tsx b/src/modules/trade/containers/TradeWidget/index.tsx index 31947fdff6..de59f44d9d 100644 --- a/src/modules/trade/containers/TradeWidget/index.tsx +++ b/src/modules/trade/containers/TradeWidget/index.tsx @@ -8,6 +8,7 @@ import { maxAmountSpend } from 'legacy/utils/maxAmountSpend' import { TradeWidgetLinks } from 'modules/application/containers/TradeWidgetLinks' import { SetRecipientProps } from 'modules/swap/containers/SetRecipient' import { useIsWrapOrUnwrap } from 'modules/trade/hooks/useIsWrapOrUnwrap' +import { TradeFormValidationUpdater } from 'modules/tradeFormValidation' import { TradeQuoteUpdater } from 'modules/tradeQuote' import { useWalletDetails, useWalletInfo } from 'modules/wallet' @@ -37,6 +38,7 @@ interface TradeWidgetParams { compactView: boolean showRecipient: boolean isTradePriceUpdating: boolean + isExpertMode: boolean priceImpact: PriceImpact isRateLoading?: boolean disableQuotePolling?: boolean @@ -78,6 +80,7 @@ export function TradeWidget(props: TradeWidgetProps) { recipient, disableQuotePolling = false, canSellAllNative = false, + isExpertMode, } = params const { chainId } = useWalletInfo() @@ -106,6 +109,7 @@ export function TradeWidget(props: TradeWidgetProps) { + diff --git a/src/pages/AdvancedOrders/index.tsx b/src/pages/AdvancedOrders/index.tsx index 6ac7580fdd..a8f9b171b6 100644 --- a/src/pages/AdvancedOrders/index.tsx +++ b/src/pages/AdvancedOrders/index.tsx @@ -5,7 +5,6 @@ import { OrdersTableWidget } from 'modules/ordersTable' import { useTradeRouteContext } from 'modules/trade/hooks/useTradeRouteContext' import * as styledEl from 'modules/trade/pure/TradePageLayout' import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' -import { TradeFormValidationUpdater } from 'modules/tradeFormValidation' import { TwapFormWidget } from 'modules/twap' import { Routes as RoutesEnum } from 'common/constants/routes' @@ -22,9 +21,6 @@ export default function AdvancedOrdersPage() { return ( <> - {/*TODO: add isExpertMode value*/} - - {/*TODO: add isUnlocked value*/} diff --git a/src/pages/LimitOrders/index.tsx b/src/pages/LimitOrders/index.tsx index 1dca417d72..c3c0ce550a 100644 --- a/src/pages/LimitOrders/index.tsx +++ b/src/pages/LimitOrders/index.tsx @@ -6,23 +6,18 @@ import { InitialPriceUpdater, ExecutionPriceUpdater, limitOrdersRawStateAtom, - limitOrdersSettingsAtom, } from 'modules/limitOrders' import { OrdersTableWidget } from 'modules/ordersTable' import * as styledEl from 'modules/trade/pure/TradePageLayout' -import { TradeFormValidationUpdater } from 'modules/tradeFormValidation' export default function LimitOrderPage() { const { isUnlocked } = useAtomValue(limitOrdersRawStateAtom) - const { expertMode } = useAtomValue(limitOrdersSettingsAtom) return ( <> - - From 64bd8a9ab3b62b536b9d31d68527c8c27746e294 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Mon, 3 Jul 2023 16:39:17 +0600 Subject: [PATCH 03/10] refactor: clean up Limit orders widget from isWrapOrUnwrap --- .../containers/LimitOrdersWidget/index.tsx | 34 ++++++------------- .../limitOrdersPropsChecker.ts | 2 -- .../trade/containers/TradeWidget/index.tsx | 4 +-- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx b/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx index 94e0e52c09..dd62327ecc 100644 --- a/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx +++ b/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx @@ -14,7 +14,6 @@ import { InfoBanner } from 'modules/limitOrders/pure/InfoBanner' import { partiallyFillableOverrideAtom } from 'modules/limitOrders/state/partiallyFillableOverride' import { TradeWidget, useSetupTradeState, useTradePriceImpact } from 'modules/trade' import { useDisableNativeTokenSelling } from 'modules/trade/hooks/useDisableNativeTokenSelling' -import { useIsWrapOrUnwrap } from 'modules/trade/hooks/useIsWrapOrUnwrap' import { useSetTradeQuoteParams, useTradeQuote } from 'modules/tradeQuote' import { useFeatureFlags } from 'common/hooks/featureFlags/useFeatureFlags' @@ -61,20 +60,11 @@ export function LimitOrdersWidget() { const { feeAmount } = useAtomValue(limitRateAtom) const { isLoading: isRateLoading } = useTradeQuote() const rateInfoParams = useRateInfoParams(inputCurrencyAmount, outputCurrencyAmount) - const isWrapOrUnwrap = useIsWrapOrUnwrap() const partiallyFillableOverride = useAtom(partiallyFillableOverrideAtom) const { partialFillsEnabled } = useFeatureFlags() const widgetActions = useLimitOrdersWidgetActions() - const showRecipient = useMemo( - () => !isWrapOrUnwrap && settingsState.showRecipient, - [settingsState.showRecipient, isWrapOrUnwrap] - ) - - const isExpertMode = useMemo( - () => !isWrapOrUnwrap && settingsState.expertMode, - [isWrapOrUnwrap, settingsState.expertMode] - ) + const { showRecipient, expertMode: isExpertMode } = settingsState const priceImpact = useTradePriceImpact() const quoteAmount = useMemo( @@ -86,7 +76,7 @@ export function LimitOrdersWidget() { const inputCurrencyInfo: CurrencyInfo = { field: Field.INPUT, - label: isWrapOrUnwrap ? undefined : isSellOrder ? 'You sell' : 'You sell at most', + label: isSellOrder ? 'You sell' : 'You sell at most', currency: inputCurrency, amount: inputCurrencyAmount, isIndependent: orderKind === OrderKind.SELL, @@ -96,9 +86,9 @@ export function LimitOrdersWidget() { } const outputCurrencyInfo: CurrencyInfo = { field: Field.OUTPUT, - label: isWrapOrUnwrap ? undefined : isSellOrder ? 'You receive at least' : 'You receive exactly', + label: isSellOrder ? 'You receive at least' : 'You receive exactly', currency: outputCurrency, - amount: isWrapOrUnwrap ? inputCurrencyAmount : outputCurrencyAmount, + amount: outputCurrencyAmount, isIndependent: orderKind === OrderKind.BUY, balance: outputCurrencyBalance, fiatAmount: outputCurrencyFiatAmount, @@ -110,7 +100,6 @@ export function LimitOrdersWidget() { outputCurrencyInfo, isUnlocked, isRateLoading, - isWrapOrUnwrap, showRecipient, isExpertMode, recipient, @@ -136,7 +125,6 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { widgetActions, partiallyFillableOverride, featurePartialFillsEnabled, - isWrapOrUnwrap, showRecipient, isExpertMode, recipient, @@ -151,10 +139,10 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { const outputCurrency = outputCurrencyInfo.currency const isTradePriceUpdating = useMemo(() => { - if (isWrapOrUnwrap || !inputCurrency || !outputCurrency) return false + if (!inputCurrency || !outputCurrency) return false return isRateLoading - }, [isRateLoading, isWrapOrUnwrap, inputCurrency, outputCurrency]) + }, [isRateLoading, inputCurrency, outputCurrency]) const isPartiallyFillable = featurePartialFillsEnabled && settingsState.partialFillsEnabled @@ -189,11 +177,9 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { ), bottomContent: ( <> - {!isWrapOrUnwrap && ( - - - - )} + + + {isExpertMode && ( @@ -205,7 +191,7 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { )} - {!isWrapOrUnwrap && } + diff --git a/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts b/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts index 6a68a69b91..3824e7c02a 100644 --- a/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts +++ b/src/modules/limitOrders/containers/LimitOrdersWidget/limitOrdersPropsChecker.ts @@ -19,7 +19,6 @@ export interface LimitOrdersProps { isUnlocked: boolean isRateLoading: boolean - isWrapOrUnwrap: boolean showRecipient: boolean isExpertMode: boolean @@ -41,7 +40,6 @@ export function limitOrdersPropsChecker(a: LimitOrdersProps, b: LimitOrdersProps checkCurrencyInfo(a.outputCurrencyInfo, b.outputCurrencyInfo) && a.isUnlocked === b.isUnlocked && a.isRateLoading === b.isRateLoading && - a.isWrapOrUnwrap === b.isWrapOrUnwrap && a.showRecipient === b.showRecipient && a.recipient === b.recipient && a.widgetActions === b.widgetActions && diff --git a/src/modules/trade/containers/TradeWidget/index.tsx b/src/modules/trade/containers/TradeWidget/index.tsx index de59f44d9d..017c42ce5f 100644 --- a/src/modules/trade/containers/TradeWidget/index.tsx +++ b/src/modules/trade/containers/TradeWidget/index.tsx @@ -134,7 +134,7 @@ export function TradeWidget(props: TradeWidgetProps) { currencyInfo={inputCurrencyInfo} showSetMax={showSetMax} maxBalance={maxBalance} - topLabel={inputCurrencyInfo.label} + topLabel={isWrapOrUnwrap ? undefined : inputCurrencyInfo.label} /> {!isWrapOrUnwrap && middleContent} @@ -168,7 +168,7 @@ export function TradeWidget(props: TradeWidgetProps) { isWrapOrUnwrap ? { ...outputCurrencyInfo, amount: inputCurrencyInfo.amount } : outputCurrencyInfo } priceImpactParams={priceImpact} - topLabel={outputCurrencyInfo.label} + topLabel={isWrapOrUnwrap ? undefined : outputCurrencyInfo.label} /> {showRecipient && ( From 44a2f64e00118b8a35cd6ab830e8877f40f042ca Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Mon, 3 Jul 2023 18:07:58 +0600 Subject: [PATCH 04/10] refactor: clean up Swap widget from isWrapOrUnwrap --- src/legacy/hooks/usePriceImpact/index.ts | 2 +- src/legacy/hooks/useWrapCallback.ts | 68 ------------------- .../ConfirmSwapModalSetup/index.tsx | 24 +------ .../swap/containers/SwapWidget/index.tsx | 21 ++---- .../swap/helpers/getSwapButtonState.ts | 22 +----- .../swap/hooks/useShowRecipientControls.ts | 7 +- .../swap/hooks/useSwapButtonContext.ts | 33 +-------- .../swap/hooks/useSwapCurrenciesAmounts.ts | 30 ++++---- .../swap/hooks/useTransactionConfirmModal.ts | 20 ------ .../swap/pure/SwapButtons/index.cosmos.tsx | 2 - src/modules/swap/pure/SwapButtons/index.tsx | 17 ----- .../swap/state/transactionConfirmAtom.ts | 13 ---- src/modules/swap/state/useSwapDerivedState.ts | 46 +++++-------- .../tokens/hooks/useOnchainBalances.ts | 4 +- .../trade/hooks/useTradePriceImpactParams.ts | 16 +++-- src/modules/trade/hooks/useWrapNativeFlow.ts | 15 ++-- .../trade/updaters/PriceImpactUpdater.tsx | 2 +- 17 files changed, 71 insertions(+), 271 deletions(-) delete mode 100644 src/modules/swap/hooks/useTransactionConfirmModal.ts delete mode 100644 src/modules/swap/state/transactionConfirmAtom.ts diff --git a/src/legacy/hooks/usePriceImpact/index.ts b/src/legacy/hooks/usePriceImpact/index.ts index b4bd615928..6a9d539ad0 100644 --- a/src/legacy/hooks/usePriceImpact/index.ts +++ b/src/legacy/hooks/usePriceImpact/index.ts @@ -26,7 +26,7 @@ export interface PriceImpact { * Warning! * The hook cannot be used more the once in the same page */ -export default function usePriceImpact({ abTrade, parsedAmounts, isWrapping }: PriceImpactParams): PriceImpact { +export function usePriceImpact({ abTrade, parsedAmounts, isWrapping }: PriceImpactParams): PriceImpact { const fiatPriceImpact = useFiatValuePriceImpact(parsedAmounts) const { impact: fallbackPriceImpact, diff --git a/src/legacy/hooks/useWrapCallback.ts b/src/legacy/hooks/useWrapCallback.ts index 5a1d65894a..5c7dce21ad 100644 --- a/src/legacy/hooks/useWrapCallback.ts +++ b/src/legacy/hooks/useWrapCallback.ts @@ -4,22 +4,14 @@ import { Contract } from '@ethersproject/contracts' import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { Nullish } from 'types' - import { wrapAnalytics } from 'legacy/components/analytics' import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' import { getOperationMessage } from 'legacy/components/TransactionConfirmationModal/LegacyConfirmationPendingContent' import { RADIX_HEX } from 'legacy/constants' -import { useWETHContract } from 'legacy/hooks/useContract' -import { useCloseModals } from 'legacy/state/application/hooks' import { useTransactionAdder } from 'legacy/state/enhancedTransactions/hooks' import { calculateGasMargin } from 'legacy/utils/calculateGasMargin' import { getChainCurrencySymbols } from 'legacy/utils/gnosis_chain/hack' -import { useTransactionConfirmModal } from 'modules/swap/hooks/useTransactionConfirmModal' -import { useNativeTokenContext } from 'modules/trade/hooks/useNativeTokenContext' -import { useWalletInfo } from 'modules/wallet' - import { formatTokenAmount } from 'utils/amountFormat' import { isRejectRequestProviderError } from '../utils/misc' @@ -27,12 +19,6 @@ import { isRejectRequestProviderError } from '../utils/misc' // Use a 180K gas as a fallback if there's issue calculating the gas estimation (fixes some issues with some nodes failing to calculate gas costs for SC wallets) const WRAP_UNWRAP_GAS_LIMIT_DEFAULT = BigNumber.from('180000') -export enum WrapType { - NOT_APPLICABLE, - WRAP, - UNWRAP, -} - export interface WrapUnwrapCallbackParams { useModals?: boolean } @@ -58,60 +44,6 @@ export interface WrapUnwrapContext { openTransactionConfirmationModal: OpenSwapConfirmModalCallback } -export function useWrapType(): WrapType { - const { isNativeIn, isNativeOut, isWrappedIn, isWrappedOut } = useNativeTokenContext() - - const isWrap = isNativeIn && isWrappedOut - const isUnwrap = isWrappedIn && isNativeOut - const isWrapOrUnwrapApplicable = isWrap || isUnwrap - - if (!isWrapOrUnwrapApplicable) { - return WrapType.NOT_APPLICABLE - } - - return isNativeIn ? WrapType.WRAP : WrapType.UNWRAP -} - -export function useWrapUnwrapContext(inputAmount: Nullish>): WrapUnwrapContext | null { - const { chainId } = useWalletInfo() - const closeModals = useCloseModals() - const wethContract = useWETHContract() - const addTransaction = useTransactionAdder() - const openTxConfirmationModal = useTransactionConfirmModal() - - if (!wethContract || !chainId || !inputAmount) { - return null - } - - const openTransactionConfirmationModal = (pendingText: string, operationType: ConfirmOperationType) => { - openTxConfirmationModal({ operationType, pendingText }) - } - - return { - chainId, - wethContract, - amount: inputAmount, - addTransaction, - closeModals, - openTransactionConfirmationModal, - } -} - -/** - * Given the selected input and output currency, return a wrap callback - */ -export function useWrapCallback(inputAmount: CurrencyAmount | null | undefined): WrapUnwrapCallback | null { - const context = useWrapUnwrapContext(inputAmount) - - if (!context) { - return null - } - - return (params?: WrapUnwrapCallbackParams) => { - return wrapUnwrapCallback(context, params) - } -} - export async function wrapUnwrapCallback( context: WrapUnwrapContext, params: WrapUnwrapCallbackParams = { useModals: true } diff --git a/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx b/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx index 67d55338f7..749fca564e 100644 --- a/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx +++ b/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx @@ -4,10 +4,6 @@ import { useCallback } from 'react' import { Percent } from '@uniswap/sdk-core' import { ConfirmSwapModal } from 'legacy/components/swap/ConfirmSwapModal' -import { TransactionConfirmationModal } from 'legacy/components/TransactionConfirmationModal' -import { useCloseModals } from 'legacy/state/application/hooks' -import { useModalIsOpen } from 'legacy/state/application/hooks' -import { ApplicationModal } from 'legacy/state/application/reducer' import { Field } from 'legacy/state/swap/actions' import { useSwapActionHandlers } from 'legacy/state/swap/hooks' import TradeGp from 'legacy/state/swap/TradeGp' @@ -15,7 +11,6 @@ import TradeGp from 'legacy/state/swap/TradeGp' import { useSwapConfirmManager } from 'modules/swap/hooks/useSwapConfirmManager' import { HandleSwapCallback } from 'modules/swap/pure/SwapButtons' import { swapConfirmAtom } from 'modules/swap/state/swapConfirmAtom' -import { transactionConfirmAtom } from 'modules/swap/state/transactionConfirmAtom' import { RateInfoParams } from 'common/pure/RateInfo' @@ -26,23 +21,14 @@ export interface ConfirmSwapModalSetupProps { handleSwap: HandleSwapCallback priceImpact?: Percent rateInfoParams: RateInfoParams - dismissNativeWrapModal(): void } export function ConfirmSwapModalSetup(props: ConfirmSwapModalSetupProps) { - const { trade, recipient, allowedSlippage, priceImpact, handleSwap, dismissNativeWrapModal, rateInfoParams } = props + const { trade, recipient, allowedSlippage, priceImpact, handleSwap, rateInfoParams } = props const swapConfirmState = useAtomValue(swapConfirmAtom) - const { operationType, pendingText } = useAtomValue(transactionConfirmAtom) const { acceptRateUpdates, closeSwapConfirm } = useSwapConfirmManager() const { onUserInput } = useSwapActionHandlers() - const closeModals = useCloseModals() - const showTransactionConfirmationModal = useModalIsOpen(ApplicationModal.TRANSACTION_CONFIRMATION) - - const onDismiss = useCallback(() => { - closeModals() - dismissNativeWrapModal() - }, [closeModals, dismissNativeWrapModal]) const handleAcceptChanges = useCallback(() => { trade && acceptRateUpdates(trade) @@ -70,14 +56,6 @@ export function ConfirmSwapModalSetup(props: ConfirmSwapModalSetupProps) { onConfirm={handleSwap} onDismiss={handleConfirmDismiss} /> - - ) } diff --git a/src/modules/swap/containers/SwapWidget/index.tsx b/src/modules/swap/containers/SwapWidget/index.tsx index 98d2a599cc..595ee55040 100644 --- a/src/modules/swap/containers/SwapWidget/index.tsx +++ b/src/modules/swap/containers/SwapWidget/index.tsx @@ -3,9 +3,7 @@ import React, { useState } from 'react' import { NetworkAlert } from 'legacy/components/NetworkAlert/NetworkAlert' import SettingsTab from 'legacy/components/Settings' import useCowBalanceAndSubsidy from 'legacy/hooks/useCowBalanceAndSubsidy' -import usePriceImpact from 'legacy/hooks/usePriceImpact' import { useHigherUSDValue } from 'legacy/hooks/useStablecoinPrice' -import { useWrapType, WrapType } from 'legacy/hooks/useWrapCallback' import { useModalIsOpen } from 'legacy/state/application/hooks' import { ApplicationModal } from 'legacy/state/application/reducer' import { useIsTradeUnsupported } from 'legacy/state/lists/hooks' @@ -41,7 +39,7 @@ import { } from 'modules/swap/pure/warnings' import { useFillSwapDerivedState } from 'modules/swap/state/useSwapDerivedState' import useCurrencyBalance from 'modules/tokens/hooks/useCurrencyBalance' -import { TradeWidget, TradeWidgetContainer, useSetupTradeState } from 'modules/trade' +import { TradeWidget, TradeWidgetContainer, useSetupTradeState, useTradePriceImpact } from 'modules/trade' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' import { useIsSafeViaWc, useIsSafeWallet, useWalletDetails, useWalletInfo } from 'modules/wallet' @@ -71,8 +69,7 @@ export function SwapWidget() { currenciesIds, v2Trade: trade, } = useDerivedSwapInfo() - const wrapType = useWrapType() - const parsedAmounts = useSwapCurrenciesAmounts(wrapType) + const parsedAmounts = useSwapCurrenciesAmounts() const { isSupportedWallet, allowsOffchainSigning } = useWalletDetails() const isSwapUnsupported = useIsTradeUnsupported(currencies.INPUT, currencies.OUTPUT) const [isExpertMode] = useExpertModeManager() @@ -85,12 +82,7 @@ export function SwapWidget() { const isEoaEthFlow = useIsEoaEthFlow() const shouldZeroApprove = useShouldZeroApprove(slippageAdjustedSellAmount) - const isWrapUnwrapMode = wrapType !== WrapType.NOT_APPLICABLE - const priceImpactParams = usePriceImpact({ - abTrade: trade, - parsedAmounts, - isWrapping: isWrapUnwrapMode, - }) + const priceImpactParams = useTradePriceImpact() const isTradePriceUpdating = useTradePricesUpdate() const { isFeeGreater, fee } = useIsFeeGreaterThanInput({ @@ -147,7 +139,6 @@ export function SwapWidget() { allowedSlippage, handleSwap: swapButtonContext.handleSwap, priceImpact: priceImpactParams.priceImpact, - dismissNativeWrapModal, rateInfoParams, } @@ -194,7 +185,7 @@ export function SwapWidget() { feeWarningAccepted, impactWarningAccepted, // don't show the unknown impact warning on: no trade, wrapping native, no error, or it's loading impact - hideUnknownImpactWarning: !trade || isWrapUnwrapMode || !priceImpactParams.error || priceImpactParams.loading, + hideUnknownImpactWarning: !trade || !priceImpactParams.error || priceImpactParams.loading, isExpertMode, showApprovalBundlingBanner, showWrapBundlingBanner, @@ -225,13 +216,11 @@ export function SwapWidget() { rateInfoParams, } - const showTradeRates = !isWrapUnwrapMode - const slots = { settingsWidget: , bottomContent: ( <> - {showTradeRates && } + diff --git a/src/modules/swap/helpers/getSwapButtonState.ts b/src/modules/swap/helpers/getSwapButtonState.ts index 6f46504e6f..74e7d390bd 100644 --- a/src/modules/swap/helpers/getSwapButtonState.ts +++ b/src/modules/swap/helpers/getSwapButtonState.ts @@ -1,7 +1,6 @@ import { Token } from '@uniswap/sdk-core' import { ApprovalState } from 'legacy/hooks/useApproveCallback' -import { WrapType } from 'legacy/hooks/useWrapCallback' import { QuoteError } from 'legacy/state/price/actions' import TradeGp from 'legacy/state/swap/TradeGp' @@ -10,9 +9,6 @@ import { getEthFlowEnabled } from 'modules/swap/helpers/getEthFlowEnabled' export enum SwapButtonState { SwapIsUnsupported = 'SwapIsUnsupported', WalletIsUnsupported = 'WalletIsUnsupported', - WrapError = 'WrapError', - ShouldWrapNativeToken = 'ShouldWrapNativeToken', - ShouldUnwrapNativeToken = 'ShouldUnwrapNativeToken', FeesExceedFromAmount = 'FeesExceedFromAmount', InsufficientLiquidity = 'InsufficientLiquidity', ZeroPrice = 'ZeroPrice', @@ -46,8 +42,6 @@ export interface SwapButtonStateParams { isSwapUnsupported: boolean isTxBundlingEnabled: boolean isEthFlowBundlingEnabled: boolean - wrapType: WrapType - wrapInputError: string | undefined quoteError: QuoteError | undefined | null inputError?: string approvalState: ApprovalState @@ -73,7 +67,7 @@ const quoteErrorToSwapButtonState: { [key in QuoteError]: SwapButtonState | null } export function getSwapButtonState(input: SwapButtonStateParams): SwapButtonState { - const { wrapType, quoteError, approvalState } = input + const { quoteError, approvalState } = input // show approve flow when: no error on inputs, not approved or pending, or approved in current session // never show if price impact is above threshold in non expert mode @@ -83,7 +77,7 @@ export function getSwapButtonState(input: SwapButtonStateParams): SwapButtonStat const isValid = !input.inputError && input.feeWarningAccepted && input.impactWarningAccepted const swapBlankState = !input.inputError && !input.trade - if (quoteError && ![WrapType.WRAP, WrapType.UNWRAP].includes(wrapType)) { + if (quoteError) { const quoteErrorState = quoteErrorToSwapButtonState[quoteError] if (quoteErrorState) return quoteErrorState @@ -101,18 +95,6 @@ export function getSwapButtonState(input: SwapButtonStateParams): SwapButtonStat return SwapButtonState.WalletIsUnsupported } - if (wrapType !== WrapType.NOT_APPLICABLE && input.wrapInputError) { - return SwapButtonState.WrapError - } - - if (wrapType === WrapType.WRAP) { - return SwapButtonState.ShouldWrapNativeToken - } - - if (wrapType === WrapType.UNWRAP) { - return SwapButtonState.ShouldUnwrapNativeToken - } - if (swapBlankState || input.isGettingNewQuote || input.isBestQuoteLoading) { return SwapButtonState.Loading } diff --git a/src/modules/swap/hooks/useShowRecipientControls.ts b/src/modules/swap/hooks/useShowRecipientControls.ts index da53edb6f7..a2bd7b328f 100644 --- a/src/modules/swap/hooks/useShowRecipientControls.ts +++ b/src/modules/swap/hooks/useShowRecipientControls.ts @@ -1,14 +1,11 @@ import { useMemo } from 'react' -import { useWrapType, WrapType } from 'legacy/hooks/useWrapCallback' import { useIsRecipientToggleVisible } from 'legacy/state/user/hooks' export function useShowRecipientControls(recipient: string | null): boolean { - const wrapType = useWrapType() - const isWrapUnwrap = wrapType !== WrapType.NOT_APPLICABLE const isRecipientToggleVisible = useIsRecipientToggleVisible() return useMemo(() => { - return !isWrapUnwrap && (isRecipientToggleVisible || !!recipient) - }, [isWrapUnwrap, isRecipientToggleVisible, recipient]) + return isRecipientToggleVisible || !!recipient + }, [isRecipientToggleVisible, recipient]) } diff --git a/src/modules/swap/hooks/useSwapButtonContext.ts b/src/modules/swap/hooks/useSwapButtonContext.ts index 8a13005ddd..4ac0493a34 100644 --- a/src/modules/swap/hooks/useSwapButtonContext.ts +++ b/src/modules/swap/hooks/useSwapButtonContext.ts @@ -1,16 +1,12 @@ import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { t } from '@lingui/macro' - import { PriceImpact } from 'legacy/hooks/usePriceImpact' -import { useWrapCallback, useWrapType, WrapType } from 'legacy/hooks/useWrapCallback' import { useToggleWalletModal } from 'legacy/state/application/hooks' import { useIsTradeUnsupported } from 'legacy/state/lists/hooks' import { useGetQuoteAndStatus, useIsBestQuoteLoading } from 'legacy/state/price/hooks' import { Field } from 'legacy/state/swap/actions' import { useDerivedSwapInfo, useSwapActionHandlers } from 'legacy/state/swap/hooks' import { useExpertModeManager } from 'legacy/state/user/hooks' -import { getChainCurrencySymbols } from 'legacy/utils/gnosis_chain/hack' import { getSwapButtonState } from 'modules/swap/helpers/getSwapButtonState' import { useEthFlowContext } from 'modules/swap/hooks/useEthFlowContext' @@ -20,6 +16,7 @@ import { useSwapConfirmManager } from 'modules/swap/hooks/useSwapConfirmManager' import { useSwapFlowContext } from 'modules/swap/hooks/useSwapFlowContext' import { SwapButtonsContext } from 'modules/swap/pure/SwapButtons' import useCurrencyBalance from 'modules/tokens/hooks/useCurrencyBalance' +import { useWrapNativeFlow } from 'modules/trade' import { useIsNativeIn } from 'modules/trade/hooks/useIsNativeInOrOut' import { useIsWrappedOut } from 'modules/trade/hooks/useIsWrappedInOrOut' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' @@ -29,7 +26,6 @@ import { useTradeApproveState } from 'common/containers/TradeApprove/useTradeApp import { useIsEthFlowBundlingEnabled } from 'common/hooks/featureFlags/useIsEthFlowBundlingEnabled' import { useIsTxBundlingEnabled } from 'common/hooks/featureFlags/useIsTxBundlingEnabled' import { useIsSmartContractWallet } from 'common/hooks/useIsSmartContractWallet' -import { formatSymbol } from 'utils/format' import { useSafeBundleEthFlowContext } from './useSafeBundleEthFlowContext' @@ -78,10 +74,8 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext const inputAmount = slippageAdjustedSellAmount || parsedAmount const wrapUnwrapAmount = isNativeInSwap ? inputAmount?.wrapped : inputAmount - const wrapType = useWrapType() - const wrapInputError = useWrapUnwrapError(wrapType, wrapUnwrapAmount) const hasEnoughWrappedBalanceForSwap = useHasEnoughWrappedBalanceForSwap(wrapUnwrapAmount) - const wrapCallback = useWrapCallback(wrapUnwrapAmount) + const wrapCallback = useWrapNativeFlow() const approvalState = useTradeApproveState(slippageAdjustedSellAmount || null) const handleSwap = useHandleSwap(priceImpactParams) @@ -107,8 +101,6 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext isSwapUnsupported, isNativeIn: isNativeInSwap, wrappedToken, - wrapType, - wrapInputError, quoteError: quote?.error, inputError: swapInputError, approvalState, @@ -126,8 +118,6 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext chainId, wrappedToken, handleSwap, - wrapInputError, - wrapUnwrapAmount, hasEnoughWrappedBalanceForSwap, onWrapOrUnwrap: wrapCallback, onEthFlow() { @@ -142,25 +132,6 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext } } -// TODO: get rid of it. The validation should be handled by modules/tradeFormValidation -function useWrapUnwrapError(wrapType: WrapType, inputAmount?: CurrencyAmount): string | undefined { - const { chainId, account } = useWalletInfo() - const { currencies } = useDerivedSwapInfo() - const { native, wrapped } = getChainCurrencySymbols(chainId) - const balance = useCurrencyBalance(account ?? undefined, currencies.INPUT) - - const symbol = wrapType === WrapType.WRAP ? native : wrapped - // Check if user has enough balance for wrap/unwrap - const sufficientBalance = !!(inputAmount && balance && !balance.lessThan(inputAmount)) - const isZero = balance && !inputAmount - - if (isZero) { - return t`Enter an amount` - } - - return !sufficientBalance ? t`Insufficient ${formatSymbol(symbol)} balance` : undefined -} - function useHasEnoughWrappedBalanceForSwap(inputAmount?: CurrencyAmount): boolean { const { currencies } = useDerivedSwapInfo() const { account } = useWalletInfo() diff --git a/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts b/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts index 4a5ea56815..60036372c1 100644 --- a/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts +++ b/src/modules/swap/hooks/useSwapCurrenciesAmounts.ts @@ -1,25 +1,31 @@ +import { useMemo } from 'react' + import { ParsedAmounts } from 'legacy/hooks/usePriceImpact/types' -import { WrapType } from 'legacy/hooks/useWrapCallback' import { Field } from 'legacy/state/swap/actions' import { useSwapState } from 'legacy/state/swap/hooks' import { useDerivedSwapInfo } from 'legacy/state/swap/hooks' -export function useSwapCurrenciesAmounts(wrapType: WrapType): ParsedAmounts { +import { useSafeMemoObject } from 'common/hooks/useSafeMemo' + +export function useSwapCurrenciesAmounts(): ParsedAmounts { const { independentField } = useSwapState() const { v2Trade: trade, parsedAmount } = useDerivedSwapInfo() const isInputIndependent = independentField === Field.INPUT - const isWrapUnwrapMode = wrapType !== WrapType.NOT_APPLICABLE + const inputAmountWithoutFee = trade?.inputAmountWithoutFee + const outputAmountWithoutFee = trade?.outputAmountWithoutFee - if (isWrapUnwrapMode) { + const context = useSafeMemoObject({ + parsedAmount, + inputAmountWithoutFee, + outputAmountWithoutFee, + }) + + return useMemo(() => { + const { parsedAmount, inputAmountWithoutFee, outputAmountWithoutFee } = context return { - [Field.INPUT]: parsedAmount, - [Field.OUTPUT]: parsedAmount, + [Field.INPUT]: isInputIndependent ? parsedAmount : inputAmountWithoutFee, + [Field.OUTPUT]: isInputIndependent ? outputAmountWithoutFee : parsedAmount, } - } - - return { - [Field.INPUT]: isInputIndependent ? parsedAmount : trade?.inputAmountWithoutFee, - [Field.OUTPUT]: isInputIndependent ? trade?.outputAmountWithoutFee : parsedAmount, - } + }, [isInputIndependent, context]) } diff --git a/src/modules/swap/hooks/useTransactionConfirmModal.ts b/src/modules/swap/hooks/useTransactionConfirmModal.ts deleted file mode 100644 index ca5b5fe690..0000000000 --- a/src/modules/swap/hooks/useTransactionConfirmModal.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useUpdateAtom } from 'jotai/utils' -import { useCallback } from 'react' - -import { useOpenModal } from 'legacy/state/application/hooks' -import { ApplicationModal } from 'legacy/state/application/reducer' - -import { transactionConfirmAtom, TransactionConfirmState } from 'modules/swap/state/transactionConfirmAtom' - -export function useTransactionConfirmModal() { - const setTransactionConfirm = useUpdateAtom(transactionConfirmAtom) - const openTxConfirmationModal = useOpenModal(ApplicationModal.TRANSACTION_CONFIRMATION) - - return useCallback( - (state: TransactionConfirmState) => { - setTransactionConfirm(state) - openTxConfirmationModal() - }, - [setTransactionConfirm, openTxConfirmationModal] - ) -} diff --git a/src/modules/swap/pure/SwapButtons/index.cosmos.tsx b/src/modules/swap/pure/SwapButtons/index.cosmos.tsx index 218a0505f0..e848722118 100644 --- a/src/modules/swap/pure/SwapButtons/index.cosmos.tsx +++ b/src/modules/swap/pure/SwapButtons/index.cosmos.tsx @@ -21,8 +21,6 @@ const swapButtonsContext: SwapButtonsContext = { wrappedToken: WETH_GOERLI, handleSwap: () => void 0, inputAmount: CurrencyAmount.fromRawAmount(currency, amount * 10 ** 18), - wrapUnwrapAmount: CurrencyAmount.fromRawAmount(WETH_GOERLI, 10000000), - wrapInputError: undefined, onWrapOrUnwrap: null, onEthFlow: () => void 0, openSwapConfirm: () => void 0, diff --git a/src/modules/swap/pure/SwapButtons/index.tsx b/src/modules/swap/pure/SwapButtons/index.tsx index cdcc26c131..a225e29457 100644 --- a/src/modules/swap/pure/SwapButtons/index.tsx +++ b/src/modules/swap/pure/SwapButtons/index.tsx @@ -32,8 +32,6 @@ export interface SwapButtonsContext { wrappedToken: Token handleSwap: HandleSwapCallback inputAmount: CurrencyAmount | undefined - wrapUnwrapAmount: CurrencyAmount | undefined - wrapInputError: string | undefined onWrapOrUnwrap: WrapUnwrapCallback | null onEthFlow: () => void openSwapConfirm: () => void @@ -56,21 +54,6 @@ const swapButtonStateMap: { [key in SwapButtonState]: (props: SwapButtonsContext ), - [SwapButtonState.WrapError]: (props: SwapButtonsContext) => ( - - {props.wrapInputError} - - ), - [SwapButtonState.ShouldWrapNativeToken]: (props: SwapButtonsContext) => ( - props.onWrapOrUnwrap?.()} buttonSize={ButtonSize.BIG}> - Wrap - - ), - [SwapButtonState.ShouldUnwrapNativeToken]: (props: SwapButtonsContext) => ( - props.onWrapOrUnwrap?.()} buttonSize={ButtonSize.BIG}> - Unwrap - - ), [SwapButtonState.SwapWithWrappedToken]: (props: SwapButtonsContext) => ( diff --git a/src/modules/swap/state/transactionConfirmAtom.ts b/src/modules/swap/state/transactionConfirmAtom.ts deleted file mode 100644 index 4e76c5467a..0000000000 --- a/src/modules/swap/state/transactionConfirmAtom.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { atom } from 'jotai' - -import { ConfirmOperationType } from 'legacy/components/TransactionConfirmationModal' - -export interface TransactionConfirmState { - operationType: ConfirmOperationType - pendingText: string -} - -export const transactionConfirmAtom = atom({ - operationType: ConfirmOperationType.UNWRAP_WETH, - pendingText: '', -}) diff --git a/src/modules/swap/state/useSwapDerivedState.ts b/src/modules/swap/state/useSwapDerivedState.ts index 33c8b062b2..e6b4dad284 100644 --- a/src/modules/swap/state/useSwapDerivedState.ts +++ b/src/modules/swap/state/useSwapDerivedState.ts @@ -7,6 +7,8 @@ import { useHigherUSDValue } from 'legacy/hooks/useStablecoinPrice' import { Field } from 'legacy/state/swap/actions' import { useDerivedSwapInfo, useSwapState } from 'legacy/state/swap/hooks' +import { useSafeMemoObject } from 'common/hooks/useSafeMemo' + import { SwapDerivedState, swapDerivedStateAtom } from './swapDerivedStateAtom' export function useSwapDerivedState(): SwapDerivedState { @@ -22,41 +24,29 @@ export function useFillSwapDerivedState() { const outputCurrency = currencies.OUTPUT || null const inputCurrencyBalance = currencyBalances.INPUT || null const outputCurrencyBalance = currencyBalances.OUTPUT || null - const inputCurrencyAmount = (isSellTrade ? parsedAmount : v2Trade?.inputAmount) || null - const outputCurrencyAmount = (!isSellTrade ? parsedAmount : v2Trade?.outputAmount) || null + const inputCurrencyAmount = (isSellTrade ? parsedAmount : v2Trade?.inputAmountWithoutFee) || null + const outputCurrencyAmount = (!isSellTrade ? parsedAmount : v2Trade?.outputAmountWithoutFee) || null const inputCurrencyFiatAmount = useHigherUSDValue(inputCurrencyAmount || undefined) const outputCurrencyFiatAmount = useHigherUSDValue(outputCurrencyAmount || undefined) const updateDerivedState = useUpdateAtom(swapDerivedStateAtom) - useEffect(() => { - updateDerivedState({ - inputCurrency, - outputCurrency, - inputCurrencyAmount, - outputCurrencyAmount, - slippageAdjustedSellAmount, - inputCurrencyBalance, - outputCurrencyBalance, - inputCurrencyFiatAmount, - outputCurrencyFiatAmount, - recipient, - orderKind: isSellTrade ? OrderKind.SELL : OrderKind.BUY, - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ + const state = useSafeMemoObject({ inputCurrency, outputCurrency, - inputCurrencyAmount?.quotient, - outputCurrencyAmount?.quotient, - slippageAdjustedSellAmount?.quotient, - inputCurrencyBalance?.quotient, - outputCurrencyBalance?.quotient, - inputCurrencyFiatAmount?.quotient, - outputCurrencyFiatAmount?.quotient, + inputCurrencyAmount, + outputCurrencyAmount, + slippageAdjustedSellAmount, + inputCurrencyBalance, + outputCurrencyBalance, + inputCurrencyFiatAmount, + outputCurrencyFiatAmount, recipient, - independentField, - updateDerivedState, - ]) + orderKind: isSellTrade ? OrderKind.SELL : OrderKind.BUY, + }) + + useEffect(() => { + updateDerivedState(state) + }, [state, updateDerivedState]) } diff --git a/src/modules/tokens/hooks/useOnchainBalances.ts b/src/modules/tokens/hooks/useOnchainBalances.ts index 43627f8201..cad2b6f077 100644 --- a/src/modules/tokens/hooks/useOnchainBalances.ts +++ b/src/modules/tokens/hooks/useOnchainBalances.ts @@ -28,13 +28,13 @@ export type OnchainAllowancesParams = OnchainAmountsParams & { spender?: string export function useOnchainBalances(params: OnchainBalancesParams): TokenAmountsResult { const { account } = params - const callParams = [account] + const callParams = useMemo(() => [account], [account]) return useOnchainErc20Amounts('balanceOf', callParams, params) } export function useOnchainAllowances(params: OnchainAllowancesParams): TokenAmountsResult { const { account, spender } = params - const callParams = [account, spender] + const callParams = useMemo(() => [account, spender], [account, spender]) return useOnchainErc20Amounts('allowance', callParams, params) } diff --git a/src/modules/trade/hooks/useTradePriceImpactParams.ts b/src/modules/trade/hooks/useTradePriceImpactParams.ts index a07ec94e73..7dfa796638 100644 --- a/src/modules/trade/hooks/useTradePriceImpactParams.ts +++ b/src/modules/trade/hooks/useTradePriceImpactParams.ts @@ -3,13 +3,17 @@ import { useMemo } from 'react' import type { PriceImpactParams } from 'legacy/hooks/usePriceImpact' import { useDerivedTradeState } from './useDerivedTradeState' +import { useIsWrapOrUnwrap } from './useIsWrapOrUnwrap' + +const emptyState = { + inputCurrencyAmount: null, + outputCurrencyAmount: null, +} export function useTradePriceImpactParams(): PriceImpactParams { const { state } = useDerivedTradeState() - const { inputCurrencyAmount, outputCurrencyAmount } = state || { - inputCurrencyAmount: null, - outputCurrencyAmount: null, - } + const isWrapOrUnwrap = useIsWrapOrUnwrap() + const { inputCurrencyAmount, outputCurrencyAmount } = state || emptyState return useMemo(() => { const abTrade = { @@ -28,8 +32,8 @@ export function useTradePriceImpactParams(): PriceImpactParams { return { abTrade, parsedAmounts, - isWrapping: false, + isWrapping: isWrapOrUnwrap, } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [inputCurrencyAmount?.quotient.toString(), outputCurrencyAmount?.quotient.toString()]) + }, [inputCurrencyAmount?.quotient.toString(), outputCurrencyAmount?.quotient.toString(), isWrapOrUnwrap]) } diff --git a/src/modules/trade/hooks/useWrapNativeFlow.ts b/src/modules/trade/hooks/useWrapNativeFlow.ts index c30550825a..d1ea61c023 100644 --- a/src/modules/trade/hooks/useWrapNativeFlow.ts +++ b/src/modules/trade/hooks/useWrapNativeFlow.ts @@ -20,15 +20,18 @@ import { useDerivedTradeState } from './useDerivedTradeState' import { wrapNativeStateAtom } from '../state/wrapNativeStateAtom' -export function useWrapNativeFlow() { - const setWrapNativeState = useUpdateAtom(wrapNativeStateAtom) +export function useWrapNativeFlow(): WrapUnwrapCallback { const derivedTradeState = useDerivedTradeState() const wrapCallback = useWrapNativeCallback(derivedTradeState.state?.inputCurrencyAmount) - return useCallback(() => { - setWrapNativeState({ isOpen: true }) - wrapCallback?.() - }, [setWrapNativeState, wrapCallback]) + return useCallback( + (params?: WrapUnwrapCallbackParams) => { + if (!wrapCallback) return Promise.resolve(null) + + return wrapCallback(params) + }, + [wrapCallback] + ) } function useWrapNativeContext(amount: Nullish>): WrapUnwrapContext | null { diff --git a/src/modules/trade/updaters/PriceImpactUpdater.tsx b/src/modules/trade/updaters/PriceImpactUpdater.tsx index 2e9fc92d2d..baeaef7b89 100644 --- a/src/modules/trade/updaters/PriceImpactUpdater.tsx +++ b/src/modules/trade/updaters/PriceImpactUpdater.tsx @@ -1,7 +1,7 @@ import { useUpdateAtom } from 'jotai/utils' import { useEffect } from 'react' -import usePriceImpact from 'legacy/hooks/usePriceImpact' +import { usePriceImpact } from 'legacy/hooks/usePriceImpact' import { useTradePriceImpactParams } from '../hooks/useTradePriceImpactParams' import { priceImpactAtom } from '../state/priceImpactAtom' From 2dd81d86fc58d7e7fd8dabb2d4f0415afbd80a27 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Mon, 3 Jul 2023 18:21:51 +0600 Subject: [PATCH 05/10] chore: fix memory leak --- src/modules/swap/state/useSwapDerivedState.ts | 46 ++++++++----------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/modules/swap/state/useSwapDerivedState.ts b/src/modules/swap/state/useSwapDerivedState.ts index 33c8b062b2..e6b4dad284 100644 --- a/src/modules/swap/state/useSwapDerivedState.ts +++ b/src/modules/swap/state/useSwapDerivedState.ts @@ -7,6 +7,8 @@ import { useHigherUSDValue } from 'legacy/hooks/useStablecoinPrice' import { Field } from 'legacy/state/swap/actions' import { useDerivedSwapInfo, useSwapState } from 'legacy/state/swap/hooks' +import { useSafeMemoObject } from 'common/hooks/useSafeMemo' + import { SwapDerivedState, swapDerivedStateAtom } from './swapDerivedStateAtom' export function useSwapDerivedState(): SwapDerivedState { @@ -22,41 +24,29 @@ export function useFillSwapDerivedState() { const outputCurrency = currencies.OUTPUT || null const inputCurrencyBalance = currencyBalances.INPUT || null const outputCurrencyBalance = currencyBalances.OUTPUT || null - const inputCurrencyAmount = (isSellTrade ? parsedAmount : v2Trade?.inputAmount) || null - const outputCurrencyAmount = (!isSellTrade ? parsedAmount : v2Trade?.outputAmount) || null + const inputCurrencyAmount = (isSellTrade ? parsedAmount : v2Trade?.inputAmountWithoutFee) || null + const outputCurrencyAmount = (!isSellTrade ? parsedAmount : v2Trade?.outputAmountWithoutFee) || null const inputCurrencyFiatAmount = useHigherUSDValue(inputCurrencyAmount || undefined) const outputCurrencyFiatAmount = useHigherUSDValue(outputCurrencyAmount || undefined) const updateDerivedState = useUpdateAtom(swapDerivedStateAtom) - useEffect(() => { - updateDerivedState({ - inputCurrency, - outputCurrency, - inputCurrencyAmount, - outputCurrencyAmount, - slippageAdjustedSellAmount, - inputCurrencyBalance, - outputCurrencyBalance, - inputCurrencyFiatAmount, - outputCurrencyFiatAmount, - recipient, - orderKind: isSellTrade ? OrderKind.SELL : OrderKind.BUY, - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ + const state = useSafeMemoObject({ inputCurrency, outputCurrency, - inputCurrencyAmount?.quotient, - outputCurrencyAmount?.quotient, - slippageAdjustedSellAmount?.quotient, - inputCurrencyBalance?.quotient, - outputCurrencyBalance?.quotient, - inputCurrencyFiatAmount?.quotient, - outputCurrencyFiatAmount?.quotient, + inputCurrencyAmount, + outputCurrencyAmount, + slippageAdjustedSellAmount, + inputCurrencyBalance, + outputCurrencyBalance, + inputCurrencyFiatAmount, + outputCurrencyFiatAmount, recipient, - independentField, - updateDerivedState, - ]) + orderKind: isSellTrade ? OrderKind.SELL : OrderKind.BUY, + }) + + useEffect(() => { + updateDerivedState(state) + }, [state, updateDerivedState]) } From 970444a9ee122f4e5f1cbff667b658926153e059 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Tue, 4 Jul 2023 13:16:16 +0600 Subject: [PATCH 06/10] chore: fix test --- src/modules/swap/hooks/useHandleSwap.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/swap/hooks/useHandleSwap.test.tsx b/src/modules/swap/hooks/useHandleSwap.test.tsx index 5cb5bca3af..4a00a9a4fe 100644 --- a/src/modules/swap/hooks/useHandleSwap.test.tsx +++ b/src/modules/swap/hooks/useHandleSwap.test.tsx @@ -23,7 +23,6 @@ jest.mock('legacy/state/swap/hooks') jest.mock('modules/swap/services/swapFlow') jest.mock('modules/swap/services/ethFlow') jest.mock('modules/swap/services/safeBundleFlow') -jest.mock('modules/swap/state/transactionConfirmAtom') const mockUseSwapActionHandlers = useSwapActionHandlers as jest.MockedFunction const mockSwapFlow = swapFlow as jest.MockedFunction From ec27dcc9d9f9cc241266d5d0a5363e73ab4d3ee0 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Tue, 4 Jul 2023 17:11:19 +0600 Subject: [PATCH 07/10] fix: fix trade form validation order --- .../services/validateTradeForm.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/tradeFormValidation/services/validateTradeForm.ts b/src/modules/tradeFormValidation/services/validateTradeForm.ts index 0f16907442..6290bed124 100644 --- a/src/modules/tradeFormValidation/services/validateTradeForm.ts +++ b/src/modules/tradeFormValidation/services/validateTradeForm.ts @@ -26,14 +26,6 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor const inputAmountIsNotSet = !inputCurrencyAmount || isFractionFalsy(inputCurrencyAmount) - if (isWrapUnwrap) { - if (inputAmountIsNotSet) { - return TradeFormValidation.WrapUnwrapAmountNotSet - } - - return TradeFormValidation.WrapUnwrapFlow - } - if (tradeQuote.error) { return TradeFormValidation.QuoteErrors } @@ -54,6 +46,14 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor return TradeFormValidation.CurrencyNotSet } + if (isWrapUnwrap) { + if (inputAmountIsNotSet) { + return TradeFormValidation.WrapUnwrapAmountNotSet + } + + return TradeFormValidation.WrapUnwrapFlow + } + if (inputAmountIsNotSet) { return TradeFormValidation.InputAmountNotSet } From 254ed246f9fcb9de97bb55bfa800b1b49230bdf5 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Wed, 5 Jul 2023 13:53:34 +0600 Subject: [PATCH 08/10] fix: fix wrap flow issues --- .../swap/containers/SwapWidget/styled.tsx | 44 ------------------- .../trade/containers/TradeWidget/index.tsx | 4 +- .../pure/TradeFormButtons/tradeButtonsMap.tsx | 2 +- .../services/validateTradeForm.ts | 2 +- 4 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 src/modules/swap/containers/SwapWidget/styled.tsx diff --git a/src/modules/swap/containers/SwapWidget/styled.tsx b/src/modules/swap/containers/SwapWidget/styled.tsx deleted file mode 100644 index 4596cc5cc6..0000000000 --- a/src/modules/swap/containers/SwapWidget/styled.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import styled from 'styled-components/macro' - -import SwapHeader from 'legacy/components/swap/SwapHeader' - -import { SetRecipient } from 'modules/swap/containers/SetRecipient' - -import { LoadingWrapper } from 'common/pure/CurrencyArrowSeparator/styled' - -export const Header = styled.div` - display: flex; - justify-content: space-between; - padding: 0 12px 4px; - margin: 5px 0 15px 0; - font-weight: 500; - font-size: 16px; -` - -export const SwapFormWrapper = styled.div` - margin: 0 0 10px; - - ${LoadingWrapper} { - ${({ theme }) => theme.mediaWidth.upToSmall` - --size: 24px; - height: var(--size); - width: var(--size); - left: calc(50% - var(--size)/2); - border-radius: var(--size); - `}; - } -` - -export const CurrencySeparatorBox = styled.div<{ withRecipient: boolean }>` - display: flex; - justify-content: space-between; - margin: ${({ withRecipient }) => (withRecipient ? '10px' : '1px 0')}; -` - -export const SwapHeaderStyled = styled(SwapHeader)` - padding: 4px 4px 16px 8px; -` - -export const SetRecipientStyled = styled(SetRecipient)` - margin: 10px 0; -` diff --git a/src/modules/trade/containers/TradeWidget/index.tsx b/src/modules/trade/containers/TradeWidget/index.tsx index 017c42ce5f..03cc9082d5 100644 --- a/src/modules/trade/containers/TradeWidget/index.tsx +++ b/src/modules/trade/containers/TradeWidget/index.tsx @@ -144,7 +144,7 @@ export function TradeWidget(props: TradeWidgetProps) { hasSeparatorLine={!compactView} border={!compactView} onSwitchTokens={throttledOnSwitchTokens} - withRecipient={showRecipient} + withRecipient={!isWrapOrUnwrap && showRecipient} isLoading={isTradePriceUpdating} /> @@ -171,7 +171,7 @@ export function TradeWidget(props: TradeWidgetProps) { topLabel={isWrapOrUnwrap ? undefined : outputCurrencyInfo.label} /> - {showRecipient && ( + {!isWrapOrUnwrap && showRecipient && ( )} diff --git a/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx b/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx index ab4e433eed..c113ba04fb 100644 --- a/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx +++ b/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx @@ -44,7 +44,7 @@ export const tradeButtonsMap: Record + context.wrapNativeFlow()}> {isNativeIn ? 'Wrap' : 'Unwrap'} ) diff --git a/src/modules/tradeFormValidation/services/validateTradeForm.ts b/src/modules/tradeFormValidation/services/validateTradeForm.ts index 6290bed124..27a525ac1c 100644 --- a/src/modules/tradeFormValidation/services/validateTradeForm.ts +++ b/src/modules/tradeFormValidation/services/validateTradeForm.ts @@ -26,7 +26,7 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor const inputAmountIsNotSet = !inputCurrencyAmount || isFractionFalsy(inputCurrencyAmount) - if (tradeQuote.error) { + if (!isWrapUnwrap && tradeQuote.error) { return TradeFormValidation.QuoteErrors } From bfe09c6f9616dbd038ab23d742a4da6fac812a2f Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Wed, 5 Jul 2023 19:15:09 +0600 Subject: [PATCH 09/10] fix: fix wrap flow validation priority --- .../pure/TradeFormButtons/tradeButtonsMap.tsx | 3 -- .../services/validateTradeForm.ts | 30 +++++++++---------- src/modules/tradeFormValidation/types.ts | 1 - 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx b/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx index c113ba04fb..db3a3432bc 100644 --- a/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx +++ b/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx @@ -37,9 +37,6 @@ const quoteErrorTexts: Record = { } export const tradeButtonsMap: Record = { - [TradeFormValidation.WrapUnwrapAmountNotSet]: { - text: 'Enter an amount', - }, [TradeFormValidation.WrapUnwrapFlow]: (context) => { const isNativeIn = !!context.derivedState.inputCurrency?.isNative diff --git a/src/modules/tradeFormValidation/services/validateTradeForm.ts b/src/modules/tradeFormValidation/services/validateTradeForm.ts index 27a525ac1c..445ef5e67b 100644 --- a/src/modules/tradeFormValidation/services/validateTradeForm.ts +++ b/src/modules/tradeFormValidation/services/validateTradeForm.ts @@ -46,28 +46,22 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor return TradeFormValidation.CurrencyNotSet } - if (isWrapUnwrap) { - if (inputAmountIsNotSet) { - return TradeFormValidation.WrapUnwrapAmountNotSet - } - - return TradeFormValidation.WrapUnwrapFlow - } - if (inputAmountIsNotSet) { return TradeFormValidation.InputAmountNotSet } - if (recipient && !recipientEnsAddress && !isAddress(recipient)) { - return TradeFormValidation.RecipientInvalid - } + if (!isWrapUnwrap) { + if (recipient && !recipientEnsAddress && !isAddress(recipient)) { + return TradeFormValidation.RecipientInvalid + } - if (isSwapUnsupported) { - return TradeFormValidation.CurrencyNotSupported - } + if (isSwapUnsupported) { + return TradeFormValidation.CurrencyNotSupported + } - if (!tradeQuote.response) { - return TradeFormValidation.QuoteLoading + if (!tradeQuote.response) { + return TradeFormValidation.QuoteLoading + } } if (!inputCurrencyBalance) { @@ -78,6 +72,10 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor return TradeFormValidation.BalanceInsufficient } + if (isWrapUnwrap) { + return TradeFormValidation.WrapUnwrapFlow + } + if (approvalRequired) { if (isTxBundlingEnabled) { if (isExpertMode) { diff --git a/src/modules/tradeFormValidation/types.ts b/src/modules/tradeFormValidation/types.ts index 919ed40c4f..4c3ed7a8de 100644 --- a/src/modules/tradeFormValidation/types.ts +++ b/src/modules/tradeFormValidation/types.ts @@ -5,7 +5,6 @@ import { TradeQuoteState } from 'modules/tradeQuote' export enum TradeFormValidation { // Wrap/unwrap - WrapUnwrapAmountNotSet, WrapUnwrapFlow, // Quote errors From aa05fee83fe7b8107b53acd9ca3262c532aa5e92 Mon Sep 17 00:00:00 2001 From: Alexandr Kazachenko Date: Wed, 5 Jul 2023 21:00:08 +0600 Subject: [PATCH 10/10] fix: don't reset amounts on switch tokens --- src/legacy/state/swap/reducer.ts | 17 +++++++++--- src/modules/trade/hooks/useIsNativeInOrOut.ts | 17 +----------- src/modules/trade/hooks/useIsWrapOrUnwrap.ts | 17 ++---------- src/utils/getIsNativeToken.ts | 16 +++++++++++ src/utils/getIsWrapOrUnwrap.ts | 27 +++++++++++++++++++ 5 files changed, 59 insertions(+), 35 deletions(-) create mode 100644 src/utils/getIsNativeToken.ts create mode 100644 src/utils/getIsWrapOrUnwrap.ts diff --git a/src/legacy/state/swap/reducer.ts b/src/legacy/state/swap/reducer.ts index c7ebef5b85..06b74ad661 100644 --- a/src/legacy/state/swap/reducer.ts +++ b/src/legacy/state/swap/reducer.ts @@ -16,6 +16,9 @@ import { } from 'legacy/state/swap/actions' import { queryParametersToSwapState } from 'legacy/state/swap/hooks' +import { getIsNativeToken } from 'utils/getIsNativeToken' +import { getIsWrapOrUnwrap } from 'utils/getIsWrapOrUnwrap' + export interface SwapState { // Mod: added chainId chainId: number | null @@ -143,10 +146,16 @@ export default createReducer(initialState, (builder) => function getEthFlowOverridesOnSwitch(state: SwapState): Pick { const chainId: ChainId = state.chainId || ChainId.MAINNET - const isNativeOut = - state[Field.OUTPUT].currencyId?.toUpperCase() === NATIVE_CURRENCY_BUY_TOKEN[chainId].symbol?.toUpperCase() - const isWrappedIn = - state[Field.INPUT].currencyId?.toUpperCase() === WRAPPED_NATIVE_CURRENCY[chainId].symbol?.toUpperCase() + const inputCurrencyId = state[Field.INPUT].currencyId?.toUpperCase() + const outputCurrencyId = state[Field.OUTPUT].currencyId?.toUpperCase() + + const isNativeOut = getIsNativeToken(chainId, outputCurrencyId || '') + const isWrapUnwrap = getIsWrapOrUnwrap(chainId, inputCurrencyId, outputCurrencyId) + const isWrappedIn = inputCurrencyId === WRAPPED_NATIVE_CURRENCY[chainId].symbol?.toUpperCase() + + if (isWrapUnwrap) { + return state + } const formerIndependentField = state.independentField diff --git a/src/modules/trade/hooks/useIsNativeInOrOut.ts b/src/modules/trade/hooks/useIsNativeInOrOut.ts index c54bcebc69..57bf3b6efe 100644 --- a/src/modules/trade/hooks/useIsNativeInOrOut.ts +++ b/src/modules/trade/hooks/useIsNativeInOrOut.ts @@ -1,26 +1,11 @@ import { useMemo } from 'react' -import { SupportedChainId } from '@cowprotocol/cow-sdk' - -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { supportedChainId } from 'legacy/utils/supportedChainId' - import { useWalletInfo } from 'modules/wallet' -import { doesTokenMatchSymbolOrAddress } from 'utils/doesTokenMatchSymbolOrAddress' +import { getIsNativeToken } from 'utils/getIsNativeToken' import { useTradeState } from './useTradeState' -function getIsNativeToken(chainId: SupportedChainId, tokenId: string): boolean { - const nativeToken = NATIVE_CURRENCY_BUY_TOKEN[chainId] - - if (!supportedChainId(chainId)) { - return false - } - - return doesTokenMatchSymbolOrAddress(nativeToken, tokenId) -} - export function useIsNativeIn(): boolean { const { chainId } = useWalletInfo() const { state } = useTradeState() diff --git a/src/modules/trade/hooks/useIsWrapOrUnwrap.ts b/src/modules/trade/hooks/useIsWrapOrUnwrap.ts index 641a0253ae..272d3930d4 100644 --- a/src/modules/trade/hooks/useIsWrapOrUnwrap.ts +++ b/src/modules/trade/hooks/useIsWrapOrUnwrap.ts @@ -1,13 +1,11 @@ import { useMemo } from 'react' -import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' -import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' import { supportedChainId } from 'legacy/utils/supportedChainId' import { useTradeState } from 'modules/trade/hooks/useTradeState' import { useWalletInfo } from 'modules/wallet' -import { doesTokenMatchSymbolOrAddress } from 'utils/doesTokenMatchSymbolOrAddress' +import { getIsWrapOrUnwrap } from 'utils/getIsWrapOrUnwrap' export function useIsWrapOrUnwrap(): boolean { const { chainId } = useWalletInfo() @@ -17,17 +15,6 @@ export function useIsWrapOrUnwrap(): boolean { return useMemo(() => { if (!chainId || !supportedChainId(chainId)) return false - if (!inputCurrencyId || !outputCurrencyId) return false - - const nativeToken = NATIVE_CURRENCY_BUY_TOKEN[chainId] - const wrappedToken = WRAPPED_NATIVE_CURRENCY[chainId] - - const isNativeIn = doesTokenMatchSymbolOrAddress(nativeToken, inputCurrencyId) - const isNativeOut = doesTokenMatchSymbolOrAddress(nativeToken, outputCurrencyId) - - const isWrappedIn = doesTokenMatchSymbolOrAddress(wrappedToken, inputCurrencyId) - const isWrappedOut = doesTokenMatchSymbolOrAddress(wrappedToken, outputCurrencyId) - - return (isNativeIn && isWrappedOut) || (isNativeOut && isWrappedIn) + return getIsWrapOrUnwrap(chainId, inputCurrencyId, outputCurrencyId) }, [chainId, inputCurrencyId, outputCurrencyId]) } diff --git a/src/utils/getIsNativeToken.ts b/src/utils/getIsNativeToken.ts new file mode 100644 index 0000000000..8dd4e04224 --- /dev/null +++ b/src/utils/getIsNativeToken.ts @@ -0,0 +1,16 @@ +import { SupportedChainId } from '@cowprotocol/cow-sdk' + +import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' +import { supportedChainId } from 'legacy/utils/supportedChainId' + +import { doesTokenMatchSymbolOrAddress } from './doesTokenMatchSymbolOrAddress' + +export function getIsNativeToken(chainId: SupportedChainId, tokenId: string): boolean { + const nativeToken = NATIVE_CURRENCY_BUY_TOKEN[chainId] + + if (!supportedChainId(chainId)) { + return false + } + + return doesTokenMatchSymbolOrAddress(nativeToken, tokenId) +} diff --git a/src/utils/getIsWrapOrUnwrap.ts b/src/utils/getIsWrapOrUnwrap.ts new file mode 100644 index 0000000000..11305d728f --- /dev/null +++ b/src/utils/getIsWrapOrUnwrap.ts @@ -0,0 +1,27 @@ +import { SupportedChainId } from '@cowprotocol/cow-sdk' + +import { NATIVE_CURRENCY_BUY_TOKEN } from 'legacy/constants' +import { WRAPPED_NATIVE_CURRENCY } from 'legacy/constants/tokens' + +import { doesTokenMatchSymbolOrAddress } from './doesTokenMatchSymbolOrAddress' + +import { Nullish } from '../types' + +export function getIsWrapOrUnwrap( + chainId: SupportedChainId, + inputCurrencyId: Nullish, + outputCurrencyId: Nullish +): boolean { + if (!inputCurrencyId || !outputCurrencyId) return false + + const nativeToken = NATIVE_CURRENCY_BUY_TOKEN[chainId] + const wrappedToken = WRAPPED_NATIVE_CURRENCY[chainId] + + const isNativeIn = doesTokenMatchSymbolOrAddress(nativeToken, inputCurrencyId) + const isNativeOut = doesTokenMatchSymbolOrAddress(nativeToken, outputCurrencyId) + + const isWrappedIn = doesTokenMatchSymbolOrAddress(wrappedToken, inputCurrencyId) + const isWrappedOut = doesTokenMatchSymbolOrAddress(wrappedToken, outputCurrencyId) + + return (isNativeIn && isWrappedOut) || (isNativeOut && isWrappedIn) +}