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

feat(yield): define token category by default for selection #5018

Merged
merged 111 commits into from
Oct 29, 2024
Merged
Changes from 1 commit
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
01c23f9
feat(yield): setup yield widget
shoom3301 Oct 7, 2024
e8514b5
fix(yield): display correct output amount
shoom3301 Oct 7, 2024
4bde353
feat(trade-quote): support fast quote requests
shoom3301 Oct 7, 2024
cf63214
feat(yield): display trade buttons
shoom3301 Oct 7, 2024
2513c89
feat(yield): display confirm details
shoom3301 Oct 7, 2024
893859f
feat(yield): scope context to trade
shoom3301 Oct 7, 2024
89aeca4
feat(yield): do trade after confirmation
shoom3301 Oct 7, 2024
ca61cbb
feat(yield): display order progress bar
shoom3301 Oct 7, 2024
0e267a9
refactor: move useIsEoaEthFlow to trade module
shoom3301 Oct 8, 2024
2df7b69
refactor: move hooks to tradeSlippage module
shoom3301 Oct 8, 2024
4ff2db5
refactor: rename swapSlippage to tradeSlippage
shoom3301 Oct 8, 2024
f5c45e9
feat(trade-slippage): split slippage state by trade type
shoom3301 Oct 8, 2024
8b8ae26
refactor: unlink TransactionSettings from swap module
shoom3301 Oct 8, 2024
39a95c3
refactor: use reach modal in Settings component
shoom3301 Oct 8, 2024
7c3c559
refactor: move Settings component in trade module
shoom3301 Oct 8, 2024
57d4ad0
feat(yield): add settings widget
shoom3301 Oct 8, 2024
4b8a40d
feat(yield): use deadline value from settings
shoom3301 Oct 8, 2024
2c2ee88
fix(trade-quote): skip fast quote if it slower than optimal
shoom3301 Oct 8, 2024
0bbec8b
refactor: generalise TradeRateDetails from swap module
shoom3301 Oct 8, 2024
fbb9a73
refactor: move TradeRateDetails into tradeWidgetAddons module
shoom3301 Oct 8, 2024
275893e
refactor: move SettingsTab into tradeWidgetAddons module
shoom3301 Oct 8, 2024
452d107
refactor(swap): generalise useHighFeeWarning()
shoom3301 Oct 10, 2024
27407be
refactor(swap): move hooks to trade module
shoom3301 Oct 10, 2024
1073d5f
refactor: move HighFeeWarning to trade widget addons
shoom3301 Oct 10, 2024
11243ee
refactor: make HighFeeWarning independent
shoom3301 Oct 10, 2024
2548e10
feat(yield): display trade warnings
shoom3301 Oct 10, 2024
f9e3d82
refactor(trade): generalise NoImpactWarning
shoom3301 Oct 10, 2024
3c6ed69
refactor(trade): generalise ZeroApprovalWarning
shoom3301 Oct 10, 2024
8070665
refactor(trade): generalise bundle tx banners
shoom3301 Oct 10, 2024
b6d9717
refactor: extract TradeWarnings
shoom3301 Oct 10, 2024
759bc0f
chore: fix yield form displaying
shoom3301 Oct 10, 2024
f320ff7
refactor(swap): generalise trade flow
shoom3301 Oct 10, 2024
057f552
feat(yield): support safe bundle swaps
shoom3301 Oct 10, 2024
b3ac906
chore: hide yield under ff
shoom3301 Oct 10, 2024
fb10141
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 10, 2024
c780d1b
chore: remove lazy loading
shoom3301 Oct 11, 2024
fb63d4e
chore: merge develop
shoom3301 Oct 14, 2024
4c88126
chore: fix imports
shoom3301 Oct 14, 2024
0bf3ba1
fix: generalize smart slippage usage
shoom3301 Oct 14, 2024
78c0b89
fix: don't sync url params while navigating with yield
shoom3301 Oct 14, 2024
1678557
feat: open settings menu on slippage click
shoom3301 Oct 14, 2024
be2e6cc
chore: update btn text
shoom3301 Oct 14, 2024
3b769af
fix: make slippage settings through
shoom3301 Oct 14, 2024
b88e78c
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 15, 2024
b153e9e
chore: merge develop
shoom3301 Oct 15, 2024
bea304e
chore: fix yield widget
shoom3301 Oct 15, 2024
9ecaf57
chore: remove old migration
shoom3301 Oct 15, 2024
2722b3e
feat: add default lp-token lists
shoom3301 Oct 15, 2024
aa53aac
feat(tokens): display custom token selector for Yield widget
shoom3301 Oct 15, 2024
ac0a957
feat(tokens): display lp-token lists
shoom3301 Oct 15, 2024
704d003
feat: display lp-token logo
shoom3301 Oct 16, 2024
bae773d
chore: slippage label
shoom3301 Oct 16, 2024
c01f9b8
fix: fix default trade state in menu
shoom3301 Oct 16, 2024
1af6c9e
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 16, 2024
0253925
chore: fix lint
shoom3301 Oct 16, 2024
170e295
Merge branch 'feat/vampire-attack-setup' of https://github.com/cowpro…
shoom3301 Oct 16, 2024
854d685
feat: fetch lp-token balances
shoom3301 Oct 16, 2024
03da23d
feat: reuse virtual list for lp-tokens list
shoom3301 Oct 16, 2024
7228879
chore: adjust balances updater
shoom3301 Oct 16, 2024
b8b3301
chore: add yield in widget conf
shoom3301 Oct 16, 2024
6d9e416
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 16, 2024
3902abb
chore: reset balances only when account changed
shoom3301 Oct 17, 2024
6060aae
feat: cache balances into localStorage
shoom3301 Oct 17, 2024
20ba5de
feat: display cached token balances
shoom3301 Oct 17, 2024
3fe1727
feat: link to create pool
shoom3301 Oct 17, 2024
629569a
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 17, 2024
4d54103
chore: merge develop
shoom3301 Oct 17, 2024
535a046
chore: fix hooks trade state
shoom3301 Oct 17, 2024
c9df5d2
fix: fix smart slippage displaying
shoom3301 Oct 18, 2024
60c1033
chore: center slippage banner
shoom3301 Oct 18, 2024
cb3f94d
Merge branch 'feat/vampire-attack-setup' of https://github.com/cowpro…
shoom3301 Oct 18, 2024
ee11cb2
chore: condition to displayCreatePoolBanner
shoom3301 Oct 18, 2024
5d5c843
fix: poll lp-token balances only in yield widget
shoom3301 Oct 18, 2024
8e64078
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 18, 2024
9abbf85
feat(yield): persist pools info
shoom3301 Oct 21, 2024
df6f4b1
feat(yield): allow using lp-tokens in widget
shoom3301 Oct 21, 2024
c43fba1
feat(yield): display lp-token logo in widget
shoom3301 Oct 21, 2024
d95fcf1
feat(yield): display pool apy
shoom3301 Oct 21, 2024
564d0b2
chore: fix lp token logo
shoom3301 Oct 21, 2024
eeaa6bb
feat(yield): pool info page
shoom3301 Oct 21, 2024
8061fd4
Merge branch 'develop' into feat/vampire-attack-lp-tokens
fairlighteth Oct 21, 2024
13a664f
Merge branch 'feat/vampire-attack-lp-tokens' of https://github.com/co…
shoom3301 Oct 22, 2024
4488bf7
chore: fix build
shoom3301 Oct 22, 2024
de38227
chore(yield): fix balance loading state
shoom3301 Oct 22, 2024
3d31e80
chore(yield): fix pools info fetching
shoom3301 Oct 22, 2024
0cf8755
chore: fix yield menu link
shoom3301 Oct 22, 2024
36fae46
chore: format pool displayed values
shoom3301 Oct 22, 2024
f246521
chore: always use address for lp-tokens in url
shoom3301 Oct 22, 2024
4092dd7
fix: fix lp-tokens usage
shoom3301 Oct 22, 2024
788c7f7
chore: fix lint
shoom3301 Oct 22, 2024
f0c3621
feat(yield): define token category by default for selection
shoom3301 Oct 22, 2024
930253b
chore: fix lint
shoom3301 Oct 22, 2024
a0bab7b
feat: add isCoWAMM indicator to LpToken
shoom3301 Oct 22, 2024
9c5d5b5
refactor: fix lp tokens segregation
shoom3301 Oct 22, 2024
1149c36
chore: fix apr default value
shoom3301 Oct 23, 2024
e6f28c2
Merge branch 'feat/vampire-attack-pools-info' of https://github.com/c…
shoom3301 Oct 23, 2024
8048049
chore: remove lp tokens duplicates
shoom3301 Oct 23, 2024
0c6f52c
fix: set lp tokens to sell wth cowamm is set as buy
shoom3301 Oct 23, 2024
4e96783
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 23, 2024
51297d9
Merge branch 'feat/vampire-attack-lp-tokens' of https://github.com/co…
shoom3301 Oct 23, 2024
6e59eee
Merge branch 'feat/vampire-attack-pools-info' of https://github.com/c…
shoom3301 Oct 23, 2024
98597c2
feat: modify pool token list layout (#5014)
fairlighteth Oct 24, 2024
5889ea4
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 28, 2024
0350976
chore: link to create pool
shoom3301 Oct 28, 2024
f3f7eac
Merge branch 'feat/vampire-attack-lp-tokens' of https://github.com/co…
shoom3301 Oct 28, 2024
8d33d3b
chore: merge changes
shoom3301 Oct 28, 2024
265b870
chore: fix balances cache
shoom3301 Oct 28, 2024
090b239
Merge branch 'feat/vampire-attack-pools-info' of https://github.com/c…
shoom3301 Oct 28, 2024
115c017
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 29, 2024
17d2230
Merge branch 'feat/vampire-attack-pools-info' of https://github.com/c…
shoom3301 Oct 29, 2024
75e7d90
Merge branch 'develop' of https://github.com/cowprotocol/cowswap into…
shoom3301 Oct 29, 2024
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
Prev Previous commit
Next Next commit
feat(yield): support safe bundle swaps
shoom3301 committed Oct 10, 2024
commit 057f55286fd6611a7deab1f69ca57a028d08f423
Original file line number Diff line number Diff line change
@@ -88,6 +88,7 @@ export function AppDataInfoUpdater({
typedHooks,
volumeFee,
replacedOrderUid,
isSmartSlippage,
])
}

