Use Network Symbol in Confirmation Modal (#1039)

* Set default unit to 'ETH' instead of 'ether'

* Use 'isEtherUnit()' everywhere

* Set default unit to empty string

* Update isEthUnit to isNetworkUnit

* Fix unit conversion for non-ethereum networks

* Set default network unit properly

* Fix tests

* fix typos

* Update isNetworkUnit selector

* Update isNetworkUnit

* Fix validationhelpers tests

* Add mock state to tests & Move isNetworkUnit to selectors

* Fix validation helper spec

* fix unit swap spec
This commit is contained in:
James Prado 2018-03-01 20:24:14 -05:00 committed by Daniel Ternyak
parent 08335fbca0
commit aabcd3f7a3
38 changed files with 198 additions and 126 deletions

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Provider } from 'react-redux'; import { Provider, connect } from 'react-redux';
import { withRouter, Switch, Redirect, HashRouter, Route, BrowserRouter } from 'react-router-dom'; import { withRouter, Switch, Redirect, HashRouter, Route, BrowserRouter } from 'react-router-dom';
// Components // Components
import Contracts from 'containers/Tabs/Contracts'; import Contracts from 'containers/Tabs/Contracts';
@ -15,27 +15,41 @@ import PageNotFound from 'components/PageNotFound';
import LogOutPrompt from 'components/LogOutPrompt'; import LogOutPrompt from 'components/LogOutPrompt';
import { TitleBar } from 'components/ui'; import { TitleBar } from 'components/ui';
import { Store } from 'redux'; import { Store } from 'redux';
import { pollOfflineStatus } from 'actions/config'; import { pollOfflineStatus, TPollOfflineStatus } from 'actions/config';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { RouteNotFound } from 'components/RouteNotFound'; import { RouteNotFound } from 'components/RouteNotFound';
import { RedirectWithQuery } from 'components/RedirectWithQuery'; import { RedirectWithQuery } from 'components/RedirectWithQuery';
import 'what-input'; import 'what-input';
import { setUnitMeta, TSetUnitMeta } from 'actions/transaction';
import { getNetworkUnit } from 'selectors/config';
interface Props { interface OwnProps {
store: Store<AppState>; store: Store<AppState>;
} }
interface StateProps {
networkUnit: string;
}
interface DispatchProps {
pollOfflineStatus: TPollOfflineStatus;
setUnitMeta: TSetUnitMeta;
}
type Props = OwnProps & StateProps & DispatchProps;
interface State { interface State {
error: Error | null; error: Error | null;
} }
export default class Root extends Component<Props, State> { class RootClass extends Component<Props, State> {
public state = { public state = {
error: null error: null
}; };
public componentDidMount() { public componentDidMount() {
this.props.store.dispatch(pollOfflineStatus()); this.props.pollOfflineStatus();
this.props.setUnitMeta(this.props.networkUnit);
} }
public componentDidCatch(error: Error) { public componentDidCatch(error: Error) {
@ -134,3 +148,14 @@ const LegacyRoutes = withRouter(props => {
</Switch> </Switch>
); );
}); });
const mapStateToProps = (state: AppState) => {
return {
networkUnit: getNetworkUnit(state)
};
};
export default connect(mapStateToProps, {
pollOfflineStatus,
setUnitMeta
})(RootClass);

View File

@ -5,23 +5,22 @@ import {
SetTokenToMetaAction SetTokenToMetaAction
} from 'actions/transaction'; } from 'actions/transaction';
type TSetTokenBalance = typeof setTokenValue; export type TSetTokenTo = typeof setTokenTo;
type TSetUnitMeta = typeof setUnitMeta; export const setTokenTo = (payload: SetTokenToMetaAction['payload']): SetTokenToMetaAction => ({
type TSetTokenTo = typeof setTokenTo;
const setTokenTo = (payload: SetTokenToMetaAction['payload']): SetTokenToMetaAction => ({
type: TypeKeys.TOKEN_TO_META_SET, type: TypeKeys.TOKEN_TO_META_SET,
payload payload
}); });
const setTokenValue = (payload: SetTokenValueMetaAction['payload']): SetTokenValueMetaAction => ({ export type TSetTokenValue = typeof setTokenValue;
export const setTokenValue = (
payload: SetTokenValueMetaAction['payload']
): SetTokenValueMetaAction => ({
type: TypeKeys.TOKEN_VALUE_META_SET, type: TypeKeys.TOKEN_VALUE_META_SET,
payload payload
}); });
const setUnitMeta = (payload: SetUnitMetaAction['payload']): SetUnitMetaAction => ({ export type TSetUnitMeta = typeof setUnitMeta;
export const setUnitMeta = (payload: SetUnitMetaAction['payload']): SetUnitMetaAction => ({
type: TypeKeys.UNIT_META_SET, type: TypeKeys.UNIT_META_SET,
payload payload
}); });
export { TSetUnitMeta, TSetTokenBalance, TSetTokenTo, setUnitMeta, setTokenValue, setTokenTo };

View File

