@rango-dev/widget-embedded 0.42.3-next.2 → 0.42.3-next.3
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/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/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/slices/settings.d.ts +3 -0
- package/dist/store/slices/settings.d.ts.map +1 -1
- package/dist/utils/settings.d.ts +2 -1
- package/dist/utils/settings.d.ts.map +1 -1
- package/dist/widget-embedded.build.json +1 -1
- package/package.json +1 -1
- 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 +26 -20
- 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/hooks/useSwapInput.ts +1 -1
- package/src/pages/ConfirmSwapPage.tsx +6 -1
- package/src/pages/Home.tsx +61 -12
- package/src/store/app.ts +1 -0
- package/src/store/slices/settings.ts +11 -0
- package/src/utils/settings.ts +11 -4
package/package.json
CHANGED
|
@@ -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
|
+
});
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
Head,
|
|
21
21
|
SlippageChip,
|
|
22
22
|
SlippageChipsContainer,
|
|
23
|
+
SlippageTextFieldContainer,
|
|
23
24
|
} from './Slippage.styles';
|
|
24
25
|
import { SlippageTooltipContent } from './SlippageTooltipContent';
|
|
25
26
|
|
|
@@ -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
|
+
});
|