Original file line number Diff line number Diff line change
@@ -78,6 +78,7 @@ export function HookDappContainer({ dapp, isPreHook, onDismiss, hookToEdit }: Ho
inputCurrencyId,
outputCurrencyId,
isDarkMode,
orderParams,
])

const dappProps = useMemo(() => ({ context, dapp, isPreHook }), [context, dapp, isPreHook])
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ export function useRescueFundsFromProxy(
} finally {
setTxSigningInProgress(false)
}
}, [provider, proxyAddress, cowShedContract, selectedTokenAddress, account, tokenBalance])
}, [provider, proxyAddress, cowShedContract, selectedTokenAddress, account, tokenBalance, cowShedHooks])

return { callback, isTxSigningInProgress, proxyAddress }
}
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ export function TenderlySimulate({ hook }: TenderlySimulateProps) {
} finally {
setIsLoading(false)
}
}, [simulate, hook, hookId])
}, [simulate, hook, hookId, setSimulationError])

if (isLoading) {
return (
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ export function BuildHookApp({ context }: HookDappProps) {
hook,
})
: context.addHook({ hook })
}, [hook, context, hookToEdit, isPreHook])
}, [hook, context, hookToEdit])

return (
<Wrapper>
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ export function ClaimGnoHookApp({ context }: HookDappProps) {
}

return SbcDepositContractInterface.encodeFunctionData('claimWithdrawal', [account])
}, [context])
}, [context, account])