@ -6,8 +6,7 @@ import { Query } from 'components/renderCbs';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getUnit } from 'selectors/transaction'; import { getUnit } from 'selectors/transaction';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkUnit } from 'selectors/config';
import { NetworkConfig } from 'types/network';
interface DispatchProps { interface DispatchProps {
setUnitMeta: TSetUnitMeta; setUnitMeta: TSetUnitMeta;
@ -18,21 +17,21 @@ interface StateProps {
tokens: TokenBalance[]; tokens: TokenBalance[];
allTokens: MergedToken[]; allTokens: MergedToken[];
showAllTokens?: boolean; showAllTokens?: boolean;
network: NetworkConfig; networkUnit: string;
} }
class UnitDropdownClass extends Component<DispatchProps & StateProps> { class UnitDropdownClass extends Component<DispatchProps & StateProps> {
public render() { public render() {
const { tokens, allTokens, showAllTokens, unit, network } = this.props; const { tokens, allTokens, showAllTokens, unit, networkUnit } = this.props;
const focusedTokens = showAllTokens ? allTokens : tokens; const focusedTokens = showAllTokens ? allTokens : tokens;
const options = [network.unit, ...getTokenSymbols(focusedTokens)]; const options = [networkUnit, ...getTokenSymbols(focusedTokens)];
return ( return (
<Query <Query
params={['readOnly']} params={['readOnly']}
withQuery={({ readOnly }) => ( withQuery={({ readOnly }) => (
<Dropdown <Dropdown
options={options} options={options}
value={unit === 'ether' ? network.unit : unit} value={unit === 'ether' ? networkUnit : unit}
onChange={this.handleOnChange} onChange={this.handleOnChange}
clearable={false} clearable={false}
searchable={options.length > 10} searchable={options.length > 10}
@ -53,7 +52,7 @@ function mapStateToProps(state: AppState) {
tokens: getShownTokenBalances(state, true), tokens: getShownTokenBalances(state, true),
allTokens: getTokens(state), allTokens: getTokens(state),
unit: getUnit(state), unit: getUnit(state),
network: getNetworkConfig(state) networkUnit: getNetworkUnit(state)
}; };
} }

View File

@ -17,7 +17,7 @@ import { getGasLimit } from 'selectors/transaction';
import { AddressField, AmountField, TXMetaDataPanel } from 'components'; import { AddressField, AmountField, TXMetaDataPanel } from 'components';
import { SetGasLimitFieldAction } from 'actions/transaction/actionTypes/fields'; import { SetGasLimitFieldAction } from 'actions/transaction/actionTypes/fields';
import { buildEIP681EtherRequest, buildEIP681TokenRequest } from 'libs/values'; import { buildEIP681EtherRequest, buildEIP681TokenRequest } from 'libs/values';
import { getNetworkConfig, getSelectedTokenContractAddress } from 'selectors/config'; import { getNetworkConfig, getSelectedTokenContractAddress, isNetworkUnit } from 'selectors/config';
import './RequestPayment.scss'; import './RequestPayment.scss';
import { reset, TReset, setCurrentTo, TSetCurrentTo } from 'actions/transaction'; import { reset, TReset, setCurrentTo, TSetCurrentTo } from 'actions/transaction';
import { NetworkConfig } from 'types/network'; import { NetworkConfig } from 'types/network';
@ -34,6 +34,7 @@ interface StateProps {
networkConfig: NetworkConfig; networkConfig: NetworkConfig;
decimal: number; decimal: number;
tokenContractAddress: string; tokenContractAddress: string;
isNetworkUnit: boolean;
} }
interface ActionProps { interface ActionProps {
@ -161,7 +162,7 @@ class RequestPayment extends React.Component<Props, {}> {
return ''; return '';
} }
if (unit === 'ether') { if (this.props.isNetworkUnit) {
return buildEIP681EtherRequest(currentTo, chainId, currentValue); return buildEIP681EtherRequest(currentTo, chainId, currentValue);
} else { } else {
return buildEIP681TokenRequest( return buildEIP681TokenRequest(
@ -184,7 +185,8 @@ function mapStateToProps(state: AppState): StateProps {
gasLimit: getGasLimit(state), gasLimit: getGasLimit(state),
networkConfig: getNetworkConfig(state), networkConfig: getNetworkConfig(state),
decimal: getDecimal(state), decimal: getDecimal(state),
tokenContractAddress: getSelectedTokenContractAddress(state) tokenContractAddress: getSelectedTokenContractAddress(state),
isNetworkUnit: isNetworkUnit(state, getUnit(state))
}; };
} }

View File

@ -103,8 +103,6 @@ const fromTokenBase = (value: TokenValue, decimal: number) =>
const toTokenBase = (value: string, decimal: number) => const toTokenBase = (value: string, decimal: number) =>
TokenValue(convertedToBaseUnit(value, decimal)); TokenValue(convertedToBaseUnit(value, decimal));
const isEtherUnit = (unit: string) => unit === 'ether' || unit === 'ETH';
const convertTokenBase = (value: TokenValue, oldDecimal: number, newDecimal: number) => { const convertTokenBase = (value: TokenValue, oldDecimal: number, newDecimal: number) => {
if (oldDecimal === newDecimal) { if (oldDecimal === newDecimal) {
return value; return value;
@ -115,7 +113,6 @@ const convertTokenBase = (value: TokenValue, oldDecimal: number, newDecimal: num
const gasPricetoBase = (price: number) => toWei(price.toString(), getDecimalFromEtherUnit('gwei')); const gasPricetoBase = (price: number) => toWei(price.toString(), getDecimalFromEtherUnit('gwei'));
export { export {
isEtherUnit,
Data, Data,
Address, Address,
TokenValue, TokenValue,

View File

@ -14,8 +14,8 @@ import {
import { Reducer } from 'redux'; import { Reducer } from 'redux';
const INITIAL_STATE: State = { const INITIAL_STATE: State = {
unit: 'ether', unit: '',
previousUnit: 'ether', previousUnit: '',
decimal: getDecimalFromEtherUnit('ether'), decimal: getDecimalFromEtherUnit('ether'),
tokenValue: { raw: '', value: null }, tokenValue: { raw: '', value: null },
tokenTo: { raw: '', value: null }, tokenTo: { raw: '', value: null },

View File

@ -11,8 +11,7 @@ import {
import { TypeKeys as WalletTK, setTokenBalancePending } from 'actions/wallet'; import { TypeKeys as WalletTK, setTokenBalancePending } from 'actions/wallet';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { showNotification } from 'actions/notifications'; import { showNotification } from 'actions/notifications';
import { isSupportedUnit } from 'selectors/config'; import { isSupportedUnit, isNetworkUnit } from 'selectors/config';
import { isEtherUnit } from 'libs/units';
import { showLiteSend, configureLiteSend } from 'actions/swap'; import { showLiteSend, configureLiteSend } from 'actions/swap';
import { TypeKeys as SwapTK } from 'actions/swap/constants'; import { TypeKeys as SwapTK } from 'actions/swap/constants';
import { isUnlocked, isEtherBalancePending } from 'selectors/wallet'; import { isUnlocked, isEtherBalancePending } from 'selectors/wallet';
@ -40,9 +39,9 @@ export function* configureLiteSendSaga(): SagaIterator {
if (!unlocked) { if (!unlocked) {
yield take(WalletTK.WALLET_SET); yield take(WalletTK.WALLET_SET);
} }
const isNetwrkUnit = yield select(isNetworkUnit, label);
//if it's a token, manually scan for that tokens balance and wait for it to resolve //if it's a token, manually scan for that tokens balance and wait for it to resolve
if (!isEtherUnit(label)) { if (!isNetwrkUnit) {
yield put(setTokenBalancePending({ tokenSymbol: label })); yield put(setTokenBalancePending({ tokenSymbol: label }));
yield take([ yield take([
WalletTK.WALLET_SET_TOKEN_BALANCE_FULFILLED, WalletTK.WALLET_SET_TOKEN_BALANCE_FULFILLED,

View File

@ -7,7 +7,7 @@ import { meta } from './meta';
import { network } from './network'; import { network } from './network';
import { signing } from './signing'; import { signing } from './signing';
import { sendEverything } from './sendEverything'; import { sendEverything } from './sendEverything';
import { reset } from './reset'; import { reset, setDefaultUnit } from './reset';
export function* transaction(): SagaIterator { export function* transaction(): SagaIterator {
yield all([ yield all([
@ -18,6 +18,7 @@ export function* transaction(): SagaIterator {
...network, ...network,
...signing, ...signing,
...sendEverything, ...sendEverything,
...reset ...reset,
setDefaultUnit
]); ]);
} }

View File

@ -9,8 +9,9 @@ import {
getValue, getValue,
getDecimalFromUnit getDecimalFromUnit
} from 'selectors/transaction'; } from 'selectors/transaction';
import { isNetworkUnit } from 'selectors/config';
import { getToken, MergedToken } from 'selectors/wallet'; import { getToken, MergedToken } from 'selectors/wallet';
import { isEtherUnit, TokenValue, Address } from 'libs/units'; import { TokenValue, Address } from 'libs/units';
import { import {
swapTokenToEther, swapTokenToEther,
swapEtherToToken, swapEtherToToken,
@ -23,10 +24,12 @@ import { validateInput, rebaseUserInput, IInput } from 'sagas/transaction/valida
export function* handleSetUnitMeta({ payload: currentUnit }: SetUnitMetaAction): SagaIterator { export function* handleSetUnitMeta({ payload: currentUnit }: SetUnitMetaAction): SagaIterator {
const previousUnit: string = yield select(getPreviousUnit); const previousUnit: string = yield select(getPreviousUnit);
const etherToEther = isEtherUnit(currentUnit) && isEtherUnit(previousUnit); const prevUnit = yield select(isNetworkUnit, previousUnit);
const etherToToken = !isEtherUnit(currentUnit) && isEtherUnit(previousUnit); const currUnit = yield select(isNetworkUnit, currentUnit);
const tokenToEther = isEtherUnit(currentUnit) && !isEtherUnit(previousUnit); const etherToEther = currUnit && prevUnit;
const tokenToToken = !isEtherUnit(currentUnit) && !isEtherUnit(previousUnit); const etherToToken = !currUnit && prevUnit;
const tokenToEther = currUnit && !prevUnit;
const tokenToToken = !currUnit && !prevUnit;
const decimal: number = yield select(getDecimalFromUnit, currentUnit); const decimal: number = yield select(getDecimalFromUnit, currentUnit);
if (etherToEther) { if (etherToEther) {

View File

@ -1,10 +1,22 @@
import { SagaIterator } from 'redux-saga'; import { SagaIterator } from 'redux-saga';
import { TypeKeys } from 'actions/wallet'; import { TypeKeys } from 'actions/wallet';
import { takeEvery, put } from 'redux-saga/effects'; import { takeEvery, put, select } from 'redux-saga/effects';
import { reset as resetActionCreator } from 'actions/transaction'; import {
reset as resetActionCreator,
setUnitMeta,
TypeKeys as Constants
} from 'actions/transaction';
import { getNetworkUnit } from 'selectors/config';
export function* resetTransactionState(): SagaIterator { export function* resetTransactionState(): SagaIterator {
yield put(resetActionCreator()); yield put(resetActionCreator());
} }
export function* setNetworkUnit(): SagaIterator {
const networkUnit = yield select(getNetworkUnit);
yield put(setUnitMeta(networkUnit));
}
export const setDefaultUnit = takeEvery(Constants.RESET, setNetworkUnit);
export const reset = [takeEvery([TypeKeys.WALLET_RESET], resetTransactionState)]; export const reset = [takeEvery([TypeKeys.WALLET_RESET], resetTransactionState)];

View File

@ -1,7 +1,7 @@
import { TokenValue, Wei, isEtherUnit, toTokenBase } from 'libs/units'; import { TokenValue, Wei, toTokenBase } from 'libs/units';
import { SagaIterator } from 'redux-saga'; import { SagaIterator } from 'redux-saga';
import { getEtherBalance, getTokenBalance } from 'selectors/wallet'; import { getEtherBalance, getTokenBalance } from 'selectors/wallet';
import { getOffline } from 'selectors/config'; import { getOffline, isNetworkUnit } from 'selectors/config';
import { select, call } from 'redux-saga/effects'; import { select, call } from 'redux-saga/effects';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getGasLimit, getGasPrice, getUnit, getDecimalFromUnit } from 'selectors/transaction'; import { getGasLimit, getGasPrice, getUnit, getDecimalFromUnit } from 'selectors/transaction';
@ -48,7 +48,7 @@ export function* validateInput(input: TokenValue | Wei | null, unit: string): Sa
const etherBalance: Wei | null = yield select(getEtherBalance); const etherBalance: Wei | null = yield select(getEtherBalance);
const isOffline: boolean = yield select(getOffline); const isOffline: boolean = yield select(getOffline);
const etherTransaction: boolean = yield call(isEtherUnit, unit); const networkUnitTransaction: boolean = yield select(isNetworkUnit, unit);
if (isOffline || !etherBalance) { if (isOffline || !etherBalance) {
return true; return true;
@ -59,14 +59,14 @@ export function* validateInput(input: TokenValue | Wei | null, unit: string): Sa
// TODO: do gas estimation here if we're switching to a token too, it should cover the last edge case // TODO: do gas estimation here if we're switching to a token too, it should cover the last edge case
//make a new transaction for validating ether balances //make a new transaction for validating ether balances
const validationTx = etherTransaction const validationTx = networkUnitTransaction
? yield call(makeCostCalculationTx, input) ? yield call(makeCostCalculationTx, input)
: yield call(makeCostCalculationTx, null); : yield call(makeCostCalculationTx, null);
// check that they have enough ether, this checks gas cost too // check that they have enough ether, this checks gas cost too
valid = valid && enoughBalanceViaTx(validationTx, etherBalance); valid = valid && enoughBalanceViaTx(validationTx, etherBalance);
if (!etherTransaction) { if (!networkUnitTransaction) {
const tokenBalance: TokenValue | null = yield select(getTokenBalance, unit); const tokenBalance: TokenValue | null = yield select(getTokenBalance, unit);
valid = valid && enoughTokensViaInput(input, tokenBalance); valid = valid && enoughTokensViaInput(input, tokenBalance);
} }

View File

@ -66,6 +66,10 @@ export const getNetworkConfig = (state: AppState): StaticNetworkConfig | CustomN
return config; return config;
}; };
export const getNetworkUnit = (state: AppState): string => {
return getNetworkConfig(state).unit;
};
export const getNetworkContracts = (state: AppState): NetworkContract[] | null => { export const getNetworkContracts = (state: AppState): NetworkContract[] | null => {
const network = getStaticNetworkConfig(state); const network = getStaticNetworkConfig(state);
return network ? network.contracts : []; return network ? network.contracts : [];
@ -74,3 +78,7 @@ export const getNetworkContracts = (state: AppState): NetworkContract[] | null =
export const getCustomNetworkConfigs = (state: AppState) => getNetworks(state).customNetworks; export const getCustomNetworkConfigs = (state: AppState) => getNetworks(state).customNetworks;
export const getStaticNetworkConfigs = (state: AppState) => getNetworks(state).staticNetworks; export const getStaticNetworkConfigs = (state: AppState) => getNetworks(state).staticNetworks;
export const isNetworkUnit = (state: AppState, unit: string) => {
return unit === getNetworkUnit(state);
};

View File

@ -1,8 +1,7 @@
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getUnit } from 'selectors/transaction/meta'; import { getUnit } from 'selectors/transaction/meta';
import { isEtherUnit } from 'libs/units';
import { SHAPESHIFT_TOKEN_WHITELIST } from 'api/shapeshift'; import { SHAPESHIFT_TOKEN_WHITELIST } from 'api/shapeshift';
import { getStaticNetworkConfig } from 'selectors/config'; import { getStaticNetworkConfig, isNetworkUnit } from 'selectors/config';
import { Token } from 'types/network'; import { Token } from 'types/network';
export function getNetworkTokens(state: AppState): Token[] { export function getNetworkTokens(state: AppState): Token[] {
@ -19,7 +18,7 @@ export function getSelectedTokenContractAddress(state: AppState): string {
const allTokens = getAllTokens(state); const allTokens = getAllTokens(state);
const currentUnit = getUnit(state); const currentUnit = getUnit(state);
if (isEtherUnit(currentUnit)) { if (isNetworkUnit(state, currentUnit)) {
return ''; return '';
} }
@ -44,7 +43,7 @@ export function tokenExists(state: AppState, token: string): boolean {
export function isSupportedUnit(state: AppState, unit: string) { export function isSupportedUnit(state: AppState, unit: string) {
const isToken: boolean = tokenExists(state, unit); const isToken: boolean = tokenExists(state, unit);
const isEther: boolean = isEtherUnit(unit); const isEther: boolean = isNetworkUnit(state, unit);
if (!isToken && !isEther) { if (!isToken && !isEther) {
return false; return false;
} }

View File

@ -1,6 +1,6 @@
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkConfig } from 'selectors/config';
import { getUnit, isEtherTransaction, getParamsFromSerializedTx } from 'selectors/transaction'; import { getUnit, getParamsFromSerializedTx } from 'selectors/transaction';
import BN from 'bn.js'; import BN from 'bn.js';
import { Wei, TokenValue } from 'libs/units'; import { Wei, TokenValue } from 'libs/units';
@ -9,13 +9,11 @@ export const getRates = (state: AppState) => state.rates;
const getUSDConversionRate = (state: AppState, unit: string) => { const getUSDConversionRate = (state: AppState, unit: string) => {
const { isTestnet } = getNetworkConfig(state); const { isTestnet } = getNetworkConfig(state);
const { rates } = getRates(state); const { rates } = getRates(state);
const isEther = isEtherTransaction(state);
const conversionUnit = isEther ? 'ETH' : unit;
if (isTestnet) { if (isTestnet) {
return null; return null;
} }
const conversionRate = rates[conversionUnit]; const conversionRate = rates[unit];
if (!conversionRate) { if (!conversionRate) {
return null; return null;
@ -29,7 +27,6 @@ export const getValueInUSD = (state: AppState, value: TokenValue | Wei) => {
if (!conversionRate) { if (!conversionRate) {
return null; return null;
} }
const sendValueUSD = value.muln(conversionRate); const sendValueUSD = value.muln(conversionRate);
return sendValueUSD; return sendValueUSD;
}; };

View File

@ -1,9 +1,10 @@
import { getTo, getValue } from './fields'; import { getTo, getValue } from './fields';
import { getUnit, getTokenTo, getTokenValue } from './meta'; import { getUnit, getTokenTo, getTokenValue } from './meta';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { isEtherUnit, TokenValue, Wei, Address } from 'libs/units'; import { TokenValue, Wei, Address } from 'libs/units';
import { gasPriceValidator, gasLimitValidator } from 'libs/validators'; import { gasPriceValidator, gasLimitValidator } from 'libs/validators';
import { getDataExists, getGasPrice, getGasLimit } from 'selectors/transaction'; import { getDataExists, getGasPrice, getGasLimit } from 'selectors/transaction';
import { isNetworkUnit } from 'selectors/config';
import { getAddressMessage, AddressMessage } from 'config'; import { getAddressMessage, AddressMessage } from 'config';
interface ICurrentValue { interface ICurrentValue {
@ -18,7 +19,7 @@ interface ICurrentTo {
const isEtherTransaction = (state: AppState) => { const isEtherTransaction = (state: AppState) => {
const unit = getUnit(state); const unit = getUnit(state);
const etherUnit = isEtherUnit(unit); const etherUnit = isNetworkUnit(state, unit);
return etherUnit; return etherUnit;
}; };

View File

@ -1,7 +1,6 @@
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { ICurrentTo, ICurrentValue } from 'selectors/transaction'; import { ICurrentTo, ICurrentValue } from 'selectors/transaction';
import { isEtherUnit } from 'libs/units'; import { isNetworkUnit } from 'selectors/config';
export const reduceToValues = (transactionFields: AppState['transaction']['fields']) => export const reduceToValues = (transactionFields: AppState['transaction']['fields']) =>
Object.keys(transactionFields).reduce( Object.keys(transactionFields).reduce(
(obj, currFieldName) => { (obj, currFieldName) => {
@ -12,6 +11,7 @@ export const reduceToValues = (transactionFields: AppState['transaction']['field
); );
export const isFullTx = ( export const isFullTx = (
state: AppState,
transactionFields: AppState['transaction']['fields'], transactionFields: AppState['transaction']['fields'],
currentTo: ICurrentTo, currentTo: ICurrentTo,
currentValue: ICurrentValue, currentValue: ICurrentValue,
@ -26,7 +26,7 @@ export const isFullTx = (
isValid && !!v.value, isValid && !!v.value,
true true
); );
if (isEtherUnit(unit)) { if (isNetworkUnit(state, unit)) {
// if theres data we can have no current value, and we dont have to check for a to address // if theres data we can have no current value, and we dont have to check for a to address
if (dataExists && validGasCost && !currentValue.value && currentValue.raw === '') { if (dataExists && validGasCost && !currentValue.value && currentValue.raw === '') {
return validPartialParams; return validPartialParams;

View File

@ -1,7 +1,8 @@
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getTransactionState } from './transaction'; import { getTransactionState } from './transaction';
import { getDecimalFromEtherUnit, isEtherUnit } from 'libs/units';
import { getToken } from 'selectors/wallet'; import { getToken } from 'selectors/wallet';
import { isNetworkUnit } from 'selectors/config/wallet';
import { getDecimalFromEtherUnit } from 'libs/units';
const getMetaState = (state: AppState) => getTransactionState(state).meta; const getMetaState = (state: AppState) => getTransactionState(state).meta;
const getFrom = (state: AppState) => getMetaState(state).from; const getFrom = (state: AppState) => getMetaState(state).from;
@ -11,7 +12,7 @@ const getTokenValue = (state: AppState) => getMetaState(state).tokenValue;
const getUnit = (state: AppState) => getMetaState(state).unit; const getUnit = (state: AppState) => getMetaState(state).unit;
const getPreviousUnit = (state: AppState) => getMetaState(state).previousUnit; const getPreviousUnit = (state: AppState) => getMetaState(state).previousUnit;
const getDecimalFromUnit = (state: AppState, unit: string) => { const getDecimalFromUnit = (state: AppState, unit: string) => {
if (isEtherUnit(unit)) { if (isNetworkUnit(state, unit)) {
return getDecimalFromEtherUnit('ether'); return getDecimalFromEtherUnit('ether');
} else { } else {
const token = getToken(state, unit); const token = getToken(state, unit);

View File

@ -34,6 +34,7 @@ const getTransaction = (state: AppState): IGetTransaction => {
const dataExists = getDataExists(state); const dataExists = getDataExists(state);
const validGasCost = getValidGasCost(state); const validGasCost = getValidGasCost(state);
const isFullTransaction = isFullTx( const isFullTransaction = isFullTx(
state,
transactionFields, transactionFields,
currentTo, currentTo,
currentValue, currentValue,

View File

@ -73,13 +73,13 @@ export function formatNumber(num: string, digits?: number): string {
} }
// TODO: Comment up this function to make it clear what's happening here. // TODO: Comment up this function to make it clear what's happening here.
export function formatGasLimit(limit: Wei, transactionUnit: string = 'ether') { export function formatGasLimit(limit: Wei, transactionUnit: string = 'ETH') {
let limitStr = limit.toString(); let limitStr = limit.toString();
// I'm guessing this is some known off-by-one-error from the node? // I'm guessing this is some known off-by-one-error from the node?
// 21k is only the limit for ethereum though, so make sure they're // 21k is only the limit for ethereum though, so make sure they're
// sending ether if we're going to fix it for them. // sending ether if we're going to fix it for them.
if (limitStr === '21001' && transactionUnit === 'ether') { if (limitStr === '21001' && transactionUnit === 'ETH') {
limitStr = '21000'; limitStr = '21000';
} }

View File

@ -1,5 +1,7 @@
import { configuredStore } from 'store';
import CONTRACTS from 'config/contracts'; import CONTRACTS from 'config/contracts';
import { isValidETHAddress } from 'libs/validators'; import { isValidETHAddress } from 'libs/validators';
configuredStore.getState();
describe('Contracts JSON', () => { describe('Contracts JSON', () => {
Object.keys(CONTRACTS).forEach(network => { Object.keys(CONTRACTS).forEach(network => {

View File

@ -1,5 +1,7 @@
import { configuredStore } from 'store';
import TOKENS from 'config/tokens'; import TOKENS from 'config/tokens';
import { isValidETHAddress } from 'libs/validators'; import { isValidETHAddress } from 'libs/validators';
configuredStore.getState();
describe('Tokens JSON', () => { describe('Tokens JSON', () => {
Object.keys(TOKENS).forEach(network => { Object.keys(TOKENS).forEach(network => {

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { import {
decryptPrivKey, decryptPrivKey,
decodeCryptojsSalt, decodeCryptojsSalt,
@ -5,6 +6,7 @@ import {
decipherBuffer, decipherBuffer,
decryptMnemonicToPrivKey decryptMnemonicToPrivKey
} from '../../common/libs/decrypt'; } from '../../common/libs/decrypt';
configuredStore.getState();
// Elements of a V1 encrypted priv key // Elements of a V1 encrypted priv key
const v1 = { const v1 = {
@ -42,11 +44,10 @@ describe('decodeCryptojsSalt', () => {
describe('evp_kdf', () => { describe('evp_kdf', () => {
it('should derive correct key and iv', () => { it('should derive correct key and iv', () => {
const result = evp_kdf( const result = evp_kdf(new Buffer(v1.pass, 'utf8'), new Buffer(v1.salt, 'base64'), {
new Buffer(v1.pass, 'utf8'), keysize: 32,
new Buffer(v1.salt, 'base64'), ivsize: 16
{ keysize: 32, ivsize: 16 } });
);
expect(result.key).toBeInstanceOf(Buffer); expect(result.key).toBeInstanceOf(Buffer);
expect(result.iv).toBeInstanceOf(Buffer); expect(result.iv).toBeInstanceOf(Buffer);
@ -78,13 +79,11 @@ describe('decipherBuffer', () => {
describe('decryptMnemonicToPrivKey', () => { describe('decryptMnemonicToPrivKey', () => {
const mocks = [ const mocks = [
{ {
phrase: phrase: 'first catalog away faculty jelly now life kingdom pigeon raise gain accident',
'first catalog away faculty jelly now life kingdom pigeon raise gain accident',
pass: '', pass: '',
path: "m/44'/60'/0'/0/8", path: "m/44'/60'/0'/0/8",
address: '0xe2EdC95134bbD88443bc6D55b809F7d0C2f0C854', address: '0xe2EdC95134bbD88443bc6D55b809F7d0C2f0C854',
privKey: privKey: '31e97f395cabc6faa37d8a9d6bb185187c35704e7b976c7a110e2f0eab37c344'
'31e97f395cabc6faa37d8a9d6bb185187c35704e7b976c7a110e2f0eab37c344'
}, },
{ {
phrase: phrase:
@ -92,8 +91,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: '', pass: '',
path: "m/44'/60'/0'/0/18", path: "m/44'/60'/0'/0/18",
address: '0xB20f8aCA62e18f4586aAEf4720daCac23cC29954', address: '0xB20f8aCA62e18f4586aAEf4720daCac23cC29954',
privKey: privKey: '594ee624ebad54b9469915c3f5eb22127727a5e380a17d24780dbe272996b401'
'594ee624ebad54b9469915c3f5eb22127727a5e380a17d24780dbe272996b401'
}, },
{ {
phrase: phrase:
@ -101,8 +99,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: '', pass: '',
path: "m/44'/60'/0'/0/24", path: "m/44'/60'/0'/0/24",
address: '0xE6D0932fFDDcB45bf0e18dE4716137dEdD2E4c2c', address: '0xE6D0932fFDDcB45bf0e18dE4716137dEdD2E4c2c',
privKey: privKey: '6aba8bb6018a85af7cb552325b52e397f83cfb56f68cf8937aa14c3875bbb0aa'
'6aba8bb6018a85af7cb552325b52e397f83cfb56f68cf8937aa14c3875bbb0aa'
}, },
{ {
phrase: phrase:
@ -110,8 +107,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: '', pass: '',
path: "m/44'/60'/0'/0/0", path: "m/44'/60'/0'/0/0",
address: '0xd163f4d95782608b251c4d985846A1754c53D32C', address: '0xd163f4d95782608b251c4d985846A1754c53D32C',
privKey: privKey: '88046b4bdbb1c88945662cb0984258ca1b09df0bb0b38fdc55bcb8998f28aad4'
'88046b4bdbb1c88945662cb0984258ca1b09df0bb0b38fdc55bcb8998f28aad4'
}, },
{ {
phrase: phrase:
@ -119,17 +115,14 @@ describe('decryptMnemonicToPrivKey', () => {
pass: '', pass: '',
path: "m/44'/60'/0'/0/4", path: "m/44'/60'/0'/0/4",
address: '0x04E2df6Fe2a28dd24dbCC49485ff30Fc3ea04822', address: '0x04E2df6Fe2a28dd24dbCC49485ff30Fc3ea04822',
privKey: privKey: 'fc9ad0931a3aee167179c1fd31825b7a7b558b4bb2eb3fb0c04028c98d495907'
'fc9ad0931a3aee167179c1fd31825b7a7b558b4bb2eb3fb0c04028c98d495907'
}, },
{ {
phrase: phrase: 'stadium river pigeon midnight grit truck fiscal eight hello rescue destroy eyebrow',
'stadium river pigeon midnight grit truck fiscal eight hello rescue destroy eyebrow',
pass: 'password', pass: 'password',
path: "m/44'/60'/0'/0/5", path: "m/44'/60'/0'/0/5",
address: '0xe74908668F594f327fd2215A2564Cf79298a136e', address: '0xe74908668F594f327fd2215A2564Cf79298a136e',
privKey: privKey: 'b65abfb2660f71b4b46aed98975f0cc1ebe1fcb3835a7a10b236e4012c93f306'
'b65abfb2660f71b4b46aed98975f0cc1ebe1fcb3835a7a10b236e4012c93f306'
}, },
{ {
phrase: phrase:
@ -137,8 +130,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: 'password', pass: 'password',
path: "m/44'/60'/0'/0/10", path: "m/44'/60'/0'/0/10",
address: '0x0d20865AfAE9B8a1F867eCd60684FBCDA3Bd1FA5', address: '0x0d20865AfAE9B8a1F867eCd60684FBCDA3Bd1FA5',
privKey: privKey: '29eb9ec0f5586d1935bc4c6bd89e6fb3de76b4fad345fa844efc5432885cfe73'
'29eb9ec0f5586d1935bc4c6bd89e6fb3de76b4fad345fa844efc5432885cfe73'
}, },
{ {
phrase: phrase:
@ -146,8 +138,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: 'password', pass: 'password',
path: "m/44'/60'/0'/0/7", path: "m/44'/60'/0'/0/7",
address: '0xdd5d6e5dEfD09c3F2BD6d994EE43B59df88c7187', address: '0xdd5d6e5dEfD09c3F2BD6d994EE43B59df88c7187',
privKey: privKey: 'd13404b9b05f6b5bf8e5cf810aa903e4b60ac654b0acf09a8ea0efe174746ae5'
'd13404b9b05f6b5bf8e5cf810aa903e4b60ac654b0acf09a8ea0efe174746ae5'
}, },
{ {
phrase: phrase:
@ -155,8 +146,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: 'password', pass: 'password',
path: "m/44'/60'/0'/0/11", path: "m/44'/60'/0'/0/11",
address: '0x6d95e7cC28113F9491b2Ec6b621575a5565Fd208', address: '0x6d95e7cC28113F9491b2Ec6b621575a5565Fd208',
privKey: privKey: 'a52329aa3d6f2426f8783a1e5f419997e2628ec9a89cc2b7b182d2eaf7f95a24'
'a52329aa3d6f2426f8783a1e5f419997e2628ec9a89cc2b7b182d2eaf7f95a24'
}, },
{ {
phrase: phrase:
@ -164,8 +154,7 @@ describe('decryptMnemonicToPrivKey', () => {
pass: 'password', pass: 'password',
path: "m/44'/60'/0'/0/4", path: "m/44'/60'/0'/0/4",
address: '0x3e583eF3d3cE5Dd483c86A1E00A479cE11Ca21Cf', address: '0x3e583eF3d3cE5Dd483c86A1E00A479cE11Ca21Cf',
privKey: privKey: '450538d4181c4d8ce076ecb34785198316adebe959d6f9462cfb68a58b1819bc'
'450538d4181c4d8ce076ecb34785198316adebe959d6f9462cfb68a58b1819bc'
}, },
{ {
phrase: phrase:
@ -173,20 +162,14 @@ describe('decryptMnemonicToPrivKey', () => {
pass: 'password123', pass: 'password123',
path: "m/44'/60'/0'/1", path: "m/44'/60'/0'/1",
address: '0x7545D615643F933c34C3E083E68CC831167F31af', address: '0x7545D615643F933c34C3E083E68CC831167F31af',
privKey: privKey: '0a43098da5ae737843e385b76b44266a9f8f856cb1b943055b5a96188d306d97'
'0a43098da5ae737843e385b76b44266a9f8f856cb1b943055b5a96188d306d97'
} }
]; ];
it('should derive correct private key from variable phrase lengths/passwords/paths', () => { it('should derive correct private key from variable phrase lengths/passwords/paths', () => {
mocks.forEach(mock => { mocks.forEach(mock => {
const { phrase, pass, path, privKey, address } = mock; const { phrase, pass, path, privKey, address } = mock;
const derivedPrivKey = decryptMnemonicToPrivKey( const derivedPrivKey = decryptMnemonicToPrivKey(phrase, pass, path, address);
phrase,
pass,
path,
address
);
expect(derivedPrivKey.toString('hex')).toEqual(privKey); expect(derivedPrivKey.toString('hex')).toEqual(privKey);
}); });
}); });

View File

@ -1,5 +1,7 @@
import { configuredStore } from 'store';
import { toWei } from 'libs/units'; import { toWei } from 'libs/units';
import ERC20 from 'libs/erc20'; import ERC20 from 'libs/erc20';
configuredStore.getState();
const MYCRYPTO_ADDRESS = '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8'; const MYCRYPTO_ADDRESS = '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8';
describe('ERC20', () => { describe('ERC20', () => {

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { import {
fromWei, fromWei,
Wei, Wei,
@ -8,6 +9,7 @@ import {
convertTokenBase, convertTokenBase,
TokenValue TokenValue
} from 'libs/units'; } from 'libs/units';
configuredStore.getState();
const Units = { const Units = {
wei: '1', wei: '1',

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { import {
isValidBTCAddress, isValidBTCAddress,
isValidETHAddress, isValidETHAddress,
@ -6,6 +7,7 @@ import {
} from '../../common/libs/validators'; } from '../../common/libs/validators';
import { DPaths } from 'config/dpaths'; import { DPaths } from 'config/dpaths';
import { valid, invalid } from '../utils/testStrings'; import { valid, invalid } from '../utils/testStrings';
configuredStore.getState();
const VALID_BTC_ADDRESS = '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6'; const VALID_BTC_ADDRESS = '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6';
const VALID_ETH_ADDRESS = '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8'; const VALID_ETH_ADDRESS = '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8';

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import React from 'react'; import React from 'react';
import Enzyme from 'enzyme'; import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16'; import Adapter from 'enzyme-adapter-react-16';
@ -6,6 +7,7 @@ import shallowWithStore from '../utils/shallowWithStore';
import { createMockStore } from 'redux-test-utils'; import { createMockStore } from 'redux-test-utils';
import { createMockRouteComponentProps } from '../utils/mockRouteComponentProps'; import { createMockRouteComponentProps } from '../utils/mockRouteComponentProps';
import { RouteComponentProps } from 'react-router'; import { RouteComponentProps } from 'react-router';
configuredStore.getState();
Enzyme.configure({ adapter: new Adapter() }); Enzyme.configure({ adapter: new Adapter() });

View File

@ -1,8 +1,10 @@
import { configuredStore } from 'store';
import { web3SetNode, web3UnsetNode } from 'actions/config'; import { web3SetNode, web3UnsetNode } from 'actions/config';
import { staticNodes, INITIAL_STATE } from 'reducers/config/nodes/staticNodes'; import { staticNodes, INITIAL_STATE } from 'reducers/config/nodes/staticNodes';
import { EtherscanNode, InfuraNode, RPCNode } from 'libs/nodes'; import { EtherscanNode, InfuraNode, RPCNode } from 'libs/nodes';
import { Web3NodeConfig } from 'types/node'; import { Web3NodeConfig } from 'types/node';
import { Web3Service } from 'libs/nodes/web3'; import { Web3Service } from 'libs/nodes/web3';
configuredStore.getState();
const expectedInitialState = { const expectedInitialState = {
eth_mycrypto: { eth_mycrypto: {

View File

@ -1,6 +1,8 @@
import { configuredStore } from 'store';
import { deterministicWallets, INITIAL_STATE } from 'reducers/deterministicWallets'; import { deterministicWallets, INITIAL_STATE } from 'reducers/deterministicWallets';
import * as dWalletActions from 'actions/deterministicWallets'; import * as dWalletActions from 'actions/deterministicWallets';
import { TokenValue } from 'libs/units'; import { TokenValue } from 'libs/units';
configuredStore.getState();
describe('deterministicWallets reducer', () => { describe('deterministicWallets reducer', () => {
const tokenValues: dWalletActions.ITokenValues = { const tokenValues: dWalletActions.ITokenValues = {

View File

@ -1,6 +1,8 @@
import { configuredStore } from 'store';
import { wallet, INITIAL_STATE } from 'reducers/wallet'; import { wallet, INITIAL_STATE } from 'reducers/wallet';
import { Wei } from 'libs/units'; import { Wei } from 'libs/units';
import * as walletActions from 'actions/wallet'; import * as walletActions from 'actions/wallet';
configuredStore.getState();
describe('wallet reducer', () => { describe('wallet reducer', () => {
it('should handle WALLET_SET', () => { it('should handle WALLET_SET', () => {

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { Address } from 'libs/units'; import { Address } from 'libs/units';
import { call, select, put } from 'redux-saga/effects'; import { call, select, put } from 'redux-saga/effects';
import { isValidETHAddress, isValidENSAddress } from 'libs/validators'; import { isValidETHAddress, isValidENSAddress } from 'libs/validators';
@ -5,6 +6,7 @@ import { setCurrentTo, setField } from 'sagas/transaction/current/currentTo';
import { isEtherTransaction } from 'selectors/transaction'; import { isEtherTransaction } from 'selectors/transaction';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator } from 'redux-saga/utils';
import { setToField, setTokenTo } from 'actions/transaction'; import { setToField, setTokenTo } from 'actions/transaction';
configuredStore.getState();
const raw = '0xa'; const raw = '0xa';
const payload = { const payload = {

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import BN from 'bn.js'; import BN from 'bn.js';
import { call, put } from 'redux-saga/effects'; import { call, put } from 'redux-saga/effects';
import { setDataField, setGasLimitField, setNonceField } from 'actions/transaction/actionCreators'; import { setDataField, setGasLimitField, setNonceField } from 'actions/transaction/actionCreators';
@ -11,6 +12,7 @@ import {
} from 'sagas/transaction/fields/fields'; } from 'sagas/transaction/fields/fields';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator } from 'redux-saga/utils';
import { setGasPriceField } from 'actions/transaction'; import { setGasPriceField } from 'actions/transaction';
configuredStore.getState();
const itShouldBeDone = gen => { const itShouldBeDone = gen => {
it('should be done', () => { it('should be done', () => {

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { select, call, put } from 'redux-saga/effects'; import { select, call, put } from 'redux-saga/effects';
import { setDataField } from 'actions/transaction'; import { setDataField } from 'actions/transaction';
import { encodeTransfer } from 'libs/transaction/utils/token'; import { encodeTransfer } from 'libs/transaction/utils/token';
@ -6,6 +7,7 @@ import { bufferToHex, toBuffer } from 'ethereumjs-util';
import { getTokenTo, getData } from 'selectors/transaction'; import { getTokenTo, getData } from 'selectors/transaction';
import { handleTokenTo, handleTokenValue } from 'sagas/transaction/meta/token'; import { handleTokenTo, handleTokenValue } from 'sagas/transaction/meta/token';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator } from 'redux-saga/utils';
configuredStore.getState();
const itShouldBeDone = gen => { const itShouldBeDone = gen => {
it('should be done', () => { it('should be done', () => {

View File

@ -19,6 +19,7 @@ import { bufferToHex } from 'ethereumjs-util';
import { rebaseUserInput, validateInput } from 'sagas/transaction/validationHelpers'; import { rebaseUserInput, validateInput } from 'sagas/transaction/validationHelpers';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator } from 'redux-saga/utils';
import { handleSetUnitMeta } from 'sagas/transaction/meta/unitSwap'; import { handleSetUnitMeta } from 'sagas/transaction/meta/unitSwap';
import { isNetworkUnit } from 'selectors/config';
const itShouldBeDone = gen => { const itShouldBeDone = gen => {
it('should be done', () => { it('should be done', () => {
@ -27,25 +28,41 @@ const itShouldBeDone = gen => {
}; };
describe('handleSetUnitMeta*', () => { describe('handleSetUnitMeta*', () => {
const expectedStart = (gen, previousUnit, currentUnit) => { const expectedStart = (
gen,
previousUnit,
currentUnit,
prevUnitIsNetworkUnit,
currUnitIsNetworkUnit
) => {
it('should select getPreviousUnit', () => { it('should select getPreviousUnit', () => {
expect(gen.next().value).toEqual(select(getPreviousUnit)); expect(gen.next().value).toEqual(select(getPreviousUnit));
}); });
it('should check if prevUnit is a network unit', () => {
expect(gen.next(previousUnit).value).toEqual(select(isNetworkUnit, previousUnit));
});
it('should check if currUnit is a network unit', () => {
expect(gen.next(prevUnitIsNetworkUnit).value).toEqual(select(isNetworkUnit, currentUnit));
});
it('should select getDeciimalFromUnit with currentUnit', () => { it('should select getDeciimalFromUnit with currentUnit', () => {
expect(gen.next(previousUnit).value).toEqual(select(getDecimalFromUnit, currentUnit)); expect(gen.next(currUnitIsNetworkUnit).value).toEqual(
select(getDecimalFromUnit, currentUnit)
);
}); });
}; };
describe('etherToEther', () => { describe('etherToEther', () => {
const currentUnit = 'ether'; const currentUnit = 'ETH';
const previousUnit = 'ether'; const previousUnit = 'ETH';
const action: any = { const action: any = {
payload: currentUnit payload: currentUnit
}; };
const gen = handleSetUnitMeta(action); const gen = handleSetUnitMeta(action);
expectedStart(gen, previousUnit, currentUnit); expectedStart(gen, previousUnit, currentUnit, true, true);
it('should return correctly', () => { it('should return correctly', () => {
expect(gen.next().value).toEqual(undefined); expect(gen.next().value).toEqual(undefined);
@ -56,7 +73,7 @@ describe('handleSetUnitMeta*', () => {
describe('tokenToEther', () => { describe('tokenToEther', () => {
const previousUnit = 'token'; const previousUnit = 'token';
const currentUnit = 'ether'; const currentUnit = 'ETH';
const action: any = { const action: any = {
payload: currentUnit payload: currentUnit
}; };
@ -67,7 +84,7 @@ describe('handleSetUnitMeta*', () => {
const value: any = 'value'; const value: any = 'value';
const gen = handleSetUnitMeta(action); const gen = handleSetUnitMeta(action);
expectedStart(gen, previousUnit, currentUnit); expectedStart(gen, previousUnit, currentUnit, false, true);
it('should select getTokenTo', () => { it('should select getTokenTo', () => {
expect(gen.next(decimal).value).toEqual(select(getTokenTo)); expect(gen.next(decimal).value).toEqual(select(getTokenTo));
@ -146,7 +163,7 @@ describe('handleSetUnitMeta*', () => {
}; };
describe('etherToToken', () => { describe('etherToToken', () => {
const previousUnit = 'ether'; const previousUnit = 'ETH';
const currentUnit = 'token'; const currentUnit = 'token';
const action: any = { const action: any = {
payload: currentUnit payload: currentUnit
@ -164,7 +181,7 @@ describe('handleSetUnitMeta*', () => {
const gens: any = {}; const gens: any = {};
gens.gen = cloneableGenerator(handleSetUnitMeta)(action); gens.gen = cloneableGenerator(handleSetUnitMeta)(action);
expectedStart(gens.gen, previousUnit, currentUnit); expectedStart(gens.gen, previousUnit, currentUnit, true, false);
sharedLogicA(gens.gen, decimal, currentUnit); sharedLogicA(gens.gen, decimal, currentUnit);
@ -211,7 +228,7 @@ describe('handleSetUnitMeta*', () => {
const gens: any = {}; const gens: any = {};
gens.gen = cloneableGenerator(handleSetUnitMeta)(action); gens.gen = cloneableGenerator(handleSetUnitMeta)(action);
expectedStart(gens.gen, previousUnit, currentUnit); expectedStart(gens.gen, previousUnit, currentUnit, false, false);
sharedLogicA(gens.gen, decimal, currentUnit); sharedLogicA(gens.gen, decimal, currentUnit);

View File

@ -1,9 +1,11 @@
import { configuredStore } from 'store';
import { apply, put, select } from 'redux-saga/effects'; import { apply, put, select } from 'redux-saga/effects';
import { getWalletInst } from 'selectors/wallet'; import { getWalletInst } from 'selectors/wallet';
import { getFromSucceeded, getFromFailed } from 'actions/transaction'; import { getFromSucceeded, getFromFailed } from 'actions/transaction';
import { showNotification } from 'actions/notifications'; import { showNotification } from 'actions/notifications';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator } from 'redux-saga/utils';
import { handleFromRequest } from 'sagas/transaction/network/from'; import { handleFromRequest } from 'sagas/transaction/network/from';
configuredStore.getState();
describe('handleFromRequest*', () => { describe('handleFromRequest*', () => {
const walletInst: any = { const walletInst: any = {

View File

@ -1,8 +1,10 @@
import { configuredStore } from 'store';
import { getWalletInst } from 'selectors/wallet'; import { getWalletInst } from 'selectors/wallet';
import { getNetworkConfig } from 'selectors/config'; import { getNetworkConfig } from 'selectors/config';
import { select, call, put, take } from 'redux-saga/effects'; import { select, call, put, take } from 'redux-saga/effects';
import { signTransactionFailed, getFromRequested, TypeKeys as TK } from 'actions/transaction'; import { signTransactionFailed, getFromRequested, TypeKeys as TK } from 'actions/transaction';
import { showNotification } from 'actions/notifications'; import { showNotification } from 'actions/notifications';
configuredStore.getState();
/* tslint:disable */ /* tslint:disable */
import 'actions/transaction'; import 'actions/transaction';

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { put, apply, call } from 'redux-saga/effects'; import { put, apply, call } from 'redux-saga/effects';
import { signLocalTransactionSucceeded, signWeb3TransactionSucceeded } from 'actions/transaction'; import { signLocalTransactionSucceeded, signWeb3TransactionSucceeded } from 'actions/transaction';
import { computeIndexingHash } from 'libs/transaction'; import { computeIndexingHash } from 'libs/transaction';
@ -5,6 +6,7 @@ import {
signLocalTransactionHandler, signLocalTransactionHandler,
signWeb3TransactionHandler signWeb3TransactionHandler
} from 'sagas/transaction/signing/signing'; } from 'sagas/transaction/signing/signing';
configuredStore.getState();
describe('signLocalTransactionHandler*', () => { describe('signLocalTransactionHandler*', () => {
const tx = 'tx'; const tx = 'tx';

View File

@ -1,7 +1,7 @@
import { select, call } from 'redux-saga/effects'; import { select, call } from 'redux-saga/effects';
import { getUnit, getDecimalFromUnit, getGasLimit, getGasPrice } from 'selectors/transaction'; import { getUnit, getDecimalFromUnit, getGasLimit, getGasPrice } from 'selectors/transaction';
import { getEtherBalance, getTokenBalance } from 'selectors/wallet'; import { getEtherBalance, getTokenBalance } from 'selectors/wallet';
import { isEtherUnit, toTokenBase, Wei } from 'libs/units'; import { toTokenBase, Wei } from 'libs/units';
import { makeTransaction } from 'libs/transaction'; import { makeTransaction } from 'libs/transaction';
import { import {
rebaseUserInput, rebaseUserInput,
@ -9,7 +9,7 @@ import {
makeCostCalculationTx makeCostCalculationTx
} from 'sagas/transaction/validationHelpers'; } from 'sagas/transaction/validationHelpers';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator } from 'redux-saga/utils';
import { getOffline } from 'selectors/config'; import { getOffline, isNetworkUnit } from 'selectors/config';
const itShouldBeDone = gen => { const itShouldBeDone = gen => {
it('should be done', () => { it('should be done', () => {
@ -80,7 +80,6 @@ describe('validateInput*', () => {
const input: any = 'input'; const input: any = 'input';
const unit = 'unit'; const unit = 'unit';
const etherBalance = Wei('1000'); const etherBalance = Wei('1000');
const isOffline = false;
const etherTransaction = true; const etherTransaction = true;
const validationTx = { const validationTx = {
gasLimit: Wei('30'), gasLimit: Wei('30'),
@ -101,27 +100,24 @@ describe('validateInput*', () => {
}); });
it('should select getOffline', () => { it('should select getOffline', () => {
gens.clone1 = gens.gen.clone();
gens.clone2 = gens.gen.clone(); gens.clone2 = gens.gen.clone();
expect(gens.gen.next(etherBalance).value).toEqual(select(getOffline)); expect(gens.gen.next(etherBalance).value).toEqual(select(getOffline));
gens.clone1 = gens.gen.clone();
}); });
it('should call isEtherUnit', () => { it('should call isNetworkUnit', () => {
expect(gens.gen.next(isOffline).value).toEqual(call(isEtherUnit, unit)); expect(gens.gen.next(false).value).toEqual(select(isNetworkUnit, unit));
gens.clone3 = gens.gen.clone(); gens.clone3 = gens.gen.clone();
}); });
it('should return true when offline', () => { it('should return true when offline', () => {
gens.clone1.next(); expect(gens.clone1.next(true).value).toEqual(select(isNetworkUnit, unit));
gens.clone1.next(true);
expect(gens.clone1.next(true).value).toEqual(true);
expect(gens.clone1.next().done).toEqual(true); expect(gens.clone1.next().done).toEqual(true);
}); });
it('should return when !etherBalance', () => { it('should return when !etherBalance', () => {
gens.clone2.next(null); expect(gens.clone2.next(null).value).toEqual(select(getOffline));
gens.clone2.next(false); expect(gens.clone2.next(true).value).toEqual(select(isNetworkUnit, unit));
expect(gens.clone2.next().value).toEqual(true);
expect(gens.clone2.next().done).toEqual(true); expect(gens.clone2.next().done).toEqual(true);
}); });

View File

@ -1,3 +1,4 @@
import { configuredStore } from 'store';
import { Wei } from 'libs/units'; import { Wei } from 'libs/units';
import { import {
toFixedIfLarger, toFixedIfLarger,
@ -5,6 +6,7 @@ import {
formatGasLimit, formatGasLimit,
formatMnemonic formatMnemonic
} from '../../common/utils/formatters'; } from '../../common/utils/formatters';
configuredStore.getState();
describe('toFixedIfLarger', () => { describe('toFixedIfLarger', () => {
it('should return same value if decimal isnt longer than default', () => { it('should return same value if decimal isnt longer than default', () => {
@ -83,11 +85,11 @@ describe('formatNumber', () => {
describe('formatGasLimit', () => { describe('formatGasLimit', () => {
it('should fix transaction gas limit off-by-one errors', () => { it('should fix transaction gas limit off-by-one errors', () => {
expect(formatGasLimit(Wei('21001'), 'ether')).toEqual('21000'); expect(formatGasLimit(Wei('21001'), 'ETH')).toEqual('21000');
}); });
it('should mark the gas limit `-1` if you exceed the limit per block', () => { it('should mark the gas limit `-1` if you exceed the limit per block', () => {
expect(formatGasLimit(Wei('999999999999999'), 'ether')).toEqual('-1'); expect(formatGasLimit(Wei('999999999999999'), 'ETH')).toEqual('-1');
}); });
it('should not alter a valid gas limit', () => { it('should not alter a valid gas limit', () => {