Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
41 changes: 29 additions & 12 deletions apps/cowswap-frontend/src/modules/trade/hooks/useResetRecipient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useEffect } from 'react'
import { useEffect, useMemo } from 'react'

import { usePrevious } from '@cowprotocol/common-hooks'
import { isEvmChain } from '@cowprotocol/cow-sdk'
import { useWalletInfo } from '@cowprotocol/wallet'

import { usePostHooksRecipientOverride } from 'entities/orderHooks/usePostHooksRecipientOverride'
import { useLocation } from 'react-router'

import { useTradeStateFromUrl } from './setupTradeState/useTradeStateFromUrl'
import { useDerivedTradeState } from './useDerivedTradeState'
Expand All @@ -22,10 +23,19 @@ export function useResetRecipient(onChangeRecipient: (recipient: string | null)
const isNativeIn = useIsNativeIn()
const hasTradeState = !!tradeStateFromUrl
const { chainId } = useWalletInfo()
const location = useLocation()

const prevPostHooksRecipientOverride = usePrevious(postHooksRecipientOverride)
const recipient = tradeState?.recipient
const hasRecipientInUrl = !!tradeStateFromUrl?.recipient
/**
* Derived synchronously from the URL rather than from the tradeStateFromUrl atom,
* which is only populated a render later. By the time the atom updates, the reset
* effects below have already wiped a recipient that was explicitly set in the URL.
*/
const hasRecipientInUrl = useMemo(() => {
const searchParams = new URLSearchParams(location.search)
return !!(searchParams.get('recipient') || searchParams.get('recipientAddress'))
}, [location.search])
const outputCurrency = tradeState?.outputCurrency
const inputCurrency = tradeState?.inputCurrency
const isBridging = !!(inputCurrency && outputCurrency && inputCurrency.chainId !== outputCurrency.chainId)
Expand All @@ -42,39 +52,46 @@ export function useResetRecipient(onChangeRecipient: (recipient: string | null)
}, [hasTradeState])

/**
* Reset recipient whenever chainId changes
* Reset recipient whenever chainId changes, but preserve any recipient set via URL
*/
useEffect(() => {
if (!postHooksRecipientOverride && !isNonEvmBridging) {
if (!postHooksRecipientOverride && !isNonEvmBridging && !hasRecipientInUrl) {
onChangeRecipient(null)
}
}, [chainId, onChangeRecipient, postHooksRecipientOverride, isNonEvmBridging])
}, [chainId, onChangeRecipient, postHooksRecipientOverride, isNonEvmBridging, hasRecipientInUrl])

/**
* Remove recipient override when its source hook was deleted
*/
useEffect(() => {
const recipientOverrideWasRemoved = !postHooksRecipientOverride && recipient === prevPostHooksRecipientOverride

if (recipientOverrideWasRemoved) {
if (recipientOverrideWasRemoved && !hasRecipientInUrl) {
onChangeRecipient(null)
}
}, [recipient, postHooksRecipientOverride, prevPostHooksRecipientOverride, isNativeIn, onChangeRecipient])
}, [
recipient,
postHooksRecipientOverride,
prevPostHooksRecipientOverride,
isNativeIn,
hasRecipientInUrl,
onChangeRecipient,
])

/**
* Remove recipient when going out from hooks-store page
* Remove recipient when going out from hooks-store page, but preserve any recipient set via URL
*/
useEffect(() => {
if (!isHooksTradeType) {
if (!isHooksTradeType && !hasRecipientInUrl) {
onChangeRecipient(null)
}
}, [isHooksTradeType, onChangeRecipient])
}, [isHooksTradeType, hasRecipientInUrl, onChangeRecipient])

useEffect(() => {
if (isHooksTradeType && isNativeIn) {
if (isHooksTradeType && isNativeIn && !hasRecipientInUrl) {
onChangeRecipient(null)
}
}, [isHooksTradeType, isNativeIn, onChangeRecipient])
}, [isHooksTradeType, isNativeIn, hasRecipientInUrl, onChangeRecipient])

return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ export function useResetRecipientOnChainChange(
stableRef.current.recipient = recipient
})

const isMountedRef = useRef(false)
const prevTargetChainId = useRef<TargetChainId | undefined>(undefined)
useEffect(() => {
if (!isMountedRef.current) {
isMountedRef.current = true
return
}
const prev = prevTargetChainId.current
prevTargetChainId.current = targetChainId

// Skip the initial `undefined -> chainId` transition: that's app init, not a
// user-driven chain change, and treating it as one wipes a URL-provided recipient.
if (prev === undefined) return

const { recipient: currentRecipient, onChangeRecipient: onChange } = stableRef.current
if (currentRecipient && !getAddressValidationStrategy(targetChainId).isValidAddress(currentRecipient)) {
onChange(null)
Expand Down
Loading