Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(swap): clean up Swap widget from isWrapOrUnwrap #2775

Merged
merged 18 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
55f8487
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jun 29, 2023
0524638
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jun 30, 2023
aff2e9f
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jul 3, 2023
9f563e7
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jul 3, 2023
8647fd1
feat(trade): generalise wrap/unwrap flow for all trade widgets
shoom3301 Jul 3, 2023
4ee14f4
fix(swap): bind swap widget to generic Wrap/Unwrap UI
shoom3301 Jul 3, 2023
64bd8a9
refactor: clean up Limit orders widget from isWrapOrUnwrap
shoom3301 Jul 3, 2023
44a2f64
refactor: clean up Swap widget from isWrapOrUnwrap
shoom3301 Jul 3, 2023
2dd81d8
chore: fix memory leak
shoom3301 Jul 3, 2023
970444a
chore: fix test
shoom3301 Jul 4, 2023
ec27dcc
fix: fix trade form validation order
shoom3301 Jul 4, 2023
91f89cb
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jul 5, 2023
254ed24
fix: fix wrap flow issues
shoom3301 Jul 5, 2023
bfe09c6
fix: fix wrap flow validation priority
shoom3301 Jul 5, 2023
a455ef2
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jul 5, 2023
0fb3acb
Merge branch 'fix/2768' of https://github.com/cowprotocol/cowswap int…
shoom3301 Jul 5, 2023
aa05fee
fix: don't reset amounts on switch tokens
shoom3301 Jul 5, 2023
604c238
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Jul 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}
/>
alfetopito marked this conversation as resolved.
Show resolved Hide resolved
</>
)
}
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