mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-26 09:45:18 +00:00
* Refactor babel/types * Refactor entry point * Refactor actions * Refactor api * Full project refactor -- Broad type fixing sweep * - completely fix merge conflicts - handle various type errors * Add tslint to package.json * Dependency cleanup * Fix module resolution * Work on type definitions for untyped libs * progress commit * Add more definition typing * various type additions * Add unit types * Fix sagaiterator + unit types * various types added * additional type additions * Fix typing on Sagas * remove flowfixmes; swap translate for translateRaw * Get rid of contracts - awaiting Henry's contract PR * Remove contracts from routing * Fix most of actions/reducers * refactor actions directory structure * fix reducer action type imports * Fix most of type errors pre-actions refactor * fix action creator imports in containers * Refactor more * Refactor index of actions * fix action imports; use module level index export * package-lock.json updated * Use action types in props * Type up action creators * Fix most of connect errors * Typefixing progress * More types * Fix run-time errors * Caching improvements for webpack * Remove path resolve from webpack * Update non-breaking packages to latest version * Fix token typing * Remove unused color code * Fix wallet decrypt dispatch * Set redux-form related props/functions to ANY, since we're stripping it out later on * Revert BigNumber.js package changes * Extend window to custom object for Perf * Format Navigation * Typecase keystore errors as any (since we shouldnt touch this) * Push wallet context fix * - find/replace value->payload in swap - properly type swap state properties - extract inline reducer into reducer function * - type local storage retrieved items as generic * - bind all RPCClient methods with fat arrow * - reformat * Change to enums for constants * Change state into any * Fix swap errors * ensure that seconds are passed into state as integers * Fix rest of errors * use parseInt explicitly instead of type coercion * Fix derivation-checker, remove flow command, add tslint command, add tslint-react, tell travis to use tslint instead of flow. * Whoops, remove those tests. * Remove unsupported (yet) config option. * Fix precommit to target ts and tsx files. * Fix some errors, ignore some silly rules. * Revert jest to v19, use ts-jest and make all tests typescript. Fixes all but one. * Get rid of saga tests * Fix tslint errors
249 lines
7.5 KiB
TypeScript
249 lines
7.5 KiB
TypeScript
import Big, { BigNumber } from 'bignumber.js';
|
|
import Identicon from 'components/ui/Identicon';
|
|
import Modal, { IButton } from 'components/ui/Modal';
|
|
import Spinner from 'components/ui/Spinner';
|
|
import { NetworkConfig, NodeConfig, Token } from 'config/data';
|
|
import EthTx from 'ethereumjs-tx';
|
|
import ERC20 from 'libs/erc20';
|
|
import {
|
|
BroadcastTransactionStatus,
|
|
getTransactionFields
|
|
} from 'libs/transaction';
|
|
import { toTokenDisplay, toUnit } from 'libs/units';
|
|
import { IWallet } from 'libs/wallet/IWallet';
|
|
import React from 'react';
|
|
import { connect } from 'react-redux';
|
|
import { getLanguageSelection, getNetworkConfig } from 'selectors/config';
|
|
import { getTokens, getTxFromState, MergedToken } from 'selectors/wallet';
|
|
import translate, { translateRaw } from 'translations';
|
|
import './ConfirmationModal.scss';
|
|
|
|
interface Props {
|
|
signedTx: string;
|
|
transaction: EthTx;
|
|
wallet: IWallet;
|
|
node: NodeConfig;
|
|
token: MergedToken | undefined;
|
|
network: NetworkConfig;
|
|
lang: string;
|
|
broadCastTxStatus: BroadcastTransactionStatus;
|
|
onConfirm(signedTx: string): void;
|
|
onClose(): void;
|
|
}
|
|
|
|
interface State {
|
|
fromAddress: string;
|
|
timeToRead: number;
|
|
hasBroadCasted: boolean;
|
|
}
|
|
|
|
class ConfirmationModal extends React.Component<Props, State> {
|
|
public state = {
|
|
fromAddress: '',
|
|
timeToRead: 5,
|
|
hasBroadCasted: false
|
|
};
|
|
|
|
private readTimer = 0;
|
|
|
|
public componentWillReceiveProps(newProps: Props) {
|
|
// Reload address if the wallet changes
|
|
if (newProps.wallet !== this.props.wallet) {
|
|
this.setWalletAddress(this.props.wallet);
|
|
}
|
|
}
|
|
|
|
public componentDidUpdate() {
|
|
if (
|
|
this.state.hasBroadCasted &&
|
|
!this.props.broadCastTxStatus.isBroadcasting
|
|
) {
|
|
this.props.onClose();
|
|
}
|
|
}
|
|
|
|
// Count down 5 seconds before allowing them to confirm
|
|
public componentDidMount() {
|
|
this.readTimer = window.setInterval(() => {
|
|
if (this.state.timeToRead > 0) {
|
|
this.setState({ timeToRead: this.state.timeToRead - 1 });
|
|
} else {
|
|
window.clearInterval(this.readTimer);
|
|
}
|
|
}, 1000);
|
|
|
|
this.setWalletAddress(this.props.wallet);
|
|
}
|
|
|
|
public render() {
|
|
const { node, token, network, onClose, broadCastTxStatus } = this.props;
|
|
const { fromAddress, timeToRead } = this.state;
|
|
const { toAddress, value, gasPrice, data } = this.decodeTransaction();
|
|
|
|
const buttonPrefix = timeToRead > 0 ? `(${timeToRead}) ` : '';
|
|
const buttons: IButton[] = [
|
|
{
|
|
text: buttonPrefix + translateRaw('SENDModal_Yes'),
|
|
type: 'primary',
|
|
disabled: timeToRead > 0,
|
|
onClick: this.confirm
|
|
},
|
|
{
|
|
text: translateRaw('SENDModal_No'),
|
|
type: 'default',
|
|
onClick: onClose
|
|
}
|
|
];
|
|
|
|
const symbol = token ? token.symbol : network.unit;
|
|
|
|
const isBroadcasting =
|
|
broadCastTxStatus && broadCastTxStatus.isBroadcasting;
|
|
|
|
return (
|
|
<Modal
|
|
title="Confirm Your Transaction"
|
|
buttons={buttons}
|
|
handleClose={onClose}
|
|
disableButtons={isBroadcasting}
|
|
isOpen={true}
|
|
>
|
|
{
|
|
<div className="ConfModal">
|
|
{isBroadcasting ? (
|
|
<div className="ConfModal-loading">
|
|
<Spinner size="5x" />
|
|
</div>
|
|
) : (
|
|
<div>
|
|
<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={true}
|
|
/>
|
|
</span>
|
|
) : (
|
|
'There is no data attached to this transaction'
|
|
)}
|
|
</li>
|
|
)}
|
|
</ul>
|
|
|
|
<div className="ConfModal-confirm">
|
|
{translate('SENDModal_Content_3')}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
}
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
public componentWillUnmount() {
|
|
window.clearInterval(this.readTimer);
|
|
}
|
|
|
|
private async setWalletAddress(wallet: IWallet) {
|
|
// TODO move getAddress to saga
|
|
const fromAddress = await wallet.getAddress();
|
|
this.setState({ fromAddress });
|
|
}
|
|
|
|
private decodeTransaction() {
|
|
const { transaction, token } = this.props;
|
|
const { to, value, data, gasPrice } = getTransactionFields(transaction);
|
|
let fixedValue;
|
|
let toAddress;
|
|
|
|
if (token) {
|
|
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
|
|
};
|
|
}
|
|
|
|
private confirm = () => {
|
|
if (this.state.timeToRead < 1) {
|
|
this.props.onConfirm(this.props.signedTx);
|
|
this.setState({ hasBroadCasted: true });
|
|
}
|
|
};
|
|
}
|
|
|
|
function mapStateToProps(state, props) {
|
|
// Convert the signedTx to an EthTx transaction
|
|
const transaction = new EthTx(props.signedTx);
|
|
|
|
// Network config for defaults
|
|
const network = getNetworkConfig(state);
|
|
|
|
const lang = getLanguageSelection(state);
|
|
|
|
const broadCastTxStatus = getTxFromState(state, props.signedTx);
|
|
|
|
// 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 {
|
|
broadCastTxStatus,
|
|
transaction,
|
|
token,
|
|
network,
|
|
lang
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps)(ConfirmationModal);
|