223 lines
6.3 KiB
JavaScript
223 lines
6.3 KiB
JavaScript
// @flow
|
|
import './ConfirmationModal.scss';
|
|
import React from 'react';
|
|
import translate, { translateRaw } from 'translations';
|
|
import Big from 'bignumber.js';
|
|
import EthTx from 'ethereumjs-tx';
|
|
import { connect } from 'react-redux';
|
|
import BaseWallet from 'libs/wallet/base';
|
|
import { toUnit, toTokenDisplay } from 'libs/units';
|
|
import ERC20 from 'libs/erc20';
|
|
import { getTransactionFields } from 'libs/transaction';
|
|
import { getTokens } from 'selectors/wallet';
|
|
import { getNetworkConfig, getLanguageSelection } from 'selectors/config';
|
|
import type { NodeConfig } from 'config/data';
|
|
import type { Token, NetworkConfig } from 'config/data';
|
|
|
|
import Modal from 'components/ui/Modal';
|
|
import Identicon from 'components/ui/Identicon';
|
|
|
|
type Props = {
|
|
signedTransaction: string,
|
|
transaction: EthTx,
|
|
wallet: BaseWallet,
|
|
node: NodeConfig,
|
|
token: ?Token,
|
|
network: NetworkConfig,
|
|
onConfirm: (string, EthTx) => void,
|
|
onCancel: () => void,
|
|
lang: string
|
|
};
|
|
|
|
type State = {
|
|
fromAddress: string,
|
|
timeToRead: number
|
|
};
|
|
|
|
class ConfirmationModal extends React.Component {
|
|
props: Props;
|
|
state: State;
|
|
|
|
constructor(props: Props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
fromAddress: '',
|
|
timeToRead: 5
|
|
};
|
|
}
|
|
|
|
componentWillReceiveProps(newProps: Props) {
|
|
// Reload address if the wallet changes
|
|
if (newProps.wallet !== this.props.wallet) {
|
|
this._setWalletAddress(this.props.wallet);
|
|
}
|
|
}
|
|
|
|
// Count down 5 seconds before allowing them to confirm
|
|
readTimer = 0;
|
|
componentDidMount() {
|
|
this.readTimer = setInterval(() => {
|
|
if (this.state.timeToRead > 0) {
|
|
this.setState({ timeToRead: this.state.timeToRead - 1 });
|
|
} else {
|
|
clearInterval(this.readTimer);
|
|
}
|
|
}, 1000);
|
|
|
|
this._setWalletAddress(this.props.wallet);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
clearInterval(this.readTimer);
|
|
}
|
|
|
|
_setWalletAddress(wallet: BaseWallet) {
|
|
wallet.getAddress().then(fromAddress => {
|
|
this.setState({ fromAddress });
|
|
});
|
|
}
|
|
|
|
_decodeTransaction() {
|
|
const { transaction, token } = this.props;
|
|
const { to, value, data, gasPrice } = getTransactionFields(transaction);
|
|
let fixedValue;
|
|
let toAddress;
|
|
|
|
if (token) {
|
|
// $FlowFixMe - If you have a token prop, you have data
|
|
const tokenData = ERC20.$transfer(data);
|
|
fixedValue = toTokenDisplay(new Big(tokenData.value), token).toString();
|
|
toAddress = tokenData.to;
|
|
} else {
|
|
fixedValue = toUnit(new Big(value, 16), 'wei', 'ether').toString();
|
|
toAddress = to;
|
|
}
|
|
|
|
return {
|
|
value: fixedValue,
|
|
gasPrice: toUnit(new Big(gasPrice, 16), 'wei', 'gwei').toString(),
|
|
data,
|
|
toAddress
|
|
};
|
|
}
|
|
|
|
_confirm() {
|
|
if (this.state.timeToRead < 1) {
|
|
const { signedTransaction, transaction } = this.props;
|
|
this.props.onConfirm(signedTransaction, transaction);
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const { node, token, network, onCancel } = this.props;
|
|
const { fromAddress, timeToRead } = this.state;
|
|
const { toAddress, value, gasPrice, data } = this._decodeTransaction();
|
|
|
|
const buttonPrefix = timeToRead > 0 ? `(${timeToRead}) ` : '';
|
|
const buttons = [
|
|
{
|
|
text: buttonPrefix + translateRaw('SENDModal_Yes'),
|
|
type: 'primary',
|
|
disabled: timeToRead > 0,
|
|
onClick: this._confirm()
|
|
},
|
|
{
|
|
text: translateRaw('SENDModal_No'),
|
|
type: 'default',
|
|
onClick: onCancel
|
|
}
|
|
];
|
|
|
|
const symbol = token ? token.symbol : network.unit;
|
|
|
|
return (
|
|
<Modal
|
|
title="Confirm Your Transaction"
|
|
buttons={buttons}
|
|
handleClose={onCancel}
|
|
isOpen={true}
|
|
>
|
|
<div className="ConfModal">
|
|
<div className="ConfModal-summary">
|
|
<div className="ConfModal-summary-icon ConfModal-summary-icon--from">
|
|
<Identicon size="100%" address={fromAddress} />
|
|
</div>
|
|
<div className="ConfModal-summary-amount">
|
|
<div className="ConfModal-summary-amount-arrow" />
|
|
<div className="ConfModal-summary-amount-currency">
|
|
{value} {symbol}
|
|
</div>
|
|
</div>
|
|
<div className="ConfModal-summary-icon ConfModal-summary-icon--to">
|
|
<Identicon size="100%" address={toAddress} />
|
|
</div>
|
|
</div>
|
|
|
|
<ul className="ConfModal-details">
|
|
<li className="ConfModal-details-detail">
|
|
You are sending from <code>{fromAddress}</code>
|
|
</li>
|
|
<li className="ConfModal-details-detail">
|
|
You are sending to <code>{toAddress}</code>
|
|
</li>
|
|
<li className="ConfModal-details-detail">
|
|
You are sending{' '}
|
|
<strong>
|
|
{value} {symbol}
|
|
</strong>{' '}
|
|
with a gas price of <strong>{gasPrice} gwei</strong>
|
|
</li>
|
|
<li className="ConfModal-details-detail">
|
|
You are interacting with the <strong>{node.network}</strong>{' '}
|
|
network provided by <strong>{node.service}</strong>
|
|
</li>
|
|
{!token &&
|
|
<li className="ConfModal-details-detail">
|
|
{data
|
|
? <span>
|
|
You are sending the following data:{' '}
|
|
<textarea
|
|
className="form-control"
|
|
value={data}
|
|
rows="3"
|
|
disabled
|
|
/>
|
|
</span>
|
|
: 'There is no data attached to this transaction'}
|
|
</li>}
|
|
</ul>
|
|
|
|
<div className="ConfModal-confirm">
|
|
{translate('SENDModal_Content_3')}
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
);
|
|
}
|
|
}
|
|
|
|
function mapStateToProps(state, props) {
|
|
// Convert the signedTransaction to an EthTx transaction
|
|
const transaction = new EthTx(props.signedTransaction);
|
|
|
|
// Network config for defaults
|
|
const network = getNetworkConfig(state);
|
|
|
|
const lang = getLanguageSelection(state);
|
|
|
|
// Determine if we're sending to a token from the transaction to address
|
|
const { to, data } = getTransactionFields(transaction);
|
|
const tokens = getTokens(state);
|
|
const token = data && tokens.find(t => t.address === to);
|
|
|
|
return {
|
|
transaction,
|
|
token,
|
|
network,
|
|
lang
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps)(ConfirmationModal);
|