Skip to content

Commit

Permalink
Merge pull request #2851 from cowprotocol/reapply-2775
Browse files Browse the repository at this point in the history
refactor(swap): clean up Swap widget from isWrapOrUnwrap (#2775)
  • Loading branch information
anxolin authored Jul 11, 2023
2 parents 704c444 + 5a5d7ac commit 6986bd5
Show file tree
Hide file tree
Showing 27 changed files with 131 additions and 350 deletions.
2 changes: 1 addition & 1 deletion src/legacy/hooks/usePriceImpact/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
68 changes: 0 additions & 68 deletions src/legacy/hooks/useWrapCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,21 @@ 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'

// 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
}
Expand All @@ -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<CurrencyAmount<Currency>>): 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<Currency> | 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 }
Expand Down
17 changes: 13 additions & 4 deletions src/legacy/state/swap/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -143,10 +146,16 @@ export default createReducer<SwapState>(initialState, (builder) =>
function getEthFlowOverridesOnSwitch(state: SwapState): Pick<SwapState, 'independentField' | 'typedValue'> {
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

Expand Down
24 changes: 1 addition & 23 deletions src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@ 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'

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'

Expand All @@ -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)
Expand Down Expand Up @@ -70,14 +56,6 @@ export function ConfirmSwapModalSetup(props: ConfirmSwapModalSetupProps) {
onConfirm={handleSwap}
onDismiss={handleConfirmDismiss}
/>

<TransactionConfirmationModal
attemptingTxn={true}
isOpen={showTransactionConfirmationModal}
pendingText={pendingText}
onDismiss={onDismiss}
operationType={operationType}
/>
</>
)
}
21 changes: 5 additions & 16 deletions src/modules/swap/containers/SwapWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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'

Expand Down Expand Up @@ -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()
Expand All @@ -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({
Expand Down Expand Up @@ -147,7 +139,6 @@ export function SwapWidget() {
allowedSlippage,
handleSwap: swapButtonContext.handleSwap,
priceImpact: priceImpactParams.priceImpact,
dismissNativeWrapModal,
rateInfoParams,
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -225,13 +216,11 @@ export function SwapWidget() {
rateInfoParams,
}

const showTradeRates = !isWrapUnwrapMode

const slots = {
settingsWidget: <SettingsTab placeholderSlippage={allowedSlippage} />,
bottomContent: (
<>
{showTradeRates && <TradeRates {...tradeRatesProps} />}
<TradeRates {...tradeRatesProps} />
<SwapWarningsTop {...swapWarningsTopProps} />
<SwapButtons {...swapButtonContext} />
<SwapWarningsBottom {...swapWarningsBottomProps} />
Expand Down
44 changes: 0 additions & 44 deletions src/modules/swap/containers/SwapWidget/styled.tsx

This file was deleted.

22 changes: 2 additions & 20 deletions src/modules/swap/helpers/getSwapButtonState.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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',
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
}
Expand Down
1 change: 0 additions & 1 deletion src/modules/swap/hooks/useHandleSwap.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof useSwapActionHandlers>
const mockSwapFlow = swapFlow as jest.MockedFunction<typeof swapFlow>
Expand Down
Loading

0 comments on commit 6986bd5

Please sign in to comment.