mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
prefer chainId when building block explorer urls (#10587)
This commit is contained in:
parent
92680cf56f
commit
38fe75b7d9
@ -319,7 +319,15 @@ export default class MetamaskController extends EventEmitter {
|
||||
status === TRANSACTION_STATUSES.FAILED
|
||||
) {
|
||||
const txMeta = this.txController.txStateManager.getTx(txId);
|
||||
this.platform.showTransactionNotification(txMeta);
|
||||
const frequentRpcListDetail = this.preferencesController.getFrequentRpcListDetail();
|
||||
let rpcPrefs = {};
|
||||
if (txMeta.chainId) {
|
||||
const rpcSettings = frequentRpcListDetail.find(
|
||||
(rpc) => txMeta.chainId === rpc.chainId,
|
||||
);
|
||||
rpcPrefs = rpcSettings?.rpcPrefs ?? {};
|
||||
}
|
||||
this.platform.showTransactionNotification(txMeta, rpcPrefs);
|
||||
|
||||
const { txReceipt } = txMeta;
|
||||
if (txReceipt && txReceipt.status === '0x0') {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import extension from 'extensionizer';
|
||||
import { createExplorerLink as explorerLink } from '@metamask/etherscan-link';
|
||||
import { getEnvironmentType, checkForError } from '../lib/util';
|
||||
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
|
||||
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction';
|
||||
import { getBlockExplorerUrlForTx } from '../../../shared/modules/transaction.utils';
|
||||
|
||||
export default class ExtensionPlatform {
|
||||
//
|
||||
@ -110,7 +110,7 @@ export default class ExtensionPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
showTransactionNotification(txMeta) {
|
||||
showTransactionNotification(txMeta, rpcPrefs) {
|
||||
const { status, txReceipt: { status: receiptStatus } = {} } = txMeta;
|
||||
|
||||
if (status === TRANSACTION_STATUSES.CONFIRMED) {
|
||||
@ -120,7 +120,7 @@ export default class ExtensionPlatform {
|
||||
txMeta,
|
||||
'Transaction encountered an error.',
|
||||
)
|
||||
: this._showConfirmedTransaction(txMeta);
|
||||
: this._showConfirmedTransaction(txMeta, rpcPrefs);
|
||||
} else if (status === TRANSACTION_STATUSES.FAILED) {
|
||||
this._showFailedTransaction(txMeta);
|
||||
}
|
||||
@ -189,10 +189,10 @@ export default class ExtensionPlatform {
|
||||
});
|
||||
}
|
||||
|
||||
_showConfirmedTransaction(txMeta) {
|
||||
_showConfirmedTransaction(txMeta, rpcPrefs) {
|
||||
this._subscribeToNotificationClicked();
|
||||
|
||||
const url = explorerLink(txMeta.hash, txMeta.metamaskNetworkId);
|
||||
const url = getBlockExplorerUrlForTx(txMeta, rpcPrefs);
|
||||
const nonce = parseInt(txMeta.txParams.nonce, 16);
|
||||
|
||||
const title = 'Confirmed transaction';
|
||||
|
@ -20,9 +20,9 @@
|
||||
"forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010",
|
||||
"dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'",
|
||||
"sendwithprivatedapp": "node development/static-server.js test/e2e/send-eth-with-private-key-test --port 8080",
|
||||
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive \"test/unit/**/*.test.js\" \"ui/app/**/*.test.js\"",
|
||||
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive \"test/unit/**/*.test.js\" \"ui/app/**/*.test.js\" \"shared/**/*.test.js\"",
|
||||
"test:unit:global": "mocha --exit --require test/env.js --require test/setup.js --recursive test/unit-global/*.test.js",
|
||||
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --recursive \"test/unit/{,**/!(permissions)}/*.test.js\" \"ui/app/**/*.test.js\"",
|
||||
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --recursive \"test/unit/{,**/!(permissions)}/*.test.js\" \"ui/app/**/*.test.js\" \"shared/**/*.test.js\"",
|
||||
"test:unit:strict": "mocha --exit --require test/env.js --require test/setup.js --recursive \"test/unit/**/permissions/*.test.js\"",
|
||||
"test:unit:path": "mocha --exit --require test/env.js --require test/setup.js --recursive",
|
||||
"test:e2e:chrome": "SELENIUM_BROWSER=chrome test/e2e/run-all.sh",
|
||||
@ -45,7 +45,7 @@
|
||||
"verify-locales": "node ./development/verify-locale-strings.js",
|
||||
"verify-locales:fix": "node ./development/verify-locale-strings.js --fix",
|
||||
"mozilla-lint": "addons-linter dist/firefox",
|
||||
"watch": "mocha --watch --require test/env.js --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/app/**/*.test.js\"",
|
||||
"watch": "mocha --watch --require test/env.js --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/app/**/*.test.js\" \"shared/**/*.test.js\"",
|
||||
"devtools:react": "react-devtools",
|
||||
"devtools:redux": "remotedev --hostname=localhost --port=8000",
|
||||
"start:dev": "concurrently -k -n build,react,redux yarn:start yarn:devtools:react yarn:devtools:redux",
|
||||
|
96
shared/modules/tests/transaction.utils.test.js
Normal file
96
shared/modules/tests/transaction.utils.test.js
Normal file
@ -0,0 +1,96 @@
|
||||
import assert from 'assert';
|
||||
import {
|
||||
MAINNET_CHAIN_ID,
|
||||
MAINNET_NETWORK_ID,
|
||||
ROPSTEN_CHAIN_ID,
|
||||
ROPSTEN_NETWORK_ID,
|
||||
} from '../../constants/network';
|
||||
import { getBlockExplorerUrlForTx } from '../transaction.utils';
|
||||
|
||||
const tests = [
|
||||
{
|
||||
expected: 'https://etherscan.io/tx/0xabcd',
|
||||
transaction: {
|
||||
metamaskNetworkId: MAINNET_NETWORK_ID,
|
||||
hash: '0xabcd',
|
||||
},
|
||||
},
|
||||
{
|
||||
expected: 'https://ropsten.etherscan.io/tx/0xdef0',
|
||||
transaction: {
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
hash: '0xdef0',
|
||||
},
|
||||
rpcPrefs: {},
|
||||
},
|
||||
{
|
||||
// test handling of `blockExplorerUrl` for a custom RPC
|
||||
expected: 'https://block.explorer/tx/0xabcd',
|
||||
transaction: {
|
||||
metamaskNetworkId: '31',
|
||||
hash: '0xabcd',
|
||||
},
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://block.explorer',
|
||||
},
|
||||
},
|
||||
{
|
||||
// test handling of trailing `/` in `blockExplorerUrl` for a custom RPC
|
||||
expected: 'https://another.block.explorer/tx/0xdef0',
|
||||
transaction: {
|
||||
networkId: '33',
|
||||
hash: '0xdef0',
|
||||
},
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://another.block.explorer/',
|
||||
},
|
||||
},
|
||||
{
|
||||
expected: 'https://etherscan.io/tx/0xabcd',
|
||||
transaction: {
|
||||
chainId: MAINNET_CHAIN_ID,
|
||||
hash: '0xabcd',
|
||||
},
|
||||
},
|
||||
{
|
||||
expected: 'https://ropsten.etherscan.io/tx/0xdef0',
|
||||
transaction: {
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
hash: '0xdef0',
|
||||
},
|
||||
rpcPrefs: {},
|
||||
},
|
||||
{
|
||||
// test handling of `blockExplorerUrl` for a custom RPC
|
||||
expected: 'https://block.explorer/tx/0xabcd',
|
||||
transaction: {
|
||||
chainId: '0x1f',
|
||||
hash: '0xabcd',
|
||||
},
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://block.explorer',
|
||||
},
|
||||
},
|
||||
{
|
||||
// test handling of trailing `/` in `blockExplorerUrl` for a custom RPC
|
||||
expected: 'https://another.block.explorer/tx/0xdef0',
|
||||
transaction: {
|
||||
chainId: '0x21',
|
||||
hash: '0xdef0',
|
||||
},
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://another.block.explorer/',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('getBlockExplorerUrlForTx', function () {
|
||||
tests.forEach((test) => {
|
||||
it(`should return '${test.expected}' for transaction with hash: '${test.transaction.hash}'`, function () {
|
||||
assert.strictEqual(
|
||||
getBlockExplorerUrlForTx(test.transaction, test.rpcPrefs),
|
||||
test.expected,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,6 +1,37 @@
|
||||
import {
|
||||
createExplorerLink,
|
||||
createExplorerLinkForChain,
|
||||
} from '@metamask/etherscan-link';
|
||||
|
||||
export function transactionMatchesNetwork(transaction, chainId, networkId) {
|
||||
if (typeof transaction.chainId !== 'undefined') {
|
||||
return transaction.chainId === chainId;
|
||||
}
|
||||
return transaction.metamaskNetworkId === networkId;
|
||||
}
|
||||
|
||||
/**
|
||||
* build the etherscan link for a transaction by either chainId, if available
|
||||
* or metamaskNetworkId as a fallback. If rpcPrefs is provided will build the
|
||||
* url for the provided blockExplorerUrl.
|
||||
*
|
||||
* @param {Object} transaction - a transaction object from state
|
||||
* @param {string} [transaction.metamaskNetworkId] - network id tx occurred on
|
||||
* @param {string} [transaction.chainId] - chain id tx occurred on
|
||||
* @param {string} [transaction.hash] - hash of the transaction
|
||||
* @param {Object} [rpcPrefs] - the rpc preferences for the current RPC network
|
||||
* @param {string} [rpcPrefs.blockExplorerUrl] - the block explorer url for RPC
|
||||
* networks
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getBlockExplorerUrlForTx(transaction, rpcPrefs = {}) {
|
||||
if (rpcPrefs.blockExplorerUrl) {
|
||||
return `${rpcPrefs.blockExplorerUrl.replace(/\/+$/u, '')}/tx/${
|
||||
transaction.hash
|
||||
}`;
|
||||
}
|
||||
if (transaction.chainId) {
|
||||
return createExplorerLinkForChain(transaction.hash, transaction.chainId);
|
||||
}
|
||||
return createExplorerLink(transaction.hash, transaction.metamaskNetworkId);
|
||||
}
|
||||
|
@ -19,12 +19,42 @@ describe('TransactionActivityLog container', function () {
|
||||
metamask: {
|
||||
conversionRate: 280.45,
|
||||
nativeCurrency: 'ETH',
|
||||
frequentRpcListDetail: [],
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepStrictEqual(mapStateToProps(mockState), {
|
||||
conversionRate: 280.45,
|
||||
nativeCurrency: 'ETH',
|
||||
rpcPrefs: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the correct props when on a custom network', function () {
|
||||
const mockState = {
|
||||
metamask: {
|
||||
conversionRate: 280.45,
|
||||
nativeCurrency: 'ETH',
|
||||
frequentRpcListDetail: [
|
||||
{
|
||||
rpcUrl: 'https://customnetwork.com/',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://customblockexplorer.com/',
|
||||
},
|
||||
},
|
||||
],
|
||||
provider: {
|
||||
rpcUrl: 'https://customnetwork.com/',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepStrictEqual(mapStateToProps(mockState), {
|
||||
conversionRate: 280.45,
|
||||
nativeCurrency: 'ETH',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://customblockexplorer.com/',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,8 @@
|
||||
import assert from 'assert';
|
||||
import {
|
||||
ROPSTEN_CHAIN_ID,
|
||||
ROPSTEN_NETWORK_ID,
|
||||
} from '../../../../../../shared/constants/network';
|
||||
import {
|
||||
TRANSACTION_STATUSES,
|
||||
TRANSACTION_TYPES,
|
||||
@ -24,7 +28,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
id: 6400627574331058,
|
||||
time: 1543958845581,
|
||||
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||
metamaskNetworkId: '3',
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
loadingDefaults: true,
|
||||
txParams: {
|
||||
from: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706',
|
||||
@ -71,7 +76,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
],
|
||||
id: 6400627574331058,
|
||||
loadingDefaults: false,
|
||||
metamaskNetworkId: '3',
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
status: TRANSACTION_STATUSES.DROPPED,
|
||||
submittedTime: 1543958848135,
|
||||
time: 1543958845581,
|
||||
@ -93,7 +99,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
id: 6400627574331060,
|
||||
time: 1543958857697,
|
||||
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||
metamaskNetworkId: '3',
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
loadingDefaults: false,
|
||||
txParams: {
|
||||
from: '0x50a9d56c2b8ba9a5c7f2c08c3d26e0499f23a706',
|
||||
@ -163,7 +170,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
id: 6400627574331060,
|
||||
lastGasPrice: '0x4190ab00',
|
||||
loadingDefaults: false,
|
||||
metamaskNetworkId: '3',
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
status: TRANSACTION_STATUSES.CONFIRMED,
|
||||
submittedTime: 1543958860054,
|
||||
time: 1543958857697,
|
||||
@ -185,6 +193,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
const expected = [
|
||||
{
|
||||
id: 6400627574331058,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
hash:
|
||||
'0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3',
|
||||
eventKey: 'transactionCreated',
|
||||
@ -193,6 +203,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
},
|
||||
{
|
||||
id: 6400627574331058,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
hash:
|
||||
'0xa14f13d36b3901e352ce3a7acb9b47b001e5a3370f06232a0953c6fc6fad91b3',
|
||||
eventKey: 'transactionSubmitted',
|
||||
@ -201,6 +213,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
},
|
||||
{
|
||||
id: 6400627574331060,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
hash:
|
||||
'0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33',
|
||||
eventKey: 'transactionResubmitted',
|
||||
@ -209,6 +223,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
},
|
||||
{
|
||||
id: 6400627574331060,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
hash:
|
||||
'0xecbe181ee67c4291d04a7cb9ffbf1d5d831e4fbaa89994fd06bab5dd4cc79b33',
|
||||
eventKey: 'transactionConfirmed',
|
||||
@ -249,7 +265,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
{
|
||||
id: 5559712943815343,
|
||||
loadingDefaults: true,
|
||||
metamaskNetworkId: '3',
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||
time: 1535507561452,
|
||||
txParams: {
|
||||
@ -389,6 +406,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
value: '0x2386f26fc10000',
|
||||
},
|
||||
hash: '0xabc',
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
};
|
||||
|
||||
const expectedResult = [
|
||||
@ -398,6 +417,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
value: '0x2386f26fc10000',
|
||||
id: 1,
|
||||
hash: '0xabc',
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
},
|
||||
{
|
||||
eventKey: 'transactionSubmitted',
|
||||
@ -405,6 +426,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
value: '0x2632e314a000',
|
||||
id: 1,
|
||||
hash: '0xabc',
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
},
|
||||
{
|
||||
eventKey: 'transactionConfirmed',
|
||||
@ -412,6 +435,8 @@ describe('TransactionActivityLog utils', function () {
|
||||
value: '0x2632e314a000',
|
||||
id: 1,
|
||||
hash: '0xabc',
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
metamaskNetworkId: ROPSTEN_NETWORK_ID,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { createExplorerLink } from '@metamask/etherscan-link';
|
||||
|
||||
import {
|
||||
getEthConversionFromWeiHex,
|
||||
getValueFromWeiHex,
|
||||
} from '../../../helpers/utils/conversions.util';
|
||||
import { formatDate } from '../../../helpers/utils/util';
|
||||
import { getBlockExplorerUrlForTx } from '../../../../../shared/modules/transaction.utils';
|
||||
import TransactionActivityLogIcon from './transaction-activity-log-icon';
|
||||
import { CONFIRMED_STATUS } from './transaction-activity-log.constants';
|
||||
|
||||
@ -28,14 +28,14 @@ export default class TransactionActivityLog extends PureComponent {
|
||||
onRetry: PropTypes.func,
|
||||
primaryTransaction: PropTypes.object,
|
||||
isEarliestNonce: PropTypes.bool,
|
||||
rpcPrefs: PropTypes.object,
|
||||
};
|
||||
|
||||
handleActivityClick = (hash) => {
|
||||
const { primaryTransaction } = this.props;
|
||||
const { metamaskNetworkId } = primaryTransaction;
|
||||
|
||||
const etherscanUrl = createExplorerLink(hash, metamaskNetworkId);
|
||||
|
||||
handleActivityClick = (activity) => {
|
||||
const etherscanUrl = getBlockExplorerUrlForTx(
|
||||
activity,
|
||||
this.props.rpcPrefs,
|
||||
);
|
||||
global.platform.openTab({ url: etherscanUrl });
|
||||
};
|
||||
|
||||
@ -79,7 +79,7 @@ export default class TransactionActivityLog extends PureComponent {
|
||||
|
||||
renderActivity(activity, index) {
|
||||
const { conversionRate, nativeCurrency } = this.props;
|
||||
const { eventKey, value, timestamp, hash } = activity;
|
||||
const { eventKey, value, timestamp } = activity;
|
||||
const ethValue =
|
||||
index === 0
|
||||
? `${getValueFromWeiHex({
|
||||
@ -111,7 +111,7 @@ export default class TransactionActivityLog extends PureComponent {
|
||||
<div
|
||||
className="transaction-activity-log__activity-text"
|
||||
title={activityText}
|
||||
onClick={() => this.handleActivityClick(hash)}
|
||||
onClick={() => this.handleActivityClick(activity)}
|
||||
>
|
||||
{activityText}
|
||||
</div>
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { findLastIndex } from 'lodash';
|
||||
import { conversionRateSelector, getNativeCurrency } from '../../../selectors';
|
||||
import {
|
||||
conversionRateSelector,
|
||||
getNativeCurrency,
|
||||
getRpcPrefsForCurrentProvider,
|
||||
} from '../../../selectors';
|
||||
import TransactionActivityLog from './transaction-activity-log.component';
|
||||
import { combineTransactionHistories } from './transaction-activity-log.util';
|
||||
import {
|
||||
@ -15,6 +19,7 @@ const mapStateToProps = (state) => {
|
||||
return {
|
||||
conversionRate: conversionRateSelector(state),
|
||||
nativeCurrency: getNativeCurrency(state),
|
||||
rpcPrefs: getRpcPrefsForCurrentProvider(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -49,6 +49,8 @@ const statusHash = {
|
||||
export function getActivities(transaction, isFirstTransaction = false) {
|
||||
const {
|
||||
id,
|
||||
chainId,
|
||||
metamaskNetworkId,
|
||||
hash,
|
||||
history = [],
|
||||
txParams: { gas: paramsGasLimit, gasPrice: paramsGasPrice },
|
||||
@ -76,6 +78,8 @@ export function getActivities(transaction, isFirstTransaction = false) {
|
||||
return acc.concat({
|
||||
id,
|
||||
hash,
|
||||
chainId,
|
||||
metamaskNetworkId,
|
||||
eventKey: TRANSACTION_CREATED_EVENT,
|
||||
timestamp,
|
||||
value,
|
||||
@ -127,6 +131,8 @@ export function getActivities(transaction, isFirstTransaction = false) {
|
||||
hash,
|
||||
eventKey,
|
||||
timestamp,
|
||||
chainId,
|
||||
metamaskNetworkId,
|
||||
value: gasFee,
|
||||
});
|
||||
}
|
||||
@ -165,6 +171,8 @@ export function getActivities(transaction, isFirstTransaction = false) {
|
||||
events.push({
|
||||
id,
|
||||
hash,
|
||||
chainId,
|
||||
metamaskNetworkId,
|
||||
eventKey: TRANSACTION_UPDATED_EVENT,
|
||||
timestamp,
|
||||
});
|
||||
@ -185,6 +193,8 @@ export function getActivities(transaction, isFirstTransaction = false) {
|
||||
? historyActivities.concat({
|
||||
id,
|
||||
hash,
|
||||
chainId,
|
||||
metamaskNetworkId,
|
||||
eventKey: TRANSACTION_ERRORED_EVENT,
|
||||
})
|
||||
: historyActivities;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import copyToClipboard from 'copy-to-clipboard';
|
||||
import { getBlockExplorerUrlForTx } from '../../../helpers/utils/transactions.util';
|
||||
import SenderToRecipient from '../../ui/sender-to-recipient';
|
||||
import { FLAT_VARIANT } from '../../ui/sender-to-recipient/sender-to-recipient.constants';
|
||||
import TransactionActivityLog from '../transaction-activity-log';
|
||||
@ -10,6 +9,7 @@ import Button from '../../ui/button';
|
||||
import Tooltip from '../../ui/tooltip';
|
||||
import Copy from '../../ui/icon/copy-icon.component';
|
||||
import Popover from '../../ui/popover';
|
||||
import { getBlockExplorerUrlForTx } from '../../../../../shared/modules/transaction.utils';
|
||||
|
||||
export default class TransactionListItemDetails extends PureComponent {
|
||||
static contextTypes = {
|
||||
@ -51,7 +51,6 @@ export default class TransactionListItemDetails extends PureComponent {
|
||||
transactionGroup: { primaryTransaction },
|
||||
rpcPrefs,
|
||||
} = this.props;
|
||||
const { hash, metamaskNetworkId } = primaryTransaction;
|
||||
|
||||
this.context.metricsEvent({
|
||||
eventOpts: {
|
||||
@ -62,7 +61,7 @@ export default class TransactionListItemDetails extends PureComponent {
|
||||
});
|
||||
|
||||
global.platform.openTab({
|
||||
url: getBlockExplorerUrlForTx(metamaskNetworkId, hash, rpcPrefs),
|
||||
url: getBlockExplorerUrlForTx(primaryTransaction, rpcPrefs),
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,6 @@ import { MethodRegistry } from 'eth-method-registry';
|
||||
import abi from 'human-standard-token-abi';
|
||||
import { ethers } from 'ethers';
|
||||
import log from 'loglevel';
|
||||
import { createExplorerLink } from '@metamask/etherscan-link';
|
||||
|
||||
import { addHexPrefix } from '../../../../app/scripts/lib/util';
|
||||
import {
|
||||
@ -193,19 +192,6 @@ export function getStatusKey(transaction) {
|
||||
return transaction.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an external block explorer URL at which a transaction can be viewed.
|
||||
* @param {number} networkId
|
||||
* @param {string} hash
|
||||
* @param {Object} rpcPrefs
|
||||
*/
|
||||
export function getBlockExplorerUrlForTx(networkId, hash, rpcPrefs = {}) {
|
||||
if (rpcPrefs.blockExplorerUrl) {
|
||||
return `${rpcPrefs.blockExplorerUrl.replace(/\/+$/u, '')}/tx/${hash}`;
|
||||
}
|
||||
return createExplorerLink(hash, networkId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a title for the given transaction category.
|
||||
*
|
||||
|
@ -60,47 +60,4 @@ describe('Transactions utils', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBlockExplorerUrlForTx', function () {
|
||||
it('should return the correct block explorer url for a transaction', function () {
|
||||
const tests = [
|
||||
{
|
||||
expected: 'https://etherscan.io/tx/0xabcd',
|
||||
networkId: '1',
|
||||
hash: '0xabcd',
|
||||
},
|
||||
{
|
||||
expected: 'https://ropsten.etherscan.io/tx/0xdef0',
|
||||
networkId: '3',
|
||||
hash: '0xdef0',
|
||||
rpcPrefs: {},
|
||||
},
|
||||
{
|
||||
// test handling of `blockExplorerUrl` for a custom RPC
|
||||
expected: 'https://block.explorer/tx/0xabcd',
|
||||
networkId: '31',
|
||||
hash: '0xabcd',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://block.explorer',
|
||||
},
|
||||
},
|
||||
{
|
||||
// test handling of trailing `/` in `blockExplorerUrl` for a custom RPC
|
||||
expected: 'https://another.block.explorer/tx/0xdef0',
|
||||
networkId: '33',
|
||||
hash: '0xdef0',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://another.block.explorer/',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
tests.forEach(({ expected, networkId, hash, rpcPrefs }) => {
|
||||
assert.strictEqual(
|
||||
utils.getBlockExplorerUrlForTx(networkId, hash, rpcPrefs),
|
||||
expected,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,12 +2,12 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { createTokenTrackerLink } from '@metamask/etherscan-link';
|
||||
import { createTokenTrackerLinkForChain } from '@metamask/etherscan-link';
|
||||
|
||||
import TransactionList from '../../../components/app/transaction-list';
|
||||
import { TokenOverview } from '../../../components/app/wallet-overview';
|
||||
import {
|
||||
getCurrentNetworkId,
|
||||
getCurrentChainId,
|
||||
getSelectedIdentity,
|
||||
} from '../../../selectors/selectors';
|
||||
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes';
|
||||
@ -18,7 +18,7 @@ import TokenOptions from './token-options';
|
||||
|
||||
export default function TokenAsset({ token }) {
|
||||
const dispatch = useDispatch();
|
||||
const network = useSelector(getCurrentNetworkId);
|
||||
const chainId = useSelector(getCurrentChainId);
|
||||
const selectedIdentity = useSelector(getSelectedIdentity);
|
||||
const selectedAccountName = selectedIdentity.name;
|
||||
const selectedAddress = selectedIdentity.address;
|
||||
@ -36,9 +36,9 @@ export default function TokenAsset({ token }) {
|
||||
dispatch(showModal({ name: 'HIDE_TOKEN_CONFIRMATION', token }))
|
||||
}
|
||||
onViewEtherscan={() => {
|
||||
const url = createTokenTrackerLink(
|
||||
const url = createTokenTrackerLinkForChain(
|
||||
token.address,
|
||||
network,
|
||||
chainId,
|
||||
selectedAddress,
|
||||
);
|
||||
global.platform.openTab({ url });
|
||||
|
@ -6,7 +6,12 @@ import { useHistory } from 'react-router-dom';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import { useNewMetricEvent } from '../../../hooks/useMetricEvent';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics.new';
|
||||
import { getCurrentCurrency, getUSDConversionRate } from '../../../selectors';
|
||||
import {
|
||||
getCurrentChainId,
|
||||
getCurrentCurrency,
|
||||
getRpcPrefsForCurrentProvider,
|
||||
getUSDConversionRate,
|
||||
} from '../../../selectors';
|
||||
import {
|
||||
getUsedQuote,
|
||||
getFetchParams,
|
||||
@ -19,7 +24,6 @@ import {
|
||||
} from '../../../ducks/swaps/swaps';
|
||||
import Mascot from '../../../components/ui/mascot';
|
||||
import PulseLoader from '../../../components/ui/pulse-loader';
|
||||
import { getBlockExplorerUrlForTx } from '../../../helpers/utils/transactions.util';
|
||||
import {
|
||||
QUOTES_EXPIRED_ERROR,
|
||||
SWAP_FAILED_ERROR,
|
||||
@ -31,6 +35,7 @@ import { ASSET_ROUTE, DEFAULT_ROUTE } from '../../../helpers/constants/routes';
|
||||
|
||||
import { getRenderableNetworkFeesForQuote } from '../swaps.util';
|
||||
import SwapsFooter from '../swaps-footer';
|
||||
import { getBlockExplorerUrlForTx } from '../../../../../shared/modules/transaction.utils';
|
||||
import SwapFailureIcon from './swap-failure-icon';
|
||||
import SwapSuccessIcon from './swap-success-icon';
|
||||
import QuotesTimeoutIcon from './quotes-timeout-icon';
|
||||
@ -40,9 +45,7 @@ export default function AwaitingSwap({
|
||||
swapComplete,
|
||||
errorKey,
|
||||
txHash,
|
||||
networkId,
|
||||
tokensReceived,
|
||||
rpcPrefs,
|
||||
submittingSwap,
|
||||
inputValue,
|
||||
maxSlippage,
|
||||
@ -60,6 +63,8 @@ export default function AwaitingSwap({
|
||||
const swapsGasPrice = useSelector(getUsedSwapsGasPrice);
|
||||
const currentCurrency = useSelector(getCurrentCurrency);
|
||||
const usdConversionRate = useSelector(getUSDConversionRate);
|
||||
const chainId = useSelector(getCurrentChainId);
|
||||
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
|
||||
|
||||
const [trackedQuotesExpiredEvent, setTrackedQuotesExpiredEvent] = useState(
|
||||
false,
|
||||
@ -96,7 +101,7 @@ export default function AwaitingSwap({
|
||||
});
|
||||
|
||||
const blockExplorerUrl =
|
||||
txHash && getBlockExplorerUrlForTx(networkId, txHash, rpcPrefs);
|
||||
txHash && getBlockExplorerUrlForTx({ chainId, hash: txHash }, rpcPrefs);
|
||||
|
||||
let headerText;
|
||||
let statusImage;
|
||||
@ -240,10 +245,8 @@ export default function AwaitingSwap({
|
||||
|
||||
AwaitingSwap.propTypes = {
|
||||
swapComplete: PropTypes.bool,
|
||||
networkId: PropTypes.string.isRequired,
|
||||
txHash: PropTypes.string,
|
||||
tokensReceived: PropTypes.string,
|
||||
rpcPrefs: PropTypes.object.isRequired,
|
||||
errorKey: PropTypes.oneOf([
|
||||
QUOTES_EXPIRED_ERROR,
|
||||
SWAP_FAILED_ERROR,
|
||||
|
@ -11,7 +11,6 @@ import BigNumber from 'bignumber.js';
|
||||
import { I18nContext } from '../../contexts/i18n';
|
||||
import {
|
||||
getSelectedAccount,
|
||||
getCurrentNetworkId,
|
||||
getCurrentChainId,
|
||||
} from '../../selectors/selectors';
|
||||
import {
|
||||
@ -55,10 +54,7 @@ import {
|
||||
setBackgroundSwapRouteState,
|
||||
setSwapsErrorKey,
|
||||
} from '../../store/actions';
|
||||
import {
|
||||
currentNetworkTxListSelector,
|
||||
getRpcPrefsForCurrentProvider,
|
||||
} from '../../selectors';
|
||||
import { currentNetworkTxListSelector } from '../../selectors';
|
||||
import { useNewMetricEvent } from '../../hooks/useMetricEvent';
|
||||
|
||||
import FeatureToggledRoute from '../../helpers/higher-order-components/feature-toggled-route';
|
||||
@ -97,8 +93,6 @@ export default function Swap() {
|
||||
const tradeTxId = useSelector(getTradeTxId);
|
||||
const approveTxId = useSelector(getApproveTxId);
|
||||
const aggregatorMetadata = useSelector(getAggregatorMetadata);
|
||||
const networkId = useSelector(getCurrentNetworkId);
|
||||
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
|
||||
const fetchingQuotes = useSelector(getFetchingQuotes);
|
||||
let swapsErrorKey = useSelector(getSwapsErrorKey);
|
||||
const swapsEnabled = useSelector(getSwapsFeatureLiveness);
|
||||
@ -317,8 +311,6 @@ export default function Swap() {
|
||||
swapComplete={false}
|
||||
errorKey={swapsErrorKey}
|
||||
txHash={tradeTxData?.hash}
|
||||
networkId={networkId}
|
||||
rpcPrefs={rpcPrefs}
|
||||
inputValue={inputValue}
|
||||
maxSlippage={maxSlippage}
|
||||
submittedTime={tradeTxData?.submittedTime}
|
||||
@ -364,11 +356,7 @@ export default function Swap() {
|
||||
exact
|
||||
render={() => {
|
||||
return swapsEnabled === false ? (
|
||||
<AwaitingSwap
|
||||
errorKey={OFFLINE_FOR_MAINTENANCE}
|
||||
networkId={networkId}
|
||||
rpcPrefs={rpcPrefs}
|
||||
/>
|
||||
<AwaitingSwap errorKey={OFFLINE_FOR_MAINTENANCE} />
|
||||
) : (
|
||||
<Redirect to={{ pathname: BUILD_QUOTE_ROUTE }} />
|
||||
);
|
||||
@ -381,13 +369,11 @@ export default function Swap() {
|
||||
return routeState === 'awaiting' || tradeTxData ? (
|
||||
<AwaitingSwap
|
||||
swapComplete={tradeConfirmed}
|
||||
networkId={networkId}
|
||||
txHash={tradeTxData?.hash}
|
||||
tokensReceived={tokensReceived}
|
||||
submittingSwap={
|
||||
routeState === 'awaiting' && !(approveTxId || tradeTxId)
|
||||
}
|
||||
rpcPrefs={rpcPrefs}
|
||||
inputValue={inputValue}
|
||||
maxSlippage={maxSlippage}
|
||||
/>
|
||||
|
Loading…
Reference in New Issue
Block a user