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;
+ }
+`