refactor etherscan.io links (#2896)

* use proper querystring builder

* etherscan.txLink helper

* refactor to etherscan.txLink

* etherscan.addressLink helper

* refactor to etherscan.addressLink

* move txLink & addressLink into common file
This commit is contained in:
Jannis Redmann 2016-10-30 09:37:15 +01:00 committed by Jaco Greeff
parent 222b2b70ea
commit 86c0dbeedc
12 changed files with 44 additions and 90 deletions

View File

@ -125,6 +125,7 @@
"material-ui": "^0.16.1", "material-ui": "^0.16.1",
"material-ui-chip-input": "^0.8.0", "material-ui-chip-input": "^0.8.0",
"moment": "^2.14.1", "moment": "^2.14.1",
"qs": "^6.3.0",
"react": "^15.2.1", "react": "^15.2.1",
"react-addons-css-transition-group": "^15.2.1", "react-addons-css-transition-group": "^15.2.1",
"react-dom": "^15.2.1", "react-dom": "^15.2.1",

View File

@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { stringify } from 'qs';
const options = { const options = {
method: 'GET', method: 'GET',
headers: { headers: {
@ -23,19 +25,14 @@ const options = {
export function call (module, action, _params, test) { export function call (module, action, _params, test) {
const host = test ? 'testnet.etherscan.io' : 'api.etherscan.io'; const host = test ? 'testnet.etherscan.io' : 'api.etherscan.io';
let params = '';
if (_params) { const query = stringify(Object.assign({
Object.keys(_params).map((param) => { module, action
const value = _params[param]; }, _params || {}));
params = `${params}&${param}=${value}`; return fetch(`https://${host}/api?${query}`, options)
});
}
return fetch(`http://${host}/api?module=${module}&action=${action}${params}`, options)
.then((response) => { .then((response) => {
if (response.status !== 200) { if (!response.ok) {
throw { code: response.status, message: response.statusText }; // eslint-disable-line throw { code: response.status, message: response.statusText }; // eslint-disable-line
} }

View File

@ -16,10 +16,13 @@
import { account } from './account'; import { account } from './account';
import { stats } from './stats'; import { stats } from './stats';
import { txLink, addressLink } from './links';
const etherscan = { const etherscan = {
account: account, account: account,
stats: stats stats: stats,
txLink: txLink,
addressLink: addressLink
}; };
export default etherscan; export default etherscan;

View File

@ -14,8 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
// links to chain explorers export const txLink = (hash, isTestnet = false) => {
export const BASE_LINK_ACCOUNT_MORDEN = 'https://testnet.etherscan.io/address/'; return `https://${isTestnet ? 'testnet.' : ''}etherscan.io/tx/${hash}`;
export const BASE_LINK_ACCOUNT_HOMESTEAD = 'https://etherscan.io/address/'; };
export const BASE_LINK_TX_MORDEN = 'https://testnet.etherscan.io/tx/';
export const BASE_LINK_TX_HOMESTEAD = 'https://etherscan.io/tx/'; export const addressLink = (address, isTestnet = false) => {
return `https://${isTestnet ? 'testnet.' : ''}etherscan.io/address/${address}`;
};

View File

@ -19,6 +19,7 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { LinearProgress } from 'material-ui'; import { LinearProgress } from 'material-ui';
import { txLink } from '../../3rdparty/etherscan/links';
import styles from './txHash.css'; import styles from './txHash.css';
@ -55,7 +56,6 @@ class TxHash extends Component {
render () { render () {
const { hash, isTest } = this.props; const { hash, isTest } = this.props;
const link = `https://${isTest ? 'testnet.' : ''}etherscan.io/tx/${hash}`;
return ( return (
<div className={ styles.details }> <div className={ styles.details }>
@ -63,7 +63,7 @@ class TxHash extends Component {
The transaction has been posted to the network with a transaction hash of The transaction has been posted to the network with a transaction hash of
</div> </div>
<div className={ styles.hash }> <div className={ styles.hash }>
<a href={ link } target='_blank'>{ hash }</a> <a href={ txLink(hash, isTest) } target='_blank'>{ hash }</a>
</div> </div>
{ this.renderConfirmations() } { this.renderConfirmations() }
</div> </div>

View File

@ -23,6 +23,7 @@ import { bindActionCreators } from 'redux';
import { fetchBlock, fetchTransaction } from '../../../../redux/providers/blockchainActions'; import { fetchBlock, fetchTransaction } from '../../../../redux/providers/blockchainActions';
import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui'; import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui';
import { txLink, addressLink } from '../../../../3rdparty/etherscan/links';
import styles from '../transactions.css'; import styles from '../transactions.css';
@ -55,9 +56,7 @@ class Transaction extends Component {
} }
render () { render () {
const { block, transaction, isTest } = this.props; const { block, transaction } = this.props;
const prefix = `https://${isTest ? 'testnet.' : ''}etherscan.io/`;
return ( return (
<tr> <tr>
@ -65,9 +64,9 @@ class Transaction extends Component {
<div>{ this.formatBlockTimestamp(block) }</div> <div>{ this.formatBlockTimestamp(block) }</div>
<div>{ this.formatNumber(transaction.blockNumber) }</div> <div>{ this.formatNumber(transaction.blockNumber) }</div>
</td> </td>
{ this.renderAddress(prefix, transaction.from) } { this.renderAddress(transaction.from) }
{ this.renderTransaction() } { this.renderTransaction() }
{ this.renderAddress(prefix, transaction.to) } { this.renderAddress(transaction.to) }
<td className={ styles.method }> <td className={ styles.method }>
{ this.renderMethod() } { this.renderMethod() }
</td> </td>
@ -93,15 +92,16 @@ class Transaction extends Component {
renderTransaction () { renderTransaction () {
const { transaction, isTest } = this.props; const { transaction, isTest } = this.props;
const prefix = `https://${isTest ? 'testnet.' : ''}etherscan.io/`;
const hashLink = `${prefix}tx/${transaction.hash}`;
return ( return (
<td className={ styles.transaction }> <td className={ styles.transaction }>
{ this.renderEtherValue() } { this.renderEtherValue() }
<div></div> <div></div>
<div> <div>
<a href={ hashLink } target='_blank' className={ styles.link }> <a
className={ styles.link }
href={ txLink(transaction.hash, isTest) }
target='_blank'
>
{ this.formatHash(transaction.hash) } { this.formatHash(transaction.hash) }
</a> </a>
</div> </div>
@ -109,10 +109,12 @@ class Transaction extends Component {
); );
} }
renderAddress (prefix, address) { renderAddress (address) {
const { isTest } = this.props;
const eslink = address ? ( const eslink = address ? (
<a <a
href={ `${prefix}address/${address}` } href={ addressLink(address, isTest) }
target='_blank' target='_blank'
className={ styles.link }> className={ styles.link }>
<IdentityName address={ address } shorten /> <IdentityName address={ address } shorten />

View File

@ -22,6 +22,7 @@ import { bindActionCreators } from 'redux';
import { fetchBlock, fetchTransaction } from '../../../../redux/providers/blockchainActions'; import { fetchBlock, fetchTransaction } from '../../../../redux/providers/blockchainActions';
import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui'; import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui';
import { txLink } from '../../../../3rdparty/etherscan/links';
import styles from '../../contract.css'; import styles from '../../contract.css';
@ -49,7 +50,7 @@ class Event extends Component {
const block = blocks[event.blockNumber.toString()]; const block = blocks[event.blockNumber.toString()];
const transaction = transactions[event.transactionHash] || {}; const transaction = transactions[event.transactionHash] || {};
const classes = `${styles.event} ${styles[event.state]}`; const classes = `${styles.event} ${styles[event.state]}`;
const url = `https://${isTest ? 'testnet.' : ''}etherscan.io/tx/${event.transactionHash}`; const url = txLink(event.transactionHash, isTest);
const keys = Object.keys(event.params).join(', '); const keys = Object.keys(event.params).join(', ');
const values = Object.keys(event.params).map((name, index) => { const values = Object.keys(event.params).map((name, index) => {
const param = event.params[name]; const param = event.params[name];

View File

@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { getAccountLink } from '../../util/account'; import { addressLink } from '../../../../../3rdparty/etherscan/links';
import styles from './AccountLink.css'; import styles from './AccountLink.css';
export default class AccountLink extends Component { export default class AccountLink extends Component {
@ -57,7 +57,7 @@ export default class AccountLink extends Component {
} }
updateLink (address, chain) { updateLink (address, chain) {
const link = getAccountLink(address, chain); const link = addressLink(address, chain === 'morden' || chain === 'testnet');
this.setState({ this.setState({
link link

View File

@ -120,8 +120,9 @@ export default class TransactionFinished extends Component {
} }
renderTxHash () { renderTxHash () {
const { txHash, chain } = this.props; const { txHash } = this.props;
if (!txHash) { const { chain } = this.state;
if (!txHash || !chain) {
return; return;
} }

View File

@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { getTxLink } from '../util/transaction'; import { txLink } from '../../../../3rdparty/etherscan/links';
export default class TxHashLink extends Component { export default class TxHashLink extends Component {
@ -27,27 +27,12 @@ export default class TxHashLink extends Component {
className: PropTypes.string className: PropTypes.string
} }
state = {
link: null
};
componentWillMount () {
const { txHash, chain } = this.props;
this.updateLink(txHash, chain);
}
componentWillReceiveProps (nextProps) {
const { txHash, chain } = nextProps;
this.updateLink(txHash, chain);
}
render () { render () {
const { children, txHash, className } = this.props; const { children, txHash, className, chain } = this.props;
const { link } = this.state;
return ( return (
<a <a
href={ link } href={ txLink(txHash, chain === 'morden' || chain === 'testnet') }
target='_blank' target='_blank'
className={ className }> className={ className }>
{ children || txHash } { children || txHash }
@ -55,9 +40,4 @@ export default class TxHashLink extends Component {
); );
} }
updateLink (txHash, chain) {
const link = getTxLink(txHash, chain);
this.setState({ link });
}
} }

View File

@ -1,25 +0,0 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { BASE_LINK_ACCOUNT_MORDEN, BASE_LINK_ACCOUNT_HOMESTEAD } from '../constants/constants';
export const getAccountLink = _getAccountLink;
function _getAccountLink (address, chain) {
const isTestNet = chain === 'morden' || chain === 'testnet';
const base = isTestNet ? BASE_LINK_ACCOUNT_MORDEN : BASE_LINK_ACCOUNT_HOMESTEAD;
return base + address;
}

View File

@ -18,7 +18,6 @@ import BigNumber from 'bignumber.js';
const WEI_TO_ETH_MULTIPLIER = 0.000000000000000001; const WEI_TO_ETH_MULTIPLIER = 0.000000000000000001;
const WEI_TO_SZABU_MULTIPLIER = 0.000000000001; const WEI_TO_SZABU_MULTIPLIER = 0.000000000001;
import { BASE_LINK_TX_MORDEN, BASE_LINK_TX_HOMESTEAD } from '../constants/constants';
export const getShortData = _getShortData; export const getShortData = _getShortData;
// calculations // calculations
@ -33,8 +32,6 @@ export const getTotalValueDisplay = _getTotalValueDisplay;
export const getTotalValueDisplayWei = _getTotalValueDisplayWei; export const getTotalValueDisplayWei = _getTotalValueDisplayWei;
export const getEthmFromWeiDisplay = _getEthmFromWeiDisplay; export const getEthmFromWeiDisplay = _getEthmFromWeiDisplay;
export const getGasDisplay = _getGasDisplay; export const getGasDisplay = _getGasDisplay;
// links
export const getTxLink = _getTxLink;
function _getShortData (data) { function _getShortData (data) {
if (data.length <= 3) { if (data.length <= 3) {
@ -111,11 +108,6 @@ function _getEthmFromWeiDisplay (weiHexString) {
return value.times(WEI_TO_ETH_MULTIPLIER).times(1e7).toFixed(5); return value.times(WEI_TO_ETH_MULTIPLIER).times(1e7).toFixed(5);
} }
function _getTxLink (txHash, chain) {
const base = chain === 'morden' || chain === 'testnet' ? BASE_LINK_TX_MORDEN : BASE_LINK_TX_HOMESTEAD;
return base + txHash;
}
function _getGasDisplay (gas) { function _getGasDisplay (gas) {
return new BigNumber(gas).times(1e-7).toFormat(4); return new BigNumber(gas).times(1e-7).toFormat(4);
} }