feat: refactor ConfirmSwapModal for clarity (#6729)

* feat: refactor ConfirmSwapModal for clarity

* fix: remove reset effect for now

* fix: catchUserReject update

* fix: remove unnecessary awaits
This commit is contained in:
eddie 2023-06-15 15:31:41 -07:00 committed by GitHub
parent 309d03b5e7
commit 0e2344ba85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -20,6 +20,7 @@ import { useCallback, useEffect, useState } from 'react'
import { InterfaceTrade } from 'state/routing/types'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import invariant from 'tiny-invariant'
import { isL2ChainId } from 'utils/chains'
import { formatSwapPriceUpdatedEventProperties } from 'utils/loggingFormatters'
import { didUserReject } from 'utils/swapErrorToUserReadableMessage'
@ -71,7 +72,7 @@ function useConfirmModalState({
// This is a function instead of a memoized value because we do _not_ want it to update as the allowance changes.
// For example, if the user needs to complete 3 steps initially, we should always show 3 step indicators
// at the bottom of the modal, even after they complete steps 1 and 2.
const prepareSwapFlow = useCallback(() => {
const generateRequiredSteps = useCallback(() => {
const steps: PendingConfirmModalState[] = []
if (allowance.state === AllowanceState.REQUIRED && allowance.needsSetupApproval) {
steps.push(ConfirmModalState.APPROVING_TOKEN)
@ -80,48 +81,66 @@ function useConfirmModalState({
steps.push(ConfirmModalState.PERMITTING)
}
steps.push(ConfirmModalState.PENDING_CONFIRMATION)
setPendingModalSteps(steps)
return steps
}, [allowance])
const { chainId } = useWeb3React()
const trace = useTrace()
const maximumAmountIn = useMaxAmountIn(trade, allowedSlippage)
const startSwapFlow = useCallback(async () => {
setApprovalError(undefined)
if (allowance.state === AllowanceState.REQUIRED) {
// Starts the approval process, by triggering either the Token Approval or the Permit signature.
try {
if (allowance.needsSetupApproval) {
setConfirmModalState(ConfirmModalState.APPROVING_TOKEN)
await allowance.approve()
sendAnalyticsEvent(InterfaceEventName.APPROVE_TOKEN_TXN_SUBMITTED, {
chain_id: chainId,
token_symbol: maximumAmountIn?.currency.symbol,
token_address: maximumAmountIn?.currency.address,
...trace,
})
} else {
setConfirmModalState(ConfirmModalState.PERMITTING)
await allowance.permit()
}
} catch (e) {
setConfirmModalState(ConfirmModalState.REVIEWING)
if (didUserReject(e)) {
return
}
console.error(e)
setApprovalError(
allowance.needsSetupApproval ? PendingModalError.TOKEN_APPROVAL_ERROR : PendingModalError.PERMIT_ERROR
)
}
} else {
setConfirmModalState(ConfirmModalState.PENDING_CONFIRMATION)
onSwap()
}
}, [allowance, chainId, maximumAmountIn?.currency.address, maximumAmountIn?.currency.symbol, onSwap, trace])
const catchUserReject = async (e: any, errorType: PendingModalError) => {
setConfirmModalState(ConfirmModalState.REVIEWING)
if (didUserReject(e)) return
console.error(e)
setApprovalError(errorType)
}
const previousPermitNeeded = usePrevious(
const performStep = useCallback(
async (step: ConfirmModalState) => {
switch (step) {
case ConfirmModalState.APPROVING_TOKEN:
setConfirmModalState(ConfirmModalState.APPROVING_TOKEN)
invariant(allowance.state === AllowanceState.REQUIRED, 'Allowance should be required')
allowance
.approve()
.then(() => {
sendAnalyticsEvent(InterfaceEventName.APPROVE_TOKEN_TXN_SUBMITTED, {
chain_id: chainId,
token_symbol: maximumAmountIn?.currency.symbol,
token_address: maximumAmountIn?.currency.address,
...trace,
})
})
.catch((e) => catchUserReject(e, PendingModalError.TOKEN_APPROVAL_ERROR))
break
case ConfirmModalState.PERMITTING:
setConfirmModalState(ConfirmModalState.PERMITTING)
invariant(allowance.state === AllowanceState.REQUIRED, 'Allowance should be required')
allowance.permit().catch((e) => catchUserReject(e, PendingModalError.TOKEN_APPROVAL_ERROR))
break
case ConfirmModalState.PENDING_CONFIRMATION:
setConfirmModalState(ConfirmModalState.PENDING_CONFIRMATION)
try {
onSwap()
} catch (e) {
catchUserReject(e, PendingModalError.CONFIRMATION_ERROR)
}
break
default:
setConfirmModalState(ConfirmModalState.REVIEWING)
break
}
},
[allowance, chainId, maximumAmountIn?.currency.address, maximumAmountIn?.currency.symbol, onSwap, trace]
)
const startSwapFlow = useCallback(() => {
const steps = generateRequiredSteps()
setPendingModalSteps(steps)
performStep(steps[0])
}, [generateRequiredSteps, performStep])
const previousSetupApprovalNeeded = usePrevious(
allowance.state === AllowanceState.REQUIRED ? allowance.needsSetupApproval : undefined
)
useEffect(() => {
@ -130,11 +149,11 @@ function useConfirmModalState({
allowance.needsPermitSignature &&
// If the token approval switched from missing to fulfilled, trigger the next step (permit2 signature).
!allowance.needsSetupApproval &&
previousPermitNeeded
previousSetupApprovalNeeded
) {
startSwapFlow()
performStep(ConfirmModalState.PERMITTING)
}
}, [allowance, previousPermitNeeded, startSwapFlow])
}, [allowance, performStep, previousSetupApprovalNeeded])
useEffect(() => {
// Automatically triggers the next phase if the local modal state still thinks we're in the approval phase,
@ -145,16 +164,16 @@ function useConfirmModalState({
setConfirmModalState(ConfirmModalState.REVIEWING)
return
}
startSwapFlow()
performStep(ConfirmModalState.PENDING_CONFIRMATION)
}
}, [allowance, confirmModalState, doesTradeDiffer, startSwapFlow])
}, [allowance, confirmModalState, doesTradeDiffer, performStep])
const onCancel = () => {
setConfirmModalState(ConfirmModalState.REVIEWING)
setApprovalError(undefined)
}
return { startSwapFlow, prepareSwapFlow, onCancel, confirmModalState, approvalError, pendingModalSteps }
return { startSwapFlow, onCancel, confirmModalState, approvalError, pendingModalSteps }
}
export default function ConfirmSwapModal({
@ -186,14 +205,13 @@ export default function ConfirmSwapModal({
}) {
const { chainId } = useWeb3React()
const doesTradeDiffer = originalTrade && tradeMeaningfullyDiffers(trade, originalTrade, allowedSlippage)
const { startSwapFlow, onCancel, confirmModalState, approvalError, pendingModalSteps, prepareSwapFlow } =
useConfirmModalState({
trade,
allowedSlippage,
onSwap: onConfirm,
allowance,
doesTradeDiffer: Boolean(doesTradeDiffer),
})
const { startSwapFlow, onCancel, confirmModalState, approvalError, pendingModalSteps } = useConfirmModalState({
trade,
allowedSlippage,
onSwap: onConfirm,
allowance,
doesTradeDiffer: Boolean(doesTradeDiffer),
})
const swapFailed = Boolean(swapError) && !didUserReject(swapError)
useEffect(() => {
@ -242,11 +260,7 @@ export default function ConfirmSwapModal({
if (confirmModalState === ConfirmModalState.REVIEWING || showAcceptChanges) {
return (
<SwapModalFooter
onConfirm={() => {
// Calculate the necessary steps once, before starting the flow.
prepareSwapFlow()
startSwapFlow()
}}
onConfirm={startSwapFlow}
trade={trade}
hash={txHash}
allowedSlippage={allowedSlippage}
@ -284,7 +298,6 @@ export default function ConfirmSwapModal({
onAcceptChanges,
swapFailed,
swapError?.message,
prepareSwapFlow,
startSwapFlow,
])