@rango-dev/widget-embedded 0.42.3-next.2 → 0.42.3-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/NoResult/NoResult.d.ts.map +1 -1
- package/dist/components/NoResult/NoResult.types.d.ts +1 -0
- package/dist/components/NoResult/NoResult.types.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.d.ts +5 -3
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.d.ts +440 -0
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts +2 -0
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts.map +1 -1
- package/dist/components/Slippage/Slippage.d.ts.map +1 -1
- package/dist/components/Slippage/Slippage.styles.d.ts +162 -0
- package/dist/components/Slippage/Slippage.styles.d.ts.map +1 -1
- package/dist/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.d.ts +4 -0
- package/dist/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.d.ts.map +1 -0
- package/dist/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.helpers.d.ts +8 -0
- package/dist/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.helpers.d.ts.map +1 -0
- package/dist/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.types.d.ts +4 -0
- package/dist/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.types.d.ts.map +1 -0
- package/dist/components/SwapMetrics/SwapMetrics.constants.d.ts +5 -0
- package/dist/components/SwapMetrics/SwapMetrics.constants.d.ts.map +1 -0
- package/dist/components/SwapMetrics/SwapMetrics.d.ts +4 -0
- package/dist/components/SwapMetrics/SwapMetrics.d.ts.map +1 -0
- package/dist/components/SwapMetrics/SwapMetrics.helpers.d.ts +11 -0
- package/dist/components/SwapMetrics/SwapMetrics.helpers.d.ts.map +1 -0
- package/dist/components/SwapMetrics/SwapMetrics.styles.d.ts +482 -0
- package/dist/components/SwapMetrics/SwapMetrics.styles.d.ts.map +1 -0
- package/dist/components/SwapMetrics/SwapMetrics.types.d.ts +27 -0
- package/dist/components/SwapMetrics/SwapMetrics.types.d.ts.map +1 -0
- package/dist/components/SwapMetrics/index.d.ts +2 -0
- package/dist/components/SwapMetrics/index.d.ts.map +1 -0
- package/dist/containers/Inputs/Inputs.d.ts.map +1 -1
- package/dist/hooks/useSyncUrlAndStore/useSyncUrlAndStore.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +4 -4
- package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
- package/dist/pages/Home.d.ts.map +1 -1
- package/dist/pages/LiquiditySourcePage.d.ts.map +1 -1
- package/dist/store/AppStore.d.ts +2 -0
- package/dist/store/AppStore.d.ts.map +1 -1
- package/dist/store/app.d.ts +2 -0
- package/dist/store/app.d.ts.map +1 -1
- package/dist/store/quote.d.ts +2 -0
- package/dist/store/quote.d.ts.map +1 -1
- package/dist/store/slices/settings.d.ts +3 -0
- package/dist/store/slices/settings.d.ts.map +1 -1
- package/dist/utils/colors.d.ts.map +1 -1
- package/dist/utils/numbers.d.ts +1 -0
- package/dist/utils/numbers.d.ts.map +1 -1
- package/dist/utils/sanitizers.d.ts +27 -0
- package/dist/utils/sanitizers.d.ts.map +1 -0
- package/dist/utils/sanitizers.test.d.ts +2 -0
- package/dist/utils/sanitizers.test.d.ts.map +1 -0
- package/dist/utils/settings.d.ts +2 -1
- package/dist/utils/settings.d.ts.map +1 -1
- package/dist/utils/validation.d.ts +26 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.test.d.ts +2 -0
- package/dist/utils/validation.test.d.ts.map +1 -0
- package/dist/utils/wallets.d.ts.map +1 -1
- package/dist/widget-embedded.build.json +1 -1
- package/package.json +3 -3
- package/src/components/NoResult/NoResult.tsx +4 -1
- package/src/components/NoResult/NoResult.types.ts +1 -0
- package/src/components/Quote/Quote.tsx +1 -1
- package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.ts +29 -4
- package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.ts +10 -1
- package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.tsx +38 -7
- package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.ts +2 -0
- package/src/components/QuoteWarningsAndErrors/SlippageWariningModal.tsx +20 -21
- package/src/components/Slippage/Slippage.styles.ts +23 -0
- package/src/components/Slippage/Slippage.tsx +28 -22
- package/src/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.helpers.ts +33 -0
- package/src/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.tsx +48 -0
- package/src/components/SlippageWarningsAndErrors/SlippageWarningsAndErrors.types.ts +3 -0
- package/src/components/SwapMetrics/SwapMetrics.constants.ts +4 -0
- package/src/components/SwapMetrics/SwapMetrics.helpers.ts +76 -0
- package/src/components/SwapMetrics/SwapMetrics.styles.ts +32 -0
- package/src/components/SwapMetrics/SwapMetrics.tsx +134 -0
- package/src/components/SwapMetrics/SwapMetrics.types.ts +26 -0
- package/src/components/SwapMetrics/index.ts +1 -0
- package/src/containers/Inputs/Inputs.tsx +2 -0
- package/src/hooks/useSwapInput.ts +1 -1
- package/src/hooks/useSyncUrlAndStore/useSyncUrlAndStore.ts +2 -0
- package/src/pages/ConfirmSwapPage.tsx +6 -1
- package/src/pages/Home.tsx +61 -12
- package/src/pages/LiquiditySourcePage.tsx +5 -3
- package/src/store/app.ts +1 -0
- package/src/store/quote.ts +23 -4
- package/src/store/slices/settings.ts +11 -0
- package/src/utils/colors.ts +3 -10
- package/src/utils/numbers.ts +11 -0
- package/src/utils/sanitizers.test.ts +122 -0
- package/src/utils/sanitizers.ts +41 -0
- package/src/utils/settings.ts +11 -4
- package/src/utils/validation.test.ts +121 -0
- package/src/utils/validation.ts +45 -0
- package/src/utils/wallets.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rango-dev/widget-embedded",
|
|
3
|
-
"version": "0.42.3-next.
|
|
3
|
+
"version": "0.42.3-next.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"source": "./src/index.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@rango-dev/queue-manager-rango-preset": "^0.45.2-next.4",
|
|
31
31
|
"@rango-dev/queue-manager-react": "^0.29.0",
|
|
32
32
|
"@rango-dev/signer-solana": "^0.39.1-next.1",
|
|
33
|
-
"@rango-dev/ui": "^0.46.2-next.
|
|
33
|
+
"@rango-dev/ui": "^0.46.2-next.6",
|
|
34
34
|
"@rango-dev/wallets-core": "^0.43.1-next.3",
|
|
35
35
|
"@rango-dev/wallets-react": "^0.30.2-next.4",
|
|
36
36
|
"@rango-dev/wallets-shared": "^0.44.2-next.4",
|
|
@@ -54,4 +54,4 @@
|
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public"
|
|
56
56
|
}
|
|
57
|
-
}
|
|
57
|
+
}
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from './NoResult.styles';
|
|
27
27
|
|
|
28
28
|
export function NoResult(props: PropTypes) {
|
|
29
|
-
const { fetch, error, size = 'small' } = props;
|
|
29
|
+
const { fetch, error, size = 'small', skipAlerts } = props;
|
|
30
30
|
const disabledLiquiditySources = useAppStore().getDisabledLiquiditySources();
|
|
31
31
|
const toggleAllLiquiditySources = useAppStore().toggleAllLiquiditySources;
|
|
32
32
|
|
|
@@ -37,6 +37,9 @@ export function NoResult(props: PropTypes) {
|
|
|
37
37
|
() => toggleAllLiquiditySources(swappers, true),
|
|
38
38
|
fetch
|
|
39
39
|
);
|
|
40
|
+
if (skipAlerts) {
|
|
41
|
+
info.alert = null;
|
|
42
|
+
}
|
|
40
43
|
|
|
41
44
|
return (
|
|
42
45
|
<Container>
|
|
@@ -263,7 +263,7 @@ export function Quote(props: QuoteProps) {
|
|
|
263
263
|
variant="body"
|
|
264
264
|
color="neutral900">
|
|
265
265
|
{i18n.t({
|
|
266
|
-
id: 'Minimum
|
|
266
|
+
id: 'Minimum suggested slippage: {minRequiredSlippage}',
|
|
267
267
|
values: {
|
|
268
268
|
...(error?.type ===
|
|
269
269
|
QuoteErrorType.INSUFFICIENT_SLIPPAGE && {
|
|
@@ -10,10 +10,17 @@ import { errorMessages } from '../../constants/errors';
|
|
|
10
10
|
import { QuoteErrorType, QuoteWarningType } from '../../types';
|
|
11
11
|
import { getPriceImpactLevel } from '../../utils/quote';
|
|
12
12
|
|
|
13
|
-
type
|
|
13
|
+
export type ActionType =
|
|
14
|
+
| 'show-info'
|
|
15
|
+
| 'change-settings'
|
|
16
|
+
| 'change-slippage'
|
|
17
|
+
| null;
|
|
18
|
+
|
|
19
|
+
export type AlertInfo = {
|
|
14
20
|
alertType: 'error' | 'warning';
|
|
15
21
|
title: string;
|
|
16
|
-
action:
|
|
22
|
+
action: ActionType;
|
|
23
|
+
actionButtonTitle: string | null;
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
export function makeAlerts(
|
|
@@ -24,7 +31,9 @@ export function makeAlerts(
|
|
|
24
31
|
alertType: 'warning',
|
|
25
32
|
title: '',
|
|
26
33
|
action: null,
|
|
34
|
+
actionButtonTitle: null,
|
|
27
35
|
};
|
|
36
|
+
|
|
28
37
|
if (error) {
|
|
29
38
|
alertInfo.alertType = 'error';
|
|
30
39
|
if (error.type === QuoteErrorType.BRIDGE_LIMIT) {
|
|
@@ -38,7 +47,8 @@ export function makeAlerts(
|
|
|
38
47
|
minRequiredSlippage: error.minRequiredSlippage,
|
|
39
48
|
},
|
|
40
49
|
});
|
|
41
|
-
alertInfo.action = 'change-
|
|
50
|
+
alertInfo.action = 'change-slippage';
|
|
51
|
+
alertInfo.actionButtonTitle = i18n.t('Increase');
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
return alertInfo;
|
|
@@ -75,7 +85,9 @@ export function makeAlerts(
|
|
|
75
85
|
minRequiredSlippage: warning.minRequiredSlippage,
|
|
76
86
|
},
|
|
77
87
|
});
|
|
78
|
-
alertInfo.action = 'change-
|
|
88
|
+
alertInfo.action = 'change-slippage';
|
|
89
|
+
alertInfo.actionButtonTitle = i18n.t('Increase');
|
|
90
|
+
|
|
79
91
|
break;
|
|
80
92
|
}
|
|
81
93
|
case QuoteWarningType.HIGH_SLIPPAGE: {
|
|
@@ -92,3 +104,16 @@ export function makeAlerts(
|
|
|
92
104
|
}
|
|
93
105
|
return null;
|
|
94
106
|
}
|
|
107
|
+
|
|
108
|
+
export function getRequiredSlippage(
|
|
109
|
+
warning: QuoteWarning | null,
|
|
110
|
+
error: BridgeLimitError | InsufficientSlippageError | null
|
|
111
|
+
) {
|
|
112
|
+
if (error?.type === QuoteErrorType.INSUFFICIENT_SLIPPAGE) {
|
|
113
|
+
return Number(error.minRequiredSlippage);
|
|
114
|
+
}
|
|
115
|
+
if (warning?.type === QuoteWarningType.INSUFFICIENT_SLIPPAGE) {
|
|
116
|
+
return Number(warning.minRequiredSlippage);
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { darkTheme, styled } from '@rango-dev/ui';
|
|
1
|
+
import { Button, darkTheme, styled } from '@rango-dev/ui';
|
|
2
2
|
|
|
3
3
|
export const Alerts = styled('div', {
|
|
4
4
|
width: '100%',
|
|
@@ -32,3 +32,12 @@ export const Action = styled('div', {
|
|
|
32
32
|
alignSelf: 'flex-start',
|
|
33
33
|
cursor: 'pointer',
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
export const SwapButton = styled(Button, {
|
|
37
|
+
'& ._text': {
|
|
38
|
+
gap: '$5',
|
|
39
|
+
display: 'flex',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
justifyContent: 'center',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import type { ActionType } from './QuoteWarningsAndErrors.helpers';
|
|
1
2
|
import type { PropTypes } from './QuoteWarningsAndErrors.types';
|
|
2
3
|
|
|
3
4
|
import { i18n } from '@lingui/core';
|
|
4
|
-
import { Alert, Button, InfoIcon } from '@rango-dev/ui';
|
|
5
|
+
import { Alert, Button, Divider, InfoIcon } from '@rango-dev/ui';
|
|
5
6
|
import React from 'react';
|
|
6
7
|
|
|
7
8
|
import { QuoteErrorType, QuoteWarningType } from '../../types';
|
|
8
9
|
import { NoResult } from '../NoResult';
|
|
9
10
|
|
|
10
11
|
import { HighValueLossWarningModal } from './HighValueLossWarningModal';
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
getRequiredSlippage,
|
|
14
|
+
makeAlerts,
|
|
15
|
+
} from './QuoteWarningsAndErrors.helpers';
|
|
12
16
|
import { Action, Alerts } from './QuoteWarningsAndErrors.styles';
|
|
13
17
|
import { SlippageWarningModal } from './SlippageWariningModal';
|
|
14
18
|
import { UnknownPriceWarningModal } from './UnknownPriceWarningModal';
|
|
@@ -20,11 +24,13 @@ export function QuoteWarningsAndErrors(props: PropTypes) {
|
|
|
20
24
|
couldChangeSettings,
|
|
21
25
|
showWarningModal,
|
|
22
26
|
confirmationDisabled,
|
|
27
|
+
skipAlerts,
|
|
23
28
|
refetchQuote,
|
|
24
29
|
onOpenWarningModal,
|
|
25
30
|
onCloseWarningModal,
|
|
26
31
|
onConfirmWarningModal,
|
|
27
32
|
onChangeSettings,
|
|
33
|
+
onChangeSlippage,
|
|
28
34
|
} = props;
|
|
29
35
|
|
|
30
36
|
const warningModalHandlers = {
|
|
@@ -49,14 +55,38 @@ export function QuoteWarningsAndErrors(props: PropTypes) {
|
|
|
49
55
|
alertInfo.action = null;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
const showAlerts = !!alertInfo;
|
|
58
|
+
const showAlerts = !!alertInfo && !skipAlerts;
|
|
59
|
+
|
|
60
|
+
const onclickActionButton = (action: ActionType) => {
|
|
61
|
+
if (action === 'change-slippage') {
|
|
62
|
+
const quoteError =
|
|
63
|
+
error?.type === QuoteErrorType.BRIDGE_LIMIT ||
|
|
64
|
+
error?.type === QuoteErrorType.INSUFFICIENT_SLIPPAGE
|
|
65
|
+
? error
|
|
66
|
+
: null;
|
|
67
|
+
const requestedSlippage = getRequiredSlippage(warning, quoteError);
|
|
68
|
+
onChangeSlippage?.(requestedSlippage);
|
|
69
|
+
} else if (action === 'change-settings') {
|
|
70
|
+
onChangeSettings();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
53
73
|
|
|
54
74
|
return (
|
|
55
75
|
<>
|
|
56
|
-
{showNoResultMessage &&
|
|
76
|
+
{showNoResultMessage && (
|
|
77
|
+
<>
|
|
78
|
+
<Divider size={10} />
|
|
79
|
+
<NoResult
|
|
80
|
+
skipAlerts={skipAlerts}
|
|
81
|
+
error={error}
|
|
82
|
+
fetch={refetchQuote}
|
|
83
|
+
/>
|
|
84
|
+
</>
|
|
85
|
+
)}
|
|
57
86
|
|
|
58
87
|
{showAlerts && (
|
|
59
88
|
<Alerts>
|
|
89
|
+
<Divider size={10} />
|
|
60
90
|
<Alert
|
|
61
91
|
title={alertInfo.title}
|
|
62
92
|
type={alertInfo.alertType}
|
|
@@ -68,14 +98,15 @@ export function QuoteWarningsAndErrors(props: PropTypes) {
|
|
|
68
98
|
</Action>
|
|
69
99
|
),
|
|
70
100
|
})}
|
|
71
|
-
{...(alertInfo.action === 'change-settings'
|
|
101
|
+
{...((alertInfo.action === 'change-settings' ||
|
|
102
|
+
alertInfo.action === 'change-slippage') && {
|
|
72
103
|
action: (
|
|
73
104
|
<Button
|
|
74
105
|
id="widget-quote-warning-error-change-settings-btn"
|
|
75
106
|
size="xxsmall"
|
|
76
107
|
type={alertInfo.alertType}
|
|
77
|
-
onClick={
|
|
78
|
-
{i18n.t('Change')}
|
|
108
|
+
onClick={() => onclickActionButton(alertInfo.action)}>
|
|
109
|
+
{alertInfo.actionButtonTitle || i18n.t('Change')}
|
|
79
110
|
</Button>
|
|
80
111
|
),
|
|
81
112
|
})}
|
|
@@ -6,11 +6,13 @@ export interface PropTypes {
|
|
|
6
6
|
showWarningModal: boolean;
|
|
7
7
|
confirmationDisabled: boolean;
|
|
8
8
|
couldChangeSettings: boolean;
|
|
9
|
+
skipAlerts?: boolean;
|
|
9
10
|
refetchQuote: () => void;
|
|
10
11
|
onOpenWarningModal: () => void;
|
|
11
12
|
onCloseWarningModal: () => void;
|
|
12
13
|
onConfirmWarningModal: () => void;
|
|
13
14
|
onChangeSettings: () => void;
|
|
15
|
+
onChangeSlippage?: (slippage: number | null) => void;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
type ModalPropTypesKeys = keyof Omit<PropTypes, 'extraSpace' | 'loading'>;
|
|
@@ -4,16 +4,17 @@ import type {
|
|
|
4
4
|
} from '../../types';
|
|
5
5
|
|
|
6
6
|
import { i18n } from '@lingui/core';
|
|
7
|
-
import { Button, Divider, MessageBox,
|
|
7
|
+
import { Button, Divider, MessageBox, WarningIcon } from '@rango-dev/ui';
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { useNavigate } from 'react-router-dom';
|
|
10
10
|
|
|
11
11
|
import { navigationRoutes } from '../../constants/navigationRoutes';
|
|
12
|
-
import { useAppStore } from '../../store/AppStore';
|
|
13
12
|
import { QuoteWarningType } from '../../types';
|
|
14
13
|
import { getContainer } from '../../utils/common';
|
|
15
14
|
import { WatermarkedModal } from '../common/WatermarkedModal';
|
|
16
15
|
|
|
16
|
+
import { SwapButton } from './QuoteWarningsAndErrors.styles';
|
|
17
|
+
|
|
17
18
|
type PropsTypes = {
|
|
18
19
|
open: boolean;
|
|
19
20
|
confirmationDisabled: boolean;
|
|
@@ -23,26 +24,13 @@ type PropsTypes = {
|
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
export function SlippageWarningModal(props: PropsTypes) {
|
|
26
|
-
const { customSlippage, slippage } = useAppStore();
|
|
27
27
|
const { open, onClose, onConfirm, warning, confirmationDisabled } = props;
|
|
28
28
|
const navigate = useNavigate();
|
|
29
|
-
const userSlippage = customSlippage ?? slippage;
|
|
30
29
|
|
|
31
30
|
return (
|
|
32
31
|
<WatermarkedModal
|
|
33
32
|
anchor="bottom"
|
|
34
33
|
open={open}
|
|
35
|
-
prefix={
|
|
36
|
-
<Button
|
|
37
|
-
size="small"
|
|
38
|
-
id="widget-slippage-warning-modal-change-settings-btn"
|
|
39
|
-
variant="ghost"
|
|
40
|
-
onClick={() => navigate('../' + navigationRoutes.settings)}>
|
|
41
|
-
<Typography variant="label" size="medium" color="$neutral900">
|
|
42
|
-
{i18n.t('Change settings')}
|
|
43
|
-
</Typography>
|
|
44
|
-
</Button>
|
|
45
|
-
}
|
|
46
34
|
container={getContainer()}
|
|
47
35
|
onClose={onClose}>
|
|
48
36
|
<MessageBox
|
|
@@ -54,10 +42,9 @@ export function SlippageWarningModal(props: PropsTypes) {
|
|
|
54
42
|
}
|
|
55
43
|
description={
|
|
56
44
|
warning.type === QuoteWarningType.HIGH_SLIPPAGE
|
|
57
|
-
? i18n.t(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
})
|
|
45
|
+
? i18n.t(
|
|
46
|
+
'Caution, your slippage is high. Your trade may be front run.'
|
|
47
|
+
)
|
|
61
48
|
: i18n.t({
|
|
62
49
|
id: 'We recommend you to increase slippage to at least {minRequiredSlippage} for this route.',
|
|
63
50
|
values: {
|
|
@@ -67,7 +54,7 @@ export function SlippageWarningModal(props: PropsTypes) {
|
|
|
67
54
|
}>
|
|
68
55
|
<Divider size={18} />
|
|
69
56
|
<Divider size={32} />
|
|
70
|
-
<
|
|
57
|
+
<SwapButton
|
|
71
58
|
id="widget-slippage-warning-modal-confirm-anyway-btn"
|
|
72
59
|
size="large"
|
|
73
60
|
type="primary"
|
|
@@ -75,7 +62,19 @@ export function SlippageWarningModal(props: PropsTypes) {
|
|
|
75
62
|
fullWidth
|
|
76
63
|
disabled={confirmationDisabled}
|
|
77
64
|
onClick={onConfirm}>
|
|
78
|
-
{
|
|
65
|
+
<WarningIcon color="white" size={16} />
|
|
66
|
+
{i18n.t('Swap anyway')}
|
|
67
|
+
</SwapButton>
|
|
68
|
+
<Divider size={10} />
|
|
69
|
+
<Button
|
|
70
|
+
id="widget-slippage-warning-modal-change-slippage-btn"
|
|
71
|
+
size="large"
|
|
72
|
+
type="primary"
|
|
73
|
+
variant="outlined"
|
|
74
|
+
fullWidth
|
|
75
|
+
disabled={confirmationDisabled}
|
|
76
|
+
onClick={() => navigate('../' + navigationRoutes.settings)}>
|
|
77
|
+
{i18n.t('Change Slippage')}
|
|
79
78
|
</Button>
|
|
80
79
|
</MessageBox>
|
|
81
80
|
</WatermarkedModal>
|
|
@@ -32,3 +32,26 @@ export const SlippageChip = styled(Chip, {
|
|
|
32
32
|
width: '61px',
|
|
33
33
|
flexShrink: 0,
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
export const SlippageTextFieldContainer = styled('div', {
|
|
37
|
+
borderWidth: 1,
|
|
38
|
+
borderStyle: 'solid',
|
|
39
|
+
borderRadius: '$xs',
|
|
40
|
+
flex: 1,
|
|
41
|
+
variants: {
|
|
42
|
+
status: {
|
|
43
|
+
safe: {
|
|
44
|
+
borderColor: '$secondary500',
|
|
45
|
+
},
|
|
46
|
+
error: {
|
|
47
|
+
borderColor: '$error500',
|
|
48
|
+
},
|
|
49
|
+
warning: {
|
|
50
|
+
borderColor: '$warning500',
|
|
51
|
+
},
|
|
52
|
+
empty: {
|
|
53
|
+
borderWidth: 0,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
@@ -14,12 +14,14 @@ import { MAX_SLIPPAGE, SLIPPAGES } from '../../constants/swapSettings';
|
|
|
14
14
|
import { useAppStore } from '../../store/AppStore';
|
|
15
15
|
import { getContainer } from '../../utils/common';
|
|
16
16
|
import { getSlippageValidation } from '../../utils/settings';
|
|
17
|
+
import { isValidCurrencyFormat } from '../../utils/validation';
|
|
17
18
|
|
|
18
19
|
import {
|
|
19
20
|
BaseContainer,
|
|
20
21
|
Head,
|
|
21
22
|
SlippageChip,
|
|
22
23
|
SlippageChipsContainer,
|
|
24
|
+
SlippageTextFieldContainer,
|
|
23
25
|
} from './Slippage.styles';
|
|
24
26
|
import { SlippageTooltipContent } from './SlippageTooltipContent';
|
|
25
27
|
|
|
@@ -54,9 +56,8 @@ export function Slippage() {
|
|
|
54
56
|
|
|
55
57
|
const onInput = (event: React.FormEvent<HTMLInputElement>) => {
|
|
56
58
|
const input = event.target as HTMLInputElement;
|
|
57
|
-
const regex = /^(0|[1-9]\d*)(\.\d{1,2})?$/;
|
|
58
59
|
const value = input.value;
|
|
59
|
-
if (!
|
|
60
|
+
if (!isValidCurrencyFormat(value)) {
|
|
60
61
|
input.value = value.slice(0, -1);
|
|
61
62
|
}
|
|
62
63
|
};
|
|
@@ -90,26 +91,31 @@ export function Slippage() {
|
|
|
90
91
|
/>
|
|
91
92
|
);
|
|
92
93
|
})}
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
customSlippage
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
94
|
+
<SlippageTextFieldContainer
|
|
95
|
+
status={
|
|
96
|
+
slippageValidation?.type || (customSlippage ? 'safe' : 'empty')
|
|
97
|
+
}>
|
|
98
|
+
<TextField
|
|
99
|
+
type="number"
|
|
100
|
+
min="0.01"
|
|
101
|
+
max="30"
|
|
102
|
+
step="0.01"
|
|
103
|
+
onInput={onInput}
|
|
104
|
+
fullWidth
|
|
105
|
+
variant="contained"
|
|
106
|
+
value={customSlippage === null ? '' : customSlippage}
|
|
107
|
+
color="dark"
|
|
108
|
+
onChange={onSlippageValueChange}
|
|
109
|
+
suffix={
|
|
110
|
+
customSlippage && (
|
|
111
|
+
<Typography variant="body" size="small">
|
|
112
|
+
%
|
|
113
|
+
</Typography>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
placeholder={i18n.t('Custom')}
|
|
117
|
+
/>
|
|
118
|
+
</SlippageTextFieldContainer>
|
|
113
119
|
</SlippageChipsContainer>
|
|
114
120
|
|
|
115
121
|
{slippageValidation && (
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AlertInfo } from '../QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers';
|
|
2
|
+
|
|
3
|
+
import { i18n } from '@lingui/core';
|
|
4
|
+
|
|
5
|
+
import { HIGH_SLIPPAGE, MIN_SLIPPAGE } from '../../constants/swapSettings';
|
|
6
|
+
|
|
7
|
+
export type ActionType = AlertInfo['action'] | 'reset-slippage';
|
|
8
|
+
|
|
9
|
+
type Alert = Omit<AlertInfo, 'action'> & {
|
|
10
|
+
action: ActionType;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function makeAlerts(slippage: number): Alert | null {
|
|
14
|
+
let alertInfo: Alert | null = null;
|
|
15
|
+
if (slippage === MIN_SLIPPAGE) {
|
|
16
|
+
alertInfo = {
|
|
17
|
+
alertType: 'error',
|
|
18
|
+
action: 'reset-slippage',
|
|
19
|
+
actionButtonTitle: i18n.t('Reset'),
|
|
20
|
+
title: i18n.t('Slippage cannot be set lower than 0.01%.'),
|
|
21
|
+
};
|
|
22
|
+
return alertInfo;
|
|
23
|
+
} else if (slippage > HIGH_SLIPPAGE) {
|
|
24
|
+
alertInfo = {
|
|
25
|
+
alertType: 'warning',
|
|
26
|
+
action: 'change-settings',
|
|
27
|
+
actionButtonTitle: i18n.t('Change'),
|
|
28
|
+
title: i18n.t('Caution, your slippage is high!'),
|
|
29
|
+
};
|
|
30
|
+
return alertInfo;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ActionType } from './SlippageWarningsAndErrors.helpers';
|
|
2
|
+
import type { PropTypes } from './SlippageWarningsAndErrors.types';
|
|
3
|
+
|
|
4
|
+
import { Alert, Button } from '@rango-dev/ui';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { DEFAULT_SLIPPAGE } from '../../constants/swapSettings';
|
|
8
|
+
import { useAppStore } from '../../store/AppStore';
|
|
9
|
+
|
|
10
|
+
import { makeAlerts } from './SlippageWarningsAndErrors.helpers';
|
|
11
|
+
|
|
12
|
+
export function SlippageWarningsAndErrors(props: PropTypes) {
|
|
13
|
+
const { slippage, customSlippage, setSlippage, setCustomSlippage } =
|
|
14
|
+
useAppStore();
|
|
15
|
+
const { onChangeSettings } = props;
|
|
16
|
+
const currentSlippage = customSlippage !== null ? customSlippage : slippage;
|
|
17
|
+
|
|
18
|
+
const alertInfo = makeAlerts(currentSlippage);
|
|
19
|
+
|
|
20
|
+
const onClickActionButton = (action: ActionType) => {
|
|
21
|
+
if (action === 'reset-slippage') {
|
|
22
|
+
setSlippage(DEFAULT_SLIPPAGE);
|
|
23
|
+
setCustomSlippage(null);
|
|
24
|
+
} else if (action === 'change-settings') {
|
|
25
|
+
onChangeSettings();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (!alertInfo) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return (
|
|
33
|
+
<Alert
|
|
34
|
+
title={alertInfo.title}
|
|
35
|
+
type={alertInfo.alertType}
|
|
36
|
+
variant="alarm"
|
|
37
|
+
action={
|
|
38
|
+
<Button
|
|
39
|
+
id="widget-slippage-warning-error-change-settings-or-reset-slippage-btn"
|
|
40
|
+
size="xxsmall"
|
|
41
|
+
type={alertInfo.alertType}
|
|
42
|
+
onClick={() => onClickActionButton(alertInfo.action)}>
|
|
43
|
+
{alertInfo.actionButtonTitle}
|
|
44
|
+
</Button>
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { SlippageColorParams } from './SwapMetrics.types';
|
|
2
|
+
|
|
3
|
+
import BigNumber from 'bignumber.js';
|
|
4
|
+
|
|
5
|
+
import { QuoteErrorType, QuoteWarningType } from '../../types';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
LARGE_VALUE_MAX_DIGITS,
|
|
9
|
+
SMALL_VALUE_DECIMALS,
|
|
10
|
+
USD_EXCHANGE_MINIMUM,
|
|
11
|
+
USD_FORMAT_DECIMALS,
|
|
12
|
+
} from './SwapMetrics.constants';
|
|
13
|
+
|
|
14
|
+
export function getSlippageColor(params: SlippageColorParams) {
|
|
15
|
+
const { error, isDarkTheme, warning } = params;
|
|
16
|
+
const { quoteError, slippageError } = error;
|
|
17
|
+
const { quoteWarning, slippageWarning } = warning;
|
|
18
|
+
const hasSlippageError =
|
|
19
|
+
!!slippageError ||
|
|
20
|
+
quoteError?.type === QuoteErrorType.INSUFFICIENT_SLIPPAGE;
|
|
21
|
+
const hasSlippageWarning =
|
|
22
|
+
!!slippageWarning ||
|
|
23
|
+
quoteWarning?.type === QuoteWarningType.INSUFFICIENT_SLIPPAGE;
|
|
24
|
+
|
|
25
|
+
if (hasSlippageError) {
|
|
26
|
+
return '$error500';
|
|
27
|
+
} else if (hasSlippageWarning) {
|
|
28
|
+
return '$warning500';
|
|
29
|
+
}
|
|
30
|
+
if (isDarkTheme) {
|
|
31
|
+
return '$neutral600';
|
|
32
|
+
}
|
|
33
|
+
return '$neutral700';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getUsdExchangeRate(params: {
|
|
37
|
+
toTokenUsdPrice: number | null;
|
|
38
|
+
fromTokenUsdPrice: number | null;
|
|
39
|
+
}) {
|
|
40
|
+
const { toTokenUsdPrice, fromTokenUsdPrice } = params;
|
|
41
|
+
if (!toTokenUsdPrice || !fromTokenUsdPrice) {
|
|
42
|
+
return { rawValue: '0', displayValue: '0' };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const toPrice = new BigNumber(toTokenUsdPrice);
|
|
46
|
+
const fromPrice = new BigNumber(fromTokenUsdPrice);
|
|
47
|
+
const rawValue = toPrice.dividedBy(fromPrice);
|
|
48
|
+
let displayValue: string;
|
|
49
|
+
|
|
50
|
+
if (rawValue.isLessThan(1)) {
|
|
51
|
+
displayValue = rawValue.toFixed(SMALL_VALUE_DECIMALS);
|
|
52
|
+
} else if (rawValue.toFixed(0).length > LARGE_VALUE_MAX_DIGITS) {
|
|
53
|
+
displayValue = rawValue.toFixed(0).slice(0, LARGE_VALUE_MAX_DIGITS);
|
|
54
|
+
} else {
|
|
55
|
+
displayValue = rawValue.toFixed(USD_FORMAT_DECIMALS);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
displayValue,
|
|
59
|
+
rawValue: rawValue.toFixed(),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function formatTokenValueInUsd(
|
|
64
|
+
usdExchangeRate: number,
|
|
65
|
+
tokenUsdPrice: number
|
|
66
|
+
): string {
|
|
67
|
+
const value = new BigNumber(usdExchangeRate).multipliedBy(tokenUsdPrice);
|
|
68
|
+
if (value.isLessThan(USD_EXCHANGE_MINIMUM)) {
|
|
69
|
+
return '$0';
|
|
70
|
+
}
|
|
71
|
+
const result = value
|
|
72
|
+
.decimalPlaces(USD_FORMAT_DECIMALS, BigNumber.ROUND_DOWN)
|
|
73
|
+
.toFormat(USD_FORMAT_DECIMALS);
|
|
74
|
+
|
|
75
|
+
return `$${result}`;
|
|
76
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { darkTheme, styled, Typography } from '@rango-dev/ui';
|
|
2
|
+
|
|
3
|
+
export const Container = styled('div', {
|
|
4
|
+
display: 'flex',
|
|
5
|
+
padding: '$4',
|
|
6
|
+
justifyContent: 'space-between',
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const Rate = styled('div', {
|
|
11
|
+
display: 'flex',
|
|
12
|
+
alignItems: 'center',
|
|
13
|
+
gap: '$2',
|
|
14
|
+
'& .rate-text': {
|
|
15
|
+
color: '$neutral700',
|
|
16
|
+
[`.${darkTheme} &`]: {
|
|
17
|
+
color: '$neutral700',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
'& ._icon-button': {
|
|
21
|
+
transform: 'rotate(90deg)',
|
|
22
|
+
width: '$16',
|
|
23
|
+
height: '$16',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const TokenName = styled(Typography, {
|
|
28
|
+
maxWidth: '$32',
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
textOverflow: 'ellipsis',
|
|
31
|
+
whiteSpace: 'nowrap',
|
|
32
|
+
});
|