useEffect(() => {
if (!account || !provider) {
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ export function PermitHookApp({ context }: HookDappProps) {
}

context.addHook({ hook })
}, [generatePermitHook, context, permitInfo, token, spenderAddress])
}, [generatePermitHook, context, permitInfo, token, spenderAddress, hookToEdit])

const buttonProps = useMemo(() => {
if (!context.account) return { message: 'Connect wallet', disabled: true }
Original file line number Diff line number Diff line change
@@ -33,6 +33,6 @@ export function useAddHook(dapp: HookDapp, isPreHook: boolean): AddHook {
}
})
},
[updateHooks, dapp],
[updateHooks, dapp, isPreHook],
)
}
Original file line number Diff line number Diff line change
@@ -25,6 +25,6 @@ export function useRemoveHook(isPreHook: boolean): RemoveHook {
}
})
},
[updateHooks],
[updateHooks, isPreHook],
)
}
Original file line number Diff line number Diff line change
@@ -19,5 +19,5 @@ export function useSetRecipientOverride() {
if (!hookRecipientOverride || !isHooksTradeType) return

onChangeRecipient(hookRecipientOverride)
}, [hookRecipientOverride, isHooksTradeType, isNativeIn])
}, [hookRecipientOverride, isHooksTradeType, isNativeIn, onChangeRecipient])
}
Original file line number Diff line number Diff line change
@@ -2,25 +2,24 @@ import { useEffect } from 'react'

import { getCurrencyAddress } from '@cowprotocol/common-utils'

import { useUserTransactionTTL } from 'legacy/state/user/hooks'

import { useTradeFlowContext } from 'modules/trade'

import { useSetOrderParams } from './useSetOrderParams'

import { useSwapFlowContext } from '../../swap/hooks/useSwapFlowContext'

export function useSetupHooksStoreOrderParams() {
const [deadline] = useUserTransactionTTL()
const tradeFlowContext = useTradeFlowContext({ deadline })
const tradeFlowContext = useSwapFlowContext()
const setOrderParams = useSetOrderParams()
const orderParams = tradeFlowContext?.orderParams

useEffect(() => {
if (!orderParams) return

setOrderParams({
validTo: orderParams.validTo,
sellTokenAddress: getCurrencyAddress(orderParams.inputAmount.currency),
buyTokenAddress: getCurrencyAddress(orderParams.outputAmount.currency),
})
}, [orderParams])
if (!orderParams) {
setOrderParams(null)
} else {
setOrderParams({
validTo: orderParams.validTo,
sellTokenAddress: getCurrencyAddress(orderParams.inputAmount.currency),
buyTokenAddress: getCurrencyAddress(orderParams.outputAmount.currency),
})
}
}, [orderParams, setOrderParams])
}
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ export function useTenderlySimulate(): (params: CowHook) => Promise<TenderlySimu

return response as TenderlySimulation | SimulationError
},
[account, chainId],
[account, chainId, settlementContract],
)
}

Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ export function ExternalDappLoader({
return () => {
isRequestRelevant = false
}
}, [input, chainId])
}, [input, isSmartContractWallet, chainId])

return null
}
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@ import { useAtomValue } from 'jotai/index'
import { useCallback, useEffect, useMemo } from 'react'

import { HookDappBase, HookDappType } from '@cowprotocol/hook-dapp-lib'
import { useWalletInfo } from '@cowprotocol/wallet'

import ms from 'ms.macro'

@@ -21,7 +20,6 @@ const getLastUpdateTimestamp = () => {
export function IframeDappsManifestUpdater() {
const hooksState = useAtomValue(customHookDappsAtom)
const upsertCustomHookDapp = useSetAtom(upsertCustomHookDappAtom)
const { chainId } = useWalletInfo()

const [preHooks, postHooks] = useMemo(
() => [Object.values(hooksState.pre), Object.values(hooksState.post)],
@@ -55,7 +53,7 @@ export function IframeDappsManifestUpdater() {
}
})
},
[chainId, upsertCustomHookDapp],
[upsertCustomHookDapp],
)

