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/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..caddfb37b5 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/swap/pure/banners/PartialApprovalBanner.tsx @@ -0,0 +1,31 @@ +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' + +const BANNER_STORAGE_KEY = 'partialPermitBannerKey:v0' + +type PartialApprovalBannerProps = { + openSettings: Command +} + +export function PartialApprovalBanner({ openSettings }: PartialApprovalBannerProps) { + return ClosableBanner(BANNER_STORAGE_KEY, (onClose) => ( + +

+ NEW: You can now choose to do minimal token approvals in the settings. +

+
+ )) +} + +const Link = styled(UnderlinedLinkStyledButton)` + padding: 0; +` 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..7090446fdb 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,19 @@ export function SettingsTab({ - Partial Approve + Minimal Approvals - 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 extra for subsequent trades. +
+
+ When this setting is enabled, approvals & permits will be for the minimum amount instead of unlimited. + This incurs additional costs on every trade. +
+
+ Existing approvals must be revoked manually before you can re-approve. } /> 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 }) +} 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 ( <> - + } /> ) } 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' 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; + } +`