feat: updated slippage ui (#7409)

* feat: updated slippage ui

* fix: update settings to also have period in max slippage string

* test: update e2e test search string
This commit is contained in:
cartcrom 2023-10-05 15:34:23 -04:00 committed by GitHub
parent e6519a7dd1
commit 1be62f0bec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1208 additions and 236 deletions

@ -6,7 +6,7 @@ describe('Swap settings', () => {
cy.contains('Settings').should('not.exist') cy.contains('Settings').should('not.exist')
cy.get(getTestSelector('open-settings-dialog-button')).click() cy.get(getTestSelector('open-settings-dialog-button')).click()
cy.get(getTestSelector('mobile-settings-menu')).should('not.exist') cy.get(getTestSelector('mobile-settings-menu')).should('not.exist')
cy.contains('Max slippage').should('exist') cy.contains('Max. slippage').should('exist')
cy.contains('Transaction deadline').should('exist') cy.contains('Transaction deadline').should('exist')
cy.contains('UniswapX').should('exist') cy.contains('UniswapX').should('exist')
cy.contains('Local routing').should('exist') cy.contains('Local routing').should('exist')
@ -26,7 +26,7 @@ describe('Swap settings', () => {
cy.get(getTestSelector('mobile-settings-menu')) cy.get(getTestSelector('mobile-settings-menu'))
.should('exist') .should('exist')
.within(() => { .within(() => {
cy.contains('Max slippage').should('exist') cy.contains('Max. slippage').should('exist')
cy.contains('UniswapX').should('exist') cy.contains('UniswapX').should('exist')
cy.contains('Local routing').should('exist') cy.contains('Local routing').should('exist')
cy.contains('Transaction deadline').should('exist') cy.contains('Transaction deadline').should('exist')

@ -46,7 +46,7 @@ describe('MaxSlippageSettings', () => {
fireEvent.change(getSlippageInput(), { target: { value: '0.5' } }) fireEvent.change(getSlippageInput(), { target: { value: '0.5' } })
expect(screen.queryAllByText('0.50%').length).toEqual(1) expect(screen.queryAllByText('0.5%').length).toEqual(1)
}) })
it('updates input value on blur with the slippage in store', () => { it('updates input value on blur with the slippage in store', () => {
renderSlippageSettings() renderSlippageSettings()
@ -56,7 +56,7 @@ describe('MaxSlippageSettings', () => {
fireEvent.change(input, { target: { value: '0.5' } }) fireEvent.change(input, { target: { value: '0.5' } })
fireEvent.blur(input) fireEvent.blur(input)
expect(input.value).toBe('0.50') expect(input.value).toBe('0.5')
}) })
it('clears errors on blur and overwrites incorrect value with the latest correct value', () => { it('clears errors on blur and overwrites incorrect value with the latest correct value', () => {
renderSlippageSettings() renderSlippageSettings()
@ -68,7 +68,7 @@ describe('MaxSlippageSettings', () => {
fireEvent.change(input, { target: { value: '500' } }) fireEvent.change(input, { target: { value: '500' } })
fireEvent.blur(input) fireEvent.blur(input)
expect(input.value).toBe('50.00') expect(input.value).toBe('50')
}) })
it('does not allow to enter more than 2 digits after the decimal point', () => { it('does not allow to enter more than 2 digits after the decimal point', () => {
renderSlippageSettings() renderSlippageSettings()

@ -8,6 +8,7 @@ import { useUserSlippageTolerance } from 'state/user/hooks'
import { SlippageTolerance } from 'state/user/types' import { SlippageTolerance } from 'state/user/types'
import styled from 'styled-components' import styled from 'styled-components'
import { CautionTriangle, ThemedText } from 'theme/components' import { CautionTriangle, ThemedText } from 'theme/components'
import { useFormatter } from 'utils/formatNumbers'
import { Input, InputContainer } from '../Input' import { Input, InputContainer } from '../Input'
@ -37,15 +38,23 @@ const NUMBER_WITH_MAX_TWO_DECIMAL_PLACES = /^(?:\d*\.\d{0,2}|\d+)$/
const MINIMUM_RECOMMENDED_SLIPPAGE = new Percent(5, 10_000) const MINIMUM_RECOMMENDED_SLIPPAGE = new Percent(5, 10_000)
const MAXIMUM_RECOMMENDED_SLIPPAGE = new Percent(1, 100) const MAXIMUM_RECOMMENDED_SLIPPAGE = new Percent(1, 100)
function useFormatSlippageInput() {
const { formatSlippage } = useFormatter()
return (slippage: Percent) => formatSlippage(slippage).slice(0, -1) // remove % sign
}
export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Percent }) { export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Percent }) {
const [userSlippageTolerance, setUserSlippageTolerance] = useUserSlippageTolerance() const [userSlippageTolerance, setUserSlippageTolerance] = useUserSlippageTolerance()
const { formatSlippage } = useFormatter()
const formatSlippageInput = useFormatSlippageInput()
// In order to trigger `custom` mode, we need to set `userSlippageTolerance` to a value that is not `auto`. // In order to trigger `custom` mode, we need to set `userSlippageTolerance` to a value that is not `auto`.
// To do so, we use `autoSlippage` value. However, since users are likely to change that value, // To do so, we use `autoSlippage` value. However, since users are likely to change that value,
// we render it as a placeholder instead of a value. // we render it as a placeholder instead of a value.
const defaultSlippageInputValue = const defaultSlippageInputValue =
userSlippageTolerance !== SlippageTolerance.Auto && !userSlippageTolerance.equalTo(autoSlippage) userSlippageTolerance !== SlippageTolerance.Auto && !userSlippageTolerance.equalTo(autoSlippage)
? userSlippageTolerance.toFixed(2) ? formatSlippageInput(userSlippageTolerance)
: '' : ''
// If user has previously entered a custom slippage, we want to show that value in the input field // If user has previously entered a custom slippage, we want to show that value in the input field
@ -101,7 +110,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
header={ header={
<Row width="auto"> <Row width="auto">
<ThemedText.BodySecondary> <ThemedText.BodySecondary>
<Trans>Max slippage</Trans> <Trans>Max. slippage</Trans>
</ThemedText.BodySecondary> </ThemedText.BodySecondary>
<QuestionHelper <QuestionHelper
text={ text={
@ -115,7 +124,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
{userSlippageTolerance === SlippageTolerance.Auto ? ( {userSlippageTolerance === SlippageTolerance.Auto ? (
<Trans>Auto</Trans> <Trans>Auto</Trans>
) : ( ) : (
`${userSlippageTolerance.toFixed(2)}%` formatSlippage(userSlippageTolerance)
)} )}
</ThemedText.BodyPrimary> </ThemedText.BodyPrimary>
} }
@ -149,7 +158,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
<InputContainer gap="md" error={!!slippageError}> <InputContainer gap="md" error={!!slippageError}>
<Input <Input
data-testid="slippage-input" data-testid="slippage-input"
placeholder={autoSlippage.toFixed(2)} placeholder={formatSlippageInput(autoSlippage)}
value={slippageInput} value={slippageInput}
onChange={(e) => parseSlippageInput(e.target.value)} onChange={(e) => parseSlippageInput(e.target.value)}
onBlur={() => { onBlur={() => {
@ -167,7 +176,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
<ThemedText.BodySmall color="deprecated_accentWarning"> <ThemedText.BodySmall color="deprecated_accentWarning">
{tooLow ? ( {tooLow ? (
<Trans> <Trans>
Slippage below {MINIMUM_RECOMMENDED_SLIPPAGE.toFixed(2)}% may result in a failed transaction Slippage below {formatSlippage(MINIMUM_RECOMMENDED_SLIPPAGE)} may result in a failed transaction
</Trans> </Trans>
) : ( ) : (
<Trans>Your transaction may be frontrun and result in an unfavorable trade.</Trans> <Trans>Your transaction may be frontrun and result in an unfavorable trade.</Trans>

@ -5,6 +5,7 @@ import { useUserSlippageTolerance } from 'state/user/hooks'
import { SlippageTolerance } from 'state/user/types' import { SlippageTolerance } from 'state/user/types'
import styled from 'styled-components' import styled from 'styled-components'
import { ThemedText } from 'theme/components' import { ThemedText } from 'theme/components'
import { useFormatter } from 'utils/formatNumbers'
import validateUserSlippageTolerance, { SlippageValidationResult } from 'utils/validateUserSlippageTolerance' import validateUserSlippageTolerance, { SlippageValidationResult } from 'utils/validateUserSlippageTolerance'
const Icon = styled(Settings)` const Icon = styled(Settings)`
@ -46,6 +47,7 @@ const IconContainerWithSlippage = styled(IconContainer)<{ displayWarning?: boole
const ButtonContent = () => { const ButtonContent = () => {
const [userSlippageTolerance] = useUserSlippageTolerance() const [userSlippageTolerance] = useUserSlippageTolerance()
const { formatSlippage } = useFormatter()
if (userSlippageTolerance === SlippageTolerance.Auto) { if (userSlippageTolerance === SlippageTolerance.Auto) {
return ( return (
@ -60,7 +62,7 @@ const ButtonContent = () => {
return ( return (
<IconContainerWithSlippage data-testid="settings-icon-with-slippage" gap="sm" displayWarning={isInvalidSlippage}> <IconContainerWithSlippage data-testid="settings-icon-with-slippage" gap="sm" displayWarning={isInvalidSlippage}>
<ThemedText.BodySmall> <ThemedText.BodySmall>
<Trans>{userSlippageTolerance.toFixed(2)}% slippage</Trans> <Trans>{formatSlippage(userSlippageTolerance)} slippage</Trans>
</ThemedText.BodySmall> </ThemedText.BodySmall>
<Icon /> <Icon />
</IconContainerWithSlippage> </IconContainerWithSlippage>

@ -0,0 +1,53 @@
import { Trans } from '@lingui/macro'
import { Percent, TradeType } from '@uniswap/sdk-core'
import Column from 'components/Column'
import { RowBetween } from 'components/Row'
import { InterfaceTrade } from 'state/routing/types'
import { ExternalLink, Separator, ThemedText } from 'theme/components'
import { NumberType, useFormatter } from 'utils/formatNumbers'
const ExactInMessage = ({ amount }: { amount: string }) => (
<Trans>
If the price moves so that you will receive less than {amount}, your transaction will be reverted. This is the
minimum amount you are guaranteed to receive.
</Trans>
)
const ExactOutMessage = ({ amount }: { amount: string }) => (
<Trans>
If the price moves so that you will pay more than {amount}, your transaction will be reverted. This is the maximum
amount you are guaranteed to pay.
</Trans>
)
function SlippageHeader({ amount, isExactIn }: { amount: string; isExactIn: boolean }) {
return (
<RowBetween>
<ThemedText.Caption color="neutral1">
{isExactIn ? <Trans>Receive at least</Trans> : <Trans>Pay at most</Trans>}
</ThemedText.Caption>
<ThemedText.Caption color="neutral1">{amount}</ThemedText.Caption>
</RowBetween>
)
}
export function MaxSlippageTooltip({ trade, allowedSlippage }: { trade: InterfaceTrade; allowedSlippage: Percent }) {
const isExactIn = trade.tradeType === TradeType.EXACT_INPUT
const amount = isExactIn ? trade.minimumAmountOut(allowedSlippage) : trade.maximumAmountIn(allowedSlippage)
const formattedAmount = useFormatter().formatCurrencyAmount({ amount, type: NumberType.SwapDetailsAmount })
const displayAmount = `${formattedAmount} ${amount.currency.symbol}`
return (
<Column gap="xs">
<SlippageHeader amount={displayAmount} isExactIn={isExactIn} />
<Separator />
<div>
{isExactIn ? <ExactInMessage amount={displayAmount} /> : <ExactOutMessage amount={displayAmount} />}{' '}
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/8643879653261-What-is-Price-Slippage-">
Learn more
</ExternalLink>
</div>
</Column>
)
}

@ -108,11 +108,9 @@ function AdvancedSwapDetails(props: SwapDetailsProps & { open: boolean }) {
<SwapDetailsWrapper gap="md" data-testid="advanced-swap-details"> <SwapDetailsWrapper gap="md" data-testid="advanced-swap-details">
<Separator /> <Separator />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.PRICE_IMPACT} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.PRICE_IMPACT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.MAX_SLIPPAGE} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.INPUT_TOKEN_FEE_ON_TRANSFER} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.INPUT_TOKEN_FEE_ON_TRANSFER} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.OUTPUT_TOKEN_FEE_ON_TRANSFER} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.OUTPUT_TOKEN_FEE_ON_TRANSFER} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.MAXIMUM_INPUT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.MINIMUM_OUTPUT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.EXPECTED_OUTPUT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.NETWORK_COST} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.NETWORK_COST} />
<Separator /> <Separator />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.ROUTING_INFO} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.ROUTING_INFO} />

@ -11,12 +11,15 @@ import { useIsMobile } from 'nft/hooks'
import React, { PropsWithChildren, useEffect, useState } from 'react' import React, { PropsWithChildren, useEffect, useState } from 'react'
import { InterfaceTrade, TradeFillType } from 'state/routing/types' import { InterfaceTrade, TradeFillType } from 'state/routing/types'
import { isPreviewTrade, isUniswapXTrade } from 'state/routing/utils' import { isPreviewTrade, isUniswapXTrade } from 'state/routing/utils'
import { useUserSlippageTolerance } from 'state/user/hooks'
import { SlippageTolerance } from 'state/user/types'
import styled, { DefaultTheme } from 'styled-components' import styled, { DefaultTheme } from 'styled-components'
import { ExternalLink, ThemedText } from 'theme/components' import { ExternalLink, ThemedText } from 'theme/components'
import { NumberType, useFormatter } from 'utils/formatNumbers' import { NumberType, useFormatter } from 'utils/formatNumbers'
import { getPriceImpactColor } from 'utils/prices' import { getPriceImpactColor } from 'utils/prices'
import { GasBreakdownTooltip, UniswapXDescription } from './GasBreakdownTooltip' import { GasBreakdownTooltip, UniswapXDescription } from './GasBreakdownTooltip'
import { MaxSlippageTooltip } from './MaxSlippageTooltip'
import SwapRoute from './SwapRoute' import SwapRoute from './SwapRoute'
export enum SwapLineItemType { export enum SwapLineItemType {
@ -25,9 +28,9 @@ export enum SwapLineItemType {
INPUT_TOKEN_FEE_ON_TRANSFER, INPUT_TOKEN_FEE_ON_TRANSFER,
OUTPUT_TOKEN_FEE_ON_TRANSFER, OUTPUT_TOKEN_FEE_ON_TRANSFER,
PRICE_IMPACT, PRICE_IMPACT,
MAX_SLIPPAGE,
MAXIMUM_INPUT, MAXIMUM_INPUT,
MINIMUM_OUTPUT, MINIMUM_OUTPUT,
EXPECTED_OUTPUT,
ROUTING_INFO, ROUTING_INFO,
} }
@ -43,6 +46,18 @@ const ColorWrapper = styled.span<{ textColor?: keyof DefaultTheme }>`
${({ textColor, theme }) => textColor && `color: ${theme[textColor]};`} ${({ textColor, theme }) => textColor && `color: ${theme[textColor]};`}
` `
const AutoBadge = styled(ThemedText.LabelMicro).attrs({ fontWeight: 535 })`
background: ${({ theme }) => theme.surface3};
border-radius: 8px;
color: ${({ theme }) => theme.neutral2};
height: 20px;
padding: 0 6px;
::after {
content: '${t`Auto`}';
}
`
function FOTTooltipContent() { function FOTTooltipContent() {
return ( return (
<> <>
@ -91,7 +106,8 @@ type LineItemData = {
function useLineItem(props: SwapLineItemProps): LineItemData | undefined { function useLineItem(props: SwapLineItemProps): LineItemData | undefined {
const { trade, syncing, allowedSlippage, type } = props const { trade, syncing, allowedSlippage, type } = props
const { formatNumber } = useFormatter() const { formatNumber, formatSlippage } = useFormatter()
const isAutoSlippage = useUserSlippageTolerance()[0] === SlippageTolerance.Auto
const isUniswapX = isUniswapXTrade(trade) const isUniswapX = isUniswapXTrade(trade)
const isPreview = isPreviewTrade(trade) const isPreview = isPreviewTrade(trade)
@ -132,10 +148,20 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined {
TooltipBody: () => <Trans>The impact your trade has on the market price of this pool.</Trans>, TooltipBody: () => <Trans>The impact your trade has on the market price of this pool.</Trans>,
Value: () => (isPreview ? <Loading /> : <ColoredPercentRow percent={trade.priceImpact} />), Value: () => (isPreview ? <Loading /> : <ColoredPercentRow percent={trade.priceImpact} />),
} }
case SwapLineItemType.MAX_SLIPPAGE:
return {
Label: () => <Trans>Max. slippage</Trans>,
TooltipBody: () => <MaxSlippageTooltip {...props} />,
Value: () => (
<Row gap="8px">
{isAutoSlippage && <AutoBadge />} {formatSlippage(allowedSlippage)}
</Row>
),
}
case SwapLineItemType.MAXIMUM_INPUT: case SwapLineItemType.MAXIMUM_INPUT:
if (trade.tradeType === TradeType.EXACT_INPUT) return if (trade.tradeType === TradeType.EXACT_INPUT) return
return { return {
Label: () => <Trans>Maximum input</Trans>, Label: () => <Trans>Pay at most</Trans>,
TooltipBody: () => ( TooltipBody: () => (
<Trans> <Trans>
The maximum amount you are guaranteed to spend. If the price slips any further, your transaction will The maximum amount you are guaranteed to spend. If the price slips any further, your transaction will
@ -148,7 +174,7 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined {
case SwapLineItemType.MINIMUM_OUTPUT: case SwapLineItemType.MINIMUM_OUTPUT:
if (trade.tradeType === TradeType.EXACT_OUTPUT) return if (trade.tradeType === TradeType.EXACT_OUTPUT) return
return { return {
Label: () => <Trans>Minimum output</Trans>, Label: () => <Trans>Receive at least</Trans>,
TooltipBody: () => ( TooltipBody: () => (
<Trans> <Trans>
The minimum amount you are guaranteed to receive. If the price slips any further, your transaction will The minimum amount you are guaranteed to receive. If the price slips any further, your transaction will
@ -158,18 +184,6 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined {
Value: () => <CurrencyAmountRow amount={trade.minimumAmountOut(allowedSlippage)} />, Value: () => <CurrencyAmountRow amount={trade.minimumAmountOut(allowedSlippage)} />,
loaderWidth: 70, loaderWidth: 70,
} }
case SwapLineItemType.EXPECTED_OUTPUT:
return {
Label: () => <Trans>Expected output</Trans>,
TooltipBody: () => (
<Trans>
The amount you expect to receive at the current market price. You may receive less or more if the market
price changes while your transaction is pending.
</Trans>
),
Value: () => <CurrencyAmountRow amount={trade.postTaxOutputAmount} />,
loaderWidth: 65,
}
case SwapLineItemType.ROUTING_INFO: case SwapLineItemType.ROUTING_INFO:
if (isPreview) return { Label: () => <Trans>Order routing</Trans>, Value: () => <Loading /> } if (isPreview) return { Label: () => <Trans>Order routing</Trans>, Value: () => <Loading /> }
return { return {

@ -74,10 +74,11 @@ export default function SwapModalFooter({
<DetailsContainer gap="md"> <DetailsContainer gap="md">
<SwapLineItem {...lineItemProps} type={SwapLineItemType.EXCHANGE_RATE} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.EXCHANGE_RATE} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.PRICE_IMPACT} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.PRICE_IMPACT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.INPUT_TOKEN_FEE_ON_TRANSFER} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.MAX_SLIPPAGE} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.OUTPUT_TOKEN_FEE_ON_TRANSFER} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.MAXIMUM_INPUT} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.MAXIMUM_INPUT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.MINIMUM_OUTPUT} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.MINIMUM_OUTPUT} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.INPUT_TOKEN_FEE_ON_TRANSFER} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.OUTPUT_TOKEN_FEE_ON_TRANSFER} />
<SwapLineItem {...lineItemProps} type={SwapLineItemType.NETWORK_COST} /> <SwapLineItem {...lineItemProps} type={SwapLineItemType.NETWORK_COST} />
</DetailsContainer> </DetailsContainer>
{showAcceptChanges ? ( {showAcceptChanges ? (

@ -43,6 +43,24 @@ exports[`SwapDetailsDropdown.tsx renders a trade 1`] = `
gap: 4px; gap: 4px;
} }
.c21 {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
padding: 0;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
gap: 8px;
}
.c4 { .c4 {
-webkit-box-pack: justify; -webkit-box-pack: justify;
-webkit-justify-content: space-between; -webkit-justify-content: space-between;
@ -138,6 +156,18 @@ exports[`SwapDetailsDropdown.tsx renders a trade 1`] = `
color: #7D7D7D; color: #7D7D7D;
} }
.c22 {
background: #22222212;
border-radius: 8px;
color: #7D7D7D;
height: 20px;
padding: 0 6px;
}
.c22::after {
content: 'Auto';
}
.c8 { .c8 {
background-color: transparent; background-color: transparent;
border: none; border: none;
@ -329,7 +359,7 @@ exports[`SwapDetailsDropdown.tsx renders a trade 1`] = `
class="c9 c19 css-142zc9n" class="c9 c19 css-142zc9n"
data-testid="swap-li-label" data-testid="swap-li-label"
> >
Minimum output Max. slippage
</div> </div>
<div <div
class="c12" class="c12"
@ -338,28 +368,14 @@ exports[`SwapDetailsDropdown.tsx renders a trade 1`] = `
<div <div
class="c9 c20 css-142zc9n" class="c9 c20 css-142zc9n"
> >
0.00000000000000098 DEF
</div>
</div>
</div>
</div>
<div <div
class="c2 c3 c4" class="c2 c21"
> >
<div <div
class="c9 c19 css-142zc9n" class="c14 c22 css-1lgneq0"
data-testid="swap-li-label" />
> 2%
Expected output
</div> </div>
<div
class="c12"
>
<div>
<div
class="c9 c20 css-142zc9n"
>
0.000000000000001 DEF
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because it is too large Load Diff

@ -26,6 +26,24 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
} }
.c10 { .c10 {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
padding: 0;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
gap: 8px;
}
.c13 {
width: 100%; width: 100%;
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
@ -54,6 +72,10 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
color: #222222; color: #222222;
} }
.c11 {
color: #7D7D7D;
}
.c0 { .c0 {
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
@ -89,6 +111,18 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
color: #7D7D7D; color: #7D7D7D;
} }
.c12 {
background: #22222212;
border-radius: 8px;
color: #7D7D7D;
height: 20px;
padding: 0 6px;
}
.c12::after {
content: 'Auto';
}
.c1 { .c1 {
padding: 0 8px; padding: 0 8px;
} }
@ -143,7 +177,35 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
class="c5 c8 css-142zc9n" class="c5 c8 css-142zc9n"
data-testid="swap-li-label" data-testid="swap-li-label"
> >
Minimum output Max. slippage
</div>
<div
class="c9"
>
<div>
<div
class="c5 c7 css-142zc9n"
>
<div
class="c2 c10"
>
<div
class="c11 c12 css-1lgneq0"
/>
2%
</div>
</div>
</div>
</div>
</div>
<div
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
data-testid="swap-li-label"
>
Receive at least
</div> </div>
<div <div
class="c9" class="c9"
@ -174,7 +236,7 @@ exports[`SwapModalFooter.tsx matches base snapshot, test trade exact input 1`] =
class="c5 c7 css-142zc9n" class="c5 c7 css-142zc9n"
> >
<div <div
class="c2 c10" class="c2 c13"
> >
<img <img
alt="gas cost icon" alt="gas cost icon"
@ -385,6 +447,24 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
justify-content: flex-start; justify-content: flex-start;
} }
.c11 {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
padding: 0;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
gap: 8px;
}
.c4 { .c4 {
-webkit-box-pack: justify; -webkit-box-pack: justify;
-webkit-justify-content: space-between; -webkit-justify-content: space-between;
@ -396,6 +476,10 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
color: #222222; color: #222222;
} }
.c12 {
color: #7D7D7D;
}
.c0 { .c0 {
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
@ -444,6 +528,18 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
color: #7D7D7D; color: #7D7D7D;
} }
.c13 {
background: #22222212;
border-radius: 8px;
color: #7D7D7D;
height: 20px;
padding: 0 6px;
}
.c13::after {
content: 'Auto';
}
.c1 { .c1 {
padding: 0 8px; padding: 0 8px;
} }
@ -503,7 +599,35 @@ exports[`SwapModalFooter.tsx renders a preview trade while disabling submission
class="c5 c8 css-142zc9n" class="c5 c8 css-142zc9n"
data-testid="swap-li-label" data-testid="swap-li-label"
> >
Minimum output Max. slippage
</div>
<div
class="c9"
>
<div>
<div
class="c5 c7 css-142zc9n"
>
<div
class="c2 c11"
>
<div
class="c12 c13 css-1lgneq0"
/>
2%
</div>
</div>
</div>
</div>
</div>
<div
class="c2 c3 c4"
>
<div
class="c5 c8 css-142zc9n"
data-testid="swap-li-label"
>
Receive at least
</div> </div>
<div <div
class="c9" class="c9"

@ -402,25 +402,25 @@ describe('formatSlippage', () => {
expect(formatSlippage(undefined)).toBe('-') expect(formatSlippage(undefined)).toBe('-')
}) })
it('correctly formats a percent with 3 significant digits', () => { it('correctly formats a percent with no trailing digits', () => {
const { formatSlippage } = renderHook(() => useFormatter()).result.current const { formatSlippage } = renderHook(() => useFormatter()).result.current
expect(formatSlippage(new Percent(1, 100000))).toBe('0.001%') expect(formatSlippage(new Percent(1, 100000))).toBe('0.001%')
expect(formatSlippage(new Percent(1, 1000))).toBe('0.100%') expect(formatSlippage(new Percent(1, 1000))).toBe('0.1%')
expect(formatSlippage(new Percent(1, 100))).toBe('1.000%') expect(formatSlippage(new Percent(1, 100))).toBe('1%')
expect(formatSlippage(new Percent(1, 10))).toBe('10.000%') expect(formatSlippage(new Percent(1, 10))).toBe('10%')
expect(formatSlippage(new Percent(1, 1))).toBe('100.000%') expect(formatSlippage(new Percent(1, 1))).toBe('100%')
}) })
it('correctly formats a percent with 3 significant digits with french locale', () => { it('correctly formats a percent with french locale', () => {
mocked(useActiveLocale).mockReturnValue('fr-FR') mocked(useActiveLocale).mockReturnValue('fr-FR')
const { formatSlippage } = renderHook(() => useFormatter()).result.current const { formatSlippage } = renderHook(() => useFormatter()).result.current
expect(formatSlippage(new Percent(1, 100000))).toBe('0,001%') expect(formatSlippage(new Percent(1, 100000))).toBe('0,001%')
expect(formatSlippage(new Percent(1, 1000))).toBe('0,100%') expect(formatSlippage(new Percent(1, 1000))).toBe('0,1%')
expect(formatSlippage(new Percent(1, 100))).toBe('1,000%') expect(formatSlippage(new Percent(1, 100))).toBe('1%')
expect(formatSlippage(new Percent(1, 10))).toBe('10,000%') expect(formatSlippage(new Percent(1, 10))).toBe('10%')
expect(formatSlippage(new Percent(1, 1))).toBe('100,000%') expect(formatSlippage(new Percent(1, 1))).toBe('100%')
}) })
}) })

@ -472,7 +472,6 @@ function formatSlippage(slippage: Percent | undefined, locale: SupportedLocale =
if (!slippage) return '-' if (!slippage) return '-'
return `${Number(slippage.toFixed(3)).toLocaleString(locale, { return `${Number(slippage.toFixed(3)).toLocaleString(locale, {
minimumFractionDigits: 3,
maximumFractionDigits: 3, maximumFractionDigits: 3,
useGrouping: false, useGrouping: false,
})}%` })}%`