mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
use etherscan-link for account-link (#10590)
This commit is contained in:
parent
38fe75b7d9
commit
aa37e30c08
@ -1,4 +1,8 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
import {
|
||||||
|
MAINNET_CHAIN_ID,
|
||||||
|
ROPSTEN_CHAIN_ID,
|
||||||
|
} from '../../../shared/constants/network';
|
||||||
import getAccountLink from '../../../ui/lib/account-link';
|
import getAccountLink from '../../../ui/lib/account-link';
|
||||||
|
|
||||||
describe('Account link', function () {
|
describe('Account link', function () {
|
||||||
@ -7,19 +11,19 @@ describe('Account link', function () {
|
|||||||
const tests = [
|
const tests = [
|
||||||
{
|
{
|
||||||
expected: 'https://etherscan.io/address/0xabcd',
|
expected: 'https://etherscan.io/address/0xabcd',
|
||||||
network: 1,
|
chainId: MAINNET_CHAIN_ID,
|
||||||
address: '0xabcd',
|
address: '0xabcd',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expected: 'https://ropsten.etherscan.io/address/0xdef0',
|
expected: 'https://ropsten.etherscan.io/address/0xdef0',
|
||||||
network: 3,
|
chainId: ROPSTEN_CHAIN_ID,
|
||||||
address: '0xdef0',
|
address: '0xdef0',
|
||||||
rpcPrefs: {},
|
rpcPrefs: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// test handling of `blockExplorerUrl` for a custom RPC
|
// test handling of `blockExplorerUrl` for a custom RPC
|
||||||
expected: 'https://block.explorer/address/0xabcd',
|
expected: 'https://block.explorer/address/0xabcd',
|
||||||
network: 31,
|
chainId: '0x21',
|
||||||
address: '0xabcd',
|
address: '0xabcd',
|
||||||
rpcPrefs: {
|
rpcPrefs: {
|
||||||
blockExplorerUrl: 'https://block.explorer',
|
blockExplorerUrl: 'https://block.explorer',
|
||||||
@ -28,7 +32,7 @@ describe('Account link', function () {
|
|||||||
{
|
{
|
||||||
// test handling of trailing `/` in `blockExplorerUrl` for a custom RPC
|
// test handling of trailing `/` in `blockExplorerUrl` for a custom RPC
|
||||||
expected: 'https://another.block.explorer/address/0xdef0',
|
expected: 'https://another.block.explorer/address/0xdef0',
|
||||||
network: 33,
|
chainId: '0x1f',
|
||||||
address: '0xdef0',
|
address: '0xdef0',
|
||||||
rpcPrefs: {
|
rpcPrefs: {
|
||||||
blockExplorerUrl: 'https://another.block.explorer/',
|
blockExplorerUrl: 'https://another.block.explorer/',
|
||||||
@ -36,8 +40,8 @@ describe('Account link', function () {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
tests.forEach(({ expected, address, network, rpcPrefs }) => {
|
tests.forEach(({ expected, address, chainId, rpcPrefs }) => {
|
||||||
assert.equal(getAccountLink(address, network, rpcPrefs), expected);
|
assert.equal(getAccountLink(address, chainId, rpcPrefs), expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -8,8 +8,8 @@ import { CONNECTED_ROUTE } from '../../../helpers/constants/routes';
|
|||||||
import { Menu, MenuItem } from '../../ui/menu';
|
import { Menu, MenuItem } from '../../ui/menu';
|
||||||
import getAccountLink from '../../../../lib/account-link';
|
import getAccountLink from '../../../../lib/account-link';
|
||||||
import {
|
import {
|
||||||
|
getCurrentChainId,
|
||||||
getCurrentKeyring,
|
getCurrentKeyring,
|
||||||
getCurrentNetwork,
|
|
||||||
getRpcPrefsForCurrentProvider,
|
getRpcPrefsForCurrentProvider,
|
||||||
getSelectedIdentity,
|
getSelectedIdentity,
|
||||||
} from '../../../selectors';
|
} from '../../../selectors';
|
||||||
@ -52,7 +52,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const keyring = useSelector(getCurrentKeyring);
|
const keyring = useSelector(getCurrentKeyring);
|
||||||
const network = useSelector(getCurrentNetwork);
|
const chainId = useSelector(getCurrentChainId);
|
||||||
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
|
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider);
|
||||||
const selectedIdentity = useSelector(getSelectedIdentity);
|
const selectedIdentity = useSelector(getSelectedIdentity);
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
viewOnEtherscanEvent();
|
viewOnEtherscanEvent();
|
||||||
global.platform.openTab({
|
global.platform.openTab({
|
||||||
url: getAccountLink(address, network, rpcPrefs),
|
url: getAccountLink(address, chainId, rpcPrefs),
|
||||||
});
|
});
|
||||||
onClose();
|
onClose();
|
||||||
}}
|
}}
|
||||||
|
@ -4,11 +4,14 @@ import { Provider } from 'react-redux';
|
|||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import { mountWithRouter } from '../../../../../../test/lib/render-helpers';
|
import { mountWithRouter } from '../../../../../../test/lib/render-helpers';
|
||||||
import MenuBar from '..';
|
import MenuBar from '..';
|
||||||
|
import { ROPSTEN_CHAIN_ID } from '../../../../../../shared/constants/network';
|
||||||
|
|
||||||
const initState = {
|
const initState = {
|
||||||
activeTab: {},
|
activeTab: {},
|
||||||
metamask: {
|
metamask: {
|
||||||
network: '1',
|
provider: {
|
||||||
|
chainId: ROPSTEN_CHAIN_ID,
|
||||||
|
},
|
||||||
selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
|
||||||
identities: {
|
identities: {
|
||||||
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
|
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
|
||||||
|
@ -9,7 +9,7 @@ import Button from '../../../ui/button';
|
|||||||
export default class AccountDetailsModal extends Component {
|
export default class AccountDetailsModal extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
selectedIdentity: PropTypes.object,
|
selectedIdentity: PropTypes.object,
|
||||||
network: PropTypes.string,
|
chainId: PropTypes.string,
|
||||||
showExportPrivateKeyModal: PropTypes.func,
|
showExportPrivateKeyModal: PropTypes.func,
|
||||||
setAccountLabel: PropTypes.func,
|
setAccountLabel: PropTypes.func,
|
||||||
keyrings: PropTypes.array,
|
keyrings: PropTypes.array,
|
||||||
@ -23,7 +23,7 @@ export default class AccountDetailsModal extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
selectedIdentity,
|
selectedIdentity,
|
||||||
network,
|
chainId,
|
||||||
showExportPrivateKeyModal,
|
showExportPrivateKeyModal,
|
||||||
setAccountLabel,
|
setAccountLabel,
|
||||||
keyrings,
|
keyrings,
|
||||||
@ -62,7 +62,7 @@ export default class AccountDetailsModal extends Component {
|
|||||||
className="account-details-modal__button"
|
className="account-details-modal__button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
global.platform.openTab({
|
global.platform.openTab({
|
||||||
url: getAccountLink(address, network, rpcPrefs),
|
url: getAccountLink(address, chainId, rpcPrefs),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -3,12 +3,13 @@ import { showModal, setAccountLabel } from '../../../../store/actions';
|
|||||||
import {
|
import {
|
||||||
getSelectedIdentity,
|
getSelectedIdentity,
|
||||||
getRpcPrefsForCurrentProvider,
|
getRpcPrefsForCurrentProvider,
|
||||||
|
getCurrentChainId,
|
||||||
} from '../../../../selectors';
|
} from '../../../../selectors';
|
||||||
import AccountDetailsModal from './account-details-modal.component';
|
import AccountDetailsModal from './account-details-modal.component';
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
return {
|
return {
|
||||||
network: state.metamask.network,
|
chainId: getCurrentChainId(state),
|
||||||
selectedIdentity: getSelectedIdentity(state),
|
selectedIdentity: getSelectedIdentity(state),
|
||||||
keyrings: state.metamask.keyrings,
|
keyrings: state.metamask.keyrings,
|
||||||
rpcPrefs: getRpcPrefsForCurrentProvider(state),
|
rpcPrefs: getRpcPrefsForCurrentProvider(state),
|
||||||
|
@ -10,7 +10,8 @@ export default class ConfirmRemoveAccount extends Component {
|
|||||||
hideModal: PropTypes.func.isRequired,
|
hideModal: PropTypes.func.isRequired,
|
||||||
removeAccount: PropTypes.func.isRequired,
|
removeAccount: PropTypes.func.isRequired,
|
||||||
identity: PropTypes.object.isRequired,
|
identity: PropTypes.object.isRequired,
|
||||||
network: PropTypes.string.isRequired,
|
chainId: PropTypes.string.isRequired,
|
||||||
|
rpcPrefs: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
@ -49,7 +50,11 @@ export default class ConfirmRemoveAccount extends Component {
|
|||||||
<div className="confirm-remove-account__account__link">
|
<div className="confirm-remove-account__account__link">
|
||||||
<a
|
<a
|
||||||
className=""
|
className=""
|
||||||
href={getAccountLink(identity.address, this.props.network)}
|
href={getAccountLink(
|
||||||
|
identity.address,
|
||||||
|
this.props.chainId,
|
||||||
|
this.props.rpcPrefs,
|
||||||
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
title={this.context.t('etherscanView')}
|
title={this.context.t('etherscanView')}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { compose } from 'redux';
|
import { compose } from 'redux';
|
||||||
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
|
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
|
||||||
|
import {
|
||||||
|
getCurrentChainId,
|
||||||
|
getRpcPrefsForCurrentProvider,
|
||||||
|
} from '../../../../selectors';
|
||||||
import { removeAccount } from '../../../../store/actions';
|
import { removeAccount } from '../../../../store/actions';
|
||||||
import ConfirmRemoveAccount from './confirm-remove-account.component';
|
import ConfirmRemoveAccount from './confirm-remove-account.component';
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
return {
|
return {
|
||||||
network: state.metamask.network,
|
chainId: getCurrentChainId(state),
|
||||||
|
rpcPrefs: getRpcPrefsForCurrentProvider(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,7 +112,11 @@ class AccountList extends Component {
|
|||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
className="hw-account-list__item__link"
|
className="hw-account-list__item__link"
|
||||||
href={getAccountLink(account.address, this.props.network)}
|
href={getAccountLink(
|
||||||
|
account.address,
|
||||||
|
this.props.chainId,
|
||||||
|
this.props.rpcPrefs,
|
||||||
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
title={this.context.t('etherscanView')}
|
title={this.context.t('etherscanView')}
|
||||||
@ -211,7 +215,8 @@ AccountList.propTypes = {
|
|||||||
onAccountChange: PropTypes.func.isRequired,
|
onAccountChange: PropTypes.func.isRequired,
|
||||||
onForgetDevice: PropTypes.func.isRequired,
|
onForgetDevice: PropTypes.func.isRequired,
|
||||||
getPage: PropTypes.func.isRequired,
|
getPage: PropTypes.func.isRequired,
|
||||||
network: PropTypes.string,
|
chainId: PropTypes.string,
|
||||||
|
rpcPrefs: PropTypes.object,
|
||||||
selectedAccounts: PropTypes.array.isRequired,
|
selectedAccounts: PropTypes.array.isRequired,
|
||||||
onUnlockAccounts: PropTypes.func,
|
onUnlockAccounts: PropTypes.func,
|
||||||
onCancel: PropTypes.func,
|
onCancel: PropTypes.func,
|
||||||
|
@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as actions from '../../../store/actions';
|
import * as actions from '../../../store/actions';
|
||||||
import {
|
import {
|
||||||
|
getCurrentChainId,
|
||||||
getMetaMaskAccounts,
|
getMetaMaskAccounts,
|
||||||
|
getRpcPrefsForCurrentProvider,
|
||||||
getMetaMaskAccountsConnected,
|
getMetaMaskAccountsConnected,
|
||||||
} from '../../../selectors';
|
} from '../../../selectors';
|
||||||
import { formatBalance } from '../../../helpers/utils/util';
|
import { formatBalance } from '../../../helpers/utils/util';
|
||||||
@ -257,7 +259,8 @@ class ConnectHardwareForm extends Component {
|
|||||||
connectedAccounts={this.props.connectedAccounts}
|
connectedAccounts={this.props.connectedAccounts}
|
||||||
selectedAccounts={this.state.selectedAccounts}
|
selectedAccounts={this.state.selectedAccounts}
|
||||||
onAccountChange={this.onAccountChange}
|
onAccountChange={this.onAccountChange}
|
||||||
network={this.props.network}
|
chainId={this.props.chainId}
|
||||||
|
rpcPrefs={this.props.rpcPrefs}
|
||||||
getPage={this.getPage}
|
getPage={this.getPage}
|
||||||
onUnlockAccounts={this.onUnlockAccounts}
|
onUnlockAccounts={this.onUnlockAccounts}
|
||||||
onForgetDevice={this.onForgetDevice}
|
onForgetDevice={this.onForgetDevice}
|
||||||
@ -287,31 +290,22 @@ ConnectHardwareForm.propTypes = {
|
|||||||
unlockHardwareWalletAccounts: PropTypes.func,
|
unlockHardwareWalletAccounts: PropTypes.func,
|
||||||
setHardwareWalletDefaultHdPath: PropTypes.func,
|
setHardwareWalletDefaultHdPath: PropTypes.func,
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
network: PropTypes.string,
|
chainId: PropTypes.string,
|
||||||
|
rpcPrefs: PropTypes.object,
|
||||||
accounts: PropTypes.object,
|
accounts: PropTypes.object,
|
||||||
connectedAccounts: PropTypes.array.isRequired,
|
connectedAccounts: PropTypes.array.isRequired,
|
||||||
defaultHdPaths: PropTypes.object,
|
defaultHdPaths: PropTypes.object,
|
||||||
mostRecentOverviewPage: PropTypes.string.isRequired,
|
mostRecentOverviewPage: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => ({
|
||||||
const {
|
chainId: getCurrentChainId(state),
|
||||||
metamask: { network },
|
rpcPrefs: getRpcPrefsForCurrentProvider(state),
|
||||||
} = state;
|
accounts: getMetaMaskAccounts(state),
|
||||||
const accounts = getMetaMaskAccounts(state);
|
connectedAccounts: getMetaMaskAccountsConnected(state),
|
||||||
const connectedAccounts = getMetaMaskAccountsConnected(state);
|
defaultHdPaths: state.appState.defaultHdPaths,
|
||||||
const {
|
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||||
appState: { defaultHdPaths },
|
});
|
||||||
} = state;
|
|
||||||
|
|
||||||
return {
|
|
||||||
network,
|
|
||||||
accounts,
|
|
||||||
connectedAccounts,
|
|
||||||
defaultHdPaths,
|
|
||||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps = (dispatch) => {
|
||||||
return {
|
return {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
export default function getAccountLink(address, network, rpcPrefs) {
|
import { createAccountLinkForChain } from '@metamask/etherscan-link';
|
||||||
|
|
||||||
|
export default function getAccountLink(address, chainId, rpcPrefs) {
|
||||||
if (rpcPrefs && rpcPrefs.blockExplorerUrl) {
|
if (rpcPrefs && rpcPrefs.blockExplorerUrl) {
|
||||||
return `${rpcPrefs.blockExplorerUrl.replace(
|
return `${rpcPrefs.blockExplorerUrl.replace(
|
||||||
/\/+$/u,
|
/\/+$/u,
|
||||||
@ -6,22 +8,5 @@ export default function getAccountLink(address, network, rpcPrefs) {
|
|||||||
)}/address/${address}`;
|
)}/address/${address}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line radix
|
return createAccountLinkForChain(address, chainId);
|
||||||
const net = parseInt(network);
|
|
||||||
switch (net) {
|
|
||||||
case 1: // main net
|
|
||||||
return `https://etherscan.io/address/${address}`;
|
|
||||||
case 2: // morden test net
|
|
||||||
return `https://morden.etherscan.io/address/${address}`;
|
|
||||||
case 3: // ropsten test net
|
|
||||||
return `https://ropsten.etherscan.io/address/${address}`;
|
|
||||||
case 4: // rinkeby test net
|
|
||||||
return `https://rinkeby.etherscan.io/address/${address}`;
|
|
||||||
case 42: // kovan test net
|
|
||||||
return `https://kovan.etherscan.io/address/${address}`;
|
|
||||||
case 5: // goerli test net
|
|
||||||
return `https://goerli.etherscan.io/address/${address}`;
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user