From f8cc62417e78470be4c4c8d0da8d8eaad9bdfc7b Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 14:12:51 +0000 Subject: [PATCH 01/18] refactor: expose UndelinedLinkStyledButton component --- .../src/common/pure/OrderProgressBarV2/index.tsx | 15 ++++++++++++--- .../src/common/pure/OrderProgressBarV2/styled.ts | 12 ++---------- libs/ui/src/pure/LinkStyledButton/index.tsx | 9 +++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/index.tsx b/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/index.tsx index 81d1eaafc2..605eb3faf3 100644 --- a/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/index.tsx +++ b/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/index.tsx @@ -22,7 +22,16 @@ import { ExplorerDataType, getExplorerLink, getRandomInt, isSellOrder, shortenAd import { OrderKind, SupportedChainId } from '@cowprotocol/cow-sdk' import { TokenLogo } from '@cowprotocol/tokens' import { Command } from '@cowprotocol/types' -import { Confetti, ExternalLink, InfoTooltip, ProductLogo, ProductVariant, TokenAmount, UI } from '@cowprotocol/ui' +import { + Confetti, + ExternalLink, + InfoTooltip, + ProductLogo, + ProductVariant, + TokenAmount, + UI, + UnderlinedLinkStyledButton, +} from '@cowprotocol/ui' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { AnimatePresence, motion } from 'framer-motion' @@ -1123,14 +1132,14 @@ function ExpiredStep(props: OrderProgressBarV2Props) {

The good news

Unlike on other exchanges, you won't be charged for this! Feel free to{' '} - { props.navigateToNewOrder?.() trackNewOrderClick() }} > place a new order - {' '} + {' '} without worry.

diff --git a/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/styled.ts b/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/styled.ts index 198fe338ff..cd1a6a3de0 100644 --- a/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/styled.ts +++ b/apps/cowswap-frontend/src/common/pure/OrderProgressBarV2/styled.ts @@ -1,6 +1,6 @@ import IMAGE_STAR_SHINE from '@cowprotocol/assets/cow-swap/star-shine.svg' import { SingleLetterLogoWrapper } from '@cowprotocol/tokens' -import { ButtonPrimary, Font, LinkStyledButton, Media, UI } from '@cowprotocol/ui' +import { ButtonPrimary, Font, Media, UI } from '@cowprotocol/ui' import styled, { css, keyframes } from 'styled-components/macro' @@ -66,6 +66,7 @@ export const StepsContainer = styled.div<{ $height: number; $minHeight?: string; padding: 0; // implement a gradient to hide the bottom of the steps container using white to opacity white using pseudo element + &::after { content: ${({ bottomGradient }) => (bottomGradient ? '""' : 'none')}; position: absolute; @@ -143,15 +144,6 @@ export const CancelButton = styled(CancelButtonOriginal)` } ` -export const Button = styled(LinkStyledButton)` - font-size: 14px; - text-decoration: underline; - - &:hover { - text-decoration: none; - } -` - export const ProgressImageWrapper = styled.div<{ bgColor?: string; padding?: string; height?: string; gap?: string }>` width: 100%; height: ${({ height }) => height || '246px'}; diff --git a/libs/ui/src/pure/LinkStyledButton/index.tsx b/libs/ui/src/pure/LinkStyledButton/index.tsx index ef1169bacd..4543fafb41 100644 --- a/libs/ui/src/pure/LinkStyledButton/index.tsx +++ b/libs/ui/src/pure/LinkStyledButton/index.tsx @@ -23,3 +23,12 @@ export const LinkStyledButton = styled.button<{ disabled?: boolean; bg?: boolean text-decoration: none; } ` + +export const UnderlinedLinkStyledButton = styled(LinkStyledButton)` + font-size: 14px; + text-decoration: underline; + + &:hover { + text-decoration: none; + } +` From f5bd799bf2bb445bb7ff89c13851bc4b74accac2 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 14:13:18 +0000 Subject: [PATCH 02/18] chore: removed unused React import --- libs/ui/src/containers/InlineBanner/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui/src/containers/InlineBanner/index.tsx b/libs/ui/src/containers/InlineBanner/index.tsx index a599327ba5..3a3f8e4cff 100644 --- a/libs/ui/src/containers/InlineBanner/index.tsx +++ b/libs/ui/src/containers/InlineBanner/index.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react' +import { ReactNode } from 'react' import { X } from 'react-feather' import SVG from 'react-inlinesvg' From 8cce489be4c19b2fc64378ff2168b6124a121388 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 14:14:10 +0000 Subject: [PATCH 03/18] refactor: export useOpenSettingsTab hook --- .../pure/Row/RowSlippageContent/index.tsx | 7 ++----- .../modules/tradeWidgetAddons/state/settingsTabState.ts | 8 +++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/pure/Row/RowSlippageContent/index.tsx b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/pure/Row/RowSlippageContent/index.tsx index 741bc17006..4a9c0ec9d9 100644 --- a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/pure/Row/RowSlippageContent/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/pure/Row/RowSlippageContent/index.tsx @@ -1,4 +1,3 @@ -import { useSetAtom } from 'jotai' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { Command } from '@cowprotocol/types' @@ -10,7 +9,7 @@ import styled from 'styled-components/macro' import { getNativeSlippageTooltip, getNonNativeSlippageTooltip } from 'common/utils/tradeSettingsTooltips' -import { settingsTabStateAtom } from '../../../state/settingsTabState' +import { useOpenSettingsTab } from '../../../state/settingsTabState' import { RowStyleProps, StyledInfoIcon, StyledRowBetween, TextWrapper, TransactionText } from '../styled' const DefaultSlippage = styled.span` @@ -65,9 +64,7 @@ export function RowSlippageContent(props: RowSlippageContentProps) { isSmartSlippageLoading, } = props - const setSettingTabState = useSetAtom(settingsTabStateAtom) - - const openSettings = () => setSettingTabState({ open: true }) + const openSettings = useOpenSettingsTab() const tooltipContent = slippageTooltip || diff --git a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/state/settingsTabState.ts b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/state/settingsTabState.ts index 659fb6321f..61b3e2561a 100644 --- a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/state/settingsTabState.ts +++ b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/state/settingsTabState.ts @@ -1,3 +1,9 @@ -import { atom } from 'jotai' +import { atom, useSetAtom } from 'jotai' export const settingsTabStateAtom = atom({ open: false }) + +export function useOpenSettingsTab() { + const setSettingTabState = useSetAtom(settingsTabStateAtom) + + return () => setSettingTabState({ open: true }) +} From 35c271c22fa0a87785bfddbcce3988ff92807ae5 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 14:15:20 +0000 Subject: [PATCH 04/18] feat: expose needsApproval flag for all token types, not just permittable --- .../src/modules/swap/hooks/useSwapButtonContext.ts | 8 +++++++- .../src/modules/swap/pure/SwapButtons/index.tsx | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts index 19906be3f4..d8ccba9e7e 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts @@ -33,7 +33,7 @@ import { useIsWrappedOut } from 'modules/trade/hooks/useIsWrappedInOrOut' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' import { QuoteDeadlineParams } from 'modules/tradeQuote' -import { useApproveState } from 'common/hooks/useApproveState' +import { ApprovalState, useApproveState } from 'common/hooks/useApproveState' import { useSafeMemo } from 'common/hooks/useSafeMemo' import { useHandleSwapOrEthFlow } from './useHandleSwapOrEthFlow' @@ -129,6 +129,10 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge isHooksStore, }) + const needsApproval = + (approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING) && + swapInputError === undefined + return useSafeMemo( () => ({ swapButtonState, @@ -146,6 +150,7 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge widgetStandaloneMode: standaloneMode, quoteDeadlineParams, isPartialApprove, + needsApproval, }), [ swapButtonState, @@ -163,6 +168,7 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge standaloneMode, quoteDeadlineParams, isPartialApprove, + needsApproval, ], ) } diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx index a0dd7e1e41..600c916cd2 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx @@ -41,6 +41,7 @@ export interface SwapButtonsContext { widgetStandaloneMode?: boolean quoteDeadlineParams: QuoteDeadlineParams isPartialApprove: boolean + needsApproval: boolean } const swapButtonStateMap: { [key in SwapButtonState]: (props: SwapButtonsContext) => JSX.Element } = { From b84cdb144c82075d09955f73cdf00ac6bb828f47 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 14:15:52 +0000 Subject: [PATCH 05/18] feat: add PartialApprovalBanner --- .../swap/containers/SwapWidget/index.tsx | 4 ++ .../pure/banners/PartialApprovalBanner.tsx | 37 +++++++++++++++++++ .../src/modules/swap/pure/warnings.tsx | 7 ++++ 3 files changed, 48 insertions(+) create mode 100644 apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx index d4fff58b3d..9e2da004cb 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx @@ -60,6 +60,7 @@ import { useRateInfoParams } from 'common/hooks/useRateInfoParams' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' import { SWAP_QUOTE_CHECK_INTERVAL } from 'common/updaters/FeesUpdater' +import { useOpenSettingsTab } from 'modules/tradeWidgetAddons/state/settingsTabState' import { SwapButtonState } from '../../helpers/getSwapButtonState' import { useDerivedSwapInfo, useSwapActionHandlers, useSwapState } from '../../hooks/useSwapState' import { useTradeQuoteStateFromLegacy } from '../../hooks/useTradeQuoteStateFromLegacy' @@ -92,6 +93,7 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { const deadlineState = useUserTransactionTTL() const partialApproveState = usePartialApprove() const isHookTradeType = useIsHooksTradeType() + const openSettings = useOpenSettingsTab() const isTradePriceUpdating = useTradePricesUpdate() @@ -216,6 +218,8 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { priceImpact: priceImpactParams.priceImpact, tradeUrlParams, isNativeSellInHooksStore, + isApprovalNeeded: !isHookTradeType && swapButtonContext.needsApproval, + openSettings, }), [ chainId, diff --git a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx new file mode 100644 index 0000000000..b63c8943c8 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx @@ -0,0 +1,37 @@ +import ICON_TOKENS from '@cowprotocol/assets/svg/tokens.svg' +import { Command } from '@cowprotocol/types' +import { BannerOrientation, ClosableBanner, InlineBanner, UnderlinedLinkStyledButton } from '@cowprotocol/ui' + +import * as timeago from 'timeago.js' + +const BANNER_STORAGE_KEY = 'partialPermitBannerKey:v0' + +const YEARS_SINCE_DEPLOYMENT = timeago.format(new Date('2021-06-08')).replace(/ ago/, '') // mainnet contract deployment date https://etherscan.io/tx/0xf49f90aa5a268c40001d1227b76bb4dd8247f18361fcad9fffd4a7a44f1320d3 + +type PartialApprovalBannerProps = { + isApprovalNeeded?: boolean + openSettings: Command +} + +export function PartialApprovalBanner({ isApprovalNeeded, openSettings }: PartialApprovalBannerProps) { + if (!isApprovalNeeded) { + return null + } + + return ClosableBanner(BANNER_STORAGE_KEY, (onClose) => ( + +

+ NEW: You can now chose do only minimal approvals in the + settings. When enabled, every + order placed that needs approval will request only the minimum necessary to trade. When disabled, you can enjoy + the same trusted experience CoW Swap has provided for the past {YEARS_SINCE_DEPLOYMENT}. +

+
+ )) +} diff --git a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx index 481c469f17..1fc3f6c8e9 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx @@ -2,6 +2,7 @@ import React from 'react' import { genericPropsChecker } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' +import { Command } from '@cowprotocol/types' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import TradeGp from 'legacy/state/swap/TradeGp' @@ -11,6 +12,7 @@ import { CompatibilityIssuesWarning } from 'modules/trade/pure/CompatibilityIssu import { TradeUrlParams } from 'modules/trade/types/TradeRawState' import { BundleTxWrapBanner, HighFeeWarning } from 'modules/tradeWidgetAddons' +import { PartialApprovalBanner } from './banners/PartialApprovalBanner' import { TwapSuggestionBanner } from './banners/TwapSuggestionBanner' export interface SwapWarningsTopProps { @@ -21,6 +23,8 @@ export interface SwapWarningsTopProps { priceImpact: Percent | undefined tradeUrlParams: TradeUrlParams isNativeSellInHooksStore: boolean + isApprovalNeeded: boolean + openSettings: Command } export interface SwapWarningsBottomProps { @@ -39,6 +43,8 @@ export const SwapWarningsTop = React.memo(function (props: SwapWarningsTopProps) priceImpact, tradeUrlParams, isNativeSellInHooksStore, + isApprovalNeeded, + openSettings } = props return ( @@ -49,6 +55,7 @@ export const SwapWarningsTop = React.memo(function (props: SwapWarningsTopProps) <> + {showTwapSuggestionBanner && ( Date: Tue, 7 Jan 2025 14:16:18 +0000 Subject: [PATCH 06/18] feat: update settings name Partial Approve to Minimal approve and tooltip --- .../tradeWidgetAddons/containers/SettingsTab/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx index 1faf7acf17..1824e97b26 100644 --- a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx @@ -125,12 +125,13 @@ export function SettingsTab({ - Partial Approve + Minimal Approve - Allows you to approve a token for a specific amount, rather than the maximum amount. + By default, token approvals & permits are for an unlimited amount, which ensures you don't pay gas for your trades. + When this setting is enabled, approvals & permits will be for the minimum amount instead of unlimited. You may incur gas costs when you trade. Existing approvals must be revoked manually before you can re-approve. } /> From 3abd7c15c6c4d980ebaec5a10b227d5b660256c0 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 14:54:54 +0000 Subject: [PATCH 07/18] fix: fix typo and padding on settings link --- .../swap/pure/banners/PartialApprovalBanner.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx index b63c8943c8..272022144f 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx @@ -2,6 +2,7 @@ import ICON_TOKENS from '@cowprotocol/assets/svg/tokens.svg' import { Command } from '@cowprotocol/types' import { BannerOrientation, ClosableBanner, InlineBanner, UnderlinedLinkStyledButton } from '@cowprotocol/ui' +import styled from 'styled-components/macro' import * as timeago from 'timeago.js' const BANNER_STORAGE_KEY = 'partialPermitBannerKey:v0' @@ -27,11 +28,14 @@ export function PartialApprovalBanner({ isApprovalNeeded, openSettings }: Partia onClose={onClose} >

- NEW: You can now chose do only minimal approvals in the - settings. When enabled, every - order placed that needs approval will request only the minimum necessary to trade. When disabled, you can enjoy - the same trusted experience CoW Swap has provided for the past {YEARS_SINCE_DEPLOYMENT}. + NEW: You can now choose to do only minimal approvals in the settings. + When enabled, every order placed that needs approval will request only the minimum necessary to trade. When + disabled, you can enjoy the same trusted experience CoW Swap has provided for the past {YEARS_SINCE_DEPLOYMENT}.

)) } + +const Link = styled(UnderlinedLinkStyledButton)` + padding: 0; +` From fd658135d98689426e8511b68bf2a3ff27a10f19 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 15:23:13 +0000 Subject: [PATCH 08/18] fix: reworked minimal approvals title and tooltip --- .../containers/SettingsTab/index.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx index 1824e97b26..9f94877ffa 100644 --- a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx @@ -125,13 +125,19 @@ export function SettingsTab({ - Minimal Approve + Minimal Approvals - By default, token approvals & permits are for an unlimited amount, which ensures you don't pay gas for your trades. - When this setting is enabled, approvals & permits will be for the minimum amount instead of unlimited. You may incur gas costs when you trade. Existing approvals must be revoked manually before you can re-approve. + By default, token approvals & permits are for an unlimited amount, which ensures you don't pay extra for subsequent trades. +
+
+ When this setting is enabled, approvals & permits will be for the minimum amount instead of unlimited. + This incurs additional costs at every trade. +
+
+ Existing approvals must be revoked manually before you can re-approve. } /> From 282d9b9ec09e69cc5ecb64b718388de0bafd076b Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 15:42:37 +0000 Subject: [PATCH 09/18] fix: lint issues --- .../src/modules/swap/containers/SwapWidget/index.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx index 9e2da004cb..6a5956cd75 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx @@ -52,6 +52,7 @@ import { import { getQuoteTimeOffset } from 'modules/tradeQuote' import { useTradeSlippage } from 'modules/tradeSlippage' import { SettingsTab, TradeRateDetails, useHighFeeWarning } from 'modules/tradeWidgetAddons' +import { useOpenSettingsTab } from 'modules/tradeWidgetAddons/state/settingsTabState' import { useTradeUsdAmounts } from 'modules/usdAmount' import { Routes } from 'common/constants/routes' @@ -60,7 +61,6 @@ import { useRateInfoParams } from 'common/hooks/useRateInfoParams' import { CurrencyInfo } from 'common/pure/CurrencyInputPanel/types' import { SWAP_QUOTE_CHECK_INTERVAL } from 'common/updaters/FeesUpdater' -import { useOpenSettingsTab } from 'modules/tradeWidgetAddons/state/settingsTabState' import { SwapButtonState } from '../../helpers/getSwapButtonState' import { useDerivedSwapInfo, useSwapActionHandlers, useSwapState } from '../../hooks/useSwapState' import { useTradeQuoteStateFromLegacy } from '../../hooks/useTradeQuoteStateFromLegacy' @@ -209,6 +209,8 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { const showTwapSuggestionBanner = !enabledTradeTypes || enabledTradeTypes.includes(TradeType.ADVANCED) const isNativeSellInHooksStore = swapButtonContext.swapButtonState === SwapButtonState.SellNativeInHooks + const isApprovalNeeded = !isHookTradeType && swapButtonContext.needsApproval + const swapWarningsTopProps: SwapWarningsTopProps = useMemo( () => ({ chainId, @@ -218,7 +220,7 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { priceImpact: priceImpactParams.priceImpact, tradeUrlParams, isNativeSellInHooksStore, - isApprovalNeeded: !isHookTradeType && swapButtonContext.needsApproval, + isApprovalNeeded, openSettings, }), [ @@ -229,6 +231,8 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { priceImpactParams.priceImpact, tradeUrlParams, isNativeSellInHooksStore, + isApprovalNeeded, + openSettings, ], ) From 12006905085752be775a20630e60591758fd5398 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Tue, 7 Jan 2025 15:57:39 +0000 Subject: [PATCH 10/18] fix: cosmos build --- .../src/modules/swap/pure/SwapButtons/index.cosmos.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx index c64663d107..f25503a650 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx @@ -27,6 +27,7 @@ const swapButtonsContext: SwapButtonsContext = { toggleWalletModal: () => void 0, hasEnoughWrappedBalanceForSwap: true, isPartialApprove: false, + needsApproval: false, quoteDeadlineParams: { validFor: 0, quoteValidTo: 0, From 511e62b7b2de7b612f38384e7e103caeb5914d53 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 08:08:00 +0000 Subject: [PATCH 11/18] fix: fix grammar --- .../modules/tradeWidgetAddons/containers/SettingsTab/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx index 9f94877ffa..7090446fdb 100644 --- a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/SettingsTab/index.tsx @@ -134,7 +134,7 @@ export function SettingsTab({

When this setting is enabled, approvals & permits will be for the minimum amount instead of unlimited. - This incurs additional costs at every trade. + This incurs additional costs on every trade.

Existing approvals must be revoked manually before you can re-approve. From e7121f8d84532bfec77bd348fdcf33835ac448ec Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 14:10:12 +0000 Subject: [PATCH 12/18] fix: do not show approval banner when selling native --- .../src/modules/swap/hooks/useSwapButtonContext.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts index d8ccba9e7e..828bd6d2f5 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts @@ -130,6 +130,7 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge }) const needsApproval = + !isNativeIn && (approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING) && swapInputError === undefined From 71b90633296a1f18f7e3c62fae6d352f621f5046 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 15:02:57 +0000 Subject: [PATCH 13/18] chore: move partial approval banner after TWAP warning --- apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx index 1fc3f6c8e9..cf3ddeafd9 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx @@ -55,7 +55,6 @@ export const SwapWarningsTop = React.memo(function (props: SwapWarningsTopProps) <> - {showTwapSuggestionBanner && ( )} + )} From 698f5783771ce066c4d711bf5724be0e80369071 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 15:31:00 +0000 Subject: [PATCH 14/18] feat: simplify text --- .../modules/swap/pure/banners/PartialApprovalBanner.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx index 272022144f..7580ae0af9 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx @@ -3,12 +3,9 @@ import { Command } from '@cowprotocol/types' import { BannerOrientation, ClosableBanner, InlineBanner, UnderlinedLinkStyledButton } from '@cowprotocol/ui' import styled from 'styled-components/macro' -import * as timeago from 'timeago.js' const BANNER_STORAGE_KEY = 'partialPermitBannerKey:v0' -const YEARS_SINCE_DEPLOYMENT = timeago.format(new Date('2021-06-08')).replace(/ ago/, '') // mainnet contract deployment date https://etherscan.io/tx/0xf49f90aa5a268c40001d1227b76bb4dd8247f18361fcad9fffd4a7a44f1320d3 - type PartialApprovalBannerProps = { isApprovalNeeded?: boolean openSettings: Command @@ -28,9 +25,7 @@ export function PartialApprovalBanner({ isApprovalNeeded, openSettings }: Partia onClose={onClose} >

- NEW: You can now choose to do only minimal approvals in the settings. - When enabled, every order placed that needs approval will request only the minimum necessary to trade. When - disabled, you can enjoy the same trusted experience CoW Swap has provided for the past {YEARS_SINCE_DEPLOYMENT}. + NEW: You can now choose to do minimal token approvals in the settings.

)) From 5621863dbe96df7fb33b69fe4fa0aff4ede7401c Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 15:58:58 +0000 Subject: [PATCH 15/18] feat: remove isApprovalNeeded prop --- .../modules/swap/pure/banners/PartialApprovalBanner.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx index 7580ae0af9..caddfb37b5 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx @@ -7,15 +7,10 @@ import styled from 'styled-components/macro' const BANNER_STORAGE_KEY = 'partialPermitBannerKey:v0' type PartialApprovalBannerProps = { - isApprovalNeeded?: boolean openSettings: Command } -export function PartialApprovalBanner({ isApprovalNeeded, openSettings }: PartialApprovalBannerProps) { - if (!isApprovalNeeded) { - return null - } - +export function PartialApprovalBanner({ openSettings }: PartialApprovalBannerProps) { return ClosableBanner(BANNER_STORAGE_KEY, (onClose) => ( Date: Wed, 8 Jan 2025 16:03:15 +0000 Subject: [PATCH 16/18] feat: remove banner from swap warnings --- .../src/modules/swap/containers/SwapWidget/index.tsx | 8 -------- .../src/modules/swap/hooks/useSwapButtonContext.ts | 9 +-------- .../src/modules/swap/pure/SwapButtons/index.tsx | 1 - apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx | 7 ------- 4 files changed, 1 insertion(+), 24 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx index 6a5956cd75..d4fff58b3d 100644 --- a/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/containers/SwapWidget/index.tsx @@ -52,7 +52,6 @@ import { import { getQuoteTimeOffset } from 'modules/tradeQuote' import { useTradeSlippage } from 'modules/tradeSlippage' import { SettingsTab, TradeRateDetails, useHighFeeWarning } from 'modules/tradeWidgetAddons' -import { useOpenSettingsTab } from 'modules/tradeWidgetAddons/state/settingsTabState' import { useTradeUsdAmounts } from 'modules/usdAmount' import { Routes } from 'common/constants/routes' @@ -93,7 +92,6 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { const deadlineState = useUserTransactionTTL() const partialApproveState = usePartialApprove() const isHookTradeType = useIsHooksTradeType() - const openSettings = useOpenSettingsTab() const isTradePriceUpdating = useTradePricesUpdate() @@ -209,8 +207,6 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { const showTwapSuggestionBanner = !enabledTradeTypes || enabledTradeTypes.includes(TradeType.ADVANCED) const isNativeSellInHooksStore = swapButtonContext.swapButtonState === SwapButtonState.SellNativeInHooks - const isApprovalNeeded = !isHookTradeType && swapButtonContext.needsApproval - const swapWarningsTopProps: SwapWarningsTopProps = useMemo( () => ({ chainId, @@ -220,8 +216,6 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { priceImpact: priceImpactParams.priceImpact, tradeUrlParams, isNativeSellInHooksStore, - isApprovalNeeded, - openSettings, }), [ chainId, @@ -231,8 +225,6 @@ export function SwapWidget({ topContent, bottomContent }: SwapWidgetProps) { priceImpactParams.priceImpact, tradeUrlParams, isNativeSellInHooksStore, - isApprovalNeeded, - openSettings, ], ) diff --git a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts index 828bd6d2f5..19906be3f4 100644 --- a/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts +++ b/apps/cowswap-frontend/src/modules/swap/hooks/useSwapButtonContext.ts @@ -33,7 +33,7 @@ import { useIsWrappedOut } from 'modules/trade/hooks/useIsWrappedInOrOut' import { useWrappedToken } from 'modules/trade/hooks/useWrappedToken' import { QuoteDeadlineParams } from 'modules/tradeQuote' -import { ApprovalState, useApproveState } from 'common/hooks/useApproveState' +import { useApproveState } from 'common/hooks/useApproveState' import { useSafeMemo } from 'common/hooks/useSafeMemo' import { useHandleSwapOrEthFlow } from './useHandleSwapOrEthFlow' @@ -129,11 +129,6 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge isHooksStore, }) - const needsApproval = - !isNativeIn && - (approvalState === ApprovalState.NOT_APPROVED || approvalState === ApprovalState.PENDING) && - swapInputError === undefined - return useSafeMemo( () => ({ swapButtonState, @@ -151,7 +146,6 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge widgetStandaloneMode: standaloneMode, quoteDeadlineParams, isPartialApprove, - needsApproval, }), [ swapButtonState, @@ -169,7 +163,6 @@ export function useSwapButtonContext(input: SwapButtonInput, actions: TradeWidge standaloneMode, quoteDeadlineParams, isPartialApprove, - needsApproval, ], ) } diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx index 600c916cd2..a0dd7e1e41 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.tsx @@ -41,7 +41,6 @@ export interface SwapButtonsContext { widgetStandaloneMode?: boolean quoteDeadlineParams: QuoteDeadlineParams isPartialApprove: boolean - needsApproval: boolean } const swapButtonStateMap: { [key in SwapButtonState]: (props: SwapButtonsContext) => JSX.Element } = { diff --git a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx index cf3ddeafd9..481c469f17 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/warnings.tsx @@ -2,7 +2,6 @@ import React from 'react' import { genericPropsChecker } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' -import { Command } from '@cowprotocol/types' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import TradeGp from 'legacy/state/swap/TradeGp' @@ -12,7 +11,6 @@ import { CompatibilityIssuesWarning } from 'modules/trade/pure/CompatibilityIssu import { TradeUrlParams } from 'modules/trade/types/TradeRawState' import { BundleTxWrapBanner, HighFeeWarning } from 'modules/tradeWidgetAddons' -import { PartialApprovalBanner } from './banners/PartialApprovalBanner' import { TwapSuggestionBanner } from './banners/TwapSuggestionBanner' export interface SwapWarningsTopProps { @@ -23,8 +21,6 @@ export interface SwapWarningsTopProps { priceImpact: Percent | undefined tradeUrlParams: TradeUrlParams isNativeSellInHooksStore: boolean - isApprovalNeeded: boolean - openSettings: Command } export interface SwapWarningsBottomProps { @@ -43,8 +39,6 @@ export const SwapWarningsTop = React.memo(function (props: SwapWarningsTopProps) priceImpact, tradeUrlParams, isNativeSellInHooksStore, - isApprovalNeeded, - openSettings } = props return ( @@ -65,7 +59,6 @@ export const SwapWarningsTop = React.memo(function (props: SwapWarningsTopProps) sellAmount={trade?.inputAmount.toExact()} /> )} - )} From 33ca8e032fc34aff0e96648835ab3c134f64b4d1 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 16:03:26 +0000 Subject: [PATCH 17/18] feat: add banner to top of Swap widget --- apps/cowswap-frontend/src/pages/Swap/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/pages/Swap/index.tsx b/apps/cowswap-frontend/src/pages/Swap/index.tsx index d672663c10..c90c727003 100644 --- a/apps/cowswap-frontend/src/pages/Swap/index.tsx +++ b/apps/cowswap-frontend/src/pages/Swap/index.tsx @@ -5,13 +5,16 @@ import { useWalletInfo } from '@cowprotocol/wallet' import { Navigate, useLocation, useParams } from 'react-router-dom' import { SwapUpdaters, SwapWidget } from 'modules/swap' +import { PartialApprovalBanner } from 'modules/swap/pure/banners/PartialApprovalBanner' import { getDefaultTradeRawState } from 'modules/trade/types/TradeRawState' import { parameterizeTradeRoute } from 'modules/trade/utils/parameterizeTradeRoute' +import { useOpenSettingsTab } from 'modules/tradeWidgetAddons/state/settingsTabState' import { Routes } from 'common/constants/routes' export function SwapPage() { const params = useParams() + const openSettings = useOpenSettingsTab() if (!params.chainId) { return @@ -20,7 +23,7 @@ export function SwapPage() { return ( <> - + } /> ) } From 75e848a542e2c235cf71d210c49c7c292d1f817a Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Wed, 8 Jan 2025 16:04:56 +0000 Subject: [PATCH 18/18] chore: remove settings from cosmos --- .../src/modules/swap/pure/SwapButtons/index.cosmos.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx index f25503a650..c64663d107 100644 --- a/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/swap/pure/SwapButtons/index.cosmos.tsx @@ -27,7 +27,6 @@ const swapButtonsContext: SwapButtonsContext = { toggleWalletModal: () => void 0, hasEnoughWrappedBalanceForSwap: true, isPartialApprove: false, - needsApproval: false, quoteDeadlineParams: { validFor: 0, quoteValidTo: 0,