Merge in typings

This commit is contained in:
henrynguyen5 2018-01-02 20:26:11 -05:00
parent 88532cdc3c
commit bc10197ebf
27 changed files with 173 additions and 88 deletions

19
common/actions/index.ts Normal file
View File

@ -0,0 +1,19 @@
import { ConfigAction } from './config';
import { CustomTokenAction } from './customTokens';
import { DeterministicWalletAction } from './deterministicWallets';
import { EnsAction } from './ens';
import { NotificationsAction } from './notifications';
import { RatesAction } from './rates';
import { SwapAction } from './swap';
import { TransactionAction } from './transaction';
import { WalletAction } from './wallet';
export type AllActions =
| ConfigAction
| CustomTokenAction
| DeterministicWalletAction
| EnsAction
| NotificationsAction
| RatesAction
| SwapAction
| TransactionAction
| WalletAction;

View File

@ -5,7 +5,7 @@ import { State } from 'reducers/rates';
import { rateSymbols, TFetchCCRates } from 'actions/rates';
import { TokenBalance } from 'selectors/wallet';
import { Balance } from 'libs/wallet';
import { ETH_DECIMAL, convertTokenBase } from 'libs/units';
import { ETH_DECIMAL, convertTokenBase, Wei, TokenValue } from 'libs/units';
import Spinner from 'components/ui/Spinner';
import UnitDisplay from 'components/ui/UnitDisplay';
import './EquivalentValues.scss';
@ -129,15 +129,19 @@ export default class EquivalentValues extends React.Component<Props, CmpState> {
};
private makeBalanceLookup(props: Props) {
interface IBalanceLookup {
[unit: string]: Wei | TokenValue | undefined;
}
const tokenBalances = props.tokenBalances || [];
this.balanceLookup = tokenBalances.reduce(
(prev, tk) => {
(balanceLookup, currentToken) => {
// Piggy-back off of this reduce to add to decimal lookup
this.decimalLookup[tk.symbol] = tk.decimal;
prev[tk.symbol] = tk.balance;
return prev;
this.decimalLookup[currentToken.symbol] = currentToken.decimal;
balanceLookup[currentToken.symbol] = currentToken.balance;
return balanceLookup;
},
{ ETH: props.balance && props.balance.wei }
{ ETH: props.balance && props.balance.wei } as IBalanceLookup
);
}
@ -168,18 +172,26 @@ export default class EquivalentValues extends React.Component<Props, CmpState> {
): {
[key: string]: BN | undefined;
} {
interface IEquivalentValues {
[unit: string]: Wei | TokenValue;
}
// Recursively call on all currencies
if (currency === ALL_OPTION) {
return ['ETH'].concat(this.requestedCurrencies || []).reduce(
(prev, curr) => {
const currValues = this.getEquivalentValues(curr);
rateSymbols.forEach(sym => (prev[sym] = prev[sym].add(currValues[sym] || new BN(0))));
rateSymbols.forEach(
sym => (prev[sym] = prev[sym].add(currValues[sym] || TokenValue('0')))
);
return prev;
},
rateSymbols.reduce((prev, sym) => {
prev[sym] = new BN(0);
return prev;
}, {})
rateSymbols.reduce(
(prev, sym) => {
prev[sym] = new BN(0);
return prev;
},
{} as IEquivalentValues
)
);
}
@ -195,9 +207,12 @@ export default class EquivalentValues extends React.Component<Props, CmpState> {
this.decimalLookup[currency] === undefined ? ETH_DECIMAL : this.decimalLookup[currency];
const adjustedBalance = convertTokenBase(balance, decimal, ETH_DECIMAL);
return rateSymbols.reduce((prev, sym) => {
prev[sym] = adjustedBalance.muln(rates[currency][sym]);
return prev;
}, {});
return rateSymbols.reduce(
(prev, sym) => {
prev[sym] = adjustedBalance.muln(rates[currency][sym]);
return prev;
},
{} as IEquivalentValues
);
}
}

View File

@ -20,7 +20,7 @@ interface State {
showCustomTokenForm: boolean;
}
export default class TokenBalances extends React.Component<Props, State> {
public state = {
public state: State = {
trackedTokens: {},
showCustomTokenForm: false
};

View File

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

View File

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

View File

@ -10,7 +10,7 @@ const NETWORK_KEYS = Object.keys(NETWORKS);
const CUSTOM = 'custom';
interface Input {
name: string;
name: keyof State;
placeholder?: string;
type?: string;
}
@ -231,7 +231,7 @@ export default class CustomNodeModal extends React.Component<Props, State> {
<input
className={classnames({
'form-control': true,
'is-invalid': this.state[input.name] && invalids[input.name]
'is-invalid': !!(this.state[input.name] && invalids[input.name])
})}
value={this.state[input.name]}
onChange={this.handleChange}

View File

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

View File

@ -117,7 +117,7 @@ export class MnemonicDecrypt extends Component<Props, State> {
this.setState({ dPath });
};
private handleUnlock = (address, index) => {
private handleUnlock = (address: string, index: number) => {
const { formattedPhrase, pass, dPath } = this.state;
this.props.onUnlock({

View File

@ -1,6 +1,7 @@
import React from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import Modal, { IButton } from 'components/ui/Modal';
import { UnregisterCallback } from 'history';
interface Props extends RouteComponentProps<{}> {
when: boolean;
@ -14,9 +15,9 @@ interface State {
}
class NavigationPromptClass extends React.Component<Props, State> {
public unblock;
public unblock: UnregisterCallback;
constructor(props) {
constructor(props: Props) {
super(props);
this.state = {
nextLocation: null,

View File

@ -19,7 +19,7 @@ interface State {
}
class InteractForm extends Component<Props, State> {
public state = {
public state: State = {
address: '',
abiJson: ''
};
@ -35,7 +35,11 @@ e":"a", "type":"uint256"}], "name":"foo", "outputs": [] }]';
const validEthAddress = isValidETHAddress(address);
const validAbiJson = isValidAbiJson(abiJson);
const showContractAccessButton = validEthAddress && validAbiJson;
let contractOptions;
interface IContractOpts {
name: string;
value: string | null;
}
let contractOptions: IContractOpts[];
if (contracts && contracts.length) {
contractOptions = [
{
@ -86,8 +90,8 @@ e":"a", "type":"uint256"}], "name":"foo", "outputs": [] }]';
onChange={this.handleSelectContract}
disabled={!contracts || !contracts.length}
>
{contractOptions.map(opt => (
<option key={opt.value} value={opt.value}>
{contractOptions.map((opt, idx) => (
<option key={opt.value || idx} value={opt.value || undefined}>
{opt.name}
</option>
))}
@ -122,9 +126,12 @@ e":"a", "type":"uint256"}], "name":"foo", "outputs": [] }]';
);
}
private handleInput = name => (ev: any) => {
private handleInput = (name: keyof State) => (
ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
this.props.resetState();
this.setState({ [name]: ev.target.value });
this.setState({ [name as any]: ev.currentTarget.value });
};
private handleSelectContract = (ev: any) => {

View File

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

View File

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

View File

@ -27,7 +27,7 @@ export interface GetAccountsRequest extends RPCRequestBase {
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;
export interface IWeb3Provider {

View File

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

View File

@ -162,7 +162,21 @@ export const isValidNonce = (value: string): boolean => {
return valid;
};
function isValidResult(response: JsonRpcResponse, schemaFormat): boolean {
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'
}
function isValidResult(response: JsonRpcResponse, schemaFormat: typeof schema.RpcNode): boolean {
return v.validate(response, schemaFormat).valid;
}
@ -174,8 +188,8 @@ function formatErrors(response: JsonRpcResponse, apiType: string) {
}
const isValidEthCall = (response: JsonRpcResponse, schemaType: typeof schema.RpcNode) => (
apiName,
cb?
apiName: API_NAME,
cb?: () => any
) => {
if (!isValidResult(response, schemaType)) {
if (cb) {
@ -187,36 +201,36 @@ const isValidEthCall = (response: JsonRpcResponse, schemaType: typeof schema.Rpc
};
export const isValidGetBalance = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Get Balance');
isValidEthCall(response, schema.RpcNode)(API_NAME.Get_Balance);
export const isValidEstimateGas = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Estimate Gas');
isValidEthCall(response, schema.RpcNode)(API_NAME.Estimate_Gas);
export const isValidCallRequest = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Call Request');
isValidEthCall(response, schema.RpcNode)(API_NAME.Call_Request);
export const isValidTokenBalance = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Token Balance', () => ({
isValidEthCall(response, schema.RpcNode)(API_NAME.Token_Balance, () => ({
result: 'Failed'
}));
export const isValidTransactionCount = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Transaction Count');
isValidEthCall(response, schema.RpcNode)(API_NAME.Transaction_Count);
export const isValidCurrentBlock = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Current Block');
isValidEthCall(response, schema.RpcNode)(API_NAME.Current_Block);
export const isValidRawTxApi = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Raw Tx');
isValidEthCall(response, schema.RpcNode)(API_NAME.Raw_Tx);
export const isValidSendTransaction = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Send Transaction');
isValidEthCall(response, schema.RpcNode)(API_NAME.Send_Transaction);
export const isValidSignMessage = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Sign Message');
isValidEthCall(response, schema.RpcNode)(API_NAME.Sign_Message);
export const isValidGetAccounts = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Get Accounts');
isValidEthCall(response, schema.RpcNode)(API_NAME.Get_Accounts);
export const isValidGetNetVersion = (response: JsonRpcResponse) =>
isValidEthCall(response, schema.RpcNode)('Net Version');
isValidEthCall(response, schema.RpcNode)(API_NAME.Net_Version);

View File

@ -25,7 +25,7 @@ export interface AppState {
transaction: TransactionState;
}
export default combineReducers({
export default combineReducers<AppState>({
config,
swap,
notifications,

View File

@ -1,6 +1,5 @@
import { State, RequestStatus } from './typings';
import { TypeKeys as TK, ResetAction, NetworkAction } from 'actions/transaction';
import { Action } from 'redux';
const INITIAL_STATE: State = {
gasEstimationStatus: null,
@ -13,9 +12,9 @@ const getPostFix = (str: string) => {
return arr[arr.length - 1];
};
const nextState = (field: keyof State) => (state: State, action: Action): State => ({
const nextState = (field: keyof State) => (state: State, action: NetworkAction): State => ({
...state,
[field]: RequestStatus[getPostFix(action.type)]
[field]: RequestStatus[getPostFix(action.type) as keyof typeof RequestStatus]
});
const reset = () => INITIAL_STATE;

View File

@ -10,7 +10,7 @@ import {
select,
race
} from 'redux-saga/effects';
import { NODES, NodeConfig } from 'config/data';
import { NODES, NodeConfig, CustomNodeConfig, CustomNetworkConfig } from 'config/data';
import {
makeCustomNodeId,
getCustomNodeConfigFromId,
@ -42,6 +42,7 @@ import { Web3Wallet } from 'libs/wallet';
import { getWalletInst } from 'selectors/wallet';
import { TypeKeys as WalletTypeKeys } from 'actions/wallet/constants';
import { State as ConfigState, INITIAL_STATE as configInitialState } from 'reducers/config';
import { SetWalletAction } from 'actions/wallet';
export const getConfig = (state: AppState): ConfigState => state.config;
@ -178,14 +179,20 @@ export function* switchToNewNode(action: AddCustomNodeAction): SagaIterator {
yield put(changeNodeIntent(nodeId));
}
interface INetworksInUse {
[networkName: string]: boolean;
}
// If there are any orphaned custom networks, purge them
export function* cleanCustomNetworks(): SagaIterator {
const customNodes = yield select(getCustomNodeConfigs);
const customNetworks = yield select(getCustomNetworkConfigs);
const networksInUse = customNodes.reduce((prev, conf) => {
prev[conf.network] = true;
return prev;
}, {});
const customNodes: CustomNodeConfig[] = yield select(getCustomNodeConfigs);
const customNetworks: CustomNetworkConfig[] = yield select(getCustomNetworkConfigs);
const networksInUse = customNodes.reduce(
(prev, conf) => {
prev[conf.network] = true;
return prev;
},
{} as INetworksInUse
);
for (const net of customNetworks) {
if (!networksInUse[makeCustomNetworkId(net)]) {
@ -195,7 +202,7 @@ export function* cleanCustomNetworks(): SagaIterator {
}
// 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(getNode);
const nodeConfig = yield select(getNodeConfig);
const newWallet = action.payload;

View File

@ -13,10 +13,16 @@ export function* getTokenBalances(wallet: IWallet, tokens: Token[]) {
const node: INode = yield select(getNodeLib);
const address: string = yield apply(wallet, wallet.getAddressString);
const tokenBalances: TokenBalance[] = yield apply(node, node.getTokenBalances, [address, tokens]);
return tokens.reduce((acc, t, i) => {
acc[t.symbol] = tokenBalances[i];
return acc;
}, {});
interface ITokenbalances {
[tokenSymbol: string]: TokenBalance;
}
return tokens.reduce(
(acc, currentToken, i) => {
acc[currentToken.symbol] = tokenBalances[i];
return acc;
},
{} as ITokenbalances
);
}
// Return an array of the tokens that meet any of the following conditions:

View File

@ -45,6 +45,7 @@ import translate from 'translations';
import Web3Node, { isWeb3Node } from 'libs/nodes/web3';
import { loadWalletConfig, saveWalletConfig } from 'utils/localStorage';
import { getTokenBalances, filterScannedTokenBalances } from './helpers';
import { AllActions } from 'actions';
export interface TokenBalanceLookup {
[symbol: string]: TokenBalance;
@ -205,7 +206,7 @@ export function* unlockWeb3(): SagaIterator {
yield call(initWeb3Node);
yield put(changeNodeIntent('web3'));
yield take(
action =>
(action: AllActions) =>
action.type === ConfigTypeKeys.CONFIG_NODE_CHANGE && action.payload.nodeSelection === 'web3'
);

View File

@ -80,7 +80,10 @@ const serializedAndTransactionFieldsMatch = (state: AppState, isLocallySigned: b
const t2 = getTransactionFields(makeTransaction(serialzedTransaction));
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
const transactionsMatch = checkValidity(t1) && checkValidity(t2);
// if its signed then verify the signature too

View File

@ -10,12 +10,12 @@ import {
State as TransactionState
} from 'reducers/transaction';
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 { createLogger } from 'redux-logger';
import createSagaMiddleware from 'redux-saga';
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
import RootReducer from './reducers';
import RootReducer, { AppState } from './reducers';
import promiseMiddleware from 'redux-promise-middleware';
import { getNodeConfigFromId } from 'utils/node';
import sagas from './sagas';
@ -30,7 +30,7 @@ const configureStore = () => {
promiseTypeSuffixes: ['REQUESTED', 'SUCCEEDED', 'FAILED']
});
let middleware;
let store;
let store: Store<AppState>;
if (process.env.NODE_ENV !== 'production') {
middleware = composeWithDevTools(
@ -106,11 +106,11 @@ const configureStore = () => {
persistedInitialState.config.nodeSelection = configInitialState.nodeSelection;
}
store = createStore(RootReducer, persistedInitialState, middleware);
store = createStore<AppState>(RootReducer, persistedInitialState as AppState, middleware);
// Add all of the sagas to the middleware
Object.keys(sagas).forEach(saga => {
sagaMiddleware.run(sagas[saga]);
Object.values(sagas).forEach(saga => {
sagaMiddleware.run(saga);
});
store.subscribe(

View File

@ -3,9 +3,19 @@ import React from 'react';
import { getLanguageSelection } from 'selectors/config';
import { configuredStore } from '../store';
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/el.json'),
require('./lang/en.json'),

View File

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

View File

@ -2,6 +2,7 @@ export const REDUX_STATE = 'REDUX_STATE';
import { State as SwapState } from 'reducers/swap';
import { IWallet, WalletConfig } from 'libs/wallet';
import { sha256 } from 'ethereumjs-util';
import { AppState } from 'reducers';
export function loadState<T>(): T | undefined {
try {
@ -26,8 +27,8 @@ export const saveState = (state: any) => {
export type SwapLocalStorage = SwapState;
export function loadStatePropertyOrEmptyObject<T>(key: string): T | undefined {
const localStorageState = loadState();
export function loadStatePropertyOrEmptyObject<T>(key: keyof AppState): T | undefined {
const localStorageState: Partial<AppState> | undefined = loadState();
if (localStorageState) {
if (localStorageState.hasOwnProperty(key)) {
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
// https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features
// for more information.
const featuresStr = Object.keys(options.popupFeatures)
.map(key => `${key}=${options.popupFeatures[key]}`)
const featuresStr = Object.entries(options.popupFeatures)
.map(([key, value]) => `${key}=${value}`)
.join(',');
const popup = window.open('about:blank', 'printWindow', featuresStr);

View File

@ -16,7 +16,8 @@
"moduleResolution": "node",
"noEmitOnError": false,
"noUnusedLocals": true,
"noUnusedParameters": true
"noUnusedParameters": true,
"noImplicitAny": true
},
"include": [
"./common/",
@ -26,4 +27,4 @@
"awesomeTypescriptLoaderOptions": {
"transpileOnly": true
}
}
}