diff --git a/ui/pages/swaps/awaiting-swap/awaiting-swap.js b/ui/pages/swaps/awaiting-swap/awaiting-swap.js
index dcb3a08b1..5456c1067 100644
--- a/ui/pages/swaps/awaiting-swap/awaiting-swap.js
+++ b/ui/pages/swaps/awaiting-swap/awaiting-swap.js
@@ -17,7 +17,6 @@ import {
getUSDConversionRate,
isHardwareWallet,
getHardwareWalletType,
- getSwapsDefaultToken,
} from '../../../selectors';
import {
@@ -34,10 +33,8 @@ import {
getCurrentSmartTransactionsEnabled,
getFromTokenInputValue,
getMaxSlippage,
- setSwapsFromToken,
} from '../../../ducks/swaps/swaps';
import Mascot from '../../../components/ui/mascot';
-import Box from '../../../components/ui/box';
import {
QUOTES_EXPIRED_ERROR,
SWAP_FAILED_ERROR,
@@ -56,10 +53,11 @@ import { stopPollingForQuotes } from '../../../store/actions';
import { getRenderableNetworkFeesForQuote } from '../swaps.util';
import SwapsFooter from '../swaps-footer';
+import CreateNewSwap from '../create-new-swap';
+import ViewOnBlockExplorer from '../view-on-block-explorer';
import SwapFailureIcon from './swap-failure-icon';
import SwapSuccessIcon from './swap-success-icon';
import QuotesTimeoutIcon from './quotes-timeout-icon';
-import ViewOnEtherScanLink from './view-on-ether-scan-link';
export default function AwaitingSwap({
swapComplete,
@@ -85,8 +83,6 @@ export default function AwaitingSwap({
const usdConversionRate = useSelector(getUSDConversionRate);
const chainId = useSelector(getCurrentChainId);
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider, shallowEqual);
- const defaultSwapsToken = useSelector(getSwapsDefaultToken, isEqual);
-
const [trackedQuotesExpiredEvent, setTrackedQuotesExpiredEvent] = useState(
false,
);
@@ -141,11 +137,6 @@ export default function AwaitingSwap({
{ blockExplorerUrl: baseNetworkUrl },
);
- const isCustomBlockExplorerUrl = Boolean(
- SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP[chainId] ||
- rpcPrefs.blockExplorerUrl,
- );
-
let headerText;
let statusImage;
let descriptionText;
@@ -173,10 +164,9 @@ export default function AwaitingSwap({
submitText = t('tryAgain');
statusImage = ;
content = blockExplorerUrl && (
-
);
} else if (errorKey === QUOTES_EXPIRED_ERROR) {
@@ -221,10 +211,9 @@ export default function AwaitingSwap({
,
]);
content = blockExplorerUrl && (
-
);
} else if (!errorKey && swapComplete) {
@@ -240,35 +229,13 @@ export default function AwaitingSwap({
,
]);
content = blockExplorerUrl && (
-
);
}
- const MakeAnotherSwap = () => {
- return (
-
- {
- trackEvent({
- event: 'Make Another Swap',
- category: EVENT.CATEGORIES.SWAPS,
- sensitiveProperties,
- });
- await dispatch(navigateBackToBuildQuote(history));
- dispatch(setSwapsFromToken(defaultSwapsToken));
- }}
- >
- {t('makeAnotherSwap')}
-
-
- );
- };
-
useEffect(() => {
if (errorKey) {
// If there was an error, stop polling for quotes.
@@ -291,7 +258,9 @@ export default function AwaitingSwap({
{descriptionText}
{content}
- {!errorKey && swapComplete ? : null}
+ {!errorKey && swapComplete ? (
+
+ ) : null}
{
if (errorKey === OFFLINE_FOR_MAINTENANCE) {
diff --git a/ui/pages/swaps/awaiting-swap/index.scss b/ui/pages/swaps/awaiting-swap/index.scss
index 0750ace6f..2dd865fd3 100644
--- a/ui/pages/swaps/awaiting-swap/index.scss
+++ b/ui/pages/swaps/awaiting-swap/index.scss
@@ -20,10 +20,6 @@
justify-content: center;
}
- a {
- color: var(--color-primary-default);
- }
-
&__status-image {
margin-top: 12px;
margin-bottom: 16px;
@@ -64,7 +60,6 @@
font-weight: bold;
}
- &__view-on-etherscan,
&__support-link {
color: var(--color-primary-default);
margin-top: 24px;
@@ -75,20 +70,6 @@
@include H6;
}
- &__view-on-etherscan {
- @include H7;
-
- transition: opacity 1s ease-in-out;
- }
-
- &__view-on-etherscan--invisible {
- opacity: 0;
- }
-
- &__view-on-etherscan--visible {
- opacity: 1;
- }
-
&__amount-and-symbol {
color: var(--color-text-default);
font-weight: bold;
diff --git a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/__snapshots__/view-on-ether-scan-link.test.js.snap b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/__snapshots__/view-on-ether-scan-link.test.js.snap
deleted file mode 100644
index 89d31d36d..000000000
--- a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/__snapshots__/view-on-ether-scan-link.test.js.snap
+++ /dev/null
@@ -1,21 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`ViewOnEtherScanLink renders the component with a custom block explorer link 1`] = `
-
-
- View Swap at custom-blockchain.explorer
-
-
-`;
-
-exports[`ViewOnEtherScanLink renders the component with initial props 1`] = `
-
-
- View Swap on Etherscan
-
-
-`;
diff --git a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/index.js b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/index.js
deleted file mode 100644
index 6aa4a3347..000000000
--- a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './view-on-ether-scan-link';
diff --git a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js
deleted file mode 100644
index baa13ef02..000000000
--- a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import React, { useContext } from 'react';
-import PropTypes from 'prop-types';
-import classnames from 'classnames';
-import { I18nContext } from '../../../../contexts/i18n';
-import { getURLHostName } from '../../../../helpers/utils/util';
-import { MetaMetricsContext } from '../../../../contexts/metametrics';
-import { EVENT } from '../../../../../shared/constants/metametrics';
-
-export default function ViewOnEtherScanLink({
- txHash,
- blockExplorerUrl,
- isCustomBlockExplorerUrl,
-}) {
- const t = useContext(I18nContext);
- const trackEvent = useContext(MetaMetricsContext);
-
- return (
- {
- trackEvent({
- event: 'Clicked Block Explorer Link',
- category: EVENT.CATEGORIES.SWAPS,
- properties: {
- link_type: 'Transaction Block Explorer',
- action: 'Swap Transaction',
- block_explorer_domain: getURLHostName(blockExplorerUrl),
- },
- });
- global.platform.openTab({ url: blockExplorerUrl });
- }}
- >
- {isCustomBlockExplorerUrl
- ? t('viewOnCustomBlockExplorer', [
- t('blockExplorerSwapAction'),
- getURLHostName(blockExplorerUrl),
- ])
- : t('viewOnEtherscan', [t('blockExplorerSwapAction')])}
-
- );
-}
-
-ViewOnEtherScanLink.propTypes = {
- txHash: PropTypes.string,
- blockExplorerUrl: PropTypes.string,
- isCustomBlockExplorerUrl: PropTypes.bool,
-};
diff --git a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js b/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js
deleted file mode 100644
index 0fc96d87d..000000000
--- a/ui/pages/swaps/awaiting-swap/view-on-ether-scan-link/view-on-ether-scan-link.test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-
-import { renderWithProvider } from '../../../../../test/jest';
-import ViewOnEtherScanLink from '.';
-
-const createProps = (customProps = {}) => {
- return {
- txHash:
- '0x58e5a0fc7fbc849eddc100d44e86276168a8c7baaa5604e44ba6f5eb8ba1b7eb',
- blockExplorerUrl: 'https://block.explorer',
- isCustomBlockExplorerUrl: false,
- ...customProps,
- };
-};
-
-describe('ViewOnEtherScanLink', () => {
- it('renders the component with initial props', () => {
- const { container, getByText } = renderWithProvider(
- ,
- );
- expect(getByText('View Swap on Etherscan')).toBeInTheDocument();
- expect(container).toMatchSnapshot();
- });
-
- it('renders the component with a custom block explorer link', () => {
- const { container, getByText } = renderWithProvider(
- ,
- );
- expect(
- getByText('View Swap at custom-blockchain.explorer'),
- ).toBeInTheDocument();
- expect(container).toMatchSnapshot();
- });
-});
diff --git a/ui/pages/swaps/create-new-swap/create-new-swap.js b/ui/pages/swaps/create-new-swap/create-new-swap.js
new file mode 100644
index 000000000..273908549
--- /dev/null
+++ b/ui/pages/swaps/create-new-swap/create-new-swap.js
@@ -0,0 +1,47 @@
+import React, { useContext } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import PropTypes from 'prop-types';
+import { useHistory } from 'react-router-dom';
+import isEqual from 'lodash/isEqual';
+
+import Box from '../../../components/ui/box';
+import { I18nContext } from '../../../contexts/i18n';
+import { MetaMetricsContext } from '../../../contexts/metametrics';
+import { EVENT } from '../../../../shared/constants/metametrics';
+import {
+ navigateBackToBuildQuote,
+ setSwapsFromToken,
+} from '../../../ducks/swaps/swaps';
+import { DEFAULT_ROUTE } from '../../../helpers/constants/routes';
+import { getSwapsDefaultToken } from '../../../selectors';
+
+export default function CreateNewSwap({ sensitiveTrackingProperties }) {
+ const t = useContext(I18nContext);
+ const trackEvent = useContext(MetaMetricsContext);
+ const dispatch = useDispatch();
+ const history = useHistory();
+ const defaultSwapsToken = useSelector(getSwapsDefaultToken, isEqual);
+
+ return (
+
+
+
+ );
+}
+
+CreateNewSwap.propTypes = {
+ sensitiveTrackingProperties: PropTypes.object.isRequired,
+};
diff --git a/ui/pages/swaps/create-new-swap/create-new-swap.test.js b/ui/pages/swaps/create-new-swap/create-new-swap.test.js
new file mode 100644
index 000000000..53835efff
--- /dev/null
+++ b/ui/pages/swaps/create-new-swap/create-new-swap.test.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import configureMockStore from 'redux-mock-store';
+
+import {
+ renderWithProvider,
+ createSwapsMockStore,
+} from '../../../../test/jest';
+import CreateNewSwap from '.';
+
+const createProps = (customProps = {}) => {
+ return {
+ sensitiveProperties: {},
+ ...customProps,
+ };
+};
+
+describe('CreateNewSwap', () => {
+ it('renders the component with initial props', () => {
+ const store = configureMockStore()(createSwapsMockStore());
+ const props = createProps();
+ const { getByText } = renderWithProvider(
+ ,
+ store,
+ );
+ expect(getByText('Create a new swap')).toBeInTheDocument();
+ });
+});
diff --git a/ui/pages/swaps/create-new-swap/index.js b/ui/pages/swaps/create-new-swap/index.js
new file mode 100644
index 000000000..d9e08ef8b
--- /dev/null
+++ b/ui/pages/swaps/create-new-swap/index.js
@@ -0,0 +1 @@
+export { default } from './create-new-swap';
diff --git a/ui/pages/swaps/create-new-swap/index.scss b/ui/pages/swaps/create-new-swap/index.scss
new file mode 100644
index 000000000..fb7beecf5
--- /dev/null
+++ b/ui/pages/swaps/create-new-swap/index.scss
@@ -0,0 +1,8 @@
+.create-new-swap {
+ button {
+ @include H5;
+
+ color: var(--color-primary-default);
+ background-color: transparent;
+ }
+}
diff --git a/ui/pages/swaps/index.scss b/ui/pages/swaps/index.scss
index faa2e8b9e..de6e67a64 100644
--- a/ui/pages/swaps/index.scss
+++ b/ui/pages/swaps/index.scss
@@ -15,6 +15,8 @@
@import 'swaps-footer/index';
@import 'view-quote/index';
@import 'import-token/index';
+@import 'create-new-swap/index';
+@import 'view-on-block-explorer/index';
.swaps {
display: flex;
diff --git a/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js b/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js
index c11b7b82e..85cc42f25 100644
--- a/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js
+++ b/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js
@@ -1,6 +1,7 @@
import React, { useContext, useEffect, useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
+import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import { useHistory } from 'react-router-dom';
+import { getBlockExplorerLink } from '@metamask/etherscan-link';
import { I18nContext } from '../../../contexts/i18n';
import {
@@ -22,7 +23,9 @@ import {
getUSDConversionRate,
conversionRateSelector,
getCurrentCurrency,
+ getRpcPrefsForCurrentProvider,
} from '../../../selectors';
+import { SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP } from '../../../../shared/constants/swaps';
import { getNativeCurrency } from '../../../ducks/metamask/metamask';
import {
DEFAULT_ROUTE,
@@ -54,6 +57,8 @@ import {
getFeeForSmartTransaction,
} from '../swaps.util';
import { MetaMetricsContext } from '../../../contexts/metametrics';
+import CreateNewSwap from '../create-new-swap';
+import ViewOnBlockExplorer from '../view-on-block-explorer';
import SuccessIcon from './success-icon';
import RevertedIcon from './reverted-icon';
import CanceledIcon from './canceled-icon';
@@ -79,12 +84,17 @@ export default function SmartTransactionStatus() {
const smartTransactionsOptInStatus = useSelector(
getSmartTransactionsOptInStatus,
);
+ const chainId = useSelector(getCurrentChainId);
+ const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider, shallowEqual);
const swapsNetworkConfig = useSelector(getSwapsNetworkConfig);
const smartTransactionsEnabled = useSelector(getSmartTransactionsEnabled);
const currentSmartTransactionsEnabled = useSelector(
getCurrentSmartTransactionsEnabled,
);
- const chainId = useSelector(getCurrentChainId);
+ const baseNetworkUrl =
+ rpcPrefs.blockExplorerUrl ??
+ SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP[chainId] ??
+ null;
const nativeCurrencySymbol = useSelector(getNativeCurrency);
const conversionRate = useSelector(conversionRateSelector);
const USDConversionRate = useSelector(getUSDConversionRate);
@@ -139,6 +149,7 @@ export default function SmartTransactionStatus() {
const showCloseButtonOnly =
isSmartTransactionPending ||
smartTransactionStatus === SMART_TRANSACTION_STATUSES.SUCCESS;
+ const txHash = latestSmartTransaction?.statusMetadata?.minedHash;
useEffect(() => {
trackEvent({
@@ -190,6 +201,7 @@ export default function SmartTransactionStatus() {
let description;
let subDescription;
let icon;
+ let blockExplorerUrl;
if (isSmartTransactionPending) {
if (cancelSwapLinkClicked) {
headerText = t('stxTryingToCancel');
@@ -238,6 +250,12 @@ export default function SmartTransactionStatus() {
]);
icon = ;
}
+ if (txHash && latestSmartTransactionUuid) {
+ blockExplorerUrl = getBlockExplorerLink(
+ { hash: txHash, chainId },
+ { blockExplorerUrl: baseNetworkUrl },
+ );
+ }
const showCancelSwapLink =
latestSmartTransaction.cancellable && !cancelSwapLinkClicked;
@@ -397,12 +415,18 @@ export default function SmartTransactionStatus() {
{description && (
{description}
)}
+ {blockExplorerUrl && (
+
+ )}
}
+ {smartTransactionStatus === SMART_TRANSACTION_STATUSES.SUCCESS ? (
+
+ ) : null}
{
if (showCloseButtonOnly) {
diff --git a/ui/pages/swaps/view-on-block-explorer/__snapshots__/view-on-block-explorer.test.js.snap b/ui/pages/swaps/view-on-block-explorer/__snapshots__/view-on-block-explorer.test.js.snap
new file mode 100644
index 000000000..e7b00963c
--- /dev/null
+++ b/ui/pages/swaps/view-on-block-explorer/__snapshots__/view-on-block-explorer.test.js.snap
@@ -0,0 +1,13 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ViewOnBlockExplorer renders the component with initial props 1`] = `
+
+
+
+
+
+`;
diff --git a/ui/pages/swaps/view-on-block-explorer/index.js b/ui/pages/swaps/view-on-block-explorer/index.js
new file mode 100644
index 000000000..7f7e427fc
--- /dev/null
+++ b/ui/pages/swaps/view-on-block-explorer/index.js
@@ -0,0 +1 @@
+export { default } from './view-on-block-explorer';
diff --git a/ui/pages/swaps/view-on-block-explorer/index.scss b/ui/pages/swaps/view-on-block-explorer/index.scss
new file mode 100644
index 000000000..ed05e956c
--- /dev/null
+++ b/ui/pages/swaps/view-on-block-explorer/index.scss
@@ -0,0 +1,8 @@
+.view-on-block-explorer {
+ button {
+ @include H7;
+
+ color: var(--color-primary-default);
+ background-color: transparent;
+ }
+}
diff --git a/ui/pages/swaps/view-on-block-explorer/view-on-block-explorer.js b/ui/pages/swaps/view-on-block-explorer/view-on-block-explorer.js
new file mode 100644
index 000000000..145ca010f
--- /dev/null
+++ b/ui/pages/swaps/view-on-block-explorer/view-on-block-explorer.js
@@ -0,0 +1,47 @@
+import React, { useContext } from 'react';
+import PropTypes from 'prop-types';
+
+import Box from '../../../components/ui/box';
+import { I18nContext } from '../../../contexts/i18n';
+import { getURLHostName } from '../../../helpers/utils/util';
+import { MetaMetricsContext } from '../../../contexts/metametrics';
+import { EVENT } from '../../../../shared/constants/metametrics';
+
+export default function ViewOnBlockExplorer({
+ blockExplorerUrl,
+ sensitiveTrackingProperties,
+}) {
+ const t = useContext(I18nContext);
+ const trackEvent = useContext(MetaMetricsContext);
+ const blockExplorerHostName = getURLHostName(blockExplorerUrl);
+
+ return (
+
+
+
+ );
+}
+
+ViewOnBlockExplorer.propTypes = {
+ blockExplorerUrl: PropTypes.string.isRequired,
+ sensitiveTrackingProperties: PropTypes.object.isRequired,
+};
diff --git a/ui/pages/swaps/view-on-block-explorer/view-on-block-explorer.test.js b/ui/pages/swaps/view-on-block-explorer/view-on-block-explorer.test.js
new file mode 100644
index 000000000..e2917a68f
--- /dev/null
+++ b/ui/pages/swaps/view-on-block-explorer/view-on-block-explorer.test.js
@@ -0,0 +1,23 @@
+import React from 'react';
+
+import { renderWithProvider } from '../../../../test/jest';
+import ViewOnBlockExplorer from '.';
+
+const createProps = (customProps = {}) => {
+ return {
+ txHash:
+ '0x58e5a0fc7fbc849eddc100d44e86276168a8c7baaa5604e44ba6f5eb8ba1b7eb',
+ blockExplorerUrl: 'https://etherscan.io',
+ ...customProps,
+ };
+};
+
+describe('ViewOnBlockExplorer', () => {
+ it('renders the component with initial props', () => {
+ const { container, getByText } = renderWithProvider(
+ ,
+ );
+ expect(getByText('View Swap at etherscan.io')).toBeInTheDocument();
+ expect(container).toMatchSnapshot();
+ });
+});