@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
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { PropTypes } from './SwapMetrics.types';
|
|
2
|
+
|
|
3
|
+
import { i18n } from '@lingui/core';
|
|
4
|
+
import {
|
|
5
|
+
IconButton,
|
|
6
|
+
ReverseIcon,
|
|
7
|
+
Skeleton,
|
|
8
|
+
Tooltip,
|
|
9
|
+
Typography,
|
|
10
|
+
} from '@rango-dev/ui';
|
|
11
|
+
import React from 'react';
|
|
12
|
+
|
|
13
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
14
|
+
import { useAppStore } from '../../store/AppStore';
|
|
15
|
+
import { getContainer } from '../../utils/common';
|
|
16
|
+
import { getSlippageValidation } from '../../utils/settings';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
formatTokenValueInUsd,
|
|
20
|
+
getSlippageColor,
|
|
21
|
+
getUsdExchangeRate,
|
|
22
|
+
} from './SwapMetrics.helpers';
|
|
23
|
+
import { Container, Rate, TokenName } from './SwapMetrics.styles';
|
|
24
|
+
|
|
25
|
+
export function SwapMetrics(props: PropTypes) {
|
|
26
|
+
const { slippage, customSlippage, quoteTokensRate, changeQuoteTokensRate } =
|
|
27
|
+
useAppStore();
|
|
28
|
+
const {
|
|
29
|
+
quoteError,
|
|
30
|
+
quoteWarning,
|
|
31
|
+
fromToken: initialFromToken,
|
|
32
|
+
toToken: initialToToken,
|
|
33
|
+
quote,
|
|
34
|
+
loading,
|
|
35
|
+
} = props;
|
|
36
|
+
const currentSlippage = customSlippage !== null ? customSlippage : slippage;
|
|
37
|
+
const { mode } = useTheme({});
|
|
38
|
+
const slippageValidation = getSlippageValidation(currentSlippage);
|
|
39
|
+
const isDarkTheme = mode === 'dark';
|
|
40
|
+
const isDefaultRate = quoteTokensRate === 'default';
|
|
41
|
+
|
|
42
|
+
const error = {
|
|
43
|
+
quoteError,
|
|
44
|
+
slippageError:
|
|
45
|
+
slippageValidation?.type === 'error' ? slippageValidation.message : null,
|
|
46
|
+
};
|
|
47
|
+
const warning = {
|
|
48
|
+
quoteWarning,
|
|
49
|
+
slippageWarning:
|
|
50
|
+
slippageValidation?.type === 'warning'
|
|
51
|
+
? slippageValidation.message
|
|
52
|
+
: null,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const sourceToken = quote?.swaps[0].from || initialFromToken;
|
|
56
|
+
const destinationToken =
|
|
57
|
+
quote?.swaps[quote?.swaps.length - 1].to || initialToToken;
|
|
58
|
+
|
|
59
|
+
const fromToken = isDefaultRate ? sourceToken : destinationToken;
|
|
60
|
+
const toToken = isDefaultRate ? destinationToken : sourceToken;
|
|
61
|
+
|
|
62
|
+
const fromAmount = Number(
|
|
63
|
+
isDefaultRate ? quote?.outputAmount : quote?.requestAmount
|
|
64
|
+
);
|
|
65
|
+
const toAmount = Number(
|
|
66
|
+
isDefaultRate ? quote?.requestAmount : quote?.outputAmount
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const fromTokenUsdPrice = fromAmount || fromToken.usdPrice;
|
|
70
|
+
const toTokenUsdPrice = toAmount || toToken.usdPrice;
|
|
71
|
+
|
|
72
|
+
const { rawValue: rawExchangeRate, displayValue: displayExchangeRate } =
|
|
73
|
+
getUsdExchangeRate({
|
|
74
|
+
toTokenUsdPrice,
|
|
75
|
+
fromTokenUsdPrice,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Container>
|
|
80
|
+
<Typography
|
|
81
|
+
variant={!!error || !!warning ? 'label' : 'body'}
|
|
82
|
+
size={!!error || !!warning ? 'medium' : 'small'}
|
|
83
|
+
color={getSlippageColor({ error, warning, isDarkTheme })}>
|
|
84
|
+
{i18n.t('Slippage:')} {currentSlippage}%
|
|
85
|
+
</Typography>
|
|
86
|
+
{loading ? (
|
|
87
|
+
<Skeleton height={16} width={104} variant="rounded" />
|
|
88
|
+
) : (
|
|
89
|
+
fromTokenUsdPrice &&
|
|
90
|
+
toTokenUsdPrice && (
|
|
91
|
+
<Rate>
|
|
92
|
+
<Typography className="rate-text" variant="body" size="small">
|
|
93
|
+
1
|
|
94
|
+
</Typography>
|
|
95
|
+
<TokenName className="rate-text" variant="body" size="small">
|
|
96
|
+
{toToken.symbol}
|
|
97
|
+
</TokenName>
|
|
98
|
+
<IconButton
|
|
99
|
+
id="widget-home-page-change-rate-button"
|
|
100
|
+
onClick={changeQuoteTokensRate}>
|
|
101
|
+
<ReverseIcon size={14} color="secondary" />
|
|
102
|
+
</IconButton>
|
|
103
|
+
<Tooltip
|
|
104
|
+
container={getContainer()}
|
|
105
|
+
side="top"
|
|
106
|
+
sideOffset={4}
|
|
107
|
+
content={
|
|
108
|
+
<Typography className="rate-text" variant="body" size="small">
|
|
109
|
+
{rawExchangeRate}
|
|
110
|
+
</Typography>
|
|
111
|
+
}>
|
|
112
|
+
<Typography className="rate-text" variant="body" size="small">
|
|
113
|
+
{displayExchangeRate}
|
|
114
|
+
</Typography>
|
|
115
|
+
</Tooltip>
|
|
116
|
+
|
|
117
|
+
<TokenName className="rate-text" variant="body" size="small">
|
|
118
|
+
{fromToken.symbol}
|
|
119
|
+
</TokenName>
|
|
120
|
+
{fromToken.usdPrice && (
|
|
121
|
+
<Typography color="neutral600" variant="body" size="small">
|
|
122
|
+
~
|
|
123
|
+
{formatTokenValueInUsd(
|
|
124
|
+
Number(rawExchangeRate),
|
|
125
|
+
fromToken.usdPrice
|
|
126
|
+
)}
|
|
127
|
+
</Typography>
|
|
128
|
+
)}
|
|
129
|
+
</Rate>
|
|
130
|
+
)
|
|
131
|
+
)}
|
|
132
|
+
</Container>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { QuoteError, QuoteWarning, SelectedQuote } from '../../types';
|
|
2
|
+
import type { TokenData } from '../TokenList/TokenList.types';
|
|
3
|
+
import type { SwapResultAsset } from 'rango-sdk';
|
|
4
|
+
|
|
5
|
+
export interface PropTypes {
|
|
6
|
+
quoteError: QuoteError | null;
|
|
7
|
+
quoteWarning: QuoteWarning | null;
|
|
8
|
+
fromToken: TokenData;
|
|
9
|
+
toToken: TokenData;
|
|
10
|
+
quote: SelectedQuote | null;
|
|
11
|
+
loading: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Tokens = {
|
|
15
|
+
to: TokenData | SwapResultAsset;
|
|
16
|
+
from: TokenData | SwapResultAsset;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type SlippageColorParams = {
|
|
20
|
+
error: { quoteError: QuoteError | null; slippageError: string | null };
|
|
21
|
+
warning: {
|
|
22
|
+
quoteWarning: QuoteWarning | null;
|
|
23
|
+
slippageWarning: string | null;
|
|
24
|
+
};
|
|
25
|
+
isDarkTheme: boolean;
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SwapMetrics } from './SwapMetrics';
|
|
@@ -34,6 +34,7 @@ export function Inputs(props: PropTypes) {
|
|
|
34
34
|
toToken,
|
|
35
35
|
toBlockchain,
|
|
36
36
|
setInputAmount,
|
|
37
|
+
sanitizeInputAmount,
|
|
37
38
|
inputAmount,
|
|
38
39
|
inputUsdValue,
|
|
39
40
|
outputAmount,
|
|
@@ -79,6 +80,7 @@ export function Inputs(props: PropTypes) {
|
|
|
79
80
|
label={i18n.t('From')}
|
|
80
81
|
mode="From"
|
|
81
82
|
onInputChange={setInputAmount}
|
|
83
|
+
onInputBlur={sanitizeInputAmount}
|
|
82
84
|
balance={fromTokenFormattedBalance}
|
|
83
85
|
chain={{
|
|
84
86
|
displayName: fromBlockchain?.displayName || '',
|
|
@@ -83,6 +83,7 @@ export function useSyncUrlAndStore() {
|
|
|
83
83
|
useEffect(() => {
|
|
84
84
|
const { autoConnect, clientUrl, utmQueryParams, blockchain } =
|
|
85
85
|
getUrlSearchParams();
|
|
86
|
+
|
|
86
87
|
if (isInRouterContext && fetchMetaStatus === 'success') {
|
|
87
88
|
updateUrlSearchParams({
|
|
88
89
|
[SearchParams.FROM_BLOCKCHAIN]: fromBlockchain?.name,
|
|
@@ -107,6 +108,7 @@ export function useSyncUrlAndStore() {
|
|
|
107
108
|
toBlockchain,
|
|
108
109
|
toToken,
|
|
109
110
|
campaignMode,
|
|
111
|
+
fetchMetaStatus,
|
|
110
112
|
]);
|
|
111
113
|
|
|
112
114
|
useEffect(() => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-magic-numbers */
|
|
2
1
|
import type {
|
|
3
2
|
ConfirmSwap,
|
|
4
3
|
ConfirmSwapFetchResult,
|
|
@@ -29,6 +28,7 @@ import { useConfirmSwap } from '../hooks/useConfirmSwap';
|
|
|
29
28
|
import { useAppStore } from '../store/AppStore';
|
|
30
29
|
import { useQuoteStore } from '../store/quote';
|
|
31
30
|
import { useUiStore } from '../store/ui';
|
|
31
|
+
import { QuoteErrorType, QuoteWarningType } from '../types';
|
|
32
32
|
import { isQuoteWarningConfirmationRequired } from '../utils/quote';
|
|
33
33
|
import { joinList } from '../utils/ui';
|
|
34
34
|
|
|
@@ -121,6 +121,7 @@ export function ConfirmSwapPage() {
|
|
|
121
121
|
setInputAmount('');
|
|
122
122
|
}, 0);
|
|
123
123
|
} catch (e) {
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
124
125
|
setDbErrorMessage('Error: ' + (e as any)?.message);
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -209,6 +210,10 @@ export function ConfirmSwapPage() {
|
|
|
209
210
|
error={quoteError}
|
|
210
211
|
couldChangeSettings={false}
|
|
211
212
|
refetchQuote={onRefresh}
|
|
213
|
+
skipAlerts={
|
|
214
|
+
quoteError?.type === QuoteErrorType.INSUFFICIENT_SLIPPAGE ||
|
|
215
|
+
quoteWarning?.type === QuoteWarningType.INSUFFICIENT_SLIPPAGE
|
|
216
|
+
}
|
|
212
217
|
showWarningModal={showQuoteWarningModal}
|
|
213
218
|
confirmationDisabled={!isActiveTab}
|
|
214
219
|
onOpenWarningModal={() => setShowQuoteWarningModal(true)}
|
package/src/pages/Home.tsx
CHANGED
|
@@ -10,6 +10,8 @@ import { HeaderButtons } from '../components/HeaderButtons';
|
|
|
10
10
|
import { Layout, PageContainer } from '../components/Layout';
|
|
11
11
|
import { QuoteWarningsAndErrors } from '../components/QuoteWarningsAndErrors';
|
|
12
12
|
import { SameTokensWarning } from '../components/SameTokensWarning';
|
|
13
|
+
import { SlippageWarningsAndErrors } from '../components/SlippageWarningsAndErrors/SlippageWarningsAndErrors';
|
|
14
|
+
import { SwapMetrics } from '../components/SwapMetrics';
|
|
13
15
|
import { navigationRoutes } from '../constants/navigationRoutes';
|
|
14
16
|
import { ExpandedQuotes } from '../containers/ExpandedQuotes';
|
|
15
17
|
import { Inputs } from '../containers/Inputs';
|
|
@@ -22,6 +24,7 @@ import { useUiStore } from '../store/ui';
|
|
|
22
24
|
import { UiEventTypes } from '../types';
|
|
23
25
|
import { isVariantExpandable } from '../utils/configs';
|
|
24
26
|
import { emitPreventableEvent } from '../utils/events';
|
|
27
|
+
import { getSlippageValidation } from '../utils/settings';
|
|
25
28
|
import { getSwapButtonState, isTokensIdentical } from '../utils/swap';
|
|
26
29
|
|
|
27
30
|
const MainContainer = styled('div', {
|
|
@@ -50,6 +53,7 @@ export function Home() {
|
|
|
50
53
|
setQuoteWarningsConfirmed,
|
|
51
54
|
updateQuotePartialState,
|
|
52
55
|
} = useQuoteStore();
|
|
56
|
+
|
|
53
57
|
const [isVisibleExpanded, setIsVisibleExpanded] = useState<boolean>(false);
|
|
54
58
|
const { isLargeScreen, isExtraLargeScreen } = useScreenDetect();
|
|
55
59
|
|
|
@@ -58,10 +62,17 @@ export function Home() {
|
|
|
58
62
|
config,
|
|
59
63
|
fetchStatus: fetchMetaStatus,
|
|
60
64
|
connectedWallets,
|
|
65
|
+
customSlippage,
|
|
66
|
+
slippage,
|
|
67
|
+
setSlippage,
|
|
68
|
+
setCustomSlippage,
|
|
61
69
|
} = useAppStore();
|
|
62
70
|
|
|
63
71
|
const { isActiveTab } = useUiStore();
|
|
64
72
|
const [showQuoteWarningModal, setShowQuoteWarningModal] = useState(false);
|
|
73
|
+
const currentSlippage = customSlippage !== null ? customSlippage : slippage;
|
|
74
|
+
|
|
75
|
+
const slippageValidation = getSlippageValidation(currentSlippage);
|
|
65
76
|
|
|
66
77
|
const needsToWarnEthOnPath = false;
|
|
67
78
|
|
|
@@ -91,19 +102,16 @@ export function Home() {
|
|
|
91
102
|
|
|
92
103
|
const fetchingQuote = hasInputs && fetchMetaStatus === 'success' && loading;
|
|
93
104
|
|
|
105
|
+
const currentQuoteWarning =
|
|
106
|
+
slippageValidation?.quoteValidation || quoteWarning;
|
|
107
|
+
|
|
94
108
|
const hasValidQuotes =
|
|
95
109
|
!isExpandable || (isExpandable && quotes?.results.length);
|
|
96
|
-
const hasWarningOrError =
|
|
110
|
+
const hasWarningOrError = currentQuoteWarning || quoteError;
|
|
97
111
|
const showMessages = hasValidQuotes && hasWarningOrError;
|
|
98
112
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
updateQuotePartialState('refetchQuote', true);
|
|
102
|
-
}, []);
|
|
103
|
-
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
setIsVisibleExpanded(hasInputs);
|
|
106
|
-
}, [hasInputs]);
|
|
113
|
+
const showSwapMetrics = !!fromToken && !!toToken;
|
|
114
|
+
const showSlippageAlerts = showSwapMetrics && !!slippageValidation;
|
|
107
115
|
|
|
108
116
|
const onClickRefresh =
|
|
109
117
|
(!!selectedQuote || quoteError) && !showQuoteWarningModal
|
|
@@ -127,6 +135,22 @@ export function Home() {
|
|
|
127
135
|
}
|
|
128
136
|
};
|
|
129
137
|
|
|
138
|
+
const onChangeSlippage = (slippage: number | null) => {
|
|
139
|
+
if (slippage) {
|
|
140
|
+
setSlippage(slippage);
|
|
141
|
+
setCustomSlippage(null);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
resetQuoteWallets();
|
|
147
|
+
updateQuotePartialState('refetchQuote', true);
|
|
148
|
+
}, []);
|
|
149
|
+
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
setIsVisibleExpanded(hasInputs);
|
|
152
|
+
}, [hasInputs]);
|
|
153
|
+
|
|
130
154
|
return (
|
|
131
155
|
<MainContainer>
|
|
132
156
|
<Layout
|
|
@@ -194,7 +218,7 @@ export function Home() {
|
|
|
194
218
|
loading={fetchingQuote}
|
|
195
219
|
error={quoteError}
|
|
196
220
|
tagHidden={false}
|
|
197
|
-
warning={
|
|
221
|
+
warning={currentQuoteWarning}
|
|
198
222
|
type="basic"
|
|
199
223
|
onClickAllRoutes={
|
|
200
224
|
!!quotes && quotes.results.length > 1
|
|
@@ -206,19 +230,33 @@ export function Home() {
|
|
|
206
230
|
}
|
|
207
231
|
/>
|
|
208
232
|
) : null}
|
|
233
|
+
{showSwapMetrics && (
|
|
234
|
+
<>
|
|
235
|
+
<Divider size={8} />
|
|
236
|
+
<SwapMetrics
|
|
237
|
+
quoteError={quoteError}
|
|
238
|
+
quoteWarning={currentQuoteWarning}
|
|
239
|
+
fromToken={fromToken}
|
|
240
|
+
toToken={toToken}
|
|
241
|
+
quote={selectedQuote}
|
|
242
|
+
loading={fetchingQuote}
|
|
243
|
+
/>
|
|
244
|
+
</>
|
|
245
|
+
)}
|
|
209
246
|
|
|
210
247
|
{showMessages ? (
|
|
211
248
|
<>
|
|
212
|
-
<Divider size="10" />
|
|
213
249
|
<QuoteWarningsAndErrors
|
|
214
|
-
warning={
|
|
250
|
+
warning={currentQuoteWarning}
|
|
215
251
|
error={quoteError}
|
|
252
|
+
skipAlerts={!!slippageValidation}
|
|
216
253
|
couldChangeSettings={true}
|
|
217
254
|
refetchQuote={fetchQuote}
|
|
218
255
|
showWarningModal={showQuoteWarningModal}
|
|
219
256
|
confirmationDisabled={!isActiveTab}
|
|
220
257
|
onOpenWarningModal={() => setShowQuoteWarningModal(true)}
|
|
221
258
|
onCloseWarningModal={() => setShowQuoteWarningModal(false)}
|
|
259
|
+
onChangeSlippage={onChangeSlippage}
|
|
222
260
|
onConfirmWarningModal={() => {
|
|
223
261
|
setShowQuoteWarningModal(false);
|
|
224
262
|
setQuoteWarningsConfirmed(true);
|
|
@@ -230,6 +268,17 @@ export function Home() {
|
|
|
230
268
|
/>
|
|
231
269
|
</>
|
|
232
270
|
) : null}
|
|
271
|
+
|
|
272
|
+
{showSlippageAlerts && (
|
|
273
|
+
<>
|
|
274
|
+
<Divider size="10" />
|
|
275
|
+
<SlippageWarningsAndErrors
|
|
276
|
+
onChangeSettings={() =>
|
|
277
|
+
onHandleNavigation(navigationRoutes.settings)
|
|
278
|
+
}
|
|
279
|
+
/>
|
|
280
|
+
</>
|
|
281
|
+
)}
|
|
233
282
|
<SameTokensWarning />
|
|
234
283
|
</PageContainer>
|
|
235
284
|
</Layout>
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from '../components/SettingsContainer';
|
|
23
23
|
import { useAppStore } from '../store/AppStore';
|
|
24
24
|
import { containsText } from '../utils/numbers';
|
|
25
|
+
import { replaceSpacesWithDash } from '../utils/sanitizers';
|
|
25
26
|
import { getUniqueSwappersGroups } from '../utils/settings';
|
|
26
27
|
|
|
27
28
|
interface PropTypes {
|
|
@@ -70,9 +71,10 @@ export function LiquiditySourcePage({ sourceType }: PropTypes) {
|
|
|
70
71
|
const list = liquiditySources.map((sourceItem) => {
|
|
71
72
|
const { selected, groupTitle, logo, id, ...restSourceItem } = sourceItem;
|
|
72
73
|
return {
|
|
73
|
-
id: `widget-setting-liquidity-source-${
|
|
74
|
-
.toLowerCase()
|
|
75
|
-
|
|
74
|
+
id: `widget-setting-liquidity-source-${replaceSpacesWithDash(
|
|
75
|
+
id.toLowerCase()
|
|
76
|
+
)}-item-btn`,
|
|
77
|
+
|
|
76
78
|
start: <Image src={logo} size={22} type="circular" />,
|
|
77
79
|
onClick: () => {
|
|
78
80
|
if (!campaignMode) {
|
package/src/store/app.ts
CHANGED
|
@@ -46,6 +46,7 @@ export function createAppStore(initialData?: WidgetConfig) {
|
|
|
46
46
|
infiniteApprove: state.infiniteApprove,
|
|
47
47
|
preferredBlockchains: state.preferredBlockchains,
|
|
48
48
|
disabledLiquiditySources: state.disabledLiquiditySources,
|
|
49
|
+
quoteTokensRate: state.quoteTokensRate,
|
|
49
50
|
};
|
|
50
51
|
},
|
|
51
52
|
version: 1,
|
package/src/store/quote.ts
CHANGED
|
@@ -21,8 +21,13 @@ import {
|
|
|
21
21
|
type Wallet,
|
|
22
22
|
WidgetEvents,
|
|
23
23
|
} from '../types';
|
|
24
|
-
import { isPositiveNumber } from '../utils/numbers';
|
|
24
|
+
import { isPositiveNumber, sanitizeInputAmount } from '../utils/numbers';
|
|
25
|
+
import {
|
|
26
|
+
ensureLeadingZeroForDecimal,
|
|
27
|
+
removeLeadingZeros,
|
|
28
|
+
} from '../utils/sanitizers';
|
|
25
29
|
import { getUsdInputFrom, getUsdOutputFrom } from '../utils/swap';
|
|
30
|
+
import { isZeroValue } from '../utils/validation';
|
|
26
31
|
|
|
27
32
|
import createSelectors from './selectors';
|
|
28
33
|
|
|
@@ -87,6 +92,7 @@ export interface QuoteState {
|
|
|
87
92
|
value: SomeQuoteState[K]
|
|
88
93
|
) => void;
|
|
89
94
|
setInputAmount: (amount: string) => void;
|
|
95
|
+
sanitizeInputAmount: (amount: string) => void;
|
|
90
96
|
setSelectedQuote: (quote: SelectedQuote | null) => void;
|
|
91
97
|
retry: (retryQuote: RetryQuote) => void;
|
|
92
98
|
switchFromAndTo: () => void;
|
|
@@ -223,16 +229,29 @@ export const useQuoteStore = createSelectors(
|
|
|
223
229
|
}),
|
|
224
230
|
}));
|
|
225
231
|
},
|
|
232
|
+
sanitizeInputAmount: (amount) => {
|
|
233
|
+
const sanitized = sanitizeInputAmount(amount);
|
|
234
|
+
|
|
235
|
+
set(() => ({
|
|
236
|
+
inputAmount: sanitized,
|
|
237
|
+
}));
|
|
238
|
+
},
|
|
226
239
|
setInputAmount: (amount) => {
|
|
240
|
+
let sanitized = amount;
|
|
241
|
+
if (!isZeroValue(amount)) {
|
|
242
|
+
// sanitize once a meaningful digit is entered (e.g. "00001" → "1")
|
|
243
|
+
sanitized = removeLeadingZeros(sanitized);
|
|
244
|
+
sanitized = ensureLeadingZeroForDecimal(sanitized);
|
|
245
|
+
}
|
|
227
246
|
set((state) => ({
|
|
228
|
-
inputAmount:
|
|
229
|
-
...(!
|
|
247
|
+
inputAmount: sanitized,
|
|
248
|
+
...(!sanitized && {
|
|
230
249
|
outputAmount: null,
|
|
231
250
|
outputUsdValue: new BigNumber(0),
|
|
232
251
|
selectedQuote: null,
|
|
233
252
|
}),
|
|
234
253
|
...(!!state.fromToken && {
|
|
235
|
-
inputUsdValue: getUsdValue(state.fromToken,
|
|
254
|
+
inputUsdValue: getUsdValue(state.fromToken, sanitized),
|
|
236
255
|
}),
|
|
237
256
|
}));
|
|
238
257
|
},
|
|
@@ -16,6 +16,7 @@ import { isFeatureHidden } from '../../utils/settings';
|
|
|
16
16
|
import { getSupportedBlockchainsFromConfig } from '../utils';
|
|
17
17
|
|
|
18
18
|
export type ThemeMode = 'auto' | 'dark' | 'light';
|
|
19
|
+
export type QuoteTokensRate = 'default' | 'reversed';
|
|
19
20
|
|
|
20
21
|
export interface SettingsSlice {
|
|
21
22
|
theme: ThemeMode;
|
|
@@ -30,6 +31,8 @@ export interface SettingsSlice {
|
|
|
30
31
|
affiliatePercent: number | null;
|
|
31
32
|
affiliateWallets: { [key: string]: string } | null;
|
|
32
33
|
_customTokens: Token[];
|
|
34
|
+
quoteTokensRate: QuoteTokensRate;
|
|
35
|
+
|
|
33
36
|
setSlippage: (slippage: number) => void;
|
|
34
37
|
setCustomSlippage: (customSlippage: number | null) => void;
|
|
35
38
|
toggleInfiniteApprove: () => void;
|
|
@@ -50,6 +53,7 @@ export interface SettingsSlice {
|
|
|
50
53
|
setCustomToken: (token: TokenData) => void;
|
|
51
54
|
deleteCustomToken: (token: Token) => void;
|
|
52
55
|
customTokens: () => Token[];
|
|
56
|
+
changeQuoteTokensRate: () => void;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
export const createSettingsSlice: StateCreator<
|
|
@@ -69,6 +73,13 @@ export const createSettingsSlice: StateCreator<
|
|
|
69
73
|
affiliatePercent: null,
|
|
70
74
|
affiliateWallets: null,
|
|
71
75
|
_customTokens: [],
|
|
76
|
+
quoteTokensRate: 'default',
|
|
77
|
+
|
|
78
|
+
changeQuoteTokensRate: () =>
|
|
79
|
+
set((state) => ({
|
|
80
|
+
quoteTokensRate:
|
|
81
|
+
state.quoteTokensRate === 'default' ? 'reversed' : 'default',
|
|
82
|
+
})),
|
|
72
83
|
addPreferredBlockchain: (blockchain) => {
|
|
73
84
|
const currentPreferredBlockchains = get().preferredBlockchains;
|
|
74
85
|
|
package/src/utils/colors.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Types
|
|
3
3
|
import type { ThemeColors, WidgetColors, WidgetColorsKeys } from '../types';
|
|
4
4
|
|
|
5
|
+
import { isColorKeyOverridden } from './validation';
|
|
6
|
+
|
|
5
7
|
type RGB = {
|
|
6
8
|
red: number;
|
|
7
9
|
green: number;
|
|
@@ -40,15 +42,6 @@ function expandShortHexColor(hexColor: string) {
|
|
|
40
42
|
return `#${hexColor}`;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
/*
|
|
44
|
-
* We letting users to override some specific colors (e.g. `primary550`, `secondary100`).
|
|
45
|
-
* So we are generating a range of colors if `primary` (or other keys) has passed but if user is passing a specific color,
|
|
46
|
-
* we will override the user color to generated range.
|
|
47
|
-
*/
|
|
48
|
-
function isOverridingColor(colorKey: string): boolean {
|
|
49
|
-
return /[0-9]+$/.test(colorKey);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
45
|
// pad a hexadecimal string with zeros if it needs it
|
|
53
46
|
function pad(number: string, length: number) {
|
|
54
47
|
return number.padStart(length, '0');
|
|
@@ -171,7 +164,7 @@ export function expandToGenerateThemeColors(
|
|
|
171
164
|
*/
|
|
172
165
|
const isSingleColor = ['background', 'foreground'].includes(colorKey);
|
|
173
166
|
|
|
174
|
-
if (!isSingleColor && !
|
|
167
|
+
if (!isSingleColor && !isColorKeyOverridden(colorKey)) {
|
|
175
168
|
const expandedHexColor = expandShortHexColor(expandColor);
|
|
176
169
|
Object.assign(
|
|
177
170
|
output,
|
package/src/utils/numbers.ts
CHANGED
|
@@ -4,6 +4,9 @@ import type { BestRouteResponse } from 'rango-sdk';
|
|
|
4
4
|
|
|
5
5
|
import { BigNumber } from 'bignumber.js';
|
|
6
6
|
|
|
7
|
+
import { stripTrailingZeros } from './sanitizers';
|
|
8
|
+
import { isZeroValue } from './validation';
|
|
9
|
+
|
|
7
10
|
/*
|
|
8
11
|
* if time > 1h -> rounded with 5 minutes precision
|
|
9
12
|
* if time < 1h -> rounded with 15 seconds precision
|
|
@@ -125,3 +128,11 @@ export const containsText = (text: string, searchText: string) =>
|
|
|
125
128
|
|
|
126
129
|
export const isPositiveNumber = (text?: string) =>
|
|
127
130
|
!!text && parseFloat(text) > 0;
|
|
131
|
+
|
|
132
|
+
export function sanitizeInputAmount(amount: string): string {
|
|
133
|
+
if (isZeroValue(amount)) {
|
|
134
|
+
return '0';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return stripTrailingZeros(amount);
|
|
138
|
+
}
|