Enable no-implicit-any (#1263)

* Progress commit

* Update more types

* Fix more types

* Fix abi function types

* Fix lib types

* Fix rest of types

* Address wbobeirne changes

* Change origin and destination check
This commit is contained in:
HenryNguyen5 2018-03-07 18:36:05 -05:00 committed by Daniel Ternyak
parent 0e26f7af4c
commit c340246ca0
107 changed files with 737 additions and 291 deletions

View File

@ -29,7 +29,7 @@ export function loadBityRatesSucceededSwap(
export type TLoadShapeshiftRatesSucceededSwap = typeof loadShapeshiftRatesSucceededSwap; export type TLoadShapeshiftRatesSucceededSwap = typeof loadShapeshiftRatesSucceededSwap;
export function loadShapeshiftRatesSucceededSwap( export function loadShapeshiftRatesSucceededSwap(
payload payload: interfaces.LoadShapeshiftRatesSucceededSwapAction['payload']
): interfaces.LoadShapeshiftRatesSucceededSwapAction { ): interfaces.LoadShapeshiftRatesSucceededSwapAction {
return { return {
type: TypeKeys.SWAP_LOAD_SHAPESHIFT_RATES_SUCCEEDED, type: TypeKeys.SWAP_LOAD_SHAPESHIFT_RATES_SUCCEEDED,

View File

@ -29,10 +29,14 @@ const repOptions = {
name: 'Augur' name: 'Augur'
}; };
export interface MappedRates {
[key: string]: any;
}
export function getAllRates() { export function getAllRates() {
const mappedRates = {}; const mappedRates: MappedRates = {};
return _getAllRates().then(bityRates => { return _getAllRates().then(bityRates => {
bityRates.objects.forEach(each => { bityRates.objects.forEach((each: any) => {
const pairName = each.pair; const pairName = each.pair;
const from = { id: pairName.substring(0, 3) }; const from = { id: pairName.substring(0, 3) };
const to = { id: pairName.substring(3, 6) }; const to = { id: pairName.substring(3, 6) };

View File

@ -1,4 +1,5 @@
import { checkHttpStatus, parseJSON } from './utils'; import { checkHttpStatus, parseJSON } from './utils';
import { Omit } from 'react-redux';
const MAX_GAS_FAST = 250; const MAX_GAS_FAST = 250;
@ -21,15 +22,29 @@ export interface GasEstimates {
isDefault: boolean; isDefault: boolean;
} }
interface GasExpressResponse {
block_time: number;
blockNum: number;
fast: number;
fastest: number;
safeLow: number;
standard: number;
}
export function fetchGasEstimates(): Promise<GasEstimates> { export function fetchGasEstimates(): Promise<GasEstimates> {
return fetch('https://dev.blockscale.net/api/gasexpress.json', { return fetch('https://dev.blockscale.net/api/gasexpress.json', {
mode: 'cors' mode: 'cors'
}) })
.then(checkHttpStatus) .then(checkHttpStatus)
.then(parseJSON) .then(parseJSON)
.then((res: object) => { .then((res: GasExpressResponse) => {
// Make sure it looks like a raw gas estimate, and it has valid values // Make sure it looks like a raw gas estimate, and it has valid values
const keys = ['safeLow', 'standard', 'fast', 'fastest']; const keys: (keyof Omit<GasExpressResponse, 'block_time' | 'blockNum'>)[] = [
'safeLow',
'standard',
'fast',
'fastest'
];
keys.forEach(key => { keys.forEach(key => {
if (typeof res[key] !== 'number') { if (typeof res[key] !== 'number') {
throw new Error( throw new Error(

View File

@ -28,6 +28,44 @@ export const SHAPESHIFT_TOKEN_WHITELIST = [
]; ];
export const SHAPESHIFT_WHITELIST = [...SHAPESHIFT_TOKEN_WHITELIST, 'ETH', 'ETC', 'BTC']; export const SHAPESHIFT_WHITELIST = [...SHAPESHIFT_TOKEN_WHITELIST, 'ETH', 'ETC', 'BTC'];
interface IPairData {
limit: number;
maxLimit: number;
min: number;
minerFee: number;
pair: string;
rate: string;
}
interface IExtraPairData {
status: string;
image: string;
name: string;
}
interface IAvailablePairData {
[pairName: string]: IExtraPairData;
}
interface ShapeshiftMarketInfo {
rate: string;
limit: number;
pair: string;
maxLimit: number;
min: number;
minerFee: number;
}
interface TokenMap {
[pairName: string]: {
id: string;
rate: string;
limit: number;
min: number;
options: (IExtraPairData & { id: string })[];
};
}
class ShapeshiftService { class ShapeshiftService {
public whitelist = SHAPESHIFT_WHITELIST; public whitelist = SHAPESHIFT_WHITELIST;
private url = SHAPESHIFT_BASE_URL; private url = SHAPESHIFT_BASE_URL;
@ -36,13 +74,18 @@ class ShapeshiftService {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}; };
public checkStatus(address) { public checkStatus(address: string) {
return fetch(`${this.url}/txStat/${address}`) return fetch(`${this.url}/txStat/${address}`)
.then(checkHttpStatus) .then(checkHttpStatus)
.then(parseJSON); .then(parseJSON);
} }
public sendAmount(withdrawal, originKind, destinationKind, destinationAmount) { public sendAmount(
withdrawal: string,
originKind: string,
destinationKind: string,
destinationAmount: number
) {
const pair = `${originKind.toLowerCase()}_${destinationKind.toLowerCase()}`; const pair = `${originKind.toLowerCase()}_${destinationKind.toLowerCase()}`;
return fetch(`${this.url}/sendamount`, { return fetch(`${this.url}/sendamount`, {
@ -81,7 +124,7 @@ class ShapeshiftService {
return mappedRates; return mappedRates;
}; };
private getPairRates(marketInfo) { private getPairRates(marketInfo: ShapeshiftMarketInfo[]) {
const filteredMarketInfo = marketInfo.filter(obj => { const filteredMarketInfo = marketInfo.filter(obj => {
const { pair } = obj; const { pair } = obj;
const pairArr = pair.split('_'); const pairArr = pair.split('_');
@ -97,7 +140,7 @@ class ShapeshiftService {
return pairRates; return pairRates;
} }
private async checkAvl(pairRates) { private async checkAvl(pairRates: IPairData[]) {
const avlCoins = await this.getAvlCoins(); const avlCoins = await this.getAvlCoins();
const mapAvl = pairRates.map(p => { const mapAvl = pairRates.map(p => {
const { pair } = p; const { pair } = p;
@ -121,7 +164,8 @@ class ShapeshiftService {
}; };
} }
}); });
return mapAvl; const filered = mapAvl.filter(v => v);
return filered as (IPairData & IAvailablePairData)[];
} }
private getAvlCoins() { private getAvlCoins() {
@ -130,7 +174,7 @@ class ShapeshiftService {
.then(parseJSON); .then(parseJSON);
} }
private getSinglePairRate(pair) { private getSinglePairRate(pair: string) {
return fetch(`${this.url}/rate/${pair}`) return fetch(`${this.url}/rate/${pair}`)
.then(checkHttpStatus) .then(checkHttpStatus)
.then(parseJSON); .then(parseJSON);
@ -142,12 +186,12 @@ class ShapeshiftService {
.then(parseJSON); .then(parseJSON);
} }
private isWhitelisted(coin) { private isWhitelisted(coin: string) {
return this.whitelist.includes(coin); return this.whitelist.includes(coin);
} }
private mapMarketInfo(marketInfo) { private mapMarketInfo(marketInfo: (IPairData & IAvailablePairData)[]) {
const tokenMap = {}; const tokenMap: TokenMap = {};
marketInfo.forEach(m => { marketInfo.forEach(m => {
const originKind = m.pair.substring(0, 3); const originKind = m.pair.substring(0, 3);
const destinationKind = m.pair.substring(4, 7); const destinationKind = m.pair.substring(4, 7);

View File

@ -37,5 +37,8 @@ export const AmountField: React.SFC<Props> = ({
/> />
); );
const isAmountValid = (raw, customValidator, isValid) => const isAmountValid = (
customValidator ? customValidator(raw) : isValid; raw: string,
customValidator: ((rawAmount: string) => boolean) | undefined,
isValid: boolean
) => (customValidator ? customValidator(raw) : isValid);

View File

@ -8,7 +8,6 @@ import { chain, flatMap } from 'lodash';
import { TokenBalance, getShownTokenBalances } from 'selectors/wallet'; import { TokenBalance, getShownTokenBalances } from 'selectors/wallet';
import { Balance } from 'libs/wallet'; import { Balance } from 'libs/wallet';
import './EquivalentValues.scss'; import './EquivalentValues.scss';
import { Wei } from 'libs/units';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getNetworkConfig, getOffline } from 'selectors/config'; import { getNetworkConfig, getOffline } from 'selectors/config';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
@ -16,6 +15,7 @@ import btcIco from 'assets/images/bitcoin.png';
import ethIco from 'assets/images/ether.png'; import ethIco from 'assets/images/ether.png';
import repIco from 'assets/images/augur.png'; import repIco from 'assets/images/augur.png';
import { NetworkConfig } from 'types/network'; import { NetworkConfig } from 'types/network';
import BN from 'bn.js';
interface AllValue { interface AllValue {
symbol: string; symbol: string;
@ -51,6 +51,14 @@ interface DispatchProps {
fetchCCRates: TFetchCCRatesRequested; fetchCCRates: TFetchCCRatesRequested;
} }
interface FiatSymbols {
[key: string]: string;
}
interface Rates {
[rate: string]: number;
}
type Props = StateProps & DispatchProps; type Props = StateProps & DispatchProps;
class EquivalentValues extends React.Component<Props, State> { class EquivalentValues extends React.Component<Props, State> {
@ -110,7 +118,7 @@ class EquivalentValues extends React.Component<Props, State> {
} }
} }
public selectOption = equivalentValues => { public selectOption = (equivalentValues: Option) => {
this.setState({ equivalentValues }); this.setState({ equivalentValues });
}; };
@ -120,28 +128,38 @@ class EquivalentValues extends React.Component<Props, State> {
const isFetching = const isFetching =
!balance || balance.isPending || !tokenBalances || Object.keys(rates).length === 0; !balance || balance.isPending || !tokenBalances || Object.keys(rates).length === 0;
const pairRates = this.generateValues(equivalentValues.label, equivalentValues.value); const pairRates = this.generateValues(equivalentValues.label, equivalentValues.value);
const fiatSymbols = { const fiatSymbols: FiatSymbols = {
USD: '$', USD: '$',
EUR: '€', EUR: '€',
GBP: '£', GBP: '£',
CHF: ' ' CHF: ' '
}; };
const coinAndTokenSymbols = { const coinAndTokenSymbols: any = {
BTC: btcIco, BTC: btcIco,
ETH: ethIco, ETH: ethIco,
REP: repIco REP: repIco
}; };
interface ValueProps {
className: string;
rate: string;
value: BN | null;
symbol?: string;
icon?: string;
key?: number | string;
}
const Value = ({ className = '', rate, value, symbol = '', icon = '' }) => ( const Value = (props: ValueProps) => (
<div className={`EquivalentValues-values-currency ${className}`}> <div className={`EquivalentValues-values-currency ${props.className}`}>
<img src={icon} /> <img src={props.icon} />
{!!symbol && <span className="EquivalentValues-values-currency-fiat-symbol">{symbol}</span>} {!!props.symbol && (
<span className="EquivalentValues-values-currency-label">{rate}</span>{' '} <span className="EquivalentValues-values-currency-fiat-symbol">{props.symbol}</span>
)}
<span className="EquivalentValues-values-currency-label">{props.rate}</span>{' '}
<span className="EquivalentValues-values-currency-value"> <span className="EquivalentValues-values-currency-value">
<UnitDisplay <UnitDisplay
unit={'ether'} unit={'ether'}
value={value} value={props.value}
displayShortBalance={rateSymbols.isFiat(rate) ? 2 : 3} displayShortBalance={rateSymbols.isFiat(props.rate) ? 2 : 3}
checkOffline={true} checkOffline={true}
/> />
</span> </span>
@ -157,7 +175,7 @@ class EquivalentValues extends React.Component<Props, State> {
// TODO: Update type // TODO: Update type
value={equivalentValues as any} value={equivalentValues as any}
options={options as any} options={options as any}
onChange={this.selectOption} onChange={this.selectOption as any}
clearable={false} clearable={false}
searchable={false} searchable={false}
/> />
@ -224,7 +242,7 @@ class EquivalentValues extends React.Component<Props, State> {
const allRates = Object.values(balance).map( const allRates = Object.values(balance).map(
value => !!rates[value.symbol] && rates[value.symbol] value => !!rates[value.symbol] && rates[value.symbol]
); );
const allEquivalentValues = allRates.map((rateType, i) => { const allEquivalentValues = allRates.map((rateType: any, i) => {
return { return {
symbol: Object.keys(rates)[i], symbol: Object.keys(rates)[i],
equivalentValues: [ equivalentValues: [
@ -260,9 +278,9 @@ class EquivalentValues extends React.Component<Props, State> {
// return equivalent value (unit * rate * balance) // return equivalent value (unit * rate * balance)
private handleValues(unit: string, balance: Balance['wei']) { private handleValues(unit: string, balance: Balance['wei']) {
const { rates } = this.props; const { rates } = this.props;
const ratesObj = { ...rates[unit] }; const ratesObj: Rates = { ...rates[unit] };
return Object.keys(ratesObj).map(key => { return Object.keys(ratesObj).map(key => {
const value = (balance as Wei).muln(ratesObj[key]); const value = balance!.muln(ratesObj[key]);
return { rate: key, value }; return { rate: key, value };
}); });
} }

View File

@ -5,7 +5,7 @@ import './Promos.scss';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { AppState } from '../../reducers'; import { AppState } from '../../reducers';
const CarouselAnimation = ({ children, ...props }) => ( const CarouselAnimation = ({ children, ...props }: any) => (
<CSSTransition {...props} timeout={300} classNames="carousel"> <CSSTransition {...props} timeout={300} classNames="carousel">
{children} {children}
</CSSTransition> </CSSTransition>

View File

@ -15,19 +15,23 @@ interface Props {
onRemoveCustomToken(symbol: string): any; onRemoveCustomToken(symbol: string): any;
} }
interface TrackedTokens {
[symbol: string]: boolean;
}
interface State { interface State {
trackedTokens: { [symbol: string]: boolean }; trackedTokens: { [symbol: string]: boolean };
showCustomTokenForm: boolean; showCustomTokenForm: boolean;
} }
export default class TokenBalances extends React.PureComponent<Props, State> { export default class TokenBalances extends React.PureComponent<Props, State> {
public state = { public state: State = {
trackedTokens: {}, trackedTokens: {},
showCustomTokenForm: false showCustomTokenForm: false
}; };
public componentWillReceiveProps(nextProps: Props) { public componentWillReceiveProps(nextProps: Props) {
if (nextProps.tokenBalances !== this.props.tokenBalances) { if (nextProps.tokenBalances !== this.props.tokenBalances) {
const trackedTokens = nextProps.tokenBalances.reduce((prev, t) => { const trackedTokens = nextProps.tokenBalances.reduce<TrackedTokens>((prev, t) => {
prev[t.symbol] = !t.balance.isZero(); prev[t.symbol] = !t.balance.isZero();
return prev; return prev;
}, {}); }, {});

View File

@ -13,7 +13,7 @@ interface StateProps {
} }
interface OwnProps { interface OwnProps {
withProps(props: CallBackProps); withProps(props: CallBackProps): null | React.ReactElement<any>;
onChange(value: React.FormEvent<HTMLInputElement>): void; onChange(value: React.FormEvent<HTMLInputElement>): void;
} }

View File

@ -41,9 +41,9 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
} }
} }
public componentWillReceiveProps(nextProps) { public componentWillReceiveProps(nextProps: Props) {
if (nextProps.privateKey !== this.props.privateKey) { if (nextProps.privateKey !== this.props.privateKey) {
this.setState({ privateKey: nextProps.privateKey }); this.setState({ privateKey: nextProps.privateKey || '' });
} }
} }

View File

@ -17,7 +17,7 @@ import { Input } from 'components/ui';
const CUSTOM = 'custom'; const CUSTOM = 'custom';
interface InputProps { interface InputProps {
name: string; name: keyof Omit<State, 'hasAuth'>;
placeholder?: string; placeholder?: string;
type?: string; type?: string;
autoComplete?: 'off'; autoComplete?: 'off';

View File

@ -18,7 +18,7 @@ interface State {
} }
class LogOutPromptClass extends React.Component<Props, State> { class LogOutPromptClass extends React.Component<Props, State> {
constructor(props) { constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
nextLocation: null, nextLocation: null,

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import Slider from 'rc-slider'; import Slider, { createSliderWithTooltip } from 'rc-slider';
import translate, { translateRaw } from 'translations'; import translate, { translateRaw } from 'translations';
import FeeSummary from './FeeSummary'; import FeeSummary from './FeeSummary';
import './SimpleGas.scss'; import './SimpleGas.scss';
@ -16,12 +16,13 @@ import { getEstimates, getIsEstimating } from 'selectors/gas';
import { Wei, fromWei } from 'libs/units'; import { Wei, fromWei } from 'libs/units';
import { gasPriceDefaults } from 'config'; import { gasPriceDefaults } from 'config';
import { InlineSpinner } from 'components/ui/InlineSpinner'; import { InlineSpinner } from 'components/ui/InlineSpinner';
const SliderWithTooltip = Slider.createSliderWithTooltip(Slider); import { TInputGasPrice } from 'actions/transaction';
const SliderWithTooltip = createSliderWithTooltip(Slider);
interface OwnProps { interface OwnProps {
gasPrice: AppState['transaction']['fields']['gasPrice']; gasPrice: AppState['transaction']['fields']['gasPrice'];
inputGasPrice(rawGas: string); setGasPrice: TInputGasPrice;
setGasPrice(rawGas: string); inputGasPrice(rawGas: string): void;
} }
interface StateProps { interface StateProps {

View File

@ -7,6 +7,7 @@ import { connect } from 'react-redux';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { getUnit } from 'selectors/transaction'; import { getUnit } from 'selectors/transaction';
import { getNetworkUnit } from 'selectors/config'; import { getNetworkUnit } from 'selectors/config';
import { Option } from 'react-select';
interface DispatchProps { interface DispatchProps {
setUnitMeta: TSetUnitMeta; setUnitMeta: TSetUnitMeta;
@ -41,7 +42,10 @@ class UnitDropdownClass extends Component<DispatchProps & StateProps> {
/> />
); );
} }
private handleOnChange = unit => { private handleOnChange = (unit: Option<string>) => {
if (!unit.value) {
throw Error('No unit value found');
}
this.props.setUnitMeta(unit.value); this.props.setUnitMeta(unit.value);
}; };
} }

View File

@ -126,7 +126,7 @@ type InsecureWallets = { [key in InsecureWalletName]: InsecureWalletInfo };
type MiscWallet = { [key in MiscWalletName]: MiscWalletInfo }; type MiscWallet = { [key in MiscWalletName]: MiscWalletInfo };
type Wallets = SecureWallets & InsecureWallets & MiscWallet; type Wallets = SecureWallets & InsecureWallets & MiscWallet;
const WEB3_TYPE: string | false = const WEB3_TYPE: keyof typeof WEB3_TYPES | false =
(window as any).web3 && (window as any).web3.currentProvider.constructor.name; (window as any).web3 && (window as any).web3.currentProvider.constructor.name;
const SECURE_WALLETS = Object.values(SecureWalletName); const SECURE_WALLETS = Object.values(SecureWalletName);

View File

@ -73,7 +73,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
this.getAddresses(); this.getAddresses();
} }
public componentWillReceiveProps(nextProps) { public componentWillReceiveProps(nextProps: Props) {
const { publicKey, chainCode, seed, dPath } = this.props; const { publicKey, chainCode, seed, dPath } = this.props;
if ( if (
nextProps.publicKey !== publicKey || nextProps.publicKey !== publicKey ||
@ -245,7 +245,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
} }
}; };
private selectAddress(selectedAddress, selectedAddrIndex) { private selectAddress(selectedAddress: string, selectedAddrIndex: number) {
this.setState({ selectedAddress, selectedAddrIndex }); this.setState({ selectedAddress, selectedAddrIndex });
} }

View File

@ -129,7 +129,7 @@ class LedgerNanoSDecryptClass extends PureComponent<Props, State> {
showTip: false showTip: false
}); });
ledger.comm_u2f.create_async().then(comm => { ledger.comm_u2f.create_async().then((comm: any) => {
new ledger.eth(comm) new ledger.eth(comm)
.getAddress_async(dPath, false, true) .getAddress_async(dPath, false, true)
.then(res => { .then(res => {
@ -139,7 +139,7 @@ class LedgerNanoSDecryptClass extends PureComponent<Props, State> {
isLoading: false isLoading: false
}); });
}) })
.catch(err => { .catch((err: any) => {
if (err && err.metaData && err.metaData.code === 5) { if (err && err.metaData && err.metaData.code === 5) {
this.showTip(); this.showTip();
} }

View File

@ -59,7 +59,7 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
isValid={isValidMnemonic} isValid={isValidMnemonic}
isTextareaWhenVisible={true} isTextareaWhenVisible={true}
onChange={this.onMnemonicChange} onChange={this.onMnemonicChange}
onEnter={isValidMnemonic && this.onDWModalOpen} onEnter={isValidMnemonic ? this.onDWModalOpen : undefined}
/> />
</div> </div>
<div className="form-group"> <div className="form-group">
@ -134,7 +134,7 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
this.setState({ dPath }); this.setState({ dPath });
}; };
private handleUnlock = (address, index) => { private handleUnlock = (address: string, index: number) => {
const { formattedPhrase, pass, dPath } = this.state; const { formattedPhrase, pass, dPath } = this.state;
this.props.onUnlock({ this.props.onUnlock({

View File

@ -108,7 +108,7 @@ class TrezorDecryptClass extends PureComponent<Props, State> {
(TrezorConnect as any).getXPubKey( (TrezorConnect as any).getXPubKey(
dPath, dPath,
res => { (res: any) => {
if (res.success) { if (res.success) {
this.setState({ this.setState({
dPath, dPath,

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import Select, { ReactSelectProps } from 'react-select'; import Select, { ReactSelectProps, Option } from 'react-select';
interface Props extends ReactSelectProps { interface Props extends ReactSelectProps {
className?: string; className?: string;
@ -13,11 +13,11 @@ export default class Dropdown extends React.Component<Props> {
hasBlurred: false hasBlurred: false
}; };
public handleChange = selectedOption => { public handleChange = (selectedOption: Option) => {
this.setState({ selectedOption }); this.setState({ selectedOption });
}; };
public formatOptions = options => { public formatOptions = (options: Option[]) => {
if (typeof options[0] === 'object') { if (typeof options[0] === 'object') {
return options; return options;
} }
@ -38,7 +38,7 @@ export default class Dropdown extends React.Component<Props> {
// use ref to prevent <label /> from stealing focus when used inline with an input // use ref to prevent <label /> from stealing focus when used inline with an input
ref={el => { ref={el => {
if (!!el && !!(el as any).control) { if (!!el && !!(el as any).control) {
(el as any).control.addEventListener('click', e => { (el as any).control.addEventListener('click', (e: React.FormEvent<any>) => {
e.preventDefault(); e.preventDefault();
}); });
} }
@ -46,7 +46,7 @@ export default class Dropdown extends React.Component<Props> {
className={`${this.props.className} ${this.state.hasBlurred ? 'has-blurred' : ''}`} className={`${this.props.className} ${this.state.hasBlurred ? 'has-blurred' : ''}`}
value={value} value={value}
onChange={obj => { onChange={obj => {
this.handleChange(obj); this.handleChange(obj as any);
onChange(); onChange();
}} }}
{...this.props} {...this.props}
@ -56,7 +56,7 @@ export default class Dropdown extends React.Component<Props> {
this.props.onBlur(e); this.props.onBlur(e);
} }
}} }}
options={options} options={options as any}
/> />
); );
} }

View File

@ -23,7 +23,7 @@ interface ModalStyle {
maxWidth?: string; maxWidth?: string;
} }
const Fade = ({ children, ...props }) => ( const Fade = ({ children, ...props }: any) => (
<CSSTransition {...props} timeout={300} classNames="animate-modal"> <CSSTransition {...props} timeout={300} classNames="animate-modal">
{children} {children}
</CSSTransition> </CSSTransition>

View File

@ -64,8 +64,8 @@ export default class DropdownComponent<T> extends PureComponent<Props<T>, State>
overflowY: 'auto' overflowY: 'auto'
}; };
const searchRegex = new RegExp(search, 'gi'); const searchRegex = new RegExp(search, 'gi');
const onSearchChange = e => { const onSearchChange = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({ search: e.target.value }); this.setState({ search: e.currentTarget.value });
}; };
return ( return (

View File

@ -25,15 +25,15 @@ const ValueComp: React.SFC = (props: any) => {
}; };
const OptionComp: React.SFC = (props: any) => { const OptionComp: React.SFC = (props: any) => {
const handleMouseDown = event => { const handleMouseDown = (event: React.MouseEvent<any>) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
props.onSelect(props.option, event); props.onSelect(props.option, event);
}; };
const handleMouseEnter = event => { const handleMouseEnter = (event: React.MouseEvent<any>) => {
props.onFocus(props.option, event); props.onFocus(props.option, event);
}; };
const handleMouseMove = event => { const handleMouseMove = (event: React.MouseEvent<any>) => {
if (props.isFocused) { if (props.isFocused) {
return; return;
} }

View File

@ -6,7 +6,11 @@ import { HELP_ARTICLE } from 'config';
import OnboardSlide from './OnboardSlide'; import OnboardSlide from './OnboardSlide';
import onboardIconTen from 'assets/images/onboarding/slide-10.svg'; import onboardIconTen from 'assets/images/onboarding/slide-10.svg';
const FinalSlide = ({ closeModal }) => { interface Props {
closeModal(): void;
}
const FinalSlide: React.SFC<Props> = ({ closeModal }) => {
const header = translate('ONBOARD_final_title'); const header = translate('ONBOARD_final_title');
const subheader = translate('ONBOARD_final_subtitle'); const subheader = translate('ONBOARD_final_subtitle');

View File

@ -49,7 +49,7 @@ interface Props {
class OnboardModal extends React.Component<Props, State> { class OnboardModal extends React.Component<Props, State> {
private modal: Modal | null = null; private modal: Modal | null = null;
constructor(props) { constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
isOpen: false isOpen: false

View File

@ -36,7 +36,7 @@ interface State {
inputs: { inputs: {
[key: string]: { rawData: string; parsedData: string[] | string }; [key: string]: { rawData: string; parsedData: string[] | string };
}; };
outputs; outputs: any;
selectedFunction: null | ContractOption; selectedFunction: null | ContractOption;
} }
@ -124,7 +124,7 @@ class InteractExplorerClass extends Component<Props, State> {
</div> </div>
); );
})} })}
{selectedFunction.contract.outputs.map((output, index) => { {selectedFunction.contract.outputs.map((output: any, index: number) => {
const { type, name } = output; const { type, name } = output;
const parsedName = name === '' ? index : name; const parsedName = name === '' ? index : name;

View File

@ -20,7 +20,7 @@ interface StateProps {
} }
interface OwnProps { interface OwnProps {
accessContract(contractAbi: string, address: string): (ev) => void; accessContract(contractAbi: string, address: string): (ev: any) => void;
resetState(): void; resetState(): void;
} }
@ -45,7 +45,7 @@ const abiJsonPlaceholder = [
class InteractForm extends Component<Props, State> { class InteractForm extends Component<Props, State> {
private abiJsonPlaceholder = JSON.stringify(abiJsonPlaceholder, null, 0); private abiJsonPlaceholder = JSON.stringify(abiJsonPlaceholder, null, 0);
constructor(props) { constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
address: '', address: '',
@ -140,7 +140,9 @@ class InteractForm extends Component<Props, State> {
); );
} }
private handleInput = name => (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>) => { private handleInput = (name: any) => (
ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
this.props.resetState(); this.props.resetState();
this.setState({ [name]: ev.currentTarget.value }); this.setState({ [name]: ev.currentTarget.value });
}; };

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { IOwnedDomainRequest } from 'libs/ens'; import { IOwnedDomainRequest } from 'libs/ens';
import { NewTabLink, Address } from 'components/ui'; import { NewTabLink, Address } from 'components/ui';
const lookupLink = name => `https://etherscan.io/enslookup?q=${name}`; const lookupLink = (name: string) => `https://etherscan.io/enslookup?q=${name}`;
type ChildrenProps = any; type ChildrenProps = any;

View File

@ -22,7 +22,7 @@ class CountDown extends Component<Props, State> {
private startCountDown = () => { private startCountDown = () => {
const time = moment(this.props.initialTime); const time = moment(this.props.initialTime);
let intervalId; let intervalId: number;
const setTimeDisplay = () => { const setTimeDisplay = () => {
const diff = moment.duration(time.diff(moment())); const diff = moment.duration(time.diff(moment()));
@ -44,7 +44,7 @@ class CountDown extends Component<Props, State> {
this.setState({ timeDisplay }); this.setState({ timeDisplay });
}; };
intervalId = setInterval(setTimeDisplay, 1000); intervalId = window.setInterval(setTimeDisplay, 1000);
setTimeDisplay(); setTimeDisplay();
}; };
} }

View File

@ -46,7 +46,7 @@ const WalletTypes: React.SFC<{}> = () => {
<div className="WalletTypes-types row"> <div className="WalletTypes-types row">
<div className="col-md-1" /> <div className="col-md-1" />
{Object.keys(typeInfo).map(type => ( {Object.keys(typeInfo).map((type: keyof typeof typeInfo) => (
<div key={type} className="WalletType col-md-5"> <div key={type} className="WalletType col-md-5">
<h2 className="WalletType-title">{translate(typeInfo[type].name)}</h2> <h2 className="WalletType-title">{translate(typeInfo[type].name)}</h2>
<ul className="WalletType-features"> <ul className="WalletType-features">

View File

@ -44,7 +44,8 @@ interface ActionProps {
type Props = OwnProps & StateProps & ActionProps; type Props = OwnProps & StateProps & ActionProps;
const isValidAmount = decimal => amount => validNumber(+amount) && validDecimal(amount, decimal); const isValidAmount = (decimal: number) => (amount: string) =>
validNumber(+amount) && validDecimal(amount, decimal);
class RequestPayment extends React.Component<Props, {}> { class RequestPayment extends React.Component<Props, {}> {
public state = { public state = {
@ -145,7 +146,7 @@ class RequestPayment extends React.Component<Props, {}> {
private generateEIP681String( private generateEIP681String(
currentTo: string, currentTo: string,
tokenContractAddress: string, tokenContractAddress: string,
currentValue, currentValue: { raw: string; value: BN | null },
gasLimit: { raw: string; value: BN | null }, gasLimit: { raw: string; value: BN | null },
unit: string, unit: string,
decimal: number, decimal: number,
@ -162,7 +163,11 @@ class RequestPayment extends React.Component<Props, {}> {
return ''; return '';
} }
if (this.props.isNetworkUnit) { const currentValueIsEther = (
_: AppState['transaction']['fields']['value'] | AppState['transaction']['meta']['tokenTo']
): _ is AppState['transaction']['fields']['value'] => this.props.isNetworkUnit;
if (currentValueIsEther(currentValue)) {
return buildEIP681EtherRequest(currentTo, chainId, currentValue); return buildEIP681EtherRequest(currentTo, chainId, currentValue);
} else { } else {
return buildEIP681TokenRequest( return buildEIP681TokenRequest(

View File

@ -30,8 +30,8 @@ export interface ActionProps {
interface State { interface State {
disabled: boolean; disabled: boolean;
origin: SwapInput; origin: SwapOpt;
destination: SwapInput; destination: SwapOpt;
originKindOptions: any[]; originKindOptions: any[];
destinationKindOptions: any[]; destinationKindOptions: any[];
originErr: string; originErr: string;
@ -49,7 +49,7 @@ interface SwapOpt extends SwapInput {
} }
export default class CurrencySwap extends PureComponent<Props, State> { export default class CurrencySwap extends PureComponent<Props, State> {
public state = { public state: State = {
disabled: true, disabled: true,
origin: { origin: {
label: 'BTC', label: 'BTC',
@ -57,14 +57,14 @@ export default class CurrencySwap extends PureComponent<Props, State> {
status: 'available', status: 'available',
image: 'https://shapeshift.io/images/coins/bitcoin.png', image: 'https://shapeshift.io/images/coins/bitcoin.png',
amount: NaN amount: NaN
} as SwapOpt, },
destination: { destination: {
label: 'ETH', label: 'ETH',
value: 'Ether', value: 'Ether',
status: 'available', status: 'available',
image: 'https://shapeshift.io/images/coins/ether.png', image: 'https://shapeshift.io/images/coins/ether.png',
amount: NaN amount: NaN
} as SwapOpt, },
originKindOptions: [], originKindOptions: [],
destinationKindOptions: [], destinationKindOptions: [],
originErr: '', originErr: '',
@ -151,7 +151,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
return merge(shapeshiftRates, bityRates); return merge(shapeshiftRates, bityRates);
}; };
public getMinMax = (originKind: WhitelistedCoins, destinationKind) => { public getMinMax = (originKind: WhitelistedCoins, destinationKind: string) => {
let min; let min;
let max; let max;
@ -176,7 +176,11 @@ export default class CurrencySwap extends PureComponent<Props, State> {
return { min, max }; return { min, max };
}; };
public isMinMaxValid = (originAmount: number, originKind: WhitelistedCoins, destinationKind) => { public isMinMaxValid = (
originAmount: number,
originKind: WhitelistedCoins,
destinationKind: string
) => {
const rate = this.getMinMax(originKind, destinationKind); const rate = this.getMinMax(originKind, destinationKind);
const higherThanMin = originAmount >= rate.min; const higherThanMin = originAmount >= rate.min;
const lowerThanMax = originAmount <= rate.max; const lowerThanMax = originAmount <= rate.max;
@ -201,7 +205,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
this.debouncedCreateErrString(origin, destination, showError); this.debouncedCreateErrString(origin, destination, showError);
} }
public setErrorMessages = (originErr, destinationErr) => { public setErrorMessages = (originErr: string, destinationErr: string) => {
this.setState({ this.setState({
originErr, originErr,
destinationErr destinationErr
@ -269,15 +273,17 @@ export default class CurrencySwap extends PureComponent<Props, State> {
: this.updateDestinationAmount(origin, destination, amount); : this.updateDestinationAmount(origin, destination, amount);
}; };
public onChangeOriginKind = newOption => { public onChangeOriginKind = (newOption: any) => {
const { origin, destination, destinationKindOptions } = this.state; const { origin, destination, destinationKindOptions } = this.state;
const { options, initSwap } = this.props; const { options, initSwap } = this.props;
const newOrigin = { ...origin, label: newOption.label, value: newOption.value, amount: '' }; const newOrigin = { ...origin, label: newOption.label, value: newOption.value, amount: 0 };
const newDest = { const newDest = {
label: newOption.label === destination.label ? origin.label : destination.label, label: newOption.label === destination.label ? origin.label : destination.label,
value: newOption.value === destination.value ? origin.value : destination.value, value: newOption.value === destination.value ? origin.value : destination.value,
amount: '' amount: 0,
status: '',
image: ''
}; };
this.setState({ this.setState({
@ -292,16 +298,16 @@ export default class CurrencySwap extends PureComponent<Props, State> {
initSwap({ origin: newOrigin, destination: newDest }); initSwap({ origin: newOrigin, destination: newDest });
}; };
public onChangeDestinationKind = newOption => { public onChangeDestinationKind = (newOption: any) => {
const { initSwap } = this.props; const { initSwap } = this.props;
const { origin, destination } = this.state; const { origin, destination } = this.state;
const newOrigin = { const newOrigin = {
...origin, ...origin,
amount: '' amount: 0
}; };
const newDest = { ...destination, label: newOption.label, value: newOption.value, amount: '' }; const newDest = { ...destination, label: newOption.label, value: newOption.value, amount: 0 };
this.setState({ this.setState({
origin: newOrigin, origin: newOrigin,
destination: newDest destination: newDest
@ -339,7 +345,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
<Input <Input
id="origin-swap-input" id="origin-swap-input"
className={`input-group-input ${ className={`input-group-input ${
String(origin.amount) !== '' && !origin.amount &&
this.isMinMaxValid(origin.amount, origin.label, destination.label) this.isMinMaxValid(origin.amount, origin.label, destination.label)
? '' ? ''
: 'invalid' : 'invalid'
@ -364,7 +370,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
<Input <Input
id="destination-swap-input" id="destination-swap-input"
className={`${ className={`${
String(destination.amount) !== '' && !destination.amount &&
this.isMinMaxValid(origin.amount, origin.label, destination.label) this.isMinMaxValid(origin.amount, origin.label, destination.label)
? '' ? ''
: 'invalid' : 'invalid'

View File

@ -24,6 +24,7 @@ import { getOffline } from 'selectors/config';
import Rates from './Rates'; import Rates from './Rates';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import './CurrentRates.scss'; import './CurrentRates.scss';
import { Optional } from 'utils/types';
interface StateProps { interface StateProps {
isOffline: boolean; isOffline: boolean;
@ -40,7 +41,7 @@ interface ActionProps {
type Props = StateProps & ActionProps; type Props = StateProps & ActionProps;
class CurrentRates extends PureComponent<Props> { class CurrentRates extends PureComponent<Props> {
private shapeShiftRateCache = null; private shapeShiftRateCache: any = null;
public componentDidMount() { public componentDidMount() {
if (!this.props.isOffline) { if (!this.props.isOffline) {
@ -79,7 +80,7 @@ class CurrentRates extends PureComponent<Props> {
public buildSSPairs = (shapeshiftRates: NormalizedShapeshiftRates, n: number = 4) => { public buildSSPairs = (shapeshiftRates: NormalizedShapeshiftRates, n: number = 4) => {
const pairCollection = times(n, () => this.getRandomSSPairData(shapeshiftRates)); const pairCollection = times(n, () => this.getRandomSSPairData(shapeshiftRates));
const byId = pairCollection.reduce((acc, cur) => { const byId = pairCollection.reduce<{ [id: string]: NormalizedShapeshiftRate }>((acc, cur) => {
acc[cur.id] = cur; acc[cur.id] = cur;
return acc; return acc;
}, {}); }, {});
@ -90,7 +91,7 @@ class CurrentRates extends PureComponent<Props> {
}; };
}; };
public isValidRates = rates => { public isValidRates = (rates: Optional<NormalizedShapeshiftRates>) => {
return rates && rates.allIds && rates.allIds.length > 0; return rates && rates.allIds && rates.allIds.length > 0;
}; };
@ -118,7 +119,7 @@ class CurrentRates extends PureComponent<Props> {
return fixedRates; return fixedRates;
}; };
public swapEl = (providerURL, providerLogo, children) => { public swapEl = (providerURL: string, providerLogo: string, children: any) => {
return ( return (
<article className="SwapRates"> <article className="SwapRates">
<h3 className="SwapRates-title">{translate('SWAP_rates')}</h3> <h3 className="SwapRates-title">{translate('SWAP_rates')}</h3>

View File

@ -47,7 +47,7 @@ interface State {
} }
export default class Rates extends Component<Props, State> { export default class Rates extends Component<Props, State> {
public state = { public state: State = {
pairs: {} pairs: {}
}; };
@ -72,7 +72,7 @@ export default class Rates extends Component<Props, State> {
public getPairs = () => { public getPairs = () => {
const { rates } = this.props; const { rates } = this.props;
const { allIds } = rates; const { allIds } = rates;
return allIds.reduce((acc, cur) => { return allIds.reduce<{ [id: string]: 1 }>((acc, cur) => {
acc[cur] = 1; acc[cur] = 1;
return acc; return acc;
}, {}); }, {});

View File

@ -1,7 +1,14 @@
import abi from 'ethereumjs-abi'; import abi from 'ethereumjs-abi';
import { toChecksumAddress, addHexPrefix } from 'ethereumjs-util'; import { toChecksumAddress, addHexPrefix } from 'ethereumjs-util';
import BN from 'bn.js'; import BN from 'bn.js';
import { FuncParams, FunctionOutputMappings, Output, Input } from './types'; import {
FuncParams,
FunctionOutputMappings,
Output,
Input,
ITypeMapping,
ISuppliedArgs
} from './types';
export default class AbiFunction { export default class AbiFunction {
public constant: boolean; public constant: boolean;
@ -53,7 +60,6 @@ export default class AbiFunction {
// Convert argdata to a hex buffer for ethereumjs-abi // Convert argdata to a hex buffer for ethereumjs-abi
const argBuffer = new Buffer(argString, 'hex'); const argBuffer = new Buffer(argString, 'hex');
// Decode! // Decode!
const argArr = abi.rawDecode(this.outputTypes, argBuffer); const argArr = abi.rawDecode(this.outputTypes, argBuffer);
@ -80,13 +86,13 @@ export default class AbiFunction {
} }
private parsePostDecodedValue = (type: string, value: any) => { private parsePostDecodedValue = (type: string, value: any) => {
const valueMapping = { const valueMapping: ITypeMapping = {
address: val => toChecksumAddress(val.toString(16)) address: (val: any) => toChecksumAddress(val.toString(16))
}; };
return valueMapping[type] const mapppedType = valueMapping[type];
? valueMapping[type](value)
: BN.isBN(value) ? value.toString() : value; return mapppedType ? mapppedType(value) : BN.isBN(value) ? value.toString() : value;
}; };
private parsePreEncodedValue = (_: string, value: any) => private parsePreEncodedValue = (_: string, value: any) =>
@ -95,7 +101,7 @@ export default class AbiFunction {
private makeFuncParams = () => private makeFuncParams = () =>
this.inputs.reduce((accumulator, currInput) => { this.inputs.reduce((accumulator, currInput) => {
const { name, type } = currInput; const { name, type } = currInput;
const inputHandler = inputToParse => const inputHandler = (inputToParse: any) =>
//TODO: introduce typechecking and typecasting mapping for inputs //TODO: introduce typechecking and typecasting mapping for inputs
({ name, type, value: this.parsePreEncodedValue(type, inputToParse) }); ({ name, type, value: this.parsePreEncodedValue(type, inputToParse) });
@ -110,7 +116,7 @@ export default class AbiFunction {
return addHexPrefix(`${this.methodSelector}${encodedArgs}`); return addHexPrefix(`${this.methodSelector}${encodedArgs}`);
}; };
private processSuppliedArgs = (suppliedArgs: object) => private processSuppliedArgs = (suppliedArgs: ISuppliedArgs) =>
this.inputNames.map(name => { this.inputNames.map(name => {
const type = this.funcParams[name].type; const type = this.funcParams[name].type;
//TODO: parse args based on type //TODO: parse args based on type

View File

@ -6,6 +6,11 @@ const ABIFUNC_METHOD_NAMES = ['encodeInput', 'decodeInput', 'decodeOutput'];
enum ABIMethodTypes { enum ABIMethodTypes {
FUNC = 'function' FUNC = 'function'
} }
export default interface Contract {
[key: string]: any;
};
export type TContract = typeof Contract; export type TContract = typeof Contract;
export default class Contract { export default class Contract {
@ -22,14 +27,14 @@ export default class Contract {
return isFunc ? { ...accu, [currContractMethodName]: currContractMethod } : accu; return isFunc ? { ...accu, [currContractMethodName]: currContractMethod } : accu;
}, {}); }, {});
public abi; public abi: any;
constructor(abi, outputMappings: ContractOutputMappings = {}) { constructor(abi: any, outputMappings: ContractOutputMappings = {}) {
this.assignABIFuncs(abi, outputMappings); this.assignABIFuncs(abi, outputMappings);
} }
private assignABIFuncs = (abi, outputMappings: ContractOutputMappings) => { private assignABIFuncs = (abi: any, outputMappings: ContractOutputMappings) => {
abi.forEach(currentABIMethod => { abi.forEach((currentABIMethod: any) => {
const { name, type } = currentABIMethod; const { name, type } = currentABIMethod;
if (type === ABIMethodTypes.FUNC) { if (type === ABIMethodTypes.FUNC) {
//only grab the functions we need //only grab the functions we need

View File

@ -36,3 +36,11 @@ export interface FuncParams {
processInput(value: any): any; processInput(value: any): any;
}; };
} }
export interface ITypeMapping {
[type: string]: (value: any) => any;
}
export interface ISuppliedArgs {
[argumentName: string]: any;
}

View File

@ -1,7 +1,7 @@
import { mnemonicToSeed, validateMnemonic } from 'bip39'; import { mnemonicToSeed, validateMnemonic } from 'bip39';
import { createDecipheriv, createHash } from 'crypto'; import { createDecipheriv, createHash } from 'crypto';
import { privateToAddress } from 'ethereumjs-util'; import { privateToAddress } from 'ethereumjs-util';
import { fromMasterSeed } from 'hdkey'; import HDkey from 'hdkey';
import { stripHexPrefixAndLower } from 'libs/values'; import { stripHexPrefixAndLower } from 'libs/values';
// adapted from https://github.com/kvhnuke/etherwallet/blob/de536ffebb4f2d1af892a32697e89d1a0d906b01/app/scripts/myetherwallet.js#L230 // adapted from https://github.com/kvhnuke/etherwallet/blob/de536ffebb4f2d1af892a32697e89d1a0d906b01/app/scripts/myetherwallet.js#L230
@ -37,7 +37,7 @@ export function decodeCryptojsSalt(input: string): any {
export function evp_kdf(data: Buffer, salt: Buffer, opts: any) { export function evp_kdf(data: Buffer, salt: Buffer, opts: any) {
// A single EVP iteration, returns `D_i`, where block equlas to `D_(i-1)` // A single EVP iteration, returns `D_i`, where block equlas to `D_(i-1)`
function iter(block) { function iter(block: Buffer) {
let hash = createHash(opts.digest || 'md5'); let hash = createHash(opts.digest || 'md5');
hash.update(block); hash.update(block);
hash.update(data); hash.update(data);
@ -83,7 +83,7 @@ export function decryptMnemonicToPrivKey(
} }
const seed = mnemonicToSeed(phrase, pass); const seed = mnemonicToSeed(phrase, pass);
const derived = fromMasterSeed(seed).derive(path); const derived = HDkey.fromMasterSeed(seed).derive(path);
const dPrivKey = derived.privateKey; const dPrivKey = derived.privateKey;
const dAddress = privateToAddress(dPrivKey).toString('hex'); const dAddress = privateToAddress(dPrivKey).toString('hex');

View File

@ -1,7 +1,7 @@
import uts46 from 'idna-uts46'; import uts46 from 'idna-uts46';
import ethUtil from 'ethereumjs-util'; import ethUtil from 'ethereumjs-util';
export function normalise(name: string) { export function normalise(name: string): string {
try { try {
return uts46.toUnicode(name, { useStd3ASCII: true, transitional: false }); return uts46.toUnicode(name, { useStd3ASCII: true, transitional: false });
} catch (e) { } catch (e) {
@ -65,7 +65,7 @@ export enum NameState {
NotYetAvailable = '5' NotYetAvailable = '5'
} }
export const modeStrMap = name => [ export const modeStrMap = (name: string) => [
`${name} is available and the auction hasnt started`, `${name} is available and the auction hasnt started`,
`${name} is available and the auction has been started`, `${name} is available and the auction has been started`,
`${name} is taken and currently owned by someone`, `${name} is taken and currently owned by someone`,

View File

@ -11,6 +11,7 @@ import {
GetCurrentBlockRequest GetCurrentBlockRequest
} from './types'; } from './types';
import { Token } from 'types/network'; import { Token } from 'types/network';
import { IHexStrWeb3Transaction, IHexStrTransaction } from 'libs/transaction';
export default class EtherscanRequests extends RPCRequests { export default class EtherscanRequests extends RPCRequests {
public sendRawTx(signedTx: string): SendRawTxRequest { public sendRawTx(signedTx: string): SendRawTxRequest {
@ -21,7 +22,7 @@ export default class EtherscanRequests extends RPCRequests {
}; };
} }
public estimateGas(transaction): EstimateGasRequest { public estimateGas(transaction: IHexStrWeb3Transaction): EstimateGasRequest {
return { return {
module: 'proxy', module: 'proxy',
action: 'eth_estimateGas', action: 'eth_estimateGas',
@ -41,7 +42,7 @@ export default class EtherscanRequests extends RPCRequests {
}; };
} }
public ethCall(transaction): CallRequest { public ethCall(transaction: Pick<IHexStrTransaction, 'to' | 'data'>): CallRequest {
return { return {
module: 'proxy', module: 'proxy',
action: 'eth_call', action: 'eth_call',

View File

@ -41,10 +41,10 @@ export default class RPCClient {
}).then(r => r.json()); }).then(r => r.json());
}; };
private createHeaders = headerObject => { private createHeaders = (headerObject: HeadersInit) => {
const headers = new Headers(); const headers = new Headers();
Object.keys(headerObject).forEach(name => { Object.entries(headerObject).forEach(([name, value]) => {
headers.append(name, headerObject[name]); headers.append(name, value);
}); });
return headers; return headers;
}; };

View File

@ -2,7 +2,6 @@ import BN from 'bn.js';
import { IHexStrTransaction } from 'libs/transaction'; import { IHexStrTransaction } from 'libs/transaction';
import { Wei, TokenValue } from 'libs/units'; import { Wei, TokenValue } from 'libs/units';
import { stripHexPrefix } from 'libs/values'; import { stripHexPrefix } from 'libs/values';
import { hexToNumber } from 'utils/formatters';
import { INode, TxObj, TransactionData, TransactionReceipt } from '../INode'; import { INode, TxObj, TransactionData, TransactionReceipt } from '../INode';
import RPCClient from './client'; import RPCClient from './client';
import RPCRequests from './requests'; import RPCRequests from './requests';
@ -18,6 +17,7 @@ import {
isValidRawTxApi isValidRawTxApi
} from 'libs/validators'; } from 'libs/validators';
import { Token } from 'types/network'; import { Token } from 'types/network';
import { hexToNumber } from 'utils/formatters';
export default class RpcNode implements INode { export default class RpcNode implements INode {
public client: RPCClient; public client: RPCClient;

View File

@ -13,14 +13,13 @@ import {
import { hexEncodeData } from './utils'; import { hexEncodeData } from './utils';
import { TxObj } from '../INode'; import { TxObj } from '../INode';
import { Token } from 'types/network'; import { Token } from 'types/network';
import { IHexStrTransaction } from 'libs/transaction';
export default class RPCRequests { export default class RPCRequests {
public getNetVersion() { public getNetVersion() {
return { method: 'net_version' }; return { method: 'net_version' };
} }
/* TODO: Fix `| any` on all of these */
public sendRawTx(signedTx: string): SendRawTxRequest | any { public sendRawTx(signedTx: string): SendRawTxRequest | any {
return { return {
method: 'eth_sendRawTransaction', method: 'eth_sendRawTransaction',
@ -28,7 +27,7 @@ export default class RPCRequests {
}; };
} }
public estimateGas(transaction): EstimateGasRequest | any { public estimateGas(transaction: Partial<IHexStrTransaction>): EstimateGasRequest | any {
return { return {
method: 'eth_estimateGas', method: 'eth_estimateGas',
params: [transaction] params: [transaction]

View File

@ -27,7 +27,7 @@ export interface GetAccountsRequest extends RPCRequestBase {
method: 'eth_accounts'; method: 'eth_accounts';
} }
type TWeb3ProviderCallback = (error, result: JsonRpcResponse | JsonRpcResponse[]) => any; type TWeb3ProviderCallback = (error: string, result: JsonRpcResponse | JsonRpcResponse[]) => any;
type TSendAsync = (request: RPCRequest | any, callback: TWeb3ProviderCallback) => void; type TSendAsync = (request: RPCRequest | any, callback: TWeb3ProviderCallback) => void;
export interface IWeb3Provider { export interface IWeb3Provider {

View File

@ -10,9 +10,9 @@ export interface ITransaction {
gasPrice: Wei; gasPrice: Wei;
nonce: BN; nonce: BN;
chainId: number; chainId: number;
v; v: Buffer;
r; r: Buffer;
s; s: Buffer;
} }
export interface IHexStrTransaction { export interface IHexStrTransaction {

View File

@ -6,6 +6,7 @@ import { IFullWallet } from 'libs/wallet';
import { translateRaw } from 'translations'; import { translateRaw } from 'translations';
import { ITransaction, IHexStrTransaction } from '../typings'; import { ITransaction, IHexStrTransaction } from '../typings';
import { hexEncodeQuantity, hexEncodeData } from 'libs/nodes/rpc/utils'; import { hexEncodeQuantity, hexEncodeData } from 'libs/nodes/rpc/utils';
import { TransactionFieldValues } from 'selectors/transaction/helpers';
// we dont include the signature paramaters because web3 transactions are unsigned // we dont include the signature paramaters because web3 transactions are unsigned
const computeIndexingHash = (tx: Buffer) => bufferToHex(makeTransaction(tx).hash(false)); const computeIndexingHash = (tx: Buffer) => bufferToHex(makeTransaction(tx).hash(false));
@ -75,7 +76,13 @@ const validAddress = (t: ITransaction) => {
}; };
const makeTransaction = ( const makeTransaction = (
t: Partial<Tx> | Partial<ITransaction> | Partial<IHexStrTransaction> | Buffer | string t:
| Partial<Tx>
| Partial<ITransaction>
| Partial<IHexStrTransaction>
| Buffer
| string
| TransactionFieldValues
) => new Tx(t); ) => new Tx(t);
//TODO: check that addresses are always checksummed //TODO: check that addresses are always checksummed

View File

@ -184,7 +184,7 @@ export const isValidNonce = (value: string): boolean => {
return valid; return valid;
}; };
function isValidResult(response: JsonRpcResponse, schemaFormat): boolean { function isValidResult(response: JsonRpcResponse, schemaFormat: typeof schema.RpcNode): boolean {
return v.validate(response, schemaFormat).valid; return v.validate(response, schemaFormat).valid;
} }
@ -204,9 +204,25 @@ function formatErrors(response: JsonRpcResponse, apiType: string) {
return `Invalid ${apiType} Error`; return `Invalid ${apiType} Error`;
} }
enum API_NAME {
Get_Balance = 'Get Balance',
Estimate_Gas = 'Estimate Gas',
Call_Request = 'Call Request',
Token_Balance = 'Token Balance',
Transaction_Count = 'Transaction Count',
Current_Block = 'Current Block',
Raw_Tx = 'Raw Tx',
Send_Transaction = 'Send Transaction',
Sign_Message = 'Sign Message',
Get_Accounts = 'Get Accounts',
Net_Version = 'Net Version',
Transaction_By_Hash = 'Transaction By Hash',
Transaction_Receipt = 'Transaction Receipt'
}
const isValidEthCall = (response: JsonRpcResponse, schemaType: typeof schema.RpcNode) => ( const isValidEthCall = (response: JsonRpcResponse, schemaType: typeof schema.RpcNode) => (
apiName, apiName: API_NAME,
cb? cb?: (res: JsonRpcResponse) => any
) => { ) => {
if (!isValidResult(response, schemaType)) { if (!isValidResult(response, schemaType)) {
if (cb) { if (cb) {
@ -218,45 +234,44 @@ const isValidEthCall = (response: JsonRpcResponse, schemaType: typeof schema.Rpc
}; };
export const isValidGetBalance = (response: JsonRpcResponse) => export const isValidGetBalance = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Get Balance'); isValidEthCall(response, schema.RpcNode)(API_NAME.Get_Balance);
export const isValidEstimateGas = (response: JsonRpcResponse) => export const isValidEstimateGas = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Estimate Gas'); isValidEthCall(response, schema.RpcNode)(API_NAME.Estimate_Gas);
export const isValidCallRequest = (response: JsonRpcResponse) => export const isValidCallRequest = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Call Request'); isValidEthCall(response, schema.RpcNode)(API_NAME.Call_Request);
export const isValidTokenBalance = (response: JsonRpcResponse) => export const isValidTokenBalance = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Token Balance', () => ({ isValidEthCall(response, schema.RpcNode)(API_NAME.Token_Balance, () => ({
result: 'Failed' result: 'Failed'
})); }));
export const isValidTransactionCount = (response: JsonRpcResponse) => export const isValidTransactionCount = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Transaction Count'); isValidEthCall(response, schema.RpcNode)(API_NAME.Transaction_Count);
export const isValidTransactionByHash = (response: JsonRpcResponse) => export const isValidTransactionByHash = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Transaction By Hash'); isValidEthCall(response, schema.RpcNode)(API_NAME.Transaction_By_Hash);
export const isValidTransactionReceipt = (response: JsonRpcResponse) => export const isValidTransactionReceipt = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Transaction Receipt'); isValidEthCall(response, schema.RpcNode)(API_NAME.Transaction_Receipt);
export const isValidCurrentBlock = (response: JsonRpcResponse) => export const isValidCurrentBlock = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Current Block'); isValidEthCall(response, schema.RpcNode)(API_NAME.Current_Block);
export const isValidRawTxApi = (response: JsonRpcResponse) => export const isValidRawTxApi = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Raw Tx'); isValidEthCall(response, schema.RpcNode)(API_NAME.Raw_Tx);
export const isValidSendTransaction = (response: JsonRpcResponse) => export const isValidSendTransaction = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Send Transaction'); isValidEthCall(response, schema.RpcNode)(API_NAME.Send_Transaction);
export const isValidSignMessage = (response: JsonRpcResponse) => export const isValidSignMessage = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Sign Message'); isValidEthCall(response, schema.RpcNode)(API_NAME.Sign_Message);
export const isValidGetAccounts = (response: JsonRpcResponse) => export const isValidGetAccounts = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Get Accounts'); isValidEthCall(response, schema.RpcNode)(API_NAME.Get_Accounts);
export const isValidGetNetVersion = (response: JsonRpcResponse) => export const isValidGetNetVersion = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Net Version'); isValidEthCall(response, schema.RpcNode)(API_NAME.Net_Version);
export const isValidTxHash = (hash: string) => export const isValidTxHash = (hash: string) =>
hash.substring(0, 2) === '0x' && hash.length === 66 && isValidHex(hash); hash.substring(0, 2) === '0x' && hash.length === 66 && isValidHex(hash);

View File

@ -1,6 +1,6 @@
import { Wei, toTokenBase } from 'libs/units'; import { Wei, toTokenBase } from 'libs/units';
import { addHexPrefix } from 'ethereumjs-util'; import { addHexPrefix } from 'ethereumjs-util';
import BN from 'bn.js'; import { AppState } from 'reducers';
export function stripHexPrefix(value: string) { export function stripHexPrefix(value: string) {
return value.replace('0x', ''); return value.replace('0x', '');
@ -26,16 +26,16 @@ export function sanitizeHex(hex: string) {
export const buildEIP681EtherRequest = ( export const buildEIP681EtherRequest = (
recipientAddr: string, recipientAddr: string,
chainId: number, chainId: number,
etherValue: { raw: string; value: Wei | '' } etherValue: AppState['transaction']['fields']['value']
) => `ethereum:${recipientAddr}${chainId !== 1 ? `@${chainId}` : ''}?value=${etherValue.raw}e18`; ) => `ethereum:${recipientAddr}${chainId !== 1 ? `@${chainId}` : ''}?value=${etherValue.raw}e18`;
export const buildEIP681TokenRequest = ( export const buildEIP681TokenRequest = (
recipientAddr: string, recipientAddr: string,
contractAddr: string, contractAddr: string,
chainId: number, chainId: number,
tokenValue: { raw: string; value: Wei | '' }, tokenValue: AppState['transaction']['meta']['tokenTo'],
decimal: number, decimal: number,
gasLimit: { raw: string; value: BN | null } gasLimit: AppState['transaction']['fields']['gasLimit']
) => ) =>
`ethereum:${contractAddr}${ `ethereum:${contractAddr}${
chainId !== 1 ? `@${chainId}` : '' chainId !== 1 ? `@${chainId}` : ''

View File

@ -7,11 +7,11 @@ import { IFullWallet } from '../IWallet';
import { translateRaw } from 'translations'; import { translateRaw } from 'translations';
export class LedgerWallet extends DeterministicWallet implements IFullWallet { export class LedgerWallet extends DeterministicWallet implements IFullWallet {
private ethApp: any; private ethApp: ledger.eth;
constructor(address: string, dPath: string, index: number) { constructor(address: string, dPath: string, index: number) {
super(address, dPath, index); super(address, dPath, index);
ledger.comm_u2f.create_async().then(comm => { ledger.comm_u2f.create_async().then((comm: any) => {
this.ethApp = new ledger.eth(comm); this.ethApp = new ledger.eth(comm);
}); });
} }
@ -50,9 +50,12 @@ export class LedgerWallet extends DeterministicWallet implements IFullWallet {
const msgHex = Buffer.from(msg).toString('hex'); const msgHex = Buffer.from(msg).toString('hex');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.ethApp.signPersonalMessage_async(this.getPath(), msgHex, async (signed, error) => { this.ethApp.signPersonalMessage_async(
this.getPath(),
msgHex,
async (signed: any, error: any) => {
if (error) { if (error) {
return reject(this.ethApp.getError(error)); return reject((this.ethApp as any).getError(error));
} }
try { try {
@ -61,7 +64,8 @@ export class LedgerWallet extends DeterministicWallet implements IFullWallet {
} catch (err) { } catch (err) {
reject(err); reject(err);
} }
}); }
);
}); });
} }

View File

@ -30,7 +30,7 @@ export class TrezorWallet extends DeterministicWallet implements IFullWallet {
cleanedTx.data, cleanedTx.data,
chainId, chainId,
// Callback // Callback
result => { (result: any) => {
if (!result.success) { if (!result.success) {
return reject(Error(result.error)); return reject(Error(result.error));
} }
@ -64,7 +64,7 @@ export class TrezorWallet extends DeterministicWallet implements IFullWallet {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
(TrezorConnect as any).ethereumGetAddress( (TrezorConnect as any).ethereumGetAddress(
dPath + '/' + index, dPath + '/' + index,
res => { (res: any) => {
if (res.error) { if (res.error) {
reject(res.error); reject(res.error);
} else { } else {

View File

@ -15,9 +15,9 @@ const INITIAL_STATE: State = {
gasPriceStatus: null gasPriceStatus: null
}; };
const getPostFix = (str: string) => { const getPostFix = (str: string): keyof typeof RequestStatus => {
const arr = str.split('_'); const arr = str.split('_');
return arr[arr.length - 1]; return arr[arr.length - 1] as any;
}; };
const nextState = (field: keyof State) => (state: State, action: Action): State => ({ const nextState = (field: keyof State) => (state: State, action: Action): State => ({

View File

@ -22,14 +22,14 @@ export const resetHOF = (
if (includeFields) { if (includeFields) {
(includeFields as any[]).forEach(fieldName => { (includeFields as any[]).forEach(fieldName => {
stateCopy[fieldName] = returnState[fieldName]; (stateCopy as any)[fieldName] = (returnState as any)[fieldName];
}); });
return returnCb ? returnCb(state, returnState) : { ...stateCopy }; return returnCb ? returnCb(state, returnState) : { ...stateCopy };
} }
if (excludeFields) { if (excludeFields) {
(excludeFields as any[]).forEach(fieldName => { (excludeFields as any[]).forEach(fieldName => {
returnState[fieldName] = state[fieldName]; (returnState as any)[fieldName] = (state as any)[fieldName];
}); });
} }

View File

@ -15,7 +15,7 @@ export function* pruneCustomNetworks(): SagaIterator {
//construct lookup table of networks //construct lookup table of networks
const linkedNetworks = Object.values(customNodes).reduce( const linkedNetworks: { [key: string]: boolean } = Object.values(customNodes).reduce(
(networkMap, currentNode) => ({ ...networkMap, [currentNode.network]: true }), (networkMap, currentNode) => ({ ...networkMap, [currentNode.network]: true }),
{} {}
); );

View File

@ -6,6 +6,7 @@ import { changeNodeForce, TypeKeys, web3SetNode } from 'actions/config';
import { getNodeId, getStaticAltNodeIdToWeb3, getNetworkNameByChainId } from 'selectors/config'; import { getNodeId, getStaticAltNodeIdToWeb3, getNetworkNameByChainId } from 'selectors/config';
import { setupWeb3Node, Web3Service } from 'libs/nodes/web3'; import { setupWeb3Node, Web3Service } from 'libs/nodes/web3';
import { Web3NodeConfig } from 'types/node'; import { Web3NodeConfig } from 'types/node';
import { SetWalletAction } from 'actions/wallet';
export function* initWeb3Node(): SagaIterator { export function* initWeb3Node(): SagaIterator {
const { networkId, lib } = yield call(setupWeb3Node); const { networkId, lib } = yield call(setupWeb3Node);
@ -24,7 +25,7 @@ export function* initWeb3Node(): SagaIterator {
} }
// unset web3 as the selected node if a non-web3 wallet has been selected // unset web3 as the selected node if a non-web3 wallet has been selected
export function* unsetWeb3NodeOnWalletEvent(action): SagaIterator { export function* unsetWeb3NodeOnWalletEvent(action: SetWalletAction): SagaIterator {
const node = yield select(getNodeId); const node = yield select(getNodeId);
const newWallet = action.payload; const newWallet = action.payload;
const isWeb3Wallet = newWallet instanceof Web3Wallet; const isWeb3Wallet = newWallet instanceof Web3Wallet;
@ -52,6 +53,5 @@ export function* unsetWeb3Node(): SagaIterator {
export const web3 = [ export const web3 = [
takeEvery(TypeKeys.CONFIG_NODE_WEB3_UNSET, unsetWeb3Node), takeEvery(TypeKeys.CONFIG_NODE_WEB3_UNSET, unsetWeb3Node),
takeEvery(WalletTypeKeys.WALLET_SET, unsetWeb3NodeOnWalletEvent), takeEvery(WalletTypeKeys.WALLET_SET, unsetWeb3NodeOnWalletEvent)
takeEvery(WalletTypeKeys.WALLET_RESET, unsetWeb3NodeOnWalletEvent)
]; ];

View File

@ -96,7 +96,7 @@ export function* updateWalletTokenValues(): SagaIterator {
const calls = wallets.map(w => { const calls = wallets.map(w => {
return apply(node, node.getTokenBalance, [w.address, token]); return apply(node, node.getTokenBalance, [w.address, token]);
}); });
const tokenBalances: { balance: TokenValue; error: string | null } = yield all(calls); const tokenBalances: { balance: TokenValue; error: string | null }[] = yield all(calls);
for (let i = 0; i < wallets.length; i++) { for (let i = 0; i < wallets.length; i++) {
if (!tokenBalances[i].error) { if (!tokenBalances[i].error) {

View File

@ -45,7 +45,7 @@ function* resolveDomain(): SagaIterator {
const node: INode = yield select(getNodeLib); const node: INode = yield select(getNodeLib);
const result: { domainData: IBaseDomainRequest; error } = yield race({ const result: { domainData: IBaseDomainRequest; error: any } = yield race({
domainData: call(resolveDomainRequest, domain, node), domainData: call(resolveDomainRequest, domain, node),
err: call(delay, 10000) err: call(delay, 10000)
}); });

View File

@ -3,7 +3,13 @@ import { INode } from 'libs/nodes/INode';
import { getNodeLib } from 'selectors/config'; import { getNodeLib } from 'selectors/config';
import { SagaIterator } from 'redux-saga'; import { SagaIterator } from 'redux-saga';
export function* makeEthCallAndDecode({ to, data, decoder }): SagaIterator { interface Params {
to: any;
data: any;
decoder: any;
}
export function* makeEthCallAndDecode({ to, data, decoder }: Params): SagaIterator {
const node: INode = yield select(getNodeLib); const node: INode = yield select(getNodeLib);
const result: string = yield apply(node, node.sendCallRequest, [{ data, to }]); const result: string = yield apply(node, node.sendCallRequest, [{ data, to }]);
const decodedResult = yield call(decoder, result); const decodedResult = yield call(decoder, result);

View File

@ -8,7 +8,12 @@ import {
import { select, call, put, takeEvery } from 'redux-saga/effects'; import { select, call, put, takeEvery } from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga'; import { SagaIterator } from 'redux-saga';
import { setTokenValue, setValueField } from 'actions/transaction/actionCreators'; import { setTokenValue, setValueField } from 'actions/transaction/actionCreators';
import { SetCurrentValueAction, TypeKeys } from 'actions/transaction'; import {
SetCurrentValueAction,
TypeKeys,
TSetValueField,
TSetTokenValue
} from 'actions/transaction';
import { toTokenBase } from 'libs/units'; import { toTokenBase } from 'libs/units';
import { validateInput, IInput } from 'sagas/transaction/validationHelpers'; import { validateInput, IInput } from 'sagas/transaction/validationHelpers';
import { validNumber, validDecimal } from 'libs/validators'; import { validNumber, validDecimal } from 'libs/validators';
@ -19,7 +24,10 @@ export function* setCurrentValue(action: SetCurrentValueAction): SagaIterator {
return yield call(valueHandler, action, setter); return yield call(valueHandler, action, setter);
} }
export function* valueHandler({ payload }: SetCurrentValueAction, setter) { export function* valueHandler(
{ payload }: SetCurrentValueAction,
setter: TSetValueField | TSetTokenValue
) {
const decimal: number = yield select(getDecimal); const decimal: number = yield select(getDecimal);
const unit: string = yield select(getUnit); const unit: string = yield select(getUnit);

View File

@ -13,7 +13,7 @@ export function* getTokenBalances(wallet: IWallet, tokens: Token[]) {
const node: INode = yield select(getNodeLib); const node: INode = yield select(getNodeLib);
const address: string = yield apply(wallet, wallet.getAddressString); const address: string = yield apply(wallet, wallet.getAddressString);
const tokenBalances: TokenBalance[] = yield apply(node, node.getTokenBalances, [address, tokens]); const tokenBalances: TokenBalance[] = yield apply(node, node.getTokenBalances, [address, tokens]);
return tokens.reduce((acc, t, i) => { return tokens.reduce<{ [TokenSymbol: string]: TokenBalance }>((acc, t, i) => {
acc[t.symbol] = tokenBalances[i]; acc[t.symbol] = tokenBalances[i];
return acc; return acc;
}, {}); }, {});

View File

@ -263,7 +263,7 @@ export function* unlockWeb3(): SagaIterator {
yield call(initWeb3Node); yield call(initWeb3Node);
yield put(changeNodeIntent('web3')); yield put(changeNodeIntent('web3'));
yield take( yield take(
action => (action: any) =>
action.type === ConfigTypeKeys.CONFIG_NODE_CHANGE && action.payload.nodeId === 'web3' action.type === ConfigTypeKeys.CONFIG_NODE_CHANGE && action.payload.nodeId === 'web3'
); );

View File

@ -86,7 +86,7 @@ export function getSelectedNode(state: AppState) {
return getNodes(state).selectedNode; return getNodes(state).selectedNode;
} }
export function isNodeChanging(state): boolean { export function isNodeChanging(state: AppState): boolean {
return getSelectedNode(state).pending; return getSelectedNode(state).pending;
} }

View File

@ -75,7 +75,7 @@ export function isWalletFormatSupportedOnNetwork(state: AppState, format: Wallet
} }
export function unSupportedWalletFormatsOnNetwork(state: AppState): WalletName[] { export function unSupportedWalletFormatsOnNetwork(state: AppState): WalletName[] {
const supportedFormats = walletNames.filter(walletName => const supportedFormats = walletNames.filter((walletName: WalletName) =>
isWalletFormatSupportedOnNetwork(state, walletName) isWalletFormatSupportedOnNetwork(state, walletName)
); );
return difference(walletNames, supportedFormats); return difference(walletNames, supportedFormats);

View File

@ -1,13 +1,20 @@
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { ICurrentTo, ICurrentValue } from 'selectors/transaction'; import { ICurrentTo, ICurrentValue } from 'selectors/transaction';
import { isNetworkUnit } from 'selectors/config'; import { isNetworkUnit } from 'selectors/config';
type TransactionFields = AppState['transaction']['fields'];
export type TransactionFieldValues = {
[field in keyof TransactionFields]: TransactionFields[field]['value']
};
export const reduceToValues = (transactionFields: AppState['transaction']['fields']) => export const reduceToValues = (transactionFields: AppState['transaction']['fields']) =>
Object.keys(transactionFields).reduce( Object.keys(transactionFields).reduce<TransactionFieldValues>(
(obj, currFieldName) => { (obj, currFieldName: keyof TransactionFields) => {
const currField = transactionFields[currFieldName]; const currField = transactionFields[currFieldName];
return { ...obj, [currFieldName]: currField.value }; return { ...obj, [currFieldName]: currField.value };
}, },
{} as any //TODO: Fix types {} as TransactionFieldValues
); );
export const isFullTx = ( export const isFullTx = (

View File

@ -81,7 +81,10 @@ const serializedAndTransactionFieldsMatch = (state: AppState, isLocallySigned: b
const t2 = getTransactionFields(makeTransaction(serialzedTransaction)); const t2 = getTransactionFields(makeTransaction(serialzedTransaction));
const checkValidity = (tx: IHexStrTransaction) => const checkValidity = (tx: IHexStrTransaction) =>
Object.keys(tx).reduce((match, currField) => match && t1[currField] === t2[currField], true); Object.keys(tx).reduce(
(match, currField: keyof IHexStrTransaction) => match && t1[currField] === t2[currField],
true
);
//reduce both ways to make sure both are exact same //reduce both ways to make sure both are exact same
const transactionsMatch = checkValidity(t1) && checkValidity(t2); const transactionsMatch = checkValidity(t1) && checkValidity(t2);
// if its signed then verify the signature too // if its signed then verify the signature too

View File

@ -5,7 +5,7 @@ import {
State as TransactionState State as TransactionState
} from 'reducers/transaction'; } from 'reducers/transaction';
import { State as SwapState, INITIAL_STATE as swapInitialState } from 'reducers/swap'; import { State as SwapState, INITIAL_STATE as swapInitialState } from 'reducers/swap';
import { applyMiddleware, createStore } from 'redux'; import { applyMiddleware, createStore, Store } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension'; import { composeWithDevTools } from 'redux-devtools-extension';
import { createLogger } from 'redux-logger'; import { createLogger } from 'redux-logger';
import createSagaMiddleware from 'redux-saga'; import createSagaMiddleware from 'redux-saga';
@ -24,7 +24,7 @@ const configureStore = () => {
}); });
const sagaMiddleware = createSagaMiddleware(); const sagaMiddleware = createSagaMiddleware();
let middleware; let middleware;
let store; let store: Store<AppState>;
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
middleware = composeWithDevTools( middleware = composeWithDevTools(
@ -45,7 +45,7 @@ const configureStore = () => {
const savedTransactionState = loadStatePropertyOrEmptyObject<TransactionState>('transaction'); const savedTransactionState = loadStatePropertyOrEmptyObject<TransactionState>('transaction');
const persistedInitialState = { const persistedInitialState: Partial<AppState> = {
transaction: { transaction: {
...transactionInitialState, ...transactionInitialState,
fields: { fields: {
@ -65,10 +65,10 @@ const configureStore = () => {
...rehydrateConfigAndCustomTokenState() ...rehydrateConfigAndCustomTokenState()
}; };
store = createStore(RootReducer, persistedInitialState, middleware); store = createStore<AppState>(RootReducer, persistedInitialState as any, middleware);
// Add all of the sagas to the middleware // Add all of the sagas to the middleware
Object.keys(sagas).forEach(saga => { Object.keys(sagas).forEach((saga: keyof typeof sagas) => {
sagaMiddleware.run(sagas[saga]); sagaMiddleware.run(sagas[saga]);
}); });

View File

@ -3,9 +3,20 @@ import React from 'react';
import { getLanguageSelection } from 'selectors/config'; import { getLanguageSelection } from 'selectors/config';
import { configuredStore } from '../store'; import { configuredStore } from '../store';
const fallbackLanguage = 'en'; const fallbackLanguage = 'en';
const repository = {}; const repository: {
[language: string]: {
[translationName: string]: string;
};
} = {};
const languages = [ interface ILanguage {
code: string;
data: {
[translationName: string]: string;
};
}
const languages: ILanguage[] = [
require('./lang/de.json'), require('./lang/de.json'),
require('./lang/el.json'), require('./lang/el.json'),
require('./lang/en.json'), require('./lang/en.json'),

View File

@ -0,0 +1,3 @@
declare module 'ethereum-blockies' {
export function toDataUrl(address: string): string;
}

24
common/typescript/ethereumjs-abi.d.ts vendored Normal file
View File

@ -0,0 +1,24 @@
declare module 'ethereumjs-abi' {
import BN from 'bn.js';
type Values = (string | number | BN)[];
type Types = string[];
export function eventID(name: string, types: Types): Buffer;
export function methodID(name: string, types: Types): Buffer;
export function rawEncode(types: Types, values: Values): Buffer;
export function rawDecode(
types: Types,
data: string | Buffer
): (Buffer | boolean | number | BN | string)[];
export function simpleEncode(method: string, values: Values): Buffer;
export function simpleDecode(
method: string,
data: string | Buffer
): (Buffer | boolean | number | BN | string)[];
export function stringify(types: Types, values: Values): string;
export function solidityPack(types: Types, values: Values): Buffer;
export function soliditySHA3(types: Types, values: Values): Buffer;
export function soliditySHA256(types: Types, values: Values): Buffer;
export function solidityRIPEMD160(types: Types, values: Values): Buffer;
export function fromSerpent(sig: string): Types;
export function toSerpent(types: Types): string;
}

View File

@ -92,7 +92,7 @@ declare module 'ethereumjs-tx' {
* sign a transaction with a given a private key * sign a transaction with a given a private key
* @param {Buffer} privateKey * @param {Buffer} privateKey
*/ */
public sign(privateKey: Buffer); public sign(privateKey: Buffer): void;
/** /**
* The amount of gas paid for the data in this tx * The amount of gas paid for the data in this tx

View File

@ -65,7 +65,7 @@ declare module 'ethereumjs-wallet/hdkey' {
/** /**
* @description derive a node based on a child index * @description derive a node based on a child index
*/ */
deriveChild(index): IHDNodePublic; deriveChild(index: any): IHDNodePublic;
/** /**
* @description return a Wallet instance * @description return a Wallet instance
@ -97,7 +97,7 @@ declare module 'ethereumjs-wallet/hdkey' {
/** /**
* @description derive a node based on a child index * @description derive a node based on a child index
*/ */
deriveChild(index): IHDNodePrivate | IHDNodePublic; deriveChild(index: any): IHDNodePrivate | IHDNodePublic;
/** /**
* @description return a Wallet instance * @description return a Wallet instance

15
common/typescript/ethjs-util.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
declare module 'ethjs-util' {
export function arrayContainsArray(arrayA: any[], arrayB: any[]): Boolean;
export function getBinarySize(num: string): number;
export function intToBuffer(integer: number): Buffer;
export function isHexPrefixed(hex: string): boolean;
export function stripHexPrefix(hexWithPrefix: string): string;
export function padToEven(unpaddedNumber: string): string;
export function intToHex(integer: number): string;
export function fromAscii(ascii: string): string;
export function fromUtf8(utf8: string): string;
export function toAscii(nonAscii: string): string;
export function toUtf8(nonUtf8: string): string;
export function getKeys(keys: any[], query: string): any[];
export function isHexString(inputString: string): boolean;
}

11
common/typescript/hdkey.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
declare module 'hdkey' {
export default class HDKey {
privateKey: Buffer;
publicKey: Buffer;
chainCode: Buffer | string;
static fromMasterSeed(seedBuffer: Buffer, versions?: any[]): HDKey;
static fromExtendedKey(base58key: any, versions?: any[]): HDKey;
static fromJSON(obj: any): HDKey;
derive(path: string): HDKey;
}
}

10
common/typescript/idna-uts46.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
declare module 'idna-uts46' {
export interface Options {
transitional?: boolean;
useStd3ASCII?: boolean;
verifyDnsLength?: boolean;
}
export function toAscii(domain: string, options: Options): string;
export function toUnicode(domain: string, args: Options): string;
}

45
common/typescript/ledgerco.d.ts vendored Normal file
View File

@ -0,0 +1,45 @@
declare module 'ledgerco' {
// TODO: fill the library typings out
export const comm_u2f: any;
export class eth {
constructor(transport: any);
getAddress_async(
path: string,
boolDisplay?: boolean,
boolChaincode?: boolean
): Promise<{
publicKey: string;
address: string;
chainCode: string;
}>;
signTransaction_async(
path: string,
rawTxHex: string
): Promise<{
s: string;
v: string;
r: string;
}>;
getAppConfiguration_async(): Promise<{
arbitraryDataEnabled: number;
version: string;
}>;
signPersonalMessage_async(
path: string,
messageHex: string
): Promise<{
v: number;
s: string;
r: string;
}>;
signPersonalMessage_async(
path: string,
messageHex: string,
cb: (signed: any, error: any) => any
): void;
}
}

View File

@ -0,0 +1,14 @@
declare module 'react-copy-to-clipboard' {
interface Options {
debug: boolean;
message: string;
}
interface Props {
text: string;
onCopy?(a: string, b: boolean): void;
options?: Options;
}
export class CopyToClipboard extends React.Component<Props> {}
}

View File

@ -0,0 +1,38 @@
interface PropTypes {
activeStep: number;
steps: any[];
activeColor?: string;
completeColor?: string;
defaultColor?: string;
activeTitleColor?: string;
completeTitleColor?: string;
defaultTitleColor?: string;
circleFontColor?: string;
size?: number;
circleFontSize?: number;
titleFontSize?: number;
circleTop?: number;
titleTop?: number;
defaultOpacity?: string;
completeOpacity?: string;
activeOpacity?: string;
defaultTitleOpacity?: string;
completeTitleOpacity?: string;
activeTitleOpacity?: string;
barStyle?: string;
defaultBarColor?: string;
completeBarColor?: string;
defaultBorderColor?: string;
completeBorderColor?: string;
activeBorderColor?: string;
defaultBorderStyle?: string;
completeBorderStyle?: string;
activeBorderStyle?: string;
}
declare module 'react-stepper-horizontal' {
import React from 'react';
class Stepper extends React.Component<PropTypes> {
constructor();
}
export = Stepper;
}

View File

@ -0,0 +1,6 @@
declare module 'redux-test-utils' {
import { Store } from 'react-redux';
export function createMockStore(testState: any): Store<any>;
export function createMockDispatch(testAction: any): any;
}

View File

@ -0,0 +1,36 @@
declare module 'wallet-address-validator' {
export function validate(
address: string,
currency?: CurrencyNames | CurrencySymbols,
networkType?: 'prod' | 'testnet' | 'both'
): boolean;
export function getAddressType(address: string): string;
}
type CurrencyNames =
| 'bitcoin'
| 'litecoin'
| 'peercoin'
| 'dogecoin'
| 'beavercoin'
| 'freicoin'
| 'protoshares'
| 'megacoin'
| 'primecoin'
| 'auroracoin'
| 'namecoin'
| 'biocoin';
type CurrencySymbols =
| 'BTC'
| 'LTC'
| 'PPC'
| 'DOGE'
| 'BVC'
| 'FRC'
| 'PTS'
| 'MEC'
| 'XPM'
| 'AUR'
| 'NMC'
| 'BIO';

View File

@ -1,13 +1,20 @@
import qs from 'query-string'; import qs from 'query-string';
import has from 'lodash/has'; import has from 'lodash/has';
export function objectContainsObjectKeys(checkingObject, containingObject) { interface IObjectValue {
[key: string]: any;
}
export function objectContainsObjectKeys(
checkingObject: IObjectValue,
containingObject: IObjectValue
) {
const checkingObjectKeys = Object.keys(checkingObject); const checkingObjectKeys = Object.keys(checkingObject);
const containsAll = checkingObjectKeys.map(key => has(containingObject, key)); const containsAll = checkingObjectKeys.map(key => has(containingObject, key));
return containsAll.every(isTrue => isTrue); return containsAll.every(isTrue => isTrue);
} }
export function getKeyByValue(object, value) { export function getKeyByValue(object: IObjectValue, value: any) {
return Object.keys(object).find(key => object[key] === value); return Object.keys(object).find(key => object[key] === value);
} }
@ -28,5 +35,5 @@ export function isPositiveInteger(n: number) {
return Number.isInteger(n) && n > 0; return Number.isInteger(n) && n > 0;
} }
export const getValues = (...args) => export const getValues = (...args: any[]) =>
args.reduce((acc, currArg) => [...acc, ...Object.values(currArg)], []); args.reduce((acc, currArg) => [...acc, ...Object.values(currArg)], []);

View File

@ -2,6 +2,7 @@ export const REDUX_STATE = 'REDUX_STATE';
import { State as SwapState } from 'reducers/swap'; import { State as SwapState } from 'reducers/swap';
import { IWallet, WalletConfig } from 'libs/wallet'; import { IWallet, WalletConfig } from 'libs/wallet';
import { sha256 } from 'ethereumjs-util'; import { sha256 } from 'ethereumjs-util';
import { AppState } from 'reducers';
export function loadState<T>(): T | undefined { export function loadState<T>(): T | undefined {
try { try {
@ -26,8 +27,8 @@ export const saveState = (state: any) => {
export type SwapLocalStorage = SwapState; export type SwapLocalStorage = SwapState;
export function loadStatePropertyOrEmptyObject<T>(key: string): T | undefined { export function loadStatePropertyOrEmptyObject<T>(key: keyof AppState): T | undefined {
const localStorageState = loadState(); const localStorageState: Partial<AppState> | undefined = loadState();
if (localStorageState) { if (localStorageState) {
if (localStorageState.hasOwnProperty(key)) { if (localStorageState.hasOwnProperty(key)) {
return localStorageState[key] as T; return localStorageState[key] as T;

View File

@ -18,8 +18,8 @@ export default function(element: React.ReactElement<any>, opts: PrintOptions = {
// Convert popupFeatures into a key=value,key=value string. See // Convert popupFeatures into a key=value,key=value string. See
// https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features // https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features
// for more information. // for more information.
const featuresStr = Object.keys(options.popupFeatures) const featuresStr = Object.entries(options.popupFeatures)
.map(key => `${key}=${options.popupFeatures[key]}`) .map(([key, value]) => `${key}=${value}`)
.join(','); .join(',');
const popup = window.open('about:blank', 'printWindow', featuresStr); const popup = window.open('about:blank', 'printWindow', featuresStr);

View File

@ -6,7 +6,7 @@ export function dedupeCustomTokens(networkTokens: Token[], customTokens: Token[]
} }
// If any tokens have the same symbol or contract address, remove them // If any tokens have the same symbol or contract address, remove them
const tokenCollisionMap = networkTokens.reduce((prev, token) => { const tokenCollisionMap = networkTokens.reduce<{ [tokenKey: string]: boolean }>((prev, token) => {
prev[token.symbol] = true; prev[token.symbol] = true;
prev[token.address] = true; prev[token.address] = true;
return prev; return prev;

View File

@ -6,7 +6,7 @@ import { APP_TITLE } from '../constants';
const isDevelopment = process.env.NODE_ENV !== 'production'; const isDevelopment = process.env.NODE_ENV !== 'production';
// Cached reference, preventing recreations // Cached reference, preventing recreations
let window; let window: BrowserWindow | null;
// Construct new BrowserWindow // Construct new BrowserWindow
export default function getWindow() { export default function getWindow() {
@ -39,7 +39,7 @@ export default function getWindow() {
window = null; window = null;
}); });
window.webContents.on('new-window', (ev, urlStr) => { window.webContents.on('new-window', (ev: any, urlStr: string) => {
// Kill all new window requests by default // Kill all new window requests by default
ev.preventDefault(); ev.preventDefault();
@ -53,13 +53,13 @@ export default function getWindow() {
}); });
window.webContents.on('did-finish-load', () => { window.webContents.on('did-finish-load', () => {
updater(window); updater(window!);
}); });
window.webContents.on('devtools-opened', () => { window.webContents.on('devtools-opened', () => {
window.focus(); window!.focus();
setImmediate(() => { setImmediate(() => {
window.focus(); window!.focus();
}); });
}); });

View File

@ -54,19 +54,24 @@
"zxcvbn": "4.4.2" "zxcvbn": "4.4.2"
}, },
"devDependencies": { "devDependencies": {
"@types/bip39": "2.4.0",
"@types/classnames": "2.2.3", "@types/classnames": "2.2.3",
"@types/enzyme": "3.1.8",
"@types/enzyme-adapter-react-16": "1.0.1",
"@types/history": "4.6.2", "@types/history": "4.6.2",
"@types/jest": "22.2.0", "@types/jest": "22.2.0",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/qrcode": "0.8.0", "@types/qrcode": "0.8.0",
"@types/qrcode.react": "0.6.3", "@types/qrcode.react": "0.6.3",
"@types/query-string": "5.1.0", "@types/query-string": "5.1.0",
"@types/rc-slider": "8.2.3",
"@types/react": "16.0.40", "@types/react": "16.0.40",
"@types/react-dom": "16.0.4", "@types/react-dom": "16.0.4",
"@types/react-redux": "5.0.15", "@types/react-redux": "5.0.15",
"@types/react-router-dom": "4.2.4", "@types/react-router-dom": "4.2.4",
"@types/react-router-redux": "5.0.12", "@types/react-router-redux": "5.0.12",
"@types/react-select": "1.2.3", "@types/react-select": "1.2.3",
"@types/react-transition-group": "2.0.7",
"@types/redux-logger": "3.0.5", "@types/redux-logger": "3.0.5",
"@types/uuid": "3.4.3", "@types/uuid": "3.4.3",
"@types/webpack-env": "1.13.4", "@types/webpack-env": "1.13.4",
@ -131,8 +136,8 @@
"webpack-hot-middleware": "2.21.0", "webpack-hot-middleware": "2.21.0",
"webpack-sources": "1.0.1", "webpack-sources": "1.0.1",
"webpack-subresource-integrity": "1.0.4", "webpack-subresource-integrity": "1.0.4",
"worker-loader": "1.1.1", "what-input": "5.0.5",
"what-input": "5.0.5" "worker-loader": "1.1.1"
}, },
"scripts": { "scripts": {
"freezer": "webpack --config=./webpack_config/webpack.freezer.js && node ./dist/freezer.js", "freezer": "webpack --config=./webpack_config/webpack.freezer.js && node ./dist/freezer.js",
@ -142,10 +147,14 @@
"prebuild": "check-node-version --package", "prebuild": "check-node-version --package",
"build:downloadable": "webpack --config webpack_config/webpack.html.js", "build:downloadable": "webpack --config webpack_config/webpack.html.js",
"prebuild:downloadable": "check-node-version --package", "prebuild:downloadable": "check-node-version --package",
"build:electron": "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js", "build:electron":
"build:electron:osx": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js", "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js",
"build:electron:windows": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js", "build:electron:osx":
"build:electron:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js", "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js",
"build:electron:windows":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
"build:electron:linux":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js",
"prebuild:electron": "check-node-version --package", "prebuild:electron": "check-node-version --package",
"test:coverage": "jest --config=jest_config/jest.config.json --coverage", "test:coverage": "jest --config=jest_config/jest.config.json --coverage",
"test": "jest --config=jest_config/jest.config.json", "test": "jest --config=jest_config/jest.config.json",
@ -157,14 +166,18 @@
"predev": "check-node-version --package", "predev": "check-node-version --package",
"dev:https": "HTTPS=true node webpack_config/devServer.js", "dev:https": "HTTPS=true node webpack_config/devServer.js",
"predev:https": "check-node-version --package", "predev:https": "check-node-version --package",
"dev:electron": "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'", "dev:electron":
"dev:electron:https": "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true HTTPS=true node webpack_config/devServer.js' 'HTTPS=true webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'", "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
"dev:electron:https":
"concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true HTTPS=true node webpack_config/devServer.js' 'HTTPS=true webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
"tslint": "tslint --project . --exclude common/vendor/**/*", "tslint": "tslint --project . --exclude common/vendor/**/*",
"tscheck": "tsc --noEmit", "tscheck": "tsc --noEmit",
"start": "npm run dev", "start": "npm run dev",
"precommit": "lint-staged", "precommit": "lint-staged",
"formatAll": "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override", "formatAll":
"prettier:diff": "prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"", "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
"prettier:diff":
"prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"",
"prepush": "npm run tslint && npm run tscheck" "prepush": "npm run tslint && npm run tscheck"
}, },
"lint-staged": { "lint-staged": {

View File

@ -6,10 +6,10 @@ configuredStore.getState();
describe('Contracts JSON', () => { describe('Contracts JSON', () => {
Object.keys(CONTRACTS).forEach(network => { Object.keys(CONTRACTS).forEach(network => {
it(`${network} contracts array properly formatted`, () => { it(`${network} contracts array properly formatted`, () => {
const contracts = CONTRACTS[network]; const contracts: any = (CONTRACTS as any)[network];
const addressCollisionMap = {}; const addressCollisionMap: any = {};
contracts.forEach(contract => { contracts.forEach((contract: any) => {
if (contract.address && !isValidETHAddress(contract.address)) { if (contract.address && !isValidETHAddress(contract.address)) {
throw Error(`Contract '${contract.name}' has invalid address '${contract.address}'`); throw Error(`Contract '${contract.name}' has invalid address '${contract.address}'`);
} }

View File

@ -6,11 +6,11 @@ configuredStore.getState();
describe('Tokens JSON', () => { describe('Tokens JSON', () => {
Object.keys(TOKENS).forEach(network => { Object.keys(TOKENS).forEach(network => {
it(`${network} tokens array properly formatted`, () => { it(`${network} tokens array properly formatted`, () => {
const tokens = TOKENS[network]; const tokens = (TOKENS as any)[network];
const addressCollisionMap = {}; const addressCollisionMap: any = {};
const symbolCollisionMap = {}; const symbolCollisionMap: any = {};
tokens.forEach(token => { tokens.forEach((token: any) => {
if (!isValidETHAddress(token.address)) { if (!isValidETHAddress(token.address)) {
throw Error(`Token ${token.symbol} has invalid contract address '${token.address}'`); throw Error(`Token ${token.symbol} has invalid contract address '${token.address}'`);
} }

View File

@ -1,5 +1,5 @@
import { RPCNode } from '../../common/libs/nodes'; import { RPCNode } from '../../common/libs/nodes';
import { Validator } from 'jsonschema'; import { Validator, ValidatorResult } from 'jsonschema';
import { schema } from '../../common/libs/validators'; import { schema } from '../../common/libs/validators';
import 'url-search-params-polyfill'; import 'url-search-params-polyfill';
import EtherscanNode from 'libs/nodes/etherscan'; import EtherscanNode from 'libs/nodes/etherscan';
@ -25,6 +25,10 @@ const validRequests = {
} }
}; };
interface RPCTestList {
[key: string]: ((n: RPCNode) => Promise<ValidatorResult>);
}
const testGetBalance = (n: RPCNode) => { const testGetBalance = (n: RPCNode) => {
return n.client return n.client
.call(n.requests.getBalance(validRequests.address)) .call(n.requests.getBalance(validRequests.address))
@ -44,7 +48,7 @@ const testGetTokenBalance = (n: RPCNode) => {
.then(data => v.validate(data, schema.RpcNode)); .then(data => v.validate(data, schema.RpcNode));
}; };
const RPCTests = { const RPCTests: RPCTestList = {
getBalance: testGetBalance, getBalance: testGetBalance,
estimateGas: testEstimateGas, estimateGas: testEstimateGas,
getTokenBalance: testGetTokenBalance getTokenBalance: testGetTokenBalance

View File

@ -9,7 +9,7 @@ const dockerTag = 'latest';
function promiseFromChildProcess(command: string): Promise<any> { function promiseFromChildProcess(command: string): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
return exec(command, (err, stdout) => { return exec(command, (err: string, stdout: string) => {
err ? reject(err) : resolve(stdout); err ? reject(err) : resolve(stdout);
}); });
}); });

View File

@ -1,5 +1,5 @@
import { configuredStore } from 'store'; import { configuredStore } from 'store';
import { delay } from 'redux-saga'; import { delay, SagaIterator } from 'redux-saga';
import { call, cancel, fork, put, take, select } from 'redux-saga/effects'; import { call, cancel, fork, put, take, select } from 'redux-saga/effects';
import { cloneableGenerator, createMockTask } from 'redux-saga/utils'; import { cloneableGenerator, createMockTask } from 'redux-saga/utils';
import { import {
@ -58,9 +58,9 @@ describe('pollOfflineStatus*', () => {
timeout: true timeout: true
}; };
let originalHidden; let originalHidden: any;
let originalOnLine; let originalOnLine: any;
let originalRandom; let originalRandom: any;
beforeAll(() => { beforeAll(() => {
// backup global config // backup global config
@ -143,16 +143,18 @@ describe('handlePollOfflineStatus*', () => {
}); });
describe('handleNodeChangeIntent*', () => { describe('handleNodeChangeIntent*', () => {
let originalRandom; let originalRandom: any;
// normal operation variables // normal operation variables
const defaultNodeId = selectedNodeExpectedState.initialState.nodeId; const defaultNodeId: any = selectedNodeExpectedState.initialState.nodeId;
const defaultNodeConfig: StaticNodeConfig = staticNodesExpectedState.initialState[defaultNodeId]; const defaultNodeConfig: any = (staticNodesExpectedState as any).initialState[defaultNodeId];
const newNodeId = Object.keys(staticNodesExpectedState.initialState).reduce( const newNodeId = Object.keys(staticNodesExpectedState.initialState).reduce(
(acc, cur) => (acc, cur) =>
staticNodesExpectedState.initialState[cur].network !== defaultNodeConfig.network ? cur : acc (staticNodesExpectedState as any).initialState[cur].network !== defaultNodeConfig.network
? cur
: acc
); );
const newNodeConfig: StaticNodeConfig = staticNodesExpectedState.initialState[newNodeId]; const newNodeConfig: StaticNodeConfig = (staticNodesExpectedState as any).initialState[newNodeId];
const changeNodeIntentAction = changeNodeIntent(newNodeId); const changeNodeIntentAction = changeNodeIntent(newNodeId);
const latestBlock = '0xa'; const latestBlock = '0xa';
@ -166,7 +168,7 @@ describe('handleNodeChangeIntent*', () => {
const data = {} as any; const data = {} as any;
data.gen = cloneableGenerator(handleNodeChangeIntent)(changeNodeIntentAction); data.gen = cloneableGenerator(handleNodeChangeIntent)(changeNodeIntentAction);
function shouldBailOut(gen, nextVal, errMsg) { function shouldBailOut(gen: SagaIterator, nextVal: any, errMsg: string) {
expect(gen.next(nextVal).value).toEqual(select(getNodeId)); expect(gen.next(nextVal).value).toEqual(select(getNodeId));
expect(gen.next(defaultNodeId).value).toEqual(put(showNotification('danger', errMsg, 5000))); expect(gen.next(defaultNodeId).value).toEqual(put(showNotification('danger', errMsg, 5000)));
expect(gen.next().value).toEqual( expect(gen.next().value).toEqual(
@ -297,7 +299,7 @@ describe('unsetWeb3Node*', () => {
}); });
describe('unsetWeb3NodeOnWalletEvent*', () => { describe('unsetWeb3NodeOnWalletEvent*', () => {
const fakeAction = {}; const fakeAction: any = {};
const mockNodeId = 'web3'; const mockNodeId = 'web3';
const alternativeNodeId = 'eth_mycrypto'; const alternativeNodeId = 'eth_mycrypto';
const gen = unsetWeb3NodeOnWalletEvent(fakeAction); const gen = unsetWeb3NodeOnWalletEvent(fakeAction);
@ -319,7 +321,7 @@ describe('unsetWeb3NodeOnWalletEvent*', () => {
}); });
it('should return early if node type is not web3', () => { it('should return early if node type is not web3', () => {
const gen1 = unsetWeb3NodeOnWalletEvent({ payload: false }); const gen1 = unsetWeb3NodeOnWalletEvent({ payload: false } as any);
gen1.next(); //getNode gen1.next(); //getNode
gen1.next('notWeb3'); //getNodeConfig gen1.next('notWeb3'); //getNodeConfig
expect(gen1.next().done).toEqual(true); expect(gen1.next().done).toEqual(true);
@ -329,7 +331,7 @@ describe('unsetWeb3NodeOnWalletEvent*', () => {
const mockAddress = '0x0'; const mockAddress = '0x0';
const mockNetwork = 'ETH'; const mockNetwork = 'ETH';
const mockWeb3Wallet = new Web3Wallet(mockAddress, mockNetwork); const mockWeb3Wallet = new Web3Wallet(mockAddress, mockNetwork);
const gen2 = unsetWeb3NodeOnWalletEvent({ payload: mockWeb3Wallet }); const gen2 = unsetWeb3NodeOnWalletEvent({ payload: mockWeb3Wallet } as any);
gen2.next(); //getNode gen2.next(); //getNode
gen2.next('web3'); //getNodeConfig gen2.next('web3'); //getNodeConfig
expect(gen2.next().done).toEqual(true); expect(gen2.next().done).toEqual(true);

View File

@ -12,7 +12,7 @@ import tokens from 'config/tokens/eth.json';
import { SHAPESHIFT_TOKEN_WHITELIST } from 'api/shapeshift'; import { SHAPESHIFT_TOKEN_WHITELIST } from 'api/shapeshift';
describe('ensure whitelist', () => { describe('ensure whitelist', () => {
const findToken = (tkn: string) => tokens.find(t => t.symbol === tkn); const findToken = (tkn: string) => tokens.find((t: any) => t.symbol === tkn);
SHAPESHIFT_TOKEN_WHITELIST.forEach(t => { SHAPESHIFT_TOKEN_WHITELIST.forEach(t => {
it(`Should find Token ${t}`, () => { it(`Should find Token ${t}`, () => {
expect(findToken(t)).toBeTruthy(); expect(findToken(t)).toBeTruthy();
@ -87,7 +87,7 @@ describe('swap reducer', () => {
it('should handle SWAP_LOAD_SHAPESHIFT_RATES_SUCCEEDED', () => { it('should handle SWAP_LOAD_SHAPESHIFT_RATES_SUCCEEDED', () => {
expect( expect(
swap(undefined, swapActions.loadShapeshiftRatesSucceededSwap(shapeshiftApiResponse)) swap(undefined, swapActions.loadShapeshiftRatesSucceededSwap(shapeshiftApiResponse as any))
).toEqual({ ).toEqual({
...INITIAL_STATE, ...INITIAL_STATE,
isFetchingRates: false, isFetchingRates: false,

View File

@ -85,7 +85,7 @@ describe('pollBityOrderStatus*', () => {
error: true, error: true,
msg: 'error message' msg: 'error message'
}; };
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
@ -156,7 +156,7 @@ describe('pollShapeshiftOrderStatus*', () => {
error: 'Shapeshift error', error: 'Shapeshift error',
status: 'failed' status: 'failed'
}; };
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
@ -293,7 +293,7 @@ describe('postBityOrderCreate*', () => {
const data = {} as any; const data = {} as any;
data.gen = cloneableGenerator(postBityOrderCreate)(action); data.gen = cloneableGenerator(postBityOrderCreate)(action);
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
Math.random = () => 0.001; Math.random = () => 0.001;
@ -381,7 +381,7 @@ describe('postShapeshiftOrderCreate*', () => {
const data = {} as any; const data = {} as any;
data.gen = cloneableGenerator(postShapeshiftOrderCreate)(action); data.gen = cloneableGenerator(postShapeshiftOrderCreate)(action);
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
Math.random = () => 0.001; Math.random = () => 0.001;
@ -457,7 +457,7 @@ describe('bityOrderTimeRemaining*', () => {
orderTimestampCreatedISOString: new Date(orderTimeExpired).toISOString(), orderTimestampCreatedISOString: new Date(orderTimeExpired).toISOString(),
validFor: swapValidFor validFor: swapValidFor
}; };
let random; let random: () => number;
const data = {} as any; const data = {} as any;
data.gen = cloneableGenerator(bityOrderTimeRemaining)(); data.gen = cloneableGenerator(bityOrderTimeRemaining)();
@ -538,7 +538,7 @@ describe('shapeshiftOrderTimeRemaining*', () => {
orderTimestampCreatedISOString: new Date(orderTimeExpired).toISOString(), orderTimestampCreatedISOString: new Date(orderTimeExpired).toISOString(),
validFor: swapValidFor validFor: swapValidFor
}; };
let random; let random: () => number;
const data = {} as any; const data = {} as any;
data.gen = cloneableGenerator(shapeshiftOrderTimeRemaining)(); data.gen = cloneableGenerator(shapeshiftOrderTimeRemaining)();

View File

@ -36,7 +36,7 @@ describe('loadBityRates*', () => {
} }
}; };
const err = { message: 'error' }; const err = { message: 'error' };
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
@ -103,7 +103,7 @@ describe('loadShapeshiftRates*', () => {
} }
}; };
const err = 'error'; const err = 'error';
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
@ -125,7 +125,7 @@ describe('loadShapeshiftRates*', () => {
it('should put loadShapeshiftRatesSucceededSwap', () => { it('should put loadShapeshiftRatesSucceededSwap', () => {
expect(gen1.next({ tokens: apiResponse }).value).toEqual( expect(gen1.next({ tokens: apiResponse }).value).toEqual(
put(loadShapeshiftRatesSucceededSwap(apiResponse)) put(loadShapeshiftRatesSucceededSwap(apiResponse as any))
); );
}); });

View File

@ -36,7 +36,7 @@ describe('broadcastTransactionWrapper*', () => {
blockExplorer: 'blockExplorer' blockExplorer: 'blockExplorer'
}; };
let random; let random: () => number;
const func: any = () => undefined; const func: any = () => undefined;
const action: any = {}; const action: any = {};
const gens: any = {}; const gens: any = {};

View File

@ -10,8 +10,9 @@ import {
valueHandler valueHandler
} from 'sagas/transaction/current/currentValue'; } from 'sagas/transaction/current/currentValue';
import { cloneableGenerator, SagaIteratorClone } from 'redux-saga/utils'; import { cloneableGenerator, SagaIteratorClone } from 'redux-saga/utils';
import { SagaIterator } from 'redux-saga';
const itShouldBeDone = gen => { const itShouldBeDone = (gen: SagaIterator) => {
it('should be done', () => { it('should be done', () => {
expect(gen.next().done).toEqual(true); expect(gen.next().done).toEqual(true);
}); });
@ -83,7 +84,12 @@ describe('setCurrentValue*', () => {
}); });
describe('revalidateCurrentValue*', () => { describe('revalidateCurrentValue*', () => {
const sharedLogic = (gen, etherTransaction, currVal, reparsedValue) => { const sharedLogic = (
gen: SagaIterator,
etherTransaction: boolean,
currVal: any,
reparsedValue: boolean
) => {
it('should select isEtherTransaction', () => { it('should select isEtherTransaction', () => {
expect(gen.next().value).toEqual(select(isEtherTransaction)); expect(gen.next().value).toEqual(select(isEtherTransaction));
}); });
@ -159,7 +165,7 @@ describe('revalidateCurrentValue*', () => {
}); });
describe('reparseCurrentValue*', () => { describe('reparseCurrentValue*', () => {
const sharedLogic = gen => { const sharedLogic = (gen: SagaIterator) => {
it('should select getDecimal', () => { it('should select getDecimal', () => {
expect(gen.next().value).toEqual(select(getDecimal)); expect(gen.next().value).toEqual(select(getDecimal));
}); });

View File

@ -12,9 +12,10 @@ 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';
import { SagaIterator } from 'redux-saga';
configuredStore.getState(); configuredStore.getState();
const itShouldBeDone = gen => { const itShouldBeDone = (gen: SagaIterator) => {
it('should be done', () => { it('should be done', () => {
expect(gen.next().done).toEqual(true); expect(gen.next().done).toEqual(true);
}); });

View File

@ -7,9 +7,10 @@ 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';
import { SagaIterator } from 'redux-saga';
configuredStore.getState(); configuredStore.getState();
const itShouldBeDone = gen => { const itShouldBeDone = (gen: SagaIterator) => {
it('should be done', () => { it('should be done', () => {
expect(gen.next().done).toEqual(true); expect(gen.next().done).toEqual(true);
}); });

View File

@ -17,11 +17,13 @@ import {
import { encodeTransfer } from 'libs/transaction'; import { encodeTransfer } from 'libs/transaction';
import { bufferToHex } from 'ethereumjs-util'; 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, SagaIteratorClone } from 'redux-saga/utils';
import { handleSetUnitMeta } from 'sagas/transaction/meta/unitSwap'; import { handleSetUnitMeta } from 'sagas/transaction/meta/unitSwap';
import { isNetworkUnit } from 'selectors/config'; import { isNetworkUnit } from 'selectors/config';
import { SagaIterator } from 'redux-saga';
import BN from 'bn.js';
const itShouldBeDone = gen => { const itShouldBeDone = (gen: SagaIterator) => {
it('should be done', () => { it('should be done', () => {
expect(gen.next().done).toEqual(true); expect(gen.next().done).toEqual(true);
}); });
@ -29,11 +31,11 @@ const itShouldBeDone = gen => {
describe('handleSetUnitMeta*', () => { describe('handleSetUnitMeta*', () => {
const expectedStart = ( const expectedStart = (
gen, gen: SagaIterator,
previousUnit, previousUnit: string,
currentUnit, currentUnit: string,
prevUnitIsNetworkUnit, prevUnitIsNetworkUnit: boolean,
currUnitIsNetworkUnit currUnitIsNetworkUnit: boolean
) => { ) => {
it('should select getPreviousUnit', () => { it('should select getPreviousUnit', () => {
expect(gen.next().value).toEqual(select(getPreviousUnit)); expect(gen.next().value).toEqual(select(getPreviousUnit));
@ -121,7 +123,7 @@ describe('handleSetUnitMeta*', () => {
}); });
describe('etherToToken || tokenToToken', () => { describe('etherToToken || tokenToToken', () => {
const sharedLogicA = (gen, decimal, currentUnit) => { const sharedLogicA = (gen: SagaIteratorClone, decimal: number, currentUnit: string) => {
it('should select getToken with currentUnit', () => { it('should select getToken with currentUnit', () => {
expect(gen.next(decimal).value).toEqual(select(getToken, currentUnit)); expect(gen.next(decimal).value).toEqual(select(getToken, currentUnit));
}); });
@ -132,9 +134,16 @@ describe('handleSetUnitMeta*', () => {
}); });
}; };
const sharedLogicB = (gen, input, raw, value, currentUnit, isValid) => { const sharedLogicB = (
gen: SagaIterator,
input: string,
raw: string,
value: BN,
currentUnit: string,
isValid: boolean
) => {
it('should call rebaseUserInput with input', () => { it('should call rebaseUserInput with input', () => {
expect(gen.next(input).value).toEqual(call(rebaseUserInput, input)); expect(gen.next(input).value).toEqual(call(rebaseUserInput, input as any));
}); });
it('should call validateInput with value and currentUnit', () => { it('should call validateInput with value and currentUnit', () => {
@ -146,7 +155,14 @@ describe('handleSetUnitMeta*', () => {
}); });
}; };
const constructExpectedPayload = (data, toAddress, raw, value, decimal, tokenTo?) => { const constructExpectedPayload = (
data: Buffer,
toAddress: string,
raw: string,
value: BN,
decimal: number,
tokenTo?: any
) => {
const base = { const base = {
data: { raw: bufferToHex(data), value: data }, data: { raw: bufferToHex(data), value: data },
to: { raw: '', value: Address(toAddress) }, to: { raw: '', value: Address(toAddress) },

View File

@ -14,7 +14,7 @@ describe('handleFromRequest*', () => {
const fromAddress = '0xa'; const fromAddress = '0xa';
const gens: any = {}; const gens: any = {};
gens.gen = cloneableGenerator(handleFromRequest)(); gens.gen = cloneableGenerator(handleFromRequest)();
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;

View File

@ -19,7 +19,7 @@ import {
localGasEstimation, localGasEstimation,
setAddressMessageGasLimit setAddressMessageGasLimit
} from 'sagas/transaction/network/gas'; } from 'sagas/transaction/network/gas';
import { cloneableGenerator } from 'redux-saga/utils'; import { cloneableGenerator, SagaIteratorClone } from 'redux-saga/utils';
import { Wei } from 'libs/units'; import { Wei } from 'libs/units';
import { TypeKeys as ConfigTypeKeys } from 'actions/config'; import { TypeKeys as ConfigTypeKeys } from 'actions/config';
@ -117,7 +117,7 @@ describe('estimateGas*', () => {
const gens: { [name: string]: any } = {}; const gens: { [name: string]: any } = {};
gens.successCase = cloneableGenerator(estimateGas)(); gens.successCase = cloneableGenerator(estimateGas)();
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;
Math.random = () => 0.001; Math.random = () => 0.001;
@ -251,8 +251,8 @@ describe('localGasEstimation', () => {
describe('setAddressMessageGasLimit*', () => { describe('setAddressMessageGasLimit*', () => {
const gens = cloneableGenerator(setAddressMessageGasLimit)(); const gens = cloneableGenerator(setAddressMessageGasLimit)();
const gen = gens.clone(); const gen = gens.clone();
let noAutoGen; let noAutoGen: SagaIteratorClone;
let noMessageGen; let noMessageGen: SagaIteratorClone;
const addressMessage = { const addressMessage = {
gasLimit: 123456, gasLimit: 123456,
msg: 'Thanks for donating, er, investing in SCAM' msg: 'Thanks for donating, er, investing in SCAM'

View File

@ -21,7 +21,7 @@ describe('handleNonceRequest*', () => {
const gens: any = {}; const gens: any = {};
gens.gen = cloneableGenerator(handleNonceRequest)(); gens.gen = cloneableGenerator(handleNonceRequest)();
let random; let random: () => number;
beforeAll(() => { beforeAll(() => {
random = Math.random; random = Math.random;

Some files were not shown because too many files have changed in this diff Show More