@rango-dev/widget-embedded 0.20.1-next.2 → 0.20.1-next.20
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/BlockchainList/BlockchainList.styles.d.ts +8 -0
- package/dist/components/BlockchainList/BlockchainList.styles.d.ts.map +1 -1
- package/dist/components/BlockchainsSection/BlockchainsSection.styles.d.ts +4 -0
- package/dist/components/BlockchainsSection/BlockchainsSection.styles.d.ts.map +1 -1
- package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts +514 -1088
- package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts.map +1 -1
- package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.d.ts.map +1 -1
- package/dist/components/ConfirmWalletsModal/WalletList.styles.d.ts +12 -0
- package/dist/components/ConfirmWalletsModal/WalletList.styles.d.ts.map +1 -1
- package/dist/components/CustomCollapsible/CustomCollapsible.d.ts +5 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.d.ts.map +1 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.styles.d.ts +654 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.styles.d.ts.map +1 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.types.d.ts +10 -0
- package/dist/components/CustomCollapsible/CustomCollapsible.types.d.ts.map +1 -0
- package/dist/components/HeaderButtons/HeaderButtons.styles.d.ts +179 -0
- package/dist/components/HeaderButtons/HeaderButtons.styles.d.ts.map +1 -1
- package/dist/components/HeaderButtons/HeaderButtons.types.d.ts +0 -1
- package/dist/components/HeaderButtons/HeaderButtons.types.d.ts.map +1 -1
- package/dist/components/HeaderButtons/HomeButtons.d.ts.map +1 -1
- package/dist/components/HeaderButtons/RefreshButton.d.ts +6 -0
- package/dist/components/HeaderButtons/RefreshButton.d.ts.map +1 -0
- package/dist/components/Layout/Layout.styles.d.ts +12 -0
- package/dist/components/Layout/Layout.styles.d.ts.map +1 -1
- package/dist/components/LoadingLiquiditySourceList/LoadingLiquiditySourceList.styles.d.ts +4 -0
- package/dist/components/LoadingLiquiditySourceList/LoadingLiquiditySourceList.styles.d.ts.map +1 -1
- package/dist/components/LoadingSwapDetails/LoadingSwapDetails.styles.d.ts +56 -0
- package/dist/components/LoadingSwapDetails/LoadingSwapDetails.styles.d.ts.map +1 -1
- package/dist/components/NoResult/NoResult.styles.d.ts +12 -0
- package/dist/components/NoResult/NoResult.styles.d.ts.map +1 -1
- package/dist/components/NotificationContent/NotificationContent.d.ts.map +1 -1
- package/dist/components/NotificationContent/NotificationContent.styles.d.ts +16 -0
- package/dist/components/NotificationContent/NotificationContent.styles.d.ts.map +1 -1
- package/dist/components/Quote/Quote.d.ts.map +1 -1
- package/dist/components/Quote/Quote.styles.d.ts +386 -2
- package/dist/components/Quote/Quote.styles.d.ts.map +1 -1
- package/dist/components/Quote/Quote.types.d.ts +19 -0
- package/dist/components/Quote/Quote.types.d.ts.map +1 -1
- package/dist/components/Quote/QuoteCostDetails.d.ts +4 -0
- package/dist/components/Quote/QuoteCostDetails.d.ts.map +1 -0
- package/dist/components/Quote/QuoteCostDetails.styles.d.ts +806 -0
- package/dist/components/Quote/QuoteCostDetails.styles.d.ts.map +1 -0
- package/dist/components/Quote/QuoteSummary.d.ts.map +1 -1
- package/dist/components/Quote/QuoteSummary.styles.d.ts +8 -0
- package/dist/components/Quote/QuoteSummary.styles.d.ts.map +1 -1
- package/dist/components/Quote/QuoteTrigger .d.ts +4 -0
- package/dist/components/Quote/QuoteTrigger .d.ts.map +1 -0
- package/dist/components/QuoteSkeleton/QuoteSkeleton.styles.d.ts +16 -0
- package/dist/components/QuoteSkeleton/QuoteSkeleton.styles.d.ts.map +1 -1
- package/dist/components/QuoteSkeleton/QuoteSummarySkeleton.styles.d.ts +40 -0
- package/dist/components/QuoteSkeleton/QuoteSummarySkeleton.styles.d.ts.map +1 -1
- package/dist/components/QuoteSkeleton/StepSkeleton.styles.d.ts +20 -0
- package/dist/components/QuoteSkeleton/StepSkeleton.styles.d.ts.map +1 -1
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.d.ts +16 -0
- package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.d.ts.map +1 -1
- package/dist/components/SearchInput/SearchInput.styles.d.ts +4 -0
- package/dist/components/SearchInput/SearchInput.styles.d.ts.map +1 -1
- package/dist/components/SettingsContainer/SettingsContainer.style.d.ts +16 -0
- package/dist/components/SettingsContainer/SettingsContainer.style.d.ts.map +1 -1
- package/dist/components/Slippage/Slippage.styles.d.ts +20 -0
- package/dist/components/Slippage/Slippage.styles.d.ts.map +1 -1
- package/dist/components/SwapDetails/SwapDetails.Placeholder.d.ts.map +1 -1
- package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
- package/dist/components/SwapDetails/SwapDetails.helpers.d.ts +1 -1
- package/dist/components/SwapDetails/SwapDetails.helpers.d.ts.map +1 -1
- package/dist/components/SwapDetails/SwapDetails.styles.d.ts +362 -0
- package/dist/components/SwapDetails/SwapDetails.styles.d.ts.map +1 -1
- package/dist/components/SwapDetailsAlerts/SwapDetailsAlerts.d.ts.map +1 -1
- package/dist/components/SwapDetailsAlerts/SwapDetailsAlerts.styles.d.ts +4 -0
- package/dist/components/SwapDetailsAlerts/SwapDetailsAlerts.styles.d.ts.map +1 -1
- package/dist/components/SwapDetailsAlerts/SwapDetailsAlerts.types.d.ts +2 -1
- package/dist/components/SwapDetailsAlerts/SwapDetailsAlerts.types.d.ts.map +1 -1
- package/dist/components/SwapDetailsModal/SwapDetailsModal.styles.d.ts +4 -0
- package/dist/components/SwapDetailsModal/SwapDetailsModal.styles.d.ts.map +1 -1
- package/dist/components/SwapsGroup/SwapsGroup.d.ts.map +1 -1
- package/dist/components/SwapsGroup/SwapsGroup.styles.d.ts +20 -0
- package/dist/components/SwapsGroup/SwapsGroup.styles.d.ts.map +1 -1
- package/dist/components/TokenList/TokenList.styles.d.ts +68 -0
- package/dist/components/TokenList/TokenList.styles.d.ts.map +1 -1
- package/dist/components/WalletModal/WalletModalContent.styles.d.ts +16 -0
- package/dist/components/WalletModal/WalletModalContent.styles.d.ts.map +1 -1
- package/dist/components/WidgetEvents.d.ts.map +1 -1
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/quote.d.ts +12 -0
- package/dist/constants/quote.d.ts.map +1 -0
- package/dist/containers/App/App.d.ts.map +1 -1
- package/dist/containers/App/App.styles.d.ts +4 -0
- package/dist/containers/App/App.styles.d.ts.map +1 -1
- package/dist/containers/QuoteInfo/QuoteInfo.styles.d.ts +20 -0
- package/dist/containers/QuoteInfo/QuoteInfo.styles.d.ts.map +1 -1
- package/dist/containers/Wallets/Wallets.d.ts.map +1 -1
- package/dist/containers/WidgetInfo/WidgetInfo.d.ts.map +1 -1
- package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts +5 -0
- package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts.map +1 -1
- package/dist/containers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
- package/dist/hooks/useLanguage.d.ts +2 -1
- package/dist/hooks/useLanguage.d.ts.map +1 -1
- package/dist/hooks/usePrepareBlockchainList/usePrepareBlockchainList.helpers.d.ts +2 -2
- package/dist/hooks/useSwapInput.d.ts.map +1 -1
- package/dist/hooks/useSyncStoresWithConfig.d.ts.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- 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/pages/SelectSwapItemsPage.d.ts.map +1 -1
- package/dist/store/AppStore.d.ts +2 -2
- package/dist/store/app.d.ts +2 -2
- package/dist/store/slices/data.d.ts.map +1 -1
- package/dist/store/slices/settings.d.ts +2 -2
- package/dist/store/slices/settings.d.ts.map +1 -1
- package/dist/types/config.d.ts +16 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/notification.d.ts +1 -2
- package/dist/types/notification.d.ts.map +1 -1
- package/dist/utils/configs.d.ts +8 -0
- package/dist/utils/configs.d.ts.map +1 -1
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/quote.d.ts +5 -1
- package/dist/utils/quote.d.ts.map +1 -1
- package/dist/utils/settings.d.ts +1 -1
- package/dist/utils/swap.d.ts +5 -1
- package/dist/utils/swap.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/components/ConfirmWalletsModal/ConfirmWallets.styles.ts +27 -96
- package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.tsx +25 -40
- package/src/components/CustomCollapsible/CustomCollapsible.styles.ts +75 -0
- package/src/components/CustomCollapsible/CustomCollapsible.tsx +55 -0
- package/src/components/CustomCollapsible/CustomCollapsible.types.ts +10 -0
- package/src/components/HeaderButtons/HeaderButtons.styles.ts +16 -1
- package/src/components/HeaderButtons/HeaderButtons.types.ts +0 -1
- package/src/components/HeaderButtons/HomeButtons.tsx +20 -33
- package/src/components/HeaderButtons/RefreshButton.tsx +81 -0
- package/src/components/NotificationContent/NotificationContent.tsx +10 -1
- package/src/components/Quote/Quote.styles.ts +44 -5
- package/src/components/Quote/Quote.tsx +10 -77
- package/src/components/Quote/Quote.types.ts +22 -0
- package/src/components/Quote/QuoteCostDetails.styles.ts +50 -0
- package/src/components/Quote/QuoteCostDetails.tsx +218 -0
- package/src/components/Quote/QuoteSummary.tsx +3 -2
- package/src/components/Quote/QuoteTrigger .tsx +215 -0
- package/src/components/Slippage/Slippage.tsx +5 -5
- package/src/components/Slippage/SlippageTooltipContent.tsx +1 -1
- package/src/components/SwapDetails/SwapDetails.Placeholder.tsx +12 -12
- package/src/components/SwapDetails/SwapDetails.helpers.tsx +43 -3
- package/src/components/SwapDetails/SwapDetails.styles.ts +13 -0
- package/src/components/SwapDetails/SwapDetails.tsx +10 -0
- package/src/components/SwapDetailsAlerts/SwapDetailsAlerts.tsx +13 -7
- package/src/components/SwapDetailsAlerts/SwapDetailsAlerts.types.ts +2 -0
- package/src/components/SwapsGroup/SwapsGroup.tsx +18 -7
- package/src/components/WidgetEvents.tsx +2 -14
- package/src/constants/index.ts +1 -0
- package/src/constants/quote.ts +23 -0
- package/src/containers/App/App.tsx +1 -4
- package/src/containers/Wallets/Wallets.tsx +11 -2
- package/src/containers/WidgetInfo/WidgetInfo.tsx +8 -0
- package/src/containers/WidgetInfo/WidgetInfo.types.ts +5 -0
- package/src/containers/WidgetProvider/WidgetProvider.tsx +2 -1
- package/src/hooks/useLanguage.ts +6 -4
- package/src/hooks/useSwapInput.ts +6 -2
- package/src/hooks/useSyncStoresWithConfig.ts +17 -34
- package/src/index.ts +4 -2
- package/src/pages/ConfirmSwapPage.tsx +12 -10
- package/src/pages/Home.tsx +5 -1
- package/src/pages/LiquiditySourcePage.tsx +5 -2
- package/src/pages/SelectBlockchainPage.tsx +3 -3
- package/src/pages/SelectSwapItemsPage.tsx +5 -1
- package/src/store/slices/data.ts +5 -7
- package/src/store/slices/settings.ts +3 -3
- package/src/types/config.ts +16 -3
- package/src/types/notification.ts +0 -7
- package/src/utils/configs.ts +41 -0
- package/src/utils/date.ts +5 -4
- package/src/utils/quote.ts +18 -1
- package/src/utils/swap.ts +35 -0
|
@@ -24,18 +24,27 @@ export function SwapDetailsAlerts(props: SwapAlertsProps) {
|
|
|
24
24
|
const waitingForApproval =
|
|
25
25
|
step.status === 'waitingForApproval' && !hasWarning;
|
|
26
26
|
const inProgress = step.status === 'running' && !hasWarning;
|
|
27
|
+
const waitingProgress =
|
|
28
|
+
(inProgress && !hasAlreadyProceededToSign) ||
|
|
29
|
+
(waitingForApproval && !step.explorerUrl?.length);
|
|
30
|
+
|
|
27
31
|
return (
|
|
28
32
|
<Alerts>
|
|
29
33
|
{step.explorerUrl?.map((explorerUrl, index, urls) => {
|
|
30
34
|
const key = index + explorerUrl.url;
|
|
31
35
|
const lastUrl = index === urls.length - 1;
|
|
32
|
-
const loading =
|
|
36
|
+
const loading =
|
|
37
|
+
((lastUrl && inProgress) || waitingForApproval) && !waitingProgress;
|
|
33
38
|
const error = lastUrl && step.status === 'failed';
|
|
34
39
|
|
|
35
40
|
return (
|
|
36
41
|
<Fragment key={key}>
|
|
37
42
|
<Alert
|
|
38
|
-
type={
|
|
43
|
+
type={
|
|
44
|
+
lastUrl
|
|
45
|
+
? (loading && 'loading') || (error && 'error') || 'success'
|
|
46
|
+
: 'success'
|
|
47
|
+
}
|
|
39
48
|
title={
|
|
40
49
|
!explorerUrl.description
|
|
41
50
|
? i18n.t('View transaction')
|
|
@@ -47,7 +56,7 @@ export function SwapDetailsAlerts(props: SwapAlertsProps) {
|
|
|
47
56
|
variant="ghost"
|
|
48
57
|
size="xsmall"
|
|
49
58
|
onClick={() => window.open(explorerUrl.url, '_blank')}>
|
|
50
|
-
<LinkIcon size={
|
|
59
|
+
<LinkIcon size={12} />
|
|
51
60
|
</IconButton>
|
|
52
61
|
)
|
|
53
62
|
}
|
|
@@ -55,10 +64,7 @@ export function SwapDetailsAlerts(props: SwapAlertsProps) {
|
|
|
55
64
|
</Fragment>
|
|
56
65
|
);
|
|
57
66
|
})}
|
|
58
|
-
{
|
|
59
|
-
(waitingForApproval && !step.explorerUrl?.length)) && (
|
|
60
|
-
<Alert type="loading" title={message.shortMessage} />
|
|
61
|
-
)}
|
|
67
|
+
{waitingProgress && <Alert type="loading" title={message.shortMessage} />}
|
|
62
68
|
{step.status !== 'failed' && hasWarning && (
|
|
63
69
|
<WarningAlert
|
|
64
70
|
switchNetwork={switchNetwork}
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
PendingSwap,
|
|
7
7
|
PendingSwapNetworkStatus,
|
|
8
8
|
PendingSwapStep,
|
|
9
|
+
SwapperMeta,
|
|
9
10
|
} from 'rango-types';
|
|
10
11
|
|
|
11
12
|
export interface SwapAlertsProps extends WaningAlertsProps {
|
|
@@ -26,4 +27,5 @@ export interface FailedAlertsProps {
|
|
|
26
27
|
export type GetStep = {
|
|
27
28
|
swap: PendingSwap;
|
|
28
29
|
blockchains: BlockchainMeta[];
|
|
30
|
+
swappers: SwapperMeta[];
|
|
29
31
|
} & Omit<SwapAlertsProps, 'step' | 'hasAlreadyProceededToSign'>;
|
|
@@ -4,6 +4,10 @@ import { i18n } from '@lingui/core';
|
|
|
4
4
|
import { Divider, SwapListItem, Typography } from '@rango-dev/ui';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
+
import {
|
|
8
|
+
TOKEN_AMOUNT_MAX_DECIMALS,
|
|
9
|
+
TOKEN_AMOUNT_MIN_DECIMALS,
|
|
10
|
+
} from '../../constants/routing';
|
|
7
11
|
import { getContainer } from '../../utils/common';
|
|
8
12
|
import { formatTooltipNumbers, numberToString } from '../../utils/numbers';
|
|
9
13
|
|
|
@@ -18,11 +22,11 @@ export function SwapsGroup(props: PropTypes) {
|
|
|
18
22
|
|
|
19
23
|
const loadingGroups = [
|
|
20
24
|
{
|
|
21
|
-
title: 'Today',
|
|
25
|
+
title: i18n.t('Today'),
|
|
22
26
|
swaps,
|
|
23
27
|
},
|
|
24
28
|
{
|
|
25
|
-
title: 'This month',
|
|
29
|
+
title: i18n.t('This month'),
|
|
26
30
|
swaps,
|
|
27
31
|
},
|
|
28
32
|
];
|
|
@@ -36,7 +40,7 @@ export function SwapsGroup(props: PropTypes) {
|
|
|
36
40
|
variant="label"
|
|
37
41
|
size="medium"
|
|
38
42
|
className={groupStyles()}>
|
|
39
|
-
{
|
|
43
|
+
{group.title}
|
|
40
44
|
</Typography>
|
|
41
45
|
</Time>
|
|
42
46
|
<Divider size={4} />
|
|
@@ -69,7 +73,7 @@ export function SwapsGroup(props: PropTypes) {
|
|
|
69
73
|
variant="label"
|
|
70
74
|
size="medium"
|
|
71
75
|
className={groupStyles()}>
|
|
72
|
-
{
|
|
76
|
+
{group.title}
|
|
73
77
|
</Typography>
|
|
74
78
|
</Time>
|
|
75
79
|
<Divider size={4} />
|
|
@@ -85,8 +89,8 @@ export function SwapsGroup(props: PropTypes) {
|
|
|
85
89
|
creationTime={swap.creationTime}
|
|
86
90
|
status={swap.status}
|
|
87
91
|
onClick={onSwapClick}
|
|
88
|
-
onlyShowTime={group.title === 'Today'}
|
|
89
92
|
tooltipContainer={getContainer()}
|
|
93
|
+
onlyShowTime={group.title === i18n.t('Today')}
|
|
90
94
|
swapTokenData={{
|
|
91
95
|
from: {
|
|
92
96
|
token: {
|
|
@@ -96,7 +100,12 @@ export function SwapsGroup(props: PropTypes) {
|
|
|
96
100
|
blockchain: {
|
|
97
101
|
image: firstStep.fromBlockchainLogo || '',
|
|
98
102
|
},
|
|
99
|
-
amount:
|
|
103
|
+
amount: numberToString(
|
|
104
|
+
swap.inputAmount,
|
|
105
|
+
TOKEN_AMOUNT_MIN_DECIMALS,
|
|
106
|
+
TOKEN_AMOUNT_MAX_DECIMALS
|
|
107
|
+
),
|
|
108
|
+
realAmount: formatTooltipNumbers(swap.inputAmount),
|
|
100
109
|
},
|
|
101
110
|
to: {
|
|
102
111
|
token: {
|
|
@@ -109,7 +118,9 @@ export function SwapsGroup(props: PropTypes) {
|
|
|
109
118
|
amount: numberToString(
|
|
110
119
|
lastStep.outputAmount ||
|
|
111
120
|
lastStep.expectedOutputAmountHumanReadable ||
|
|
112
|
-
''
|
|
121
|
+
'',
|
|
122
|
+
TOKEN_AMOUNT_MIN_DECIMALS,
|
|
123
|
+
TOKEN_AMOUNT_MAX_DECIMALS
|
|
113
124
|
),
|
|
114
125
|
realAmount: formatTooltipNumbers(
|
|
115
126
|
lastStep.outputAmount ||
|
|
@@ -11,14 +11,12 @@ import { useEffect } from 'react';
|
|
|
11
11
|
import { useAppStore } from '../store/AppStore';
|
|
12
12
|
import { useNotificationStore } from '../store/notification';
|
|
13
13
|
import { useWalletsStore } from '../store/wallets';
|
|
14
|
-
import { validBlockedStatuses } from '../types/notification';
|
|
15
14
|
|
|
16
15
|
export function WidgetEvents() {
|
|
17
16
|
const tokens = useAppStore().tokens();
|
|
18
17
|
const connectedWallets = useWalletsStore.use.connectedWallets();
|
|
19
18
|
const getWalletsDetails = useWalletsStore.use.getWalletsDetails();
|
|
20
19
|
const setNotification = useNotificationStore.use.setNotification();
|
|
21
|
-
const setAsRead = useNotificationStore.use.setAsRead();
|
|
22
20
|
const widgetEvents = useEvents();
|
|
23
21
|
|
|
24
22
|
useEffect(() => {
|
|
@@ -43,18 +41,8 @@ export function WidgetEvents() {
|
|
|
43
41
|
fromAccount && getWalletsDetails([fromAccount], tokens);
|
|
44
42
|
toAccount && getWalletsDetails([toAccount], tokens);
|
|
45
43
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
validBlockedStatuses.includes(event.status)) ||
|
|
49
|
-
event.type === StepEventType.FAILED
|
|
50
|
-
) {
|
|
51
|
-
setNotification(event, route);
|
|
52
|
-
} else if (
|
|
53
|
-
event.type === StepEventType.TX_EXECUTION ||
|
|
54
|
-
event.type === StepEventType.CHECK_STATUS
|
|
55
|
-
) {
|
|
56
|
-
setAsRead(route.requestId);
|
|
57
|
-
}
|
|
44
|
+
|
|
45
|
+
setNotification(event, route);
|
|
58
46
|
});
|
|
59
47
|
|
|
60
48
|
return () => widgetEvents.all.clear();
|
package/src/constants/index.ts
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SwapFee } from 'rango-sdk';
|
|
2
|
+
|
|
3
|
+
import { i18n } from '@lingui/core';
|
|
4
|
+
|
|
5
|
+
export type NameOfFees =
|
|
6
|
+
| 'Swapper Fee'
|
|
7
|
+
| 'Affiliate Fee'
|
|
8
|
+
| 'Outbound network fee'
|
|
9
|
+
| 'Rango Fee'
|
|
10
|
+
| 'Network Fee';
|
|
11
|
+
|
|
12
|
+
export const NAME_OF_FEES: Record<NameOfFees, string> = {
|
|
13
|
+
'Network Fee': i18n.t('Network Fee'),
|
|
14
|
+
'Swapper Fee': i18n.t('Protocol Fee'),
|
|
15
|
+
'Affiliate Fee': i18n.t('Affiliate Fee'),
|
|
16
|
+
'Outbound network fee': i18n.t('Outbound Fee'),
|
|
17
|
+
'Rango Fee': i18n.t('Rango Fee'),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type FeesGroup = {
|
|
21
|
+
payable: { [key in NameOfFees]?: SwapFee[] };
|
|
22
|
+
nonePayable: { [key in NameOfFees]?: SwapFee[] };
|
|
23
|
+
};
|
|
@@ -20,7 +20,7 @@ export function Main() {
|
|
|
20
20
|
|
|
21
21
|
const { config } = useAppStore();
|
|
22
22
|
const { activeTheme } = useTheme(config?.theme || {});
|
|
23
|
-
const { activeLanguage
|
|
23
|
+
const { activeLanguage } = useLanguage();
|
|
24
24
|
const [lastConnectedWalletWithNetwork, setLastConnectedWalletWithNetwork] =
|
|
25
25
|
useState<string>('');
|
|
26
26
|
const [disconnectedWallet, setDisconnectedWallet] = useState<WalletType>();
|
|
@@ -30,9 +30,6 @@ export function Main() {
|
|
|
30
30
|
void useNotificationStore.persist.rehydrate();
|
|
31
31
|
widgetContext.onConnectWallet(setLastConnectedWalletWithNetwork);
|
|
32
32
|
}, []);
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
changeLanguage(config?.language);
|
|
35
|
-
}, [config?.language]);
|
|
36
33
|
|
|
37
34
|
return (
|
|
38
35
|
<I18nManager language={activeLanguage}>
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
PropTypes,
|
|
4
4
|
WidgetContextInterface,
|
|
5
5
|
} from './Wallets.types';
|
|
6
|
+
import type { Wallet } from '../../types/wallets';
|
|
6
7
|
import type { ProvidersOptions } from '../../utils/providers';
|
|
7
8
|
import type { EventHandler } from '@rango-dev/wallets-react';
|
|
8
9
|
import type { Network } from '@rango-dev/wallets-shared';
|
|
@@ -10,7 +11,7 @@ import type { PropsWithChildren } from 'react';
|
|
|
10
11
|
|
|
11
12
|
import { Events, Provider } from '@rango-dev/wallets-react';
|
|
12
13
|
import { isEvmBlockchain } from 'rango-sdk';
|
|
13
|
-
import React, { createContext, useEffect, useRef } from 'react';
|
|
14
|
+
import React, { createContext, useEffect, useRef, useState } from 'react';
|
|
14
15
|
|
|
15
16
|
import { useSyncStoresWithConfig } from '../../hooks/useSyncStoresWithConfig';
|
|
16
17
|
import { useWalletProviders } from '../../hooks/useWalletProviders';
|
|
@@ -34,6 +35,7 @@ function Main(props: PropsWithChildren<PropTypes>) {
|
|
|
34
35
|
const walletOptions: ProvidersOptions = {
|
|
35
36
|
walletConnectProjectId: props.config?.walletConnectProjectId,
|
|
36
37
|
};
|
|
38
|
+
const [accounts, setAccounts] = useState<Wallet[]>([]);
|
|
37
39
|
const { providers } = useWalletProviders(props.config.wallets, walletOptions);
|
|
38
40
|
const { connectWallet, disconnectWallet } = useWalletsStore();
|
|
39
41
|
const onConnectWalletHandler = useRef<OnConnectHandler>();
|
|
@@ -66,7 +68,7 @@ function Main(props: PropsWithChildren<PropTypes>) {
|
|
|
66
68
|
supportedChainNames,
|
|
67
69
|
meta.isContractWallet
|
|
68
70
|
);
|
|
69
|
-
|
|
71
|
+
setAccounts(data);
|
|
70
72
|
} else {
|
|
71
73
|
disconnectWallet(type);
|
|
72
74
|
}
|
|
@@ -99,6 +101,13 @@ function Main(props: PropsWithChildren<PropTypes>) {
|
|
|
99
101
|
props.onUpdateState(type, event, value, state, meta);
|
|
100
102
|
}
|
|
101
103
|
};
|
|
104
|
+
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (accounts.length) {
|
|
107
|
+
connectWallet(accounts, tokens);
|
|
108
|
+
}
|
|
109
|
+
}, [accounts, tokens]);
|
|
110
|
+
|
|
102
111
|
return (
|
|
103
112
|
<WidgetContext.Provider
|
|
104
113
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
@@ -3,7 +3,9 @@ import type { WidgetInfoContextInterface } from './WidgetInfo.types';
|
|
|
3
3
|
import { useManager } from '@rango-dev/queue-manager-react';
|
|
4
4
|
import React, { createContext, useContext } from 'react';
|
|
5
5
|
|
|
6
|
+
import { useLanguage } from '../../hooks/useLanguage';
|
|
6
7
|
import { useAppStore } from '../../store/AppStore';
|
|
8
|
+
import { useNotificationStore } from '../../store/notification';
|
|
7
9
|
import { useQuoteStore } from '../../store/quote';
|
|
8
10
|
import { useWalletsStore } from '../../store/wallets';
|
|
9
11
|
import { calculateWalletUsdValue } from '../../utils/wallets';
|
|
@@ -26,6 +28,8 @@ export function WidgetInfo(props: React.PropsWithChildren) {
|
|
|
26
28
|
const tokens = useAppStore().tokens();
|
|
27
29
|
const swappers = useAppStore().swappers();
|
|
28
30
|
const loadingStatus = useAppStore().fetchStatus;
|
|
31
|
+
const resetLanguage = useLanguage().resetLanguage;
|
|
32
|
+
const notifications = useNotificationStore().getUnreadNotifications();
|
|
29
33
|
|
|
30
34
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
31
35
|
const value = {
|
|
@@ -42,6 +46,10 @@ export function WidgetInfo(props: React.PropsWithChildren) {
|
|
|
42
46
|
swappers,
|
|
43
47
|
loadingStatus,
|
|
44
48
|
},
|
|
49
|
+
resetLanguage,
|
|
50
|
+
notifications: {
|
|
51
|
+
list: notifications,
|
|
52
|
+
},
|
|
45
53
|
};
|
|
46
54
|
|
|
47
55
|
return (
|
|
@@ -2,6 +2,7 @@ import type { WidgetHistory } from './WidgetInfo.helpers';
|
|
|
2
2
|
import type { FetchStatus } from '../../store/slices/data';
|
|
3
3
|
import type { ConnectedWallet } from '../../store/wallets';
|
|
4
4
|
import type { Wallet } from '../../types';
|
|
5
|
+
import type { Notification } from '../../types/notification';
|
|
5
6
|
import type { BlockchainMeta, SwapperMeta, Token } from 'rango-sdk';
|
|
6
7
|
|
|
7
8
|
export interface WidgetInfoContextInterface {
|
|
@@ -18,4 +19,8 @@ export interface WidgetInfoContextInterface {
|
|
|
18
19
|
swappers: SwapperMeta[];
|
|
19
20
|
loadingStatus: FetchStatus;
|
|
20
21
|
};
|
|
22
|
+
resetLanguage: () => void;
|
|
23
|
+
notifications: {
|
|
24
|
+
list: Notification[];
|
|
25
|
+
};
|
|
21
26
|
}
|
|
@@ -17,7 +17,8 @@ export function WidgetProvider(props: PropsWithChildren<PropTypes>) {
|
|
|
17
17
|
API_KEY: config?.apiKey || RANGO_PUBLIC_API_KEY,
|
|
18
18
|
BASE_URL: config?.apiUrl || DEFAULT_BASE_URL,
|
|
19
19
|
});
|
|
20
|
-
}, [config]);
|
|
20
|
+
}, [config.apiKey, config.apiUrl]);
|
|
21
|
+
|
|
21
22
|
return (
|
|
22
23
|
<WidgetWallets config={config} onUpdateState={onUpdateState}>
|
|
23
24
|
<QueueManager apiKey={config.apiKey}>
|
package/src/hooks/useLanguage.ts
CHANGED
|
@@ -9,18 +9,20 @@ interface UseLanguage {
|
|
|
9
9
|
languages: LanguageItem[];
|
|
10
10
|
defaultLanguage: Language;
|
|
11
11
|
activeLanguage: Language;
|
|
12
|
-
changeLanguage: (language?: Language) => void;
|
|
12
|
+
changeLanguage: (language?: Language | null) => void;
|
|
13
|
+
resetLanguage: () => void;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function useLanguage(): UseLanguage {
|
|
16
|
-
const { setLanguage, language } = useAppStore();
|
|
17
|
+
const { setLanguage, language, config } = useAppStore();
|
|
17
18
|
const languages = LANGUAGES;
|
|
18
|
-
const defaultLanguage = DEFAULT_LANGUAGE;
|
|
19
|
+
const defaultLanguage = config?.language || DEFAULT_LANGUAGE;
|
|
19
20
|
|
|
20
21
|
return {
|
|
21
|
-
activeLanguage: language,
|
|
22
|
+
activeLanguage: language || defaultLanguage,
|
|
22
23
|
languages,
|
|
23
24
|
defaultLanguage,
|
|
24
25
|
changeLanguage: (language) => setLanguage(language || DEFAULT_LANGUAGE),
|
|
26
|
+
resetLanguage: () => setLanguage(null),
|
|
25
27
|
};
|
|
26
28
|
}
|
|
@@ -48,6 +48,7 @@ export function useSwapInput(): UseSwapInput {
|
|
|
48
48
|
toToken,
|
|
49
49
|
inputAmount,
|
|
50
50
|
inputUsdValue,
|
|
51
|
+
quote,
|
|
51
52
|
resetQuote,
|
|
52
53
|
setQuote,
|
|
53
54
|
} = useQuoteStore();
|
|
@@ -63,9 +64,9 @@ export function useSwapInput(): UseSwapInput {
|
|
|
63
64
|
const [error, setError] = useState<QuoteError | null>(null);
|
|
64
65
|
const [warning, setWarning] = useState<QuoteWarning | null>(null);
|
|
65
66
|
const userSlippage = customSlippage ?? slippage;
|
|
66
|
-
const
|
|
67
|
+
const tokensValueInvalid = !fromToken || !toToken;
|
|
67
68
|
const shouldSkipRequest =
|
|
68
|
-
|
|
69
|
+
tokensValueInvalid ||
|
|
69
70
|
tokensAreEqual(fromToken, toToken) ||
|
|
70
71
|
!isPositiveNumber(inputAmount);
|
|
71
72
|
|
|
@@ -153,6 +154,9 @@ export function useSwapInput(): UseSwapInput {
|
|
|
153
154
|
return;
|
|
154
155
|
}
|
|
155
156
|
if (shouldSkipRequest) {
|
|
157
|
+
if (quote) {
|
|
158
|
+
resetQuote();
|
|
159
|
+
}
|
|
156
160
|
return;
|
|
157
161
|
}
|
|
158
162
|
resetQuote();
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { Asset } from 'rango-sdk';
|
|
2
2
|
|
|
3
|
-
import { useEffect, useLayoutEffect,
|
|
3
|
+
import { useEffect, useLayoutEffect, useRef } from 'react';
|
|
4
4
|
|
|
5
5
|
import { useAppStore } from '../store/AppStore';
|
|
6
6
|
import { useQuoteStore } from '../store/quote';
|
|
7
|
+
import {
|
|
8
|
+
isBlockchainExcludedInConfig,
|
|
9
|
+
isTokenExcludedInConfig,
|
|
10
|
+
} from '../utils/configs';
|
|
7
11
|
import { tokensAreEqual } from '../utils/wallets';
|
|
8
12
|
|
|
9
13
|
export function useSyncStoresWithConfig() {
|
|
@@ -27,22 +31,10 @@ export function useSyncStoresWithConfig() {
|
|
|
27
31
|
const { setAffiliateRef, setAffiliatePercent, setAffiliateWallets } =
|
|
28
32
|
useAppStore();
|
|
29
33
|
|
|
30
|
-
const fromTokensConfig =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const fromBlockchainsConfig = useMemo(
|
|
35
|
-
() => config?.from?.blockchains,
|
|
36
|
-
[config?.from?.blockchains]
|
|
37
|
-
);
|
|
38
|
-
const toTokensConfig = useMemo(
|
|
39
|
-
() => config?.to?.tokens,
|
|
40
|
-
[config?.to?.tokens]
|
|
41
|
-
);
|
|
42
|
-
const toBlockchainsConfig = useMemo(
|
|
43
|
-
() => config?.to?.blockchains,
|
|
44
|
-
[config?.to?.blockchains]
|
|
45
|
-
);
|
|
34
|
+
const fromTokensConfig = config?.from?.tokens;
|
|
35
|
+
const fromBlockchainsConfig = config?.from?.blockchains;
|
|
36
|
+
const toTokensConfig = config?.to?.tokens;
|
|
37
|
+
const toBlockchainsConfig = config?.to?.blockchains;
|
|
46
38
|
const prevConfigFromToken = useRef<Asset | undefined>(undefined);
|
|
47
39
|
const prevConfigToToken = useRef<Asset | undefined>(undefined);
|
|
48
40
|
const prevConfigFromBlockchain = useRef<string | undefined>(undefined);
|
|
@@ -90,30 +82,21 @@ export function useSyncStoresWithConfig() {
|
|
|
90
82
|
]);
|
|
91
83
|
|
|
92
84
|
useEffect(() => {
|
|
93
|
-
if (fromToken
|
|
94
|
-
|
|
95
|
-
setFromToken({ token: null });
|
|
96
|
-
}
|
|
85
|
+
if (isTokenExcludedInConfig(fromToken, fromTokensConfig)) {
|
|
86
|
+
setFromToken({ token: null });
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
if (fromBlockchain
|
|
100
|
-
|
|
101
|
-
setFromBlockchain(null);
|
|
102
|
-
}
|
|
89
|
+
if (isBlockchainExcludedInConfig(fromBlockchain, fromBlockchainsConfig)) {
|
|
90
|
+
setFromBlockchain(null);
|
|
103
91
|
}
|
|
104
92
|
}, [fromTokensConfig, fromBlockchainsConfig]);
|
|
105
93
|
|
|
106
94
|
useEffect(() => {
|
|
107
|
-
if (toToken
|
|
108
|
-
|
|
109
|
-
setToToken({ token: null });
|
|
110
|
-
}
|
|
95
|
+
if (isTokenExcludedInConfig(toToken, toTokensConfig)) {
|
|
96
|
+
setFromToken({ token: null });
|
|
111
97
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!toBlockchainsConfig.includes(toBlockchain.name)) {
|
|
115
|
-
setToBlockchain(null);
|
|
116
|
-
}
|
|
98
|
+
if (isBlockchainExcludedInConfig(toBlockchain, toBlockchainsConfig)) {
|
|
99
|
+
setToBlockchain(null);
|
|
117
100
|
}
|
|
118
101
|
}, [toTokensConfig, toBlockchainsConfig]);
|
|
119
102
|
|
package/src/index.ts
CHANGED
|
@@ -2,13 +2,13 @@ import type { WidgetProps } from './containers/Widget';
|
|
|
2
2
|
import type { ConnectedWallet } from './store/wallets';
|
|
3
3
|
import type {
|
|
4
4
|
BlockchainAndTokenConfig,
|
|
5
|
+
Tokens,
|
|
5
6
|
WidgetColors,
|
|
6
7
|
WidgetColorsKeys,
|
|
7
8
|
WidgetConfig,
|
|
8
9
|
WidgetTheme,
|
|
9
10
|
} from './types';
|
|
10
11
|
import type {
|
|
11
|
-
EventSeverity,
|
|
12
12
|
PendingSwapWithQueueID,
|
|
13
13
|
Route,
|
|
14
14
|
RouteEvent,
|
|
@@ -39,6 +39,7 @@ import type {
|
|
|
39
39
|
import type { PendingSwap, PendingSwapStep } from 'rango-types';
|
|
40
40
|
|
|
41
41
|
import {
|
|
42
|
+
EventSeverity,
|
|
42
43
|
MainEvents,
|
|
43
44
|
RouteEventType,
|
|
44
45
|
StepEventType,
|
|
@@ -86,6 +87,7 @@ export type {
|
|
|
86
87
|
StepOutputRevealedEvent,
|
|
87
88
|
HandleWalletsUpdate,
|
|
88
89
|
ConnectedWallet,
|
|
90
|
+
Tokens,
|
|
89
91
|
};
|
|
90
92
|
export {
|
|
91
93
|
Widget,
|
|
@@ -113,7 +115,6 @@ export type {
|
|
|
113
115
|
PendingSwapWithQueueID,
|
|
114
116
|
PendingSwapStep,
|
|
115
117
|
RouteExecutionEvents,
|
|
116
|
-
EventSeverity,
|
|
117
118
|
};
|
|
118
119
|
|
|
119
120
|
// Internal function and enum exports for Rango
|
|
@@ -123,4 +124,5 @@ export {
|
|
|
123
124
|
WalletEvents,
|
|
124
125
|
WalletTypes,
|
|
125
126
|
PendingSwapNetworkStatus,
|
|
127
|
+
EventSeverity,
|
|
126
128
|
};
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
css,
|
|
13
13
|
Divider,
|
|
14
14
|
IconButton,
|
|
15
|
-
RefreshIcon,
|
|
16
15
|
SettingsIcon,
|
|
17
16
|
styled,
|
|
18
17
|
Tooltip,
|
|
@@ -26,6 +25,7 @@ import { useNavigate } from 'react-router-dom';
|
|
|
26
25
|
import { getRequiredWallets } from '../components/ConfirmWalletsModal/ConfirmWallets.helpers';
|
|
27
26
|
import { ConfirmWalletsModal } from '../components/ConfirmWalletsModal/ConfirmWalletsModal';
|
|
28
27
|
import { HeaderButton } from '../components/HeaderButtons/HeaderButtons.styles';
|
|
28
|
+
import { RefreshButton } from '../components/HeaderButtons/RefreshButton';
|
|
29
29
|
import { Layout } from '../components/Layout';
|
|
30
30
|
import { navigationRoutes } from '../constants/navigationRoutes';
|
|
31
31
|
import { getQuoteUpdateWarningMessage } from '../constants/warnings';
|
|
@@ -324,15 +324,17 @@ export function ConfirmSwapPage() {
|
|
|
324
324
|
<Typography variant="title" size="small">
|
|
325
325
|
{i18n.t('You get')}
|
|
326
326
|
</Typography>
|
|
327
|
-
<
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
327
|
+
<div className={iconStyles()}>
|
|
328
|
+
<RefreshButton
|
|
329
|
+
onClick={
|
|
330
|
+
!fetchingConfirmationQuote &&
|
|
331
|
+
!showWallets &&
|
|
332
|
+
!showQuoteWarningModal
|
|
333
|
+
? onRefresh
|
|
334
|
+
: undefined
|
|
335
|
+
}
|
|
336
|
+
/>
|
|
337
|
+
</div>
|
|
336
338
|
</div>
|
|
337
339
|
{dbErrorMessage && (
|
|
338
340
|
<>
|
package/src/pages/Home.tsx
CHANGED
|
@@ -161,7 +161,11 @@ export function Home() {
|
|
|
161
161
|
suffix: (
|
|
162
162
|
<HomeButtons
|
|
163
163
|
layoutRef={layoutRef.current}
|
|
164
|
-
onClickRefresh={
|
|
164
|
+
onClickRefresh={
|
|
165
|
+
(!!quote || quoteError) && !showQuoteWarningModal
|
|
166
|
+
? fetchQuote
|
|
167
|
+
: undefined
|
|
168
|
+
}
|
|
165
169
|
onClickHistory={() => navigate(navigationRoutes.swaps)}
|
|
166
170
|
onClickSettings={() => navigate(navigationRoutes.settings)}
|
|
167
171
|
/>
|
|
@@ -40,6 +40,7 @@ export function LiquiditySourcePage({ sourceType }: PropTypes) {
|
|
|
40
40
|
const supportedUniqueSwappersGroups: Array<UniqueSwappersGroupType> =
|
|
41
41
|
getUniqueSwappersGroups(swappers, disabledLiquiditySources);
|
|
42
42
|
|
|
43
|
+
const types = { Exchanges: i18n.t('Exchanges'), Bridges: i18n.t('Bridges') };
|
|
43
44
|
const validTypes: Array<LiquiditySourceType> = [];
|
|
44
45
|
if (sourceType === 'Exchanges') {
|
|
45
46
|
validTypes.push('DEX');
|
|
@@ -103,7 +104,7 @@ export function LiquiditySourcePage({ sourceType }: PropTypes) {
|
|
|
103
104
|
suffix: (
|
|
104
105
|
<LiquiditySourceSuffix>
|
|
105
106
|
<Button variant="ghost" size="xsmall" onClick={toggleAllSources}>
|
|
106
|
-
{i18n.t(
|
|
107
|
+
{hasSelectAll ? i18n.t('Deselect all') : i18n.t('Select all')}
|
|
107
108
|
</Button>
|
|
108
109
|
</LiquiditySourceSuffix>
|
|
109
110
|
),
|
|
@@ -115,7 +116,9 @@ export function LiquiditySourcePage({ sourceType }: PropTypes) {
|
|
|
115
116
|
fullWidth
|
|
116
117
|
color="light"
|
|
117
118
|
variant="contained"
|
|
118
|
-
placeholder={i18n.t('Search {sourceType}', {
|
|
119
|
+
placeholder={i18n.t('Search {sourceType}', {
|
|
120
|
+
sourceType: types[sourceType],
|
|
121
|
+
})}
|
|
119
122
|
onChange={searchHandler}
|
|
120
123
|
/>
|
|
121
124
|
{fetchStatus === 'loading' && <LoadingLiquiditySourceList />}
|
|
@@ -2,7 +2,7 @@ import { i18n } from '@lingui/core';
|
|
|
2
2
|
import {
|
|
3
3
|
Divider,
|
|
4
4
|
getCountCategories,
|
|
5
|
-
SelectableCategoryList
|
|
5
|
+
SelectableCategoryList,
|
|
6
6
|
} from '@rango-dev/ui';
|
|
7
7
|
import React, { useState } from 'react';
|
|
8
8
|
|
|
@@ -27,7 +27,7 @@ export function SelectBlockchainPage(props: PropTypes) {
|
|
|
27
27
|
const fetchStatus = useAppStore().fetchStatus;
|
|
28
28
|
|
|
29
29
|
const blockchains = useAppStore().blockchains({
|
|
30
|
-
type
|
|
30
|
+
type,
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
const countActiveCategories = getCountCategories(blockchains);
|
|
@@ -37,7 +37,7 @@ export function SelectBlockchainPage(props: PropTypes) {
|
|
|
37
37
|
return (
|
|
38
38
|
<Layout
|
|
39
39
|
header={{
|
|
40
|
-
title: i18n.t(`Select Blockchain`)
|
|
40
|
+
title: i18n.t(`Select Blockchain`),
|
|
41
41
|
}}>
|
|
42
42
|
<Divider size={12} />
|
|
43
43
|
|
|
@@ -68,11 +68,15 @@ export function SelectSwapItemsPage(props: PropTypes) {
|
|
|
68
68
|
setToToken({ token, meta: { blockchains, tokens } });
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
|
+
const types = {
|
|
72
|
+
source: i18n.t('Source'),
|
|
73
|
+
destination: i18n.t('Destination'),
|
|
74
|
+
};
|
|
71
75
|
|
|
72
76
|
return (
|
|
73
77
|
<Layout
|
|
74
78
|
header={{
|
|
75
|
-
title: i18n.t('Swap {type}', { type }),
|
|
79
|
+
title: i18n.t('Swap {type}', { type: types[type] }),
|
|
76
80
|
}}>
|
|
77
81
|
<BlockchainsSection
|
|
78
82
|
blockchains={blockchains}
|