diff --git a/js/src/ui/TxHash/txHash.js b/js/src/ui/TxHash/txHash.js index c054dc01fae..724004ae74f 100644 --- a/js/src/ui/TxHash/txHash.js +++ b/js/src/ui/TxHash/txHash.js @@ -1,4 +1,4 @@ -// Copyright 2015, 2016 Parity Technologies (UK) Ltd. +// Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,8 +21,10 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { txLink } from '~/3rdparty/etherscan/links'; -import ShortenedHash from '../ShortenedHash'; +import Warning from '~/ui/Warning'; +import { DEFAULT_GAS } from '~/util/constants'; +import ShortenedHash from '../ShortenedHash'; import styles from './txHash.css'; class TxHash extends Component { @@ -43,8 +45,59 @@ class TxHash extends Component { state = { blockNumber: new BigNumber(0), + isRecipientContract: false, subscriptionId: null, - transaction: null + transaction: null, + transactionReceipt: null + } + + componentWillMount () { + this.fetchTransaction(); + } + + componentWillReceiveProps (nextProps) { + const prevHash = this.props.hash; + const nextHash = nextProps.hash; + + if (prevHash !== nextHash) { + this.fetchTransaction(nextProps); + } + } + + /** + * Get the sent transaction data + */ + fetchTransaction (props = this.props) { + const { hash } = props; + + if (!hash) { + return; + } + + this.context.api.eth + .getTransactionByHash(hash) + .then((transaction) => { + this.setState({ transaction }); + + return this.fetchRecipientCode(transaction); + }); + } + + fetchRecipientCode (transaction) { + if (!transaction || !transaction.to) { + return; + } + + this.context.api.eth + .getCode(transaction.to) + .then((code) => { + const isRecipientContract = code && !/^(0x)?0*$/.test(code); + + this.setState({ isRecipientContract }); + }) + .catch((error) => { + console.error('fetchRecipientCode', error); + }); } componentDidMount () { @@ -73,24 +126,58 @@ class TxHash extends Component { return (
+ { this.renderWarning() }

{ summary ? hashLink : + values={ { hashLink } } + /> }

{ this.renderConfirmations() }
); } + renderWarning () { + const { isRecipientContract, transaction, transactionReceipt } = this.state; + + if (!(transactionReceipt && transactionReceipt.blockNumber && transactionReceipt.blockNumber.gt(0))) { + return null; + } + + const { gas, input } = transaction; + const { gasUsed = new BigNumber(0) } = transactionReceipt; + + const isOog = gasUsed.gte(gas); + + // Skip OOG check if a simple transaction to a non-contract account + // @see: https://github.com/ethcore/parity/issues/4550 + const skipOogCheck = gasUsed.eq(DEFAULT_GAS) && (!input || input === '0x') && !isRecipientContract; + + if (!isOog || skipOogCheck) { + return null; + } + + return ( + + } + /> + ); + } + renderConfirmations () { const { maxConfirmations } = this.props; - const { blockNumber, transaction } = this.state; + const { blockNumber, transactionReceipt } = this.state; - if (!(transaction && transaction.blockNumber && transaction.blockNumber.gt(0))) { + if (!(transactionReceipt && transactionReceipt.blockNumber && transactionReceipt.blockNumber.gt(0))) { return (
+ defaultMessage='waiting for confirmations' + />
); } - const confirmations = blockNumber.minus(transaction.blockNumber).plus(1); + const confirmations = blockNumber.minus(transactionReceipt.blockNumber).plus(1); const value = Math.min(confirmations.toNumber(), maxConfirmations); let count = confirmations.toFormat(0); + if (confirmations.lte(maxConfirmations)) { count = `${count}/${maxConfirmations}`; } @@ -123,7 +212,8 @@ class TxHash extends Component { max={ maxConfirmations } value={ value } color='white' - mode='determinate' /> + mode='determinate' + />
+ } } + />
@@ -143,21 +234,22 @@ class TxHash extends Component { const { api } = this.context; const { hash } = this.props; + const nextState = { blockNumber }; + if (error || !hash || /^(0x)?0*$/.test(hash)) { - return; + return this.setState(nextState); } return api.eth .getTransactionReceipt(hash) - .then((transaction) => { - this.setState({ - blockNumber, - transaction - }); + .then((transactionReceipt) => { + nextState.transactionReceipt = transactionReceipt; }) .catch((error) => { - console.warn('onBlockNumber', error); - this.setState({ blockNumber }); + console.error('onBlockNumber', error); + }) + .then(() => { + this.setState(nextState); }); } }