@@ -2,7 +2,7 @@ import { normalize, normalizeBN } from '@aave/math-utils';
2
2
import { OrderStatus , SupportedChainId , WRAPPED_NATIVE_CURRENCIES } from '@cowprotocol/cow-sdk' ;
3
3
import { SwitchVerticalIcon } from '@heroicons/react/outline' ;
4
4
import { Trans } from '@lingui/macro' ;
5
- import { Box , CircularProgress , IconButton , SvgIcon , Typography } from '@mui/material' ;
5
+ import { Box , Checkbox , CircularProgress , IconButton , SvgIcon , Typography } from '@mui/material' ;
6
6
import { useQueryClient } from '@tanstack/react-query' ;
7
7
import { debounce } from 'lodash' ;
8
8
import React , { useEffect , useMemo , useState } from 'react' ;
@@ -54,15 +54,23 @@ export type SwitchDetailsParams = Parameters<
54
54
NonNullable < SwitchModalCustomizableProps [ 'switchDetails' ] >
55
55
> [ 0 ] ;
56
56
57
- const shouldShowWarning = ( destValueInUsd : number , srcValueInUsd : number ) => {
57
+ const valueLostPercentage = ( destValueInUsd : number , srcValueInUsd : number ) => {
58
58
const receivingPercentage = destValueInUsd / srcValueInUsd ;
59
59
const valueLostPercentage = receivingPercentage ? 1 - receivingPercentage : 0 ;
60
+ return valueLostPercentage ;
61
+ } ;
62
+
63
+ const shouldShowWarning = ( lostValue : number , srcValueInUsd : number ) => {
64
+ if ( srcValueInUsd > 500000 ) return lostValue > 0.03 ;
65
+ if ( srcValueInUsd > 100000 ) return lostValue > 0.04 ;
66
+ if ( srcValueInUsd > 10000 ) return lostValue > 0.05 ;
67
+ if ( srcValueInUsd > 1000 ) return lostValue > 0.07 ;
68
+
69
+ return lostValue > 0.05 ;
70
+ } ;
60
71
61
- if ( destValueInUsd > 500000 ) return valueLostPercentage > 0.03 ;
62
- if ( destValueInUsd > 100000 ) return valueLostPercentage > 0.04 ;
63
- if ( destValueInUsd > 10000 ) return valueLostPercentage > 0.05 ;
64
- if ( destValueInUsd > 1000 ) return valueLostPercentage > 0.07 ;
65
- return valueLostPercentage > 0.1 ;
72
+ const shouldRequireConfirmation = ( lostValue : number ) => {
73
+ return lostValue > 0.2 ;
66
74
} ;
67
75
68
76
export const getFilteredTokensForSwitch = ( chainId : number ) : TokenInfoWithBalance [ ] => {
@@ -153,6 +161,7 @@ export const BaseSwitchModalContent = ({
153
161
const switchProvider = useSwitchProvider ( { chainId : selectedChainId } ) ;
154
162
const [ slippage , setSlippage ] = useState ( switchProvider == 'cowprotocol' ? '2' : '0.10' ) ;
155
163
const [ showGasStation , setShowGasStation ] = useState ( switchProvider == 'paraswap' ) ;
164
+ const [ highPriceImpactConfirmed , setHighPriceImpactConfirmed ] = useState ( false ) ;
156
165
const selectedNetworkConfig = getNetworkConfig ( selectedChainId ) ;
157
166
const isWrongNetwork = useIsWrongNetwork ( selectedChainId ) ;
158
167
@@ -186,6 +195,7 @@ export const BaseSwitchModalContent = ({
186
195
187
196
const handleInputChange = ( value : string ) => {
188
197
setTxError ( undefined ) ;
198
+ setHighPriceImpactConfirmed ( false ) ;
189
199
if ( value === '-1' ) {
190
200
// Max Selected
191
201
setInputAmount ( selectedInputToken . balance ) ;
@@ -462,12 +472,17 @@ export const BaseSwitchModalContent = ({
462
472
} )
463
473
: null ;
464
474
465
- const showWarning = switchRates
466
- ? shouldShowWarning (
467
- Number ( switchRates . destUSD ) * ( 1 - safeSlippage ) ,
468
- Number ( switchRates . srcUSD )
475
+ const lostValue = switchRates
476
+ ? valueLostPercentage (
477
+ Number ( switchRates ? .destUSD ) * ( 1 - safeSlippage ) ,
478
+ Number ( switchRates ? .srcUSD )
469
479
)
470
- : undefined ;
480
+ : 0 ;
481
+
482
+ const showWarning = switchRates
483
+ ? shouldShowWarning ( lostValue , Number ( switchRates ?. srcUSD ) )
484
+ : false ;
485
+ const requireConfirmation = switchRates ? shouldRequireConfirmation ( lostValue ) : false ;
471
486
472
487
const isSwappingSafetyModuleToken = SAFETY_MODULE_TOKENS . includes (
473
488
selectedInputToken . symbol . toLowerCase ( )
@@ -657,13 +672,43 @@ export const BaseSwitchModalContent = ({
657
672
/>
658
673
{ txError && < ParaswapErrorDisplay txError = { txError } /> }
659
674
660
- { ! ! showWarning && (
661
- < Warning severity = "warning" icon = { false } sx = { { mt : 2 , mb : 2 } } >
675
+ { showWarning && (
676
+ < Warning
677
+ severity = "warning"
678
+ icon = { false }
679
+ sx = { {
680
+ mt : 2 ,
681
+ mb : 2 ,
682
+ display : 'flex' ,
683
+ flexDirection : 'column' ,
684
+ alignItems : 'center' ,
685
+ } }
686
+ >
662
687
< Typography variant = "caption" >
663
688
< Trans >
664
689
High price impact. This route may return less due to low liquidity.
665
690
</ Trans >
666
691
</ Typography >
692
+ { requireConfirmation && (
693
+ < Box
694
+ sx = { { display : 'flex' , flexDirection : 'row' , alignItems : 'center' , mt : 2 } }
695
+ >
696
+ < Typography variant = "caption" >
697
+ < Trans >
698
+ I confirm the swap with a potential { ( lostValue * 100 ) . toFixed ( 0 ) } % value
699
+ loss
700
+ </ Trans >
701
+ </ Typography >
702
+ < Checkbox
703
+ checked = { highPriceImpactConfirmed }
704
+ onChange = { ( ) => {
705
+ setHighPriceImpactConfirmed ( ! highPriceImpactConfirmed ) ;
706
+ } }
707
+ size = "small"
708
+ data-cy = { 'high-price-impact-checkbox' }
709
+ />
710
+ </ Box >
711
+ ) }
667
712
</ Warning >
668
713
) }
669
714
@@ -697,7 +742,8 @@ export const BaseSwitchModalContent = ({
697
742
Number ( debounceInputAmount ) > Number ( selectedInputToken . balance ) ||
698
743
! user ||
699
744
slippageValidation ?. severity === ValidationSeverity . ERROR ||
700
- isSwappingSafetyModuleToken
745
+ isSwappingSafetyModuleToken ||
746
+ ( requireConfirmation && ! highPriceImpactConfirmed )
701
747
}
702
748
chainId = { selectedChainId }
703
749
switchRates = { switchRates }
0 commit comments