/**
Original file line number Diff line number Diff line change
@@ -14,11 +14,11 @@ import { calculateLimitOrdersDeadline } from 'modules/limitOrders/utils/calculat
import { emitPostedOrderEvent } from 'modules/orders'
import { handlePermit } from 'modules/permit'
import { callDataContainsPermitSigner } from 'modules/permit'
import { presignOrderStep } from 'modules/swap/services/swapFlow/steps/presignOrderStep'
import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep'
import { logTradeFlow } from 'modules/trade/utils/logger'
import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper'
import { TradeFlowAnalyticsContext, tradeFlowAnalytics } from 'modules/trade/utils/tradeFlowAnalytics'
import { presignOrderStep } from 'modules/tradeFlow/services/swapFlow/steps/presignOrderStep'

export async function tradeFlow(
params: TradeFlowContext,
Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ export function ConfirmSwapModalSetup(props: ConfirmSwapModalSetupProps) {
networkCostsSuffix: shouldPayGas ? <NetworkCostsSuffix /> : null,
networkCostsTooltipSuffix: <NetworkCostsTooltipSuffix />,
}),
[chainId, allowedSlippage, nativeCurrency.symbol, isEoaEthFlow, isExactIn, shouldPayGas],
[chainId, allowedSlippage, nativeCurrency.symbol, isEoaEthFlow, isExactIn, shouldPayGas, isSmartSlippageApplied],
)

const submittedContent = useOrderSubmittedContent(chainId)
90 changes: 0 additions & 90 deletions apps/cowswap-frontend/src/modules/swap/hooks/useHandleSwap.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback } from 'react'

import { useUserTransactionTTL } from 'legacy/state/user/hooks'

import { useTradePriceImpact } from 'modules/trade'
import { logTradeFlow } from 'modules/trade/utils/logger'
import { useHandleSwap, useTradeFlowType } from 'modules/tradeFlow'
import { FlowType } from 'modules/tradeFlow'

import { useConfirmPriceImpactWithoutFee } from 'common/hooks/useConfirmPriceImpactWithoutFee'
import { useSafeMemoObject } from 'common/hooks/useSafeMemo'

import { useEthFlowContext } from './useEthFlowContext'
import { useSwapFlowContext } from './useSwapFlowContext'

import { ethFlow } from '../services/ethFlow'

export function useHandleSwapOrEthFlow() {
const priceImpactParams = useTradePriceImpact()
const swapFlowContext = useSwapFlowContext()
const ethFlowContext = useEthFlowContext()
const tradeFlowType = useTradeFlowType()
const { confirmPriceImpactWithoutFee } = useConfirmPriceImpactWithoutFee()

const [deadline] = useUserTransactionTTL()
const { callback: handleSwap, contextIsReady } = useHandleSwap(useSafeMemoObject({ deadline }))

const callback = useCallback(() => {
if (!swapFlowContext) return

if (tradeFlowType === FlowType.EOA_ETH_FLOW) {
if (!ethFlowContext) throw new Error('Eth flow context is not ready')

logTradeFlow('ETH FLOW', 'Start eth flow')
return ethFlow(swapFlowContext, ethFlowContext, priceImpactParams, confirmPriceImpactWithoutFee)
}

return handleSwap()
}, [swapFlowContext, ethFlowContext, handleSwap, tradeFlowType, priceImpactParams, confirmPriceImpactWithoutFee])

return { callback, contextIsReady }
}
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ import { Field } from 'legacy/state/types'
import { useInjectedWidgetParams } from 'modules/injectedWidget'
import { useTokenSupportsPermit } from 'modules/permit'
import { getSwapButtonState } from 'modules/swap/helpers/getSwapButtonState'
import { useHandleSwap } from 'modules/swap/hooks/useHandleSwap'
import { SwapButtonsContext } from 'modules/swap/pure/SwapButtons'
import { TradeType, useTradeConfirmActions, useWrapNativeFlow } from 'modules/trade'
import { useIsNativeIn } from 'modules/trade/hooks/useIsNativeInOrOut'
@@ -30,7 +29,7 @@ import { QuoteDeadlineParams } from 'modules/tradeQuote'
import { useApproveState } from 'common/hooks/useApproveState'
import { useSafeMemo } from 'common/hooks/useSafeMemo'

import { useSwapFlowContext } from './useSwapFlowContext'
import { useHandleSwapOrEthFlow } from './useHandleSwapOrEthFlow'
import { useDerivedSwapInfo, useSwapActionHandlers } from './useSwapState'

export interface SwapButtonInput {
@@ -57,7 +56,6 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext
const isBestQuoteLoading = useIsBestQuoteLoading()
const tradeConfirmActions = useTradeConfirmActions()
const { standaloneMode } = useInjectedWidgetParams()
const tradeFlowContext = useSwapFlowContext()

const currencyIn = currencies[Field.INPUT]
const currencyOut = currencies[Field.OUTPUT]
@@ -78,9 +76,7 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext
const wrapCallback = useWrapNativeFlow()
const { state: approvalState } = useApproveState(slippageAdjustedSellAmount || null)

const { callback: handleSwap, contextIsReady } = useHandleSwap()

const recipientAddressOrName = tradeFlowContext?.orderParams.recipientAddressOrName || null
const { callback: handleSwap, contextIsReady } = useHandleSwapOrEthFlow()

const swapCallbackError = contextIsReady ? null : 'Missing dependencies'

@@ -137,7 +133,6 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext
toggleWalletModal,
swapInputError,
onCurrencySelection,
recipientAddressOrName,
widgetStandaloneMode: standaloneMode,
quoteDeadlineParams,
}),
@@ -154,7 +149,6 @@ export function useSwapButtonContext(input: SwapButtonInput): SwapButtonsContext
toggleWalletModal,
swapInputError,
onCurrencySelection,
recipientAddressOrName,
standaloneMode,
quoteDeadlineParams,
],
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useUserTransactionTTL } from 'legacy/state/user/hooks'

import { useTradeFlowContext } from 'modules/trade'
import { useTradeFlowContext } from 'modules/tradeFlow'

import { useSafeMemoObject } from 'common/hooks/useSafeMemo'

export function useSwapFlowContext() {
const [deadline] = useUserTransactionTTL()
return useTradeFlowContext({ deadline })
return useTradeFlowContext(useSafeMemoObject({ deadline }))
}
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ const swapButtonsContext: SwapButtonsContext = {
openSwapConfirm: () => void 0,
toggleWalletModal: () => void 0,
hasEnoughWrappedBalanceForSwap: true,
recipientAddressOrName: null,
quoteDeadlineParams: {
validFor: 0,
quoteValidTo: 0,
Original file line number Diff line number Diff line change
@@ -38,7 +38,6 @@ export interface SwapButtonsContext {
hasEnoughWrappedBalanceForSwap: boolean
swapInputError?: ReactNode
onCurrencySelection: (field: Field, currency: Currency) => void
recipientAddressOrName: string | null
widgetStandaloneMode?: boolean
quoteDeadlineParams: QuoteDeadlineParams
}
Original file line number Diff line number Diff line change
@@ -8,11 +8,11 @@ import { removePermitHookFromAppData } from 'modules/appData'
import { emitPostedOrderEvent } from 'modules/orders'
import { signEthFlowOrderStep } from 'modules/swap/services/ethFlow/steps/signEthFlowOrderStep'
import { EthFlowContext } from 'modules/swap/services/types'
import { TradeFlowContext } from 'modules/trade'
import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep'
import { logTradeFlow } from 'modules/trade/utils/logger'
import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper'
import { tradeFlowAnalytics } from 'modules/trade/utils/tradeFlowAnalytics'
import { TradeFlowContext } from 'modules/tradeFlow'
import { isQuoteExpired } from 'modules/tradeQuote'

import { calculateUniqueOrderId } from './steps/calculateUniqueOrderId'
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ export function NoImpactWarning(props: NoImpactWarningProps) {

useEffect(() => {
setIsAccepted(!showPriceImpactWarning)
}, [showPriceImpactWarning])
}, [showPriceImpactWarning, setIsAccepted])

if (!showPriceImpactWarning) return null

Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ function Custom({ stateValue }: { stateValue: string }) {
return (
<TradeConfirmModal title="Swap">
<TradeConfirmation {...confirmationState} onDismiss={console.log}>
<span>Some content</span>
{() => <span>Some content</span>}
</TradeConfirmation>
</TradeConfirmModal>
)
3 changes: 0 additions & 3 deletions apps/cowswap-frontend/src/modules/trade/index.ts
Original file line number Diff line number Diff line change
@@ -37,9 +37,6 @@ export * from './hooks/useWrappedToken'
export * from './hooks/useUnknownImpactWarning'
export * from './hooks/useIsSwapEth'
export * from './hooks/useIsSafeEthFlow'
export * from './hooks/useTradeFlowType'
export { useTradeFlowContext } from './hooks/useTradeFlowContext'
export { useSafeBundleFlowContext } from './hooks/useSafeBundleFlowContext'
export * from './containers/TradeWidget/types'
export { useIsNoImpactWarningAccepted } from './containers/NoImpactWarning/index'
export * from './utils/getReceiveAmountInfo'
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ const Fixtures = {
refreshInterval={10_000}
recipient={null}
>
<span>Trade confirmation</span>
{() => <span>Trade confirmation</span>}
</TradeConfirmation>
),
}
1 change: 0 additions & 1 deletion apps/cowswap-frontend/src/modules/trade/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './TradeDerivedState'
export * from './ReceiveAmountInfo'
export * from './TradeType'
export * from './TradeFlowContext'
56 changes: 56 additions & 0 deletions apps/cowswap-frontend/src/modules/tradeFlow/hooks/useHandleSwap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useCallback } from 'react'

import { useTradePriceImpact } from 'modules/trade'
import { logTradeFlow } from 'modules/trade/utils/logger'

import { useConfirmPriceImpactWithoutFee } from 'common/hooks/useConfirmPriceImpactWithoutFee'

import { useSafeBundleFlowContext } from './useSafeBundleFlowContext'
import { TradeFlowParams, useTradeFlowContext } from './useTradeFlowContext'
import { useTradeFlowType } from './useTradeFlowType'

import { safeBundleApprovalFlow, safeBundleEthFlow } from '../services/safeBundleFlow'
import { swapFlow } from '../services/swapFlow'
import { FlowType } from '../types/TradeFlowContext'

export function useHandleSwap(params: TradeFlowParams) {
const tradeFlowType = useTradeFlowType()
const tradeFlowContext = useTradeFlowContext(params)
const safeBundleFlowContext = useSafeBundleFlowContext()
const { confirmPriceImpactWithoutFee } = useConfirmPriceImpactWithoutFee()
const priceImpactParams = useTradePriceImpact()

const contextIsReady =
Boolean(
[FlowType.SAFE_BUNDLE_ETH, FlowType.SAFE_BUNDLE_APPROVAL].includes(tradeFlowType)
? safeBundleFlowContext
: tradeFlowContext,
) && !!tradeFlowContext

const callback = useCallback(async () => {
if (!tradeFlowContext) return

if (tradeFlowType === FlowType.SAFE_BUNDLE_APPROVAL) {
if (!safeBundleFlowContext) throw new Error('Safe bundle flow context is not ready')

logTradeFlow('SAFE BUNDLE APPROVAL FLOW', 'Start safe bundle approval flow')
return safeBundleApprovalFlow(
tradeFlowContext,
safeBundleFlowContext,
priceImpactParams,
confirmPriceImpactWithoutFee,
)
}
if (tradeFlowType === FlowType.SAFE_BUNDLE_ETH) {
if (!safeBundleFlowContext) throw new Error('Safe bundle flow context is not ready')

logTradeFlow('SAFE BUNDLE ETH FLOW', 'Start safe bundle eth flow')
return safeBundleEthFlow(tradeFlowContext, safeBundleFlowContext, priceImpactParams, confirmPriceImpactWithoutFee)
}

logTradeFlow('SWAP FLOW', 'Start swap flow')
return swapFlow(tradeFlowContext, priceImpactParams, confirmPriceImpactWithoutFee)
}, [tradeFlowType, tradeFlowContext, safeBundleFlowContext, priceImpactParams, confirmPriceImpactWithoutFee])

return { callback, contextIsReady }
}
Original file line number Diff line number Diff line change
@@ -5,12 +5,12 @@ import { useSafeAppsSdk } from '@cowprotocol/wallet'

import useSWR from 'swr'

import { useReceiveAmountInfo } from 'modules/trade'

import { useGP2SettlementContract, useTokenContract, useWETHContract } from 'common/hooks/useContract'
import { useNeedsApproval } from 'common/hooks/useNeedsApproval'
import { useTradeSpenderAddress } from 'common/hooks/useTradeSpenderAddress'

import { useReceiveAmountInfo } from './useReceiveAmountInfo'

import { SafeBundleFlowContext } from '../types/TradeFlowContext'

export function useSafeBundleFlowContext(): SafeBundleFlowContext | null {
Original file line number Diff line number Diff line change
@@ -20,11 +20,11 @@ import { useGP2SettlementContract } from 'common/hooks/useContract'

import { TradeFlowContext } from '../types/TradeFlowContext'

interface Params {
export interface TradeFlowParams {
deadline: number
}

export function useTradeFlowContext({ deadline }: Params): TradeFlowContext | null {
export function useTradeFlowContext({ deadline }: TradeFlowParams): TradeFlowContext | null {
const { chainId, account } = useWalletInfo()
const provider = useWalletProvider()
const { allowsOffchainSigning } = useWalletDetails()
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useIsSafeApprovalBundle } from 'common/hooks/useIsSafeApprovalBundle'
import { useIsEoaEthFlow, useIsSafeEthFlow, useReceiveAmountInfo } from 'modules/trade'

import { useIsEoaEthFlow } from './useIsEoaEthFlow'
import { useIsSafeEthFlow } from './useIsSafeEthFlow'
import { useReceiveAmountInfo } from './useReceiveAmountInfo'
import { useIsSafeApprovalBundle } from 'common/hooks/useIsSafeApprovalBundle'

import { FlowType } from '../types'
import { FlowType } from '../types/TradeFlowContext'

export function useTradeFlowType(): FlowType {
const isEoaEthFlow = useIsEoaEthFlow()
4 changes: 4 additions & 0 deletions apps/cowswap-frontend/src/modules/tradeFlow/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { useHandleSwap } from './hooks/useHandleSwap'
export { useTradeFlowContext } from './hooks/useTradeFlowContext'
export { useTradeFlowType } from './hooks/useTradeFlowType'
export * from './types/TradeFlowContext'
Original file line number Diff line number Diff line change
@@ -11,13 +11,14 @@ import { buildApproveTx } from 'modules/operations/bundle/buildApproveTx'
import { buildPresignTx } from 'modules/operations/bundle/buildPresignTx'
import { buildZeroApproveTx } from 'modules/operations/bundle/buildZeroApproveTx'
import { emitPostedOrderEvent } from 'modules/orders'
import { SafeBundleFlowContext, TradeFlowContext } from 'modules/trade'
import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep'
import { logTradeFlow } from 'modules/trade/utils/logger'
import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper'
import { tradeFlowAnalytics } from 'modules/trade/utils/tradeFlowAnalytics'
import { shouldZeroApprove as shouldZeroApproveFn } from 'modules/zeroApproval'

import { SafeBundleFlowContext, TradeFlowContext } from '../../types/TradeFlowContext'

const LOG_PREFIX = 'SAFE APPROVAL BUNDLE FLOW'

export async function safeBundleApprovalFlow(
Original file line number Diff line number Diff line change
@@ -12,12 +12,13 @@ import { buildApproveTx } from 'modules/operations/bundle/buildApproveTx'
import { buildPresignTx } from 'modules/operations/bundle/buildPresignTx'
import { buildWrapTx } from 'modules/operations/bundle/buildWrapTx'
import { emitPostedOrderEvent } from 'modules/orders'
import { SafeBundleFlowContext, TradeFlowContext } from 'modules/trade'
import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep'
import { logTradeFlow } from 'modules/trade/utils/logger'
import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper'
import { tradeFlowAnalytics } from 'modules/trade/utils/tradeFlowAnalytics'

import { SafeBundleFlowContext, TradeFlowContext } from '../../types/TradeFlowContext'

const LOG_PREFIX = 'SAFE BUNDLE ETH FLOW'

export async function safeBundleEthFlow(
Original file line number Diff line number Diff line change
@@ -10,14 +10,15 @@ import { signAndPostOrder } from 'legacy/utils/trade'
import { emitPostedOrderEvent } from 'modules/orders'
import { handlePermit } from 'modules/permit'
import { callDataContainsPermitSigner } from 'modules/permit'
import { TradeFlowContext } from 'modules/trade'
import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep'
import { logTradeFlow } from 'modules/trade/utils/logger'
import { getSwapErrorMessage } from 'modules/trade/utils/swapErrorHelper'
import { tradeFlowAnalytics } from 'modules/trade/utils/tradeFlowAnalytics'

import { presignOrderStep } from './steps/presignOrderStep'

import { TradeFlowContext } from '../../types/TradeFlowContext'

export async function swapFlow(
input: TradeFlowContext,
priceImpactParams: PriceImpact,
Original file line number Diff line number Diff line change
@@ -8,9 +8,8 @@ import type { PostOrderParams } from 'legacy/utils/trade'

import type { TypedAppDataHooks } from 'modules/appData'
import type { GeneratePermitHook, IsTokenPermittableResult, useGetCachedPermit } from 'modules/permit'

import type { TradeConfirmActions } from '../hooks/useTradeConfirmActions'
import type { TradeFlowAnalyticsContext } from '../utils/tradeFlowAnalytics'
import type { TradeConfirmActions } from 'modules/trade'
import type { TradeFlowAnalyticsContext } from 'modules/trade/utils/tradeFlowAnalytics'

export enum FlowType {
REGULAR = 'REGULAR',
Original file line number Diff line number Diff line change
@@ -6,7 +6,8 @@ import { bpsToPercent } from '@cowprotocol/common-utils'
import { mapSupportedNetworks, SupportedChainId } from '@cowprotocol/cow-sdk'
import { walletInfoAtom } from '@cowprotocol/wallet'

import { isEoaEthFlowAtom, TradeType, tradeTypeAtom } from 'modules/trade'
import { isEoaEthFlowAtom, tradeTypeAtom } from 'modules/trade'
import { TradeType } from 'modules/trade/types/TradeType'

type SlippageBpsPerNetwork = Record<SupportedChainId, number | null>

Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ import { useMemo } from 'react'

import { useWalletInfo } from '@cowprotocol/wallet'

import { useTradePriceImpact } from 'modules/trade'
import { useGetTradeFormValidation } from 'modules/tradeFormValidation'
import { TradeFormValidation } from 'modules/tradeFormValidation/types'

@@ -16,7 +15,6 @@ export interface TwapWarningsContext {
export function useTwapWarningsContext(): TwapWarningsContext {
const { account } = useWalletInfo()
const primaryFormValidation = useGetTradeFormValidation()
const priceImpactParams = useTradePriceImpact()

return useMemo(() => {
const canTrade = !primaryFormValidation || NOT_BLOCKING_VALIDATIONS.includes(primaryFormValidation)
@@ -26,5 +24,5 @@ export function useTwapWarningsContext(): TwapWarningsContext {
canTrade,
walletIsNotConnected,
}
}, [primaryFormValidation, account, priceImpactParams])
}, [primaryFormValidation, account])
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import React, { useCallback, useMemo } from 'react'
import React, { useMemo } from 'react'

import { useWalletDetails, useWalletInfo } from '@cowprotocol/wallet'

import type { PriceImpact } from 'legacy/hooks/usePriceImpact'

import { useAppData } from 'modules/appData'
import { swapFlow } from 'modules/swap/services/swapFlow'
import type { SwapFlowContext } from 'modules/swap/services/types'
import {
TradeBasicConfirmDetails,
TradeConfirmation,
TradeConfirmModal,
useOrderSubmittedContent,
useReceiveAmountInfo,
useTradeConfirmActions,
useTradePriceImpact,
} from 'modules/trade'
import { HighFeeWarning } from 'modules/tradeWidgetAddons'

import { useConfirmPriceImpactWithoutFee } from 'common/hooks/useConfirmPriceImpactWithoutFee'
import { useRateInfoParams } from 'common/hooks/useRateInfoParams'
import { CurrencyPreviewInfo } from 'common/pure/CurrencyAmountPreview'

@@ -27,44 +23,34 @@ import { useYieldDerivedState } from '../../hooks/useYieldDerivedState'
const CONFIRM_TITLE = 'Confirm order'

export interface YieldConfirmModalProps {
tradeFlowContext: SwapFlowContext
doTrade(): Promise<false | void>
inputCurrencyInfo: CurrencyPreviewInfo
outputCurrencyInfo: CurrencyPreviewInfo
priceImpact: PriceImpact
recipient?: string | null
}

export function YieldConfirmModal(props: YieldConfirmModalProps) {
const { inputCurrencyInfo, outputCurrencyInfo, priceImpact, recipient, tradeFlowContext: tradeContextInitial } = props
const { inputCurrencyInfo, outputCurrencyInfo, priceImpact, recipient, doTrade: _doTrade } = props

/**
* This is a very important part of the code.
* After the confirmation modal opens, the trade context should not be recreated.
* In order to prevent this, we use useMemo to keep the trade context the same when the modal was opened.
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
const tradeFlowContext = useMemo(() => tradeContextInitial, [])
const doTrade = useMemo(() => _doTrade, [])

const { account, chainId } = useWalletInfo()
const { ensName } = useWalletDetails()
const appData = useAppData()
const receiveAmountInfo = useReceiveAmountInfo()
const tradeConfirmActions = useTradeConfirmActions()
const { slippage } = useYieldDerivedState()
const priceImpactParams = useTradePriceImpact()
const { confirmPriceImpactWithoutFee } = useConfirmPriceImpactWithoutFee()

const rateInfoParams = useRateInfoParams(inputCurrencyInfo.amount, outputCurrencyInfo.amount)
const submittedContent = useOrderSubmittedContent(chainId)

const doTrade = useCallback(async () => {
if (!tradeFlowContext) return

swapFlow(tradeFlowContext, priceImpactParams, confirmPriceImpactWithoutFee)
}, [tradeFlowContext, priceImpactParams, confirmPriceImpactWithoutFee])

const isConfirmDisabled = false // TODO: add conditions if needed

return (
<TradeConfirmModal title={CONFIRM_TITLE} submittedContent={submittedContent}>
<TradeConfirmation
@@ -75,9 +61,9 @@ export function YieldConfirmModal(props: YieldConfirmModalProps) {
outputCurrencyInfo={outputCurrencyInfo}
onConfirm={doTrade}
onDismiss={tradeConfirmActions.onDismiss}
isConfirmDisabled={isConfirmDisabled}
isConfirmDisabled={false}
priceImpact={priceImpact}
buttonText="Confirm and swap" // TODO
buttonText="Confirm and swap"
recipient={recipient}
appData={appData || undefined}
isPriceStatic={true}
Original file line number Diff line number Diff line change
@@ -9,11 +9,12 @@ import {
useTradeConfirmState,
useTradePriceImpact,
} from 'modules/trade'
import { useTradeFlowContext } from 'modules/trade'
import { useHandleSwap } from 'modules/tradeFlow'
import { useTradeQuote } from 'modules/tradeQuote'
import { SettingsTab, TradeRateDetails } from 'modules/tradeWidgetAddons'

import { useRateInfoParams } from 'common/hooks/useRateInfoParams'
import { useSafeMemoObject } from 'common/hooks/useSafeMemo'
import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types'

import { useYieldDerivedState } from '../../hooks/useYieldDerivedState'
@@ -44,7 +45,7 @@ export function YieldWidget() {
outputCurrencyFiatAmount,
recipient,
} = useYieldDerivedState()
const tradeFlowContext = useTradeFlowContext({ deadline: deadlineState[0] })
const doTrade = useHandleSwap(useSafeMemoObject({ deadline: deadlineState[0] }))

const inputCurrencyInfo: CurrencyInfo = {
field: Field.INPUT,
@@ -88,7 +89,7 @@ export function YieldWidget() {
<TradeRateDetails rateInfoParams={rateInfoParams} deadline={deadlineState[0]} />
<Warnings />
{tradeWarnings}
<TradeButtons isTradeContextReady={!!tradeFlowContext} />
<TradeButtons isTradeContextReady={doTrade.contextIsReady} />
</>
)
},
@@ -112,9 +113,9 @@ export function YieldWidget() {
inputCurrencyInfo={inputCurrencyInfo}
outputCurrencyInfo={outputCurrencyInfo}
confirmModal={
tradeFlowContext ? (
doTrade.contextIsReady ? (
<YieldConfirmModal
tradeFlowContext={tradeFlowContext}
doTrade={doTrade.callback}
recipient={recipient}
priceImpact={priceImpact}
inputCurrencyInfo={inputCurrencyPreviewInfo}
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ export function getDefaultYieldState(chainId: SupportedChainId | null): YieldRaw
}

export const { atom: yieldRawStateAtom, updateAtom: updateYieldRawStateAtom } = atomWithPartialUpdate(
atomWithStorage<YieldRawState>('yieldStateAtom:v0', getDefaultYieldState(null), getJotaiIsolatedStorage()),
atomWithStorage<YieldRawState>('yieldStateAtom:v1', getDefaultYieldState(null), getJotaiIsolatedStorage()),
)

export const yieldDerivedStateAtom = atom<YieldDerivedState>({