Address Miscellaneous Todos (#534)

* Fix TODO issues

* Update / Removd old comments

* Update types & Fix todos
This commit is contained in:
James Prado 2017-12-14 19:51:42 -05:00 committed by Daniel Ternyak
parent 43d90c9dae
commit d1174fb324
11 changed files with 50 additions and 165 deletions

View File

@ -38,7 +38,7 @@ export default class AccountInfo extends React.Component<Props, State> {
}
// TODO: don't use any;
public toggleShowLongBalance = (e: any) => {
public toggleShowLongBalance = (e: React.SyntheticEvent<HTMLSpanElement>) => {
e.preventDefault();
this.setState(state => {
return {
@ -55,9 +55,7 @@ export default class AccountInfo extends React.Component<Props, State> {
return (
<div className="AccountInfo">
<div className="AccountInfo-section">
<h5 className="AccountInfo-section-header">
{translate('sidebar_AccountAddr')}
</h5>
<h5 className="AccountInfo-section-header">{translate('sidebar_AccountAddr')}</h5>
<div className="AccountInfo-address">
<div className="AccountInfo-address-icon">
<Identicon address={address} size="100%" />
@ -67,9 +65,7 @@ export default class AccountInfo extends React.Component<Props, State> {
</div>
<div className="AccountInfo-section">
<h5 className="AccountInfo-section-header">
{translate('sidebar_AccountBal')}
</h5>
<h5 className="AccountInfo-section-header">{translate('sidebar_AccountBal')}</h5>
<ul className="AccountInfo-list">
<li className="AccountInfo-list-item">
<span
@ -86,20 +82,14 @@ export default class AccountInfo extends React.Component<Props, State> {
/>
)}
</span>
{!balance.isPending ? (
balance.wei ? (
<span> {network.name}</span>
) : null
) : null}
{!balance.isPending ? balance.wei ? <span> {network.name}</span> : null : null}
</li>
</ul>
</div>
{(!!blockExplorer || !!tokenExplorer) && (
<div className="AccountInfo-section">
<h5 className="AccountInfo-section-header">
{translate('sidebar_TransHistory')}
</h5>
<h5 className="AccountInfo-section-header">{translate('sidebar_TransHistory')}</h5>
<ul className="AccountInfo-list">
{!!blockExplorer && (
<li className="AccountInfo-list-item">

View File

@ -41,11 +41,7 @@ export default class TokenRow extends React.Component<Props, State> {
/>
)}
<span>
<UnitDisplay
value={balance}
decimal={decimal}
displayShortBalance={!showLongBalance}
/>
<UnitDisplay value={balance} decimal={decimal} displayShortBalance={!showLongBalance} />
</span>
</td>
<td className="TokenRow-symbol">{symbol}</td>
@ -53,10 +49,7 @@ export default class TokenRow extends React.Component<Props, State> {
);
}
public toggleShowLongBalance = (
// TODO: don't use any
e: any
) => {
public toggleShowLongBalance = (e: React.SyntheticEvent<HTMLTableDataCellElement>) => {
e.preventDefault();
this.setState(state => {
return {

View File

@ -82,18 +82,14 @@ export class WalletDecrypt extends Component<Props, State> {
password: ''
},
unlock: this.props.unlockKeystore,
helpLink: `${
knowledgeBaseURL
}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
'mnemonic-phrase': {
lid: 'x_Mnemonic',
component: MnemonicDecrypt,
initialParams: {},
unlock: this.props.unlockMnemonic,
helpLink: `${
knowledgeBaseURL
}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
'private-key': {
lid: 'x_PrivKey2',
@ -103,9 +99,7 @@ export class WalletDecrypt extends Component<Props, State> {
password: ''
},
unlock: this.props.unlockPrivateKey,
helpLink: `${
knowledgeBaseURL
}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
'view-only': {
lid: 'View with Address Only',

View File

@ -14,10 +14,7 @@ export default function Identicon(props: Props) {
? toDataUrl(props.address.toLowerCase())
: '';
return (
<div
style={{ position: 'relative', width: size, height: size }}
title="Address Identicon"
>
<div style={{ position: 'relative', width: size, height: size }} title="Address Identicon">
<div
style={{
position: 'absolute',
@ -33,7 +30,7 @@ export default function Identicon(props: Props) {
`
}}
/>
{identiconDataUrl &&
{identiconDataUrl && (
<img
src={identiconDataUrl}
style={{
@ -41,7 +38,8 @@ export default function Identicon(props: Props) {
width: '100%',
height: '100%'
}}
/>}
/>
)}
</div>
);
}

View File

@ -104,9 +104,7 @@ export default class DownloadWallet extends Component<Props, State> {
</li>
<li>
<NewTabLink
href={`${
knowledgeBaseURL
}/private-keys-passwords/difference-beween-private-key-and-keystore-file`}
href={`${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file`}
>
<strong>{translate('GEN_Help_14')}</strong>
</NewTabLink>

View File

@ -66,9 +66,7 @@ const help = (
</li>
<li>
<NewTabLink
href={`${
knowledgeBaseURL
}/private-keys-passwords/difference-beween-private-key-and-keystore-file`}
href={`${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file`}
>
<strong>{translate('GEN_Help_16')}</strong>
</NewTabLink>

View File

@ -31,35 +31,17 @@ import {
import { UnitKey, Wei, getDecimal, toWei } from 'libs/units';
import { isValidETHAddress } from 'libs/validators';
// LIBS
import {
IWallet,
Balance,
Web3Wallet,
LedgerWallet,
TrezorWallet
} from 'libs/wallet';
import { IWallet, Balance, Web3Wallet, LedgerWallet, TrezorWallet } from 'libs/wallet';
import pickBy from 'lodash/pickBy';
import React from 'react';
// REDUX
import { connect } from 'react-redux';
import { AppState } from 'reducers';
import { showNotification, TShowNotification } from 'actions/notifications';
import {
broadcastTx,
TBroadcastTx,
resetWallet,
TResetWallet
} from 'actions/wallet';
import {
pollOfflineStatus as dPollOfflineStatus,
TPollOfflineStatus
} from 'actions/config';
import { broadcastTx, TBroadcastTx, resetWallet, TResetWallet } from 'actions/wallet';
import { pollOfflineStatus as dPollOfflineStatus, TPollOfflineStatus } from 'actions/config';
// SELECTORS
import {
getGasPriceGwei,
getNetworkConfig,
getNodeLib
} from 'selectors/config';
import { getGasPriceGwei, getNetworkConfig, getNodeLib } from 'selectors/config';
import {
getTokenBalances,
getTokens,
@ -264,9 +246,7 @@ export class SendTransaction extends React.Component<Props, State> {
const { offline, forceOffline, balance } = this.props;
const customMessage = customMessages.find(m => m.to === to);
const decimal =
unit === 'ether'
? getDecimal('ether')
: (this.state.token && this.state.token.decimal) || 0;
unit === 'ether' ? getDecimal('ether') : (this.state.token && this.state.token.decimal) || 0;
const isWeb3Wallet = this.props.wallet instanceof Web3Wallet;
const isLedgerWallet = this.props.wallet instanceof LedgerWallet;
const isTrezorWallet = this.props.wallet instanceof TrezorWallet;
@ -277,9 +257,7 @@ export class SendTransaction extends React.Component<Props, State> {
title={
<div>
{translate('NAV_SendEther')}
{offline || forceOffline ? (
<span style={{ color: 'red' }}> (Offline)</span>
) : null}
{offline || forceOffline ? <span style={{ color: 'red' }}> (Offline)</span> : null}
</div>
}
allowReadOnly={true}
@ -314,24 +292,14 @@ export class SendTransaction extends React.Component<Props, State> {
isReadOnly={readOnly}
onUnitChange={this.onUnitChange}
/>
<GasField
value={gasLimit}
onChange={readOnly ? void 0 : this.onGasChange}
/>
<GasField value={gasLimit} onChange={readOnly ? void 0 : this.onGasChange} />
{(offline || forceOffline) && (
<div>
<NonceField
value={nonce}
onChange={this.onNonceChange}
placeholder={'0'}
/>
<NonceField value={nonce} onChange={this.onNonceChange} placeholder={'0'} />
</div>
)}
{unit === 'ether' && (
<DataField
value={data}
onChange={readOnly ? void 0 : this.onDataChange}
/>
<DataField value={data} onChange={readOnly ? void 0 : this.onDataChange} />
)}
<CustomMessage message={customMessage} />
@ -341,9 +309,7 @@ export class SendTransaction extends React.Component<Props, State> {
disabled={this.state.generateDisabled}
className="btn btn-info btn-block"
onClick={
isWeb3Wallet
? this.generateWeb3TxFromState
: this.generateTxFromState
isWeb3Wallet ? this.generateWeb3TxFromState : this.generateTxFromState
}
>
{isWeb3Wallet
@ -392,17 +358,12 @@ export class SendTransaction extends React.Component<Props, State> {
/>
{offline && (
<p>
To broadcast this transaction, paste the above
into{' '}
To broadcast this transaction, paste the above into{' '}
<a href="https://myetherwallet.com/pushTx">
{' '}
myetherwallet.com/pushTx
</a>{' '}
or{' '}
<a href="https://etherscan.io/pushTx">
{' '}
etherscan.io/pushTx
</a>
or <a href="https://etherscan.io/pushTx"> etherscan.io/pushTx</a>
</p>
)}
</div>
@ -432,9 +393,7 @@ export class SendTransaction extends React.Component<Props, State> {
<main className="col-sm-8">
<div className="Tab-content-pane">
<h4>Sorry...</h4>
<p>
MetaMask / Mist wallets are not available in offline mode.
</p>
<p>MetaMask / Mist wallets are not available in offline mode.</p>
</div>
</main>
)}
@ -579,23 +538,14 @@ export class SendTransaction extends React.Component<Props, State> {
this.setState({ gasLimit: value, gasChanged: true });
};
public handleEverythingAmountChange = (
value: string,
unit: string
): string => {
public handleEverythingAmountChange = (value: string, unit: string): string => {
if (unit === 'ether') {
const { balance, gasPrice } = this.props;
const { gasLimit } = this.state;
const bigGasLimit = Wei(gasLimit);
value = getBalanceMinusGasCosts(
bigGasLimit,
gasPrice,
balance.wei
).toString();
value = getBalanceMinusGasCosts(bigGasLimit, gasPrice, balance.wei).toString();
} else {
const tokenBalance = this.props.tokenBalances.find(
tBalance => tBalance.symbol === unit
);
const tokenBalance = this.props.tokenBalances.find(tBalance => tBalance.symbol === unit);
if (!tokenBalance) {
throw new Error(`${unit}: not found in token balances;`);
}
@ -673,10 +623,7 @@ export class SendTransaction extends React.Component<Props, State> {
if (network.blockExplorer !== undefined) {
this.props.showNotification(
'success',
<TransactionSucceeded
txHash={txHash}
blockExplorer={network.blockExplorer}
/>,
<TransactionSucceeded txHash={txHash} blockExplorer={network.blockExplorer} />,
0
);
}

View File

@ -1,5 +1,6 @@
// TODO support events, constructors, fallbacks, array slots, types
import abi from 'ethereumjs-abi';
import BN from 'bn.js';
// There are too many to enumerate since they're somewhat dynamic, list here
// https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#types
@ -24,8 +25,7 @@ export type ABI = ABIMethod[];
export interface DecodedCall {
method: ABIMethod;
// TODO: Type this to be an array of BNs when we switch
args: any[];
args: BN[];
}
// Contract helper, returns data for given call
@ -52,23 +52,17 @@ export default class Contract {
}
public getMethodSelector(method: ABIMethod): string {
return abi
.methodID(method.name, this.getMethodTypes(method))
.toString('hex');
return abi.methodID(method.name, this.getMethodTypes(method)).toString('hex');
}
public call(name: string, args: any[]): string {
const method = this.getMethodAbi(name);
return (
'0x' + this.getMethodSelector(method) + this.encodeArgs(method, args)
);
return '0x' + this.getMethodSelector(method) + this.encodeArgs(method, args);
}
public $call(data: string): DecodedCall {
const method = this.abi.find(
mth => data.indexOf(this.getMethodSelector(mth)) !== -1
);
const method = this.abi.find(mth => data.indexOf(this.getMethodSelector(mth)) !== -1);
if (!method) {
throw new Error('Unknown method');
@ -89,8 +83,7 @@ export default class Contract {
return abi.rawEncode(inputTypes, args).toString('hex');
}
// TODO: Type this return to be an array of BNs when we switch
public decodeArgs(method: ABIMethod, argData: string): any[] {
public decodeArgs(method: ABIMethod, argData: string): BN[] {
// Remove method selector from data, if present
argData = argData.replace(`0x${this.getMethodSelector(method)}`, '');
// Convert argdata to a hex buffer for ethereumjs-abi

View File

@ -1,4 +1,3 @@
// TODO - move this out of transaction; it's only for estimating gas costs
export interface TransactionWithoutGas {
to: string;
value: string;

View File

@ -2,7 +2,6 @@ import { Token } from 'config/data';
import EthTx from 'ethereumjs-tx';
import { addHexPrefix, padToEven, toChecksumAddress } from 'ethereumjs-util';
import ERC20 from 'libs/erc20';
import { TransactionWithoutGas } from 'libs/messages';
import { RPCNode } from 'libs/nodes';
import { INode } from 'libs/nodes/INode';
import { UnitKey, Wei, TokenValue, toTokenBase } from 'libs/units';
@ -71,10 +70,7 @@ export function getTransactionFields(tx: EthTx) {
};
}
function getValue(
token: Token | null | undefined,
tx: ExtendedRawTransaction
): Wei {
function getValue(token: Token | null | undefined, tx: ExtendedRawTransaction): Wei {
let value;
if (token) {
value = Wei(ERC20.$transfer(tx.data).value);
@ -93,10 +89,7 @@ async function getBalance(
const ETHBalance = await node.getBalance(from);
let balance: Wei;
if (token) {
balance = toTokenBase(
await node.getTokenBalance(tx.from, token).toString(),
token.decimal
);
balance = toTokenBase(await node.getTokenBalance(tx.from, token).toString(), token.decimal);
} else {
balance = ETHBalance;
}
@ -159,9 +152,7 @@ function generateTxValidation(
// Reject gasPrice over 1000gwei (1000000000000)
const gwei = Wei('1000000000000');
if (gasPrice.gt(gwei)) {
throw new Error(
'Gas price too high. Please contact support if this was not a mistake.'
);
throw new Error('Gas price too high. Please contact support if this was not a mistake.');
}
}
@ -215,12 +206,12 @@ export async function generateCompleteTransactionFromRawTransaction(
export async function formatTxInput(
wallet: IFullWallet,
{ token, unit, value, to, data }: TransactionInput
): Promise<TransactionWithoutGas> {
): Promise<{ to: string; from: string; value: string; data: string }> {
if (unit === 'ether') {
return {
to,
from: await wallet.getAddressString(),
value: toHexWei(value), //turn users ether to wei
value: toHexWei(value), // turn users ether to wei
data
};
} else {
@ -246,10 +237,7 @@ export async function confirmAndSendWeb3Transaction(
chainId: number,
transactionInput: TransactionInput
): Promise<string> {
const { from, to, value, data } = await formatTxInput(
wallet,
transactionInput
);
const { from, to, value, data } = await formatTxInput(wallet, transactionInput);
const transaction: ExtendedRawTransaction = {
nonce: await nodeLib.getTransactionCount(from),
from,
@ -276,10 +264,7 @@ export async function generateCompleteTransaction(
offline?: boolean
): Promise<CompleteTransaction> {
const { token } = transactionInput;
const { from, to, value, data } = await formatTxInput(
wallet,
transactionInput
);
const { from, to, value, data } = await formatTxInput(wallet, transactionInput);
const transaction: ExtendedRawTransaction = {
nonce: nonce ? `0x${nonce}` : await nodeLib.getTransactionCount(from),
from,
@ -301,20 +286,14 @@ export async function generateCompleteTransaction(
}
// TODO determine best place for helper function
export function getBalanceMinusGasCosts(
gasLimit: Wei,
gasPrice: Wei,
balance: Wei
): Wei {
export function getBalanceMinusGasCosts(gasLimit: Wei, gasPrice: Wei, balance: Wei): Wei {
const weiGasCosts = gasPrice.mul(gasLimit);
const weiBalanceMinusGasCosts = balance.sub(weiGasCosts);
return Wei(weiBalanceMinusGasCosts);
}
export function decodeTransaction(transaction: EthTx, token: Token | false) {
const { to, value, data, gasPrice, nonce, from } = getTransactionFields(
transaction
);
const { to, value, data, gasPrice, nonce, from } = getTransactionFields(transaction);
let fixedValue: TokenValue;
let toAddress;

View File

@ -15,13 +15,9 @@ export function padLeftEven(hex: string) {
return hex.length % 2 !== 0 ? `0${hex}` : hex;
}
// TODO: refactor to not mutate argument
export function sanitizeHex(hex: string) {
hex = hex.substring(0, 2) === '0x' ? hex.substring(2) : hex;
if (hex === '') {
return '';
}
return `0x${padLeftEven(hex)}`;
const hexStr = hex.substring(0, 2) === '0x' ? hex.substring(2) : hex;
return hex !== '' ? `0x${padLeftEven(hexStr)}` : '';
}
export function networkIdToName(networkId: string | number): string {