pull/2/merge
Szymon Lesisz 6 years ago
parent c597f482dc
commit 15505ff263

@ -2,14 +2,48 @@
'use strict';
import * as ADDRESS from './constants/address';
import type { Action, TrezorDevice } from '../flowtype';
import type { State } from '../reducers/AccountsReducer';
export type AddressAction = {
export type AddressAction =
AddressFromStorageAction
| AddressCreateAction
| AddressSetBalanceAction
| AddressSetNonceAction;
export type AddressFromStorageAction = {
type: typeof ADDRESS.FROM_STORAGE,
payload: State
}
export type AddressCreateAction = {
type: typeof ADDRESS.CREATE,
payload: any
} | {
device: TrezorDevice,
network: string,
index: number,
path: Array<number>,
address: string
}
export type AddressSetBalanceAction = {
type: typeof ADDRESS.SET_BALANCE,
payload: any
} | {
address: string,
network: string,
balance: string
}
export type AddressSetNonceAction = {
type: typeof ADDRESS.SET_NONCE,
payload: any
address: string,
network: string,
nonce: number
}
export const setBalance = (address: string, network: string, balance: string): Action => {
return {
type: ADDRESS.SET_BALANCE,
address,
network,
balance
}
}

@ -7,24 +7,52 @@ import * as DISCOVERY from './constants/discovery';
import * as ADDRESS from './constants/address';
import * as TOKEN from './constants/token';
import * as NOTIFICATION from './constants/notification';
import type { Discovery } from '../reducers/DiscoveryReducer';
import * as AddressActions from '../actions/AddressActions';
import HDKey from 'hdkey';
import EthereumjsUtil from 'ethereumjs-util';
import { getNonceAsync, getBalanceAsync, getTokenBalanceAsync } from './Web3Actions';
import { setBalance as setTokenBalance } from './TokenActions';
import type { AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '../flowtype';
import type { Discovery, State } from '../reducers/DiscoveryReducer';
export type DiscoveryAction = {
type: typeof DISCOVERY.FROM_STORAGE,
payload: State
} | DiscoveryStartAction
| DiscoveryWaitingAction
| DiscoveryStopAction
| DiscoveryCompleteAction;
export type DiscoveryStartAction = {
type: typeof DISCOVERY.START,
} | {
device: TrezorDevice,
network: string,
xpub: string,
basePath: Array<number>,
hdKey: HDKey
}
export type DiscoveryWaitingAction = {
type: typeof DISCOVERY.WAITING,
device: TrezorDevice,
network: string
}
export type DiscoveryStopAction = {
type: typeof DISCOVERY.STOP,
} | {
device: TrezorDevice
}
export type DiscoveryCompleteAction = {
type: typeof DISCOVERY.COMPLETE,
};
device: TrezorDevice,
network: string
}
export const start = (device: any, network: string, ignoreCompleted?: boolean): any => {
return (dispatch, getState) => {
export const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const selected = findSelectedDevice(getState().connect);
if (!selected) {
@ -42,9 +70,11 @@ export const start = (device: any, network: string, ignoreCompleted?: boolean):
return;
}
const discovery = getState().discovery;
let discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network);
const discovery: State = getState().discovery;
let discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network);
if (!selected.connected && (!discoveryProcess || !discoveryProcess.completed)) {
dispatch({
type: DISCOVERY.WAITING,
@ -75,11 +105,12 @@ export const start = (device: any, network: string, ignoreCompleted?: boolean):
}
}
const begin = (device: any, network: string) => {
return async (dispatch, getState) => {
const begin = (device: TrezorDevice, network: string): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const { config } = getState().localStorage;
const coinToDiscover = config.coins.find(c => c.network === network);
if (!coinToDiscover) return;
dispatch({
type: DISCOVERY.WAITING,
@ -88,7 +119,7 @@ const begin = (device: any, network: string) => {
});
// get xpub from TREZOR
const response = await TrezorConnect.getPublicKey({
const response: Object = await TrezorConnect.getPublicKey({
device: {
path: device.path,
instance: device.instance,
@ -145,8 +176,8 @@ const begin = (device: any, network: string) => {
}
}
const discoverAddress = (device: any, discoveryProcess: Discovery): any => {
return async (dispatch, getState) => {
const discoverAddress = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const derivedKey = discoveryProcess.hdKey.derive(`m/${discoveryProcess.accountIndex}`);
const path = discoveryProcess.basePath.concat(discoveryProcess.accountIndex);
@ -236,15 +267,13 @@ const discoverAddress = (device: any, discoveryProcess: Discovery): any => {
}
const web3instance = getState().web3.find(w3 => w3.network === network);
if (!web3instance) return;
const balance = await getBalanceAsync(web3instance.web3, ethAddress);
if (discoveryProcess.interrupted) return;
dispatch({
type: ADDRESS.SET_BALANCE,
address: ethAddress,
network,
balance: web3instance.web3.fromWei(balance.toString(), 'ether')
});
dispatch(
AddressActions.setBalance(ethAddress, network, web3instance.web3.fromWei(balance.toString(), 'ether'))
);
const userTokens = [];
// const userTokens = [
@ -255,16 +284,10 @@ const discoverAddress = (device: any, discoveryProcess: Discovery): any => {
for (let i = 0; i < userTokens.length; i++) {
const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, userTokens[i].address, ethAddress);
if (discoveryProcess.interrupted) return;
dispatch({
type: TOKEN.SET_BALANCE,
tokenName: userTokens[i].symbol,
ethAddress: ethAddress,
tokenAddress: userTokens[i].address,
balance: tokenBalance.toString()
})
dispatch( setTokenBalance(userTokens[i].address, ethAddress, tokenBalance.toString()) )
}
const nonce = await getNonceAsync(web3instance.web3, ethAddress);
const nonce: number = await getNonceAsync(web3instance.web3, ethAddress);
if (discoveryProcess.interrupted) return;
dispatch({
type: ADDRESS.SET_NONCE,
@ -298,8 +321,8 @@ const discoverAddress = (device: any, discoveryProcess: Discovery): any => {
}
}
export const restore = (): any => {
return (dispatch, getState): void => {
export const restore = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const selected = findSelectedDevice(getState().connect);
if (selected && selected.connected && !selected.unacquired) {
@ -315,8 +338,8 @@ export const restore = (): any => {
// there is no discovery process but it should be
// this is possible race condition when "network" was changed in url but device was not authenticated yet
// try to start discovery after CONNECT.AUTH_DEVICE action
export const check = (): any => {
return (dispatch, getState): void => {
export const check = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const selected = findSelectedDevice(getState().connect);
if (!selected) return;
@ -330,7 +353,7 @@ export const check = (): any => {
}
}
export const stop = (device: any): any => {
export const stop = (device: TrezorDevice): Action => {
// TODO: release devices session
// corner case switch /eth to /etc (discovery start stop - should not be async)
return {

@ -6,6 +6,7 @@ import * as ADDRESS from './constants/address';
import * as TOKEN from './constants/token';
import * as DISCOVERY from './constants/discovery';
import * as STORAGE from './constants/localStorage';
import * as PENDING from '../actions/constants/pendingTx';
import { JSONRequest, httpRequest } from '../utils/networkUtils';
import type { AsyncAction, GetState, Dispatch } from '../flowtype';
@ -13,9 +14,9 @@ import type { Config, Coin, TokensCollection } from '../reducers/LocalStorageRed
export type StorageAction = {
type: typeof STORAGE.READY,
config: any,
tokens: any,
ERC20Abi: any
config: Config,
tokens: TokensCollection,
ERC20Abi: Array<Object>
} | {
type: typeof STORAGE.SAVE,
network: string,
@ -119,7 +120,7 @@ export function loadTokensFromJSON(): AsyncAction {
const pending: ?string = get('pending');
if (pending) {
dispatch({
type: 'PENDING.FROM_STORAGE',
type: PENDING.FROM_STORAGE,
payload: JSON.parse(pending)
})
}

@ -5,7 +5,7 @@ import TrezorConnect, { UI, UI_EVENT } from 'trezor-connect';
import * as MODAL from './constants/modal';
import * as CONNECT from './constants/TrezorConnect';
import type { AsyncAction, Action, GetState, Dispatch } from '../flowtype';
import type { AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '../flowtype';
export type ModalAction = {
type: typeof MODAL.CLOSE
@ -37,28 +37,28 @@ export const onPassphraseSubmit = (passphrase: string): AsyncAction => {
}
}
export const askForRemember = (device: any): Action => {
return {
type: MODAL.REMEMBER,
device
}
}
// export const askForRemember = (device: TrezorDevice): Action => {
// return {
// type: MODAL.REMEMBER,
// device
// }
// }
export const onRememberDevice = (device: any): Action => {
export const onRememberDevice = (device: TrezorDevice): Action => {
return {
type: CONNECT.REMEMBER,
device
}
}
export const onForgetDevice = (device: any): Action => {
export const onForgetDevice = (device: TrezorDevice): Action => {
return {
type: CONNECT.FORGET,
device,
}
}
export const onForgetSingleDevice = (device: any): Action => {
export const onForgetSingleDevice = (device: TrezorDevice): Action => {
return {
type: CONNECT.FORGET_SINGLE,
device,
@ -71,7 +71,7 @@ export const onCancel = (): Action => {
}
}
export const onDuplicateDevice = (device: any): AsyncAction => {
export const onDuplicateDevice = (device: TrezorDevice): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
dispatch( onCancel() );
@ -86,7 +86,7 @@ export const onDuplicateDevice = (device: any): AsyncAction => {
export default {
onPinSubmit,
onPassphraseSubmit,
askForRemember,
// askForRemember,
onRememberDevice,
onForgetDevice,
onForgetSingleDevice,

@ -3,7 +3,8 @@
import * as NOTIFICATION from './constants/notification';
import type { AsyncAction, GetState, Dispatch, RouterLocationState } from '../flowtype';
import type { Action, AsyncAction, GetState, Dispatch, RouterLocationState } from '../flowtype';
import type { CallbackAction } from '../reducers/NotificationReducer';
export type NotificationAction = {
type: typeof NOTIFICATION.ADD,
@ -12,7 +13,7 @@ export type NotificationAction = {
+title: string,
+message?: string,
+cancelable: boolean,
actions?: Array<any>
actions?: Array<CallbackAction>
}
} | {
type: typeof NOTIFICATION.CLOSE,
@ -22,8 +23,11 @@ export type NotificationAction = {
}
}
export const close = () => {
export const close = (payload: any = {}): Action => {
return {
type: NOTIFICATION.CLOSE,
payload
}
}

@ -0,0 +1,15 @@
/* @flow */
'use strict';
import * as PENDING from './constants/pendingTx';
import type { State, PendingTx } from '../reducers/PendingTxReducer'
export type PendingTxAction = {
type: typeof PENDING.FROM_STORAGE,
payload: State
} | {
type: typeof PENDING.TX_RESOLVED,
tx: PendingTx,
receipt: Object,
block: string
}

@ -78,6 +78,10 @@ export type SendFormAction = {
} | {
type: typeof SEND.DATA_CHANGE,
state: State
} | {
type: typeof SEND.SEND,
} | {
type: typeof SEND.TX_ERROR,
};
//const numberRegExp = new RegExp('^([0-9]{0,10}\\.)?[0-9]{1,18}$');

@ -20,15 +20,7 @@ export type TokenAction = {
token: Token
} | {
type: typeof TOKEN.SET_BALANCE,
payload: {
ethAddress: string,
address: string,
}
}
export const setBalance = (web3: any, coinIndex: number = 0): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
}
payload: State
}
type SelectOptions = {
@ -93,15 +85,23 @@ export const add = (token: NetworkToken, account: Account): AsyncAction => {
});
const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, token.address, account.address);
dispatch( setBalance(token.address, account.address, tokenBalance.toString()) )
}
}
export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const newState: Array<Token> = [ ...getState().tokens ];
let token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress);
if (token) {
token.loaded = true;
token.balance = balance;
}
dispatch({
type: TOKEN.SET_BALANCE,
payload: {
ethAddress: account.address,
address: token.address,
balance: tokenBalance.toString()
}
payload: newState
})
}
}

@ -38,7 +38,7 @@ import type {
export type TrezorConnectAction = {
type: typeof CONNECT.INITIALIZATION_ERROR,
error: any
error: string
} | {
type: typeof CONNECT.SELECT_DEVICE,
payload: ?{
@ -52,40 +52,41 @@ export type TrezorConnectAction = {
}
} | {
type: typeof CONNECT.AUTH_DEVICE,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.DUPLICATE,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.REMEMBER_REQUEST,
device: any
device: TrezorDevice,
instances: Array<TrezorDevice>
} | {
type: typeof CONNECT.DISCONNECT_REQUEST,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.FORGET_REQUEST,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.FORGET,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.FORGET_SINGLE,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.REMEMBER,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.TRY_TO_DUPLICATE,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.DEVICE_FROM_STORAGE,
payload: Array<any>
payload: Array<TrezorDevice>
} | {
type: typeof CONNECT.START_ACQUIRING,
device: any
device: TrezorDevice
} | {
type: typeof CONNECT.STOP_ACQUIRING,
device: any
device: TrezorDevice
};
@ -349,12 +350,12 @@ export const deviceDisconnect = (device: Device): AsyncAction => {
dispatch( DiscoveryActions.stop(selected) );
}
const affected = getState().connect.devices.filter(d => d.features && d.state && !d.remember && d.features.device_id === device.features.device_id);
if (affected.length > 0) {
const instances = getState().connect.devices.filter(d => d.features && d.state && !d.remember && d.features.device_id === device.features.device_id);
if (instances.length > 0) {
dispatch({
type: CONNECT.REMEMBER_REQUEST,
device,
instances: affected
instances,
});
}
}
@ -469,7 +470,7 @@ export const gotoDeviceSettings = (device: any): AsyncAction => {
}
// called from Aside - device menu (forget single instance)
export const forget = (device: any): Action => {
export const forget = (device: TrezorDevice): Action => {
return {
type: CONNECT.FORGET_REQUEST,
device
@ -497,6 +498,7 @@ export const onDuplicateDevice = (): AsyncAction => {
export function addAddress(): AsyncAction {
return (dispatch: Dispatch, getState: GetState): void => {
const selected = findSelectedDevice(getState().connect);
if (!selected) return;
dispatch( DiscoveryActions.start(selected, getState().router.location.state.network, true) ); // TODO: network nicer
}
}

@ -9,6 +9,8 @@ import TrezorConnect from 'trezor-connect';
import { strip } from '../utils/ethUtils';
import * as ADDRESS from './constants/address';
import * as WEB3 from './constants/web3';
import * as PENDING from './constants/pendingTx';
import * as AddressActions from '../actions/AddressActions';
import type {
Dispatch,
@ -18,13 +20,12 @@ import type {
} from '../flowtype';
import type { Account } from '../reducers/AccountsReducer';
import type { PendingTx } from '../reducers/PendingTxReducer';
export type Web3Action = {
type: typeof WEB3.READY,
} | {
type: typeof WEB3.PENDING_TX_RESOLVED
} | Web3CreateAction
| Web3UpdateBlockAction
} | Web3CreateAction
| Web3UpdateBlockAction
| Web3UpdateGasPriceAction;
export type Web3CreateAction = {
@ -261,12 +262,11 @@ export function getBalance(account: Account): AsyncAction {
if (!error) {
const newBalance: string = web3.fromWei(balance.toString(), 'ether');
if (account.balance !== newBalance) {
dispatch({
type: ADDRESS.SET_BALANCE,
address: account.address,
network: account.network,
balance: newBalance
});
dispatch(AddressActions.setBalance(
account.address,
account.network,
newBalance
));
// dispatch( loadHistory(addr) );
}
@ -282,7 +282,7 @@ export function getNonce(account: Account): AsyncAction {
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
const web3 = web3instance.web3;
web3.eth.getTransactionCount(account.address, (error, result) => {
web3.eth.getTransactionCount(account.address, (error: Error, result: number) => {
if (!error) {
if (account.nonce !== result) {
dispatch({
@ -297,7 +297,7 @@ export function getNonce(account: Account): AsyncAction {
}
}
export function getTransactionReceipt(tx: any): AsyncAction {
export const getTransactionReceipt = (tx: PendingTx): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0];
@ -305,12 +305,10 @@ export function getTransactionReceipt(tx: any): AsyncAction {
//web3.eth.getTransactionReceipt(txid, (error, tx) => {
web3.eth.getTransaction(tx.id, (error, receipt) => {
console.log("RECEIP", receipt)
if (receipt && receipt.blockNumber) {
web3.eth.getBlock(receipt.blockHash, (error, block) => {
console.log("---MAMM BLOCK", error, block, receipt, receipt.blockHash)
dispatch({
type: WEB3.PENDING_TX_RESOLVED,
type: PENDING.TX_RESOLVED,
tx,
receipt,
block
@ -359,7 +357,7 @@ export const getTokenBalanceAsync = (erc20: any, token: string, address: string)
return new Promise((resolve, reject) => {
const contr = erc20.at(token);
contr.balanceOf(address, (error, result) => {
contr.balanceOf(address, (error: Error, result) => {
if (error) {
reject(error);
} else {
@ -369,9 +367,9 @@ export const getTokenBalanceAsync = (erc20: any, token: string, address: string)
});
}
export const getNonceAsync = (web3: Web3, address: string): Promise<any> => {
export const getNonceAsync = (web3: Web3, address: string): Promise<number> => {
return new Promise((resolve, reject) => {
web3.eth.getTransactionCount(address, (error, result) => {
web3.eth.getTransactionCount(address, (error: Error, result: number) => {
if (error) {
reject(error);
} else {

@ -0,0 +1,5 @@
/* @flow */
'use strict';
export const FROM_STORAGE: 'pending__from_storage' = 'pending__from_storage';
export const TX_RESOLVED: 'pending__tx_resolved' = 'pending__tx_resolved';

@ -6,6 +6,7 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as NOTIFICATION from '../../actions/constants/notification';
import * as NotificationActions from '../../actions/NotificationActions';
import type { Action, State, Dispatch } from '../../flowtype';
type Props = {
@ -20,7 +21,7 @@ type NProps = {
title: string;
message?: string;
actions?: Array<any>;
close?: (notif?: any) => Action
close?: typeof NotificationActions.close
}
export const Notification = (props: NProps): React$Element<string> => {
@ -77,12 +78,7 @@ export default connect(
},
(dispatch: Dispatch) => {
return {
close: bindActionCreators((notif?: any): Action => {
return {
type: NOTIFICATION.CLOSE,
payload: notif
}
}, dispatch),
close: bindActionCreators(NotificationActions.close, dispatch),
};
}
)(NotificationGroup);

@ -3,10 +3,9 @@
import type {
Store as ReduxStore,
StoreEnhancer as ReduxStoreEnhancer,
Dispatch as ReduxDispatch,
Middleware as ReduxMiddleware,
MiddlewareAPI as ReduxMiddlewareAPI,
Middleware as ReduxMiddleware,
ThunkAction as ReduxThunkAction,
ThunkDispatch as ReduxThunkDispatch,
PlainDispatch as ReduxPlainDispatch
@ -22,6 +21,7 @@ import type { StorageAction } from '../actions/LocalStorageActions';
import type { LogAction } from '../actions/LogActions';
import type { ModalAction } from '../actions/ModalActions';
import type { NotificationAction } from '../actions/NotificationActions';
import type { PendingTxAction } from '../actions/PendingTxActions';
import type { ReceiveAction } from '../actions/ReceiveActions';
import type { SendFormAction } from '../actions/SendFormActions';
import type { SummaryAction } from '../actions/SummaryActions';
@ -58,6 +58,22 @@ export type TrezorDevice = {
ts: number;
}
export type AcquiredDevice = {
remember: boolean;
connected: boolean;
available: boolean; // device cannot be used because of features.passphrase_protection is different then expected (saved)
path: string;
label: string;
state: string;
instance: ?number;
instanceLabel: string;
features: Features;
acquiring: boolean;
isUsedElsewhere?: boolean;
featuresNeedsReload?: boolean;
ts: number;
}
export type RouterLocationState = LocationState;
// Cast event from TrezorConnect event listener to react Action
@ -96,6 +112,7 @@ export type Action =
| LogAction
| ModalAction
| NotificationAction
| PendingTxAction
| ReceiveAction
| SendFormAction
| SummaryAction
@ -111,7 +128,6 @@ export type Accounts = $ElementType<State, 'accounts'>;
export type LocalStorage = $ElementType<State, 'localStorage'>;
export type Config = $PropertyType<$ElementType<State, 'localStorage'>, 'config'>;
export type Dispatch = ReduxDispatch<State, Action>;
export type MiddlewareDispatch = ReduxPlainDispatch<Action>;
@ -119,8 +135,5 @@ export type MiddlewareAPI = ReduxMiddlewareAPI<State, Action>;
export type Middleware = ReduxMiddleware<State, Action>;
export type Store = ReduxStore<State, Action>;
export type StoreEnhancer = ReduxStoreEnhancer<State, Action>;
export type GetState = () => State;
export type AsyncAction = ReduxThunkAction<State, Action>;

@ -0,0 +1,74 @@
// flow-typed signature: cca4916b0213065533df8335c3285a4a
// flow-typed version: cab04034e7/redux_v3.x.x/flow_>=v0.55.x
declare module 'redux' {
/*
S = State
A = Action
D = Dispatch
*/
declare export type DispatchAPI<A> = (action: A) => A;
// declare export type Dispatch<A: { type: $Subtype<string> }> = DispatchAPI<A>;
/* NEW: Dispatch is now a combination of these different dispatch types */
declare export type Dispatch<S, A> = PlainDispatch<A> & ThunkDispatch<S, A>;
// declare export type ThunkAction<S, A> = (dispatch: Dispatch<S, A>, getState: () => S) => Promise<void> | void;
//declare export type ThunkAction<S, A> = (dispatch: PlainDispatch<A> | ThunkDispatch<S, A>, getState: () => S) => Promise<void> | void;
declare export type ThunkAction<S, A> = (dispatch: ThunkDispatch<S, A>, getState: () => S) => Promise<void> | void;
//declare export type ThunkDispatch<S, A> = (action: ThunkAction<S, A>) => void;
declare export type ThunkDispatch<S, A> = (action: PlainDispatch<A> | ThunkDispatch<S, A>) => void;
declare export type PlainDispatch<A: {type: $Subtype<string>}> = DispatchAPI<A>;
// declare export type ThunkAction<S, D> = (dispatch: D, getState: () => S) => Promise<void> | void;
// declare type ThunkDispatch<S, D> = (action: ThunkAction<S, D & ThunkDispatch<S, D>>) => void;
declare export type MiddlewareAPI<S, A> = {
dispatch: ThunkDispatch<S, A>;
// dispatch: (action: PlainDispatch<A> | ThunkDispatch<S, A>) => void;
getState(): S;
};
declare export type Middleware<S, A> =
(api: MiddlewareAPI<S, A>) =>
(next: PlainDispatch<A>) => PlainDispatch<A>;
declare export type Store<S, A, D = Dispatch<S, A>> = {
// rewrite MiddlewareAPI members in order to get nicer error messages (intersections produce long messages)
dispatch: D;
getState(): S;
subscribe(listener: () => void): () => void;
replaceReducer(nextReducer: Reducer<S, A>): void
};
declare export type Reducer<S, A> = (state: S | void, action: A) => S;
declare export type CombinedReducer<S, A> = (state: $Shape<S> & {} | void, action: A) => S;
declare export type StoreCreator<S, A, D = Dispatch<S, A>> = {
(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
(reducer: Reducer<S, A>, preloadedState: S, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
};
declare export type StoreEnhancer<S, A, D = Dispatch<S, A>> = (next: StoreCreator<S, A, D>) => StoreCreator<S, A, D>;
declare export function createStore<S, A, D>(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
declare export function createStore<S, A, D>(reducer: Reducer<S, A>, preloadedState?: S, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
declare export function applyMiddleware<S, A, D>(...middlewares: Array<Middleware<S, A>>): StoreEnhancer<S, A, D>;
declare export type ActionCreator<A, B> = (...args: Array<B>) => A;
declare export type ActionCreators<K, A> = { [key: K]: ActionCreator<A, any> };
declare export function bindActionCreators<A, C: ActionCreator<A, any>, D: DispatchAPI<A>>(actionCreator: C, dispatch: D): C;
declare export function bindActionCreators<A, K, C: ActionCreators<K, A>, D: DispatchAPI<A>>(actionCreators: C, dispatch: D): C;
declare export function combineReducers<O: Object, A>(reducers: O): CombinedReducer<$ObjMap<O, <S>(r: Reducer<S, any>) => S>, A>;
declare export var compose: $Compose;
}

@ -4,6 +4,13 @@
import * as CONNECT from '../actions/constants/TrezorConnect';
import * as ADDRESS from '../actions/constants/address';
import type { Action, TrezorDevice } from '../flowtype';
import type {
AddressCreateAction,
AddressSetBalanceAction,
AddressSetNonceAction
} from '../actions/AddressActions';
export type Account = {
loaded: boolean;
+network: string;
@ -16,17 +23,19 @@ export type Account = {
nonce: number;
}
const initialState: Array<Account> = [];
export type State = Array<Account>;
const initialState: State = [];
export const findAccount = (state: Array<Account>, index: number, deviceState: string, network: string): ?Account => {
export const findAccount = (state: State, index: number, deviceState: string, network: string): ?Account => {
return state.find(a => a.deviceState === deviceState && a.index === index && a.network === network);
}
const createAccount = (state: Array<Account>, action: any): Array<Account> => {
const createAccount = (state: State, action: AddressCreateAction): State => {
// TODO check with device_id
// check if account was created before
const exist: ?Account = state.find((account: Account) => account.address === action.address && account.network === action.network && account.deviceID === action.device.features.device_id);
const exist: ?Account = state.find((account: Account) => account.address === action.address && account.network === action.network && action.device.features && account.deviceID === action.device.features.device_id);
if (exist) {
return state;
}
@ -34,7 +43,7 @@ const createAccount = (state: Array<Account>, action: any): Array<Account> => {
const address: Account = {
loaded: false,
network: action.network,
deviceID: action.device.features.device_id,
deviceID: action.device.features ? action.device.features.device_id : '0',
deviceState: action.device.state,
index: action.index,
addressPath: action.path,
@ -43,36 +52,36 @@ const createAccount = (state: Array<Account>, action: any): Array<Account> => {
nonce: 0,
}
const newState: Array<Account> = [ ...state ];
const newState: State = [ ...state ];
newState.push(address);
return newState;
}
const removeAccounts = (state: Array<Account>, action: any): Array<Account> => {
return state.filter(account => account.deviceID !== action.device.features.device_id);
const removeAccounts = (state: State, device: TrezorDevice): State => {
return state.filter(account => device.features && account.deviceID !== device.features.device_id);
}
const forgetAccounts = (state: Array<Account>, action: any): Array<Account> => {
return state.filter(account => action.accounts.indexOf(account) === -1);
}
// const forgetAccounts = (state: State, action: any): State => {
// return state.filter(account => action.accounts.indexOf(account) === -1);
// }
const setBalance = (state: Array<Account>, action: any): Array<Account> => {
const setBalance = (state: State, action: AddressSetBalanceAction): State => {
const index: number = state.findIndex(account => account.address === action.address && account.network === action.network);
const newState: Array<Account> = [ ...state ];
const newState: State = [ ...state ];
newState[index].loaded = true;
newState[index].balance = action.balance;
return newState;
}
const setNonce = (state: Array<Account>, action: any): Array<Account> => {
const setNonce = (state: State, action: AddressSetNonceAction): State => {
const index: number = state.findIndex(account => account.address === action.address && account.network === action.network);
const newState: Array<Account> = [ ...state ];
const newState: State = [ ...state ];
newState[index].loaded = true;
newState[index].nonce = action.nonce;
return newState;
}
export default (state: Array<Account> = initialState, action: any): Array<Account> => {
export default (state: State = initialState, action: Action): State => {
switch (action.type) {
@ -81,7 +90,7 @@ export default (state: Array<Account> = initialState, action: any): Array<Accoun
case CONNECT.FORGET :
case CONNECT.FORGET_SINGLE :
return removeAccounts(state, action);
return removeAccounts(state, action.device);
//case CONNECT.FORGET_SINGLE :
// return forgetAccounts(state, action);

@ -1,15 +1,29 @@
/* @flow */
'use strict';
import HDKey from 'hdkey';
import * as DISCOVERY from '../actions/constants/discovery';
import * as ADDRESS from '../actions/constants/address';
import * as CONNECT from '../actions/constants/TrezorConnect';
import type { Action, TrezorDevice } from '../flowtype';
import type {
DiscoveryStartAction,
DiscoveryWaitingAction,
DiscoveryStopAction,
DiscoveryCompleteAction
} from '../actions/DiscoveryActions';
import type {
AddressCreateAction
} from '../actions/AddressActions'
export type Discovery = {
network: string;
xpub: string;
hdKey: any;
basePath: any;
hdKey: HDKey;
basePath: Array<number>;
deviceState: string;
accountIndex: number;
interrupted: boolean;
@ -18,28 +32,29 @@ export type Discovery = {
waitingForAuth?: boolean;
}
const initialState: Array<Discovery> = [];
export type State = Array<Discovery>;
const initialState: State = [];
const findIndex = (state: Array<Discovery>, network: string, deviceState: string): number => {
const findIndex = (state: State, network: string, deviceState: string): number => {
return state.findIndex(d => d.network === network && d.deviceState === deviceState);
}
const start = (state: Array<Discovery>, action: any): Array<Discovery> => {
const start = (state: State, action: DiscoveryStartAction): State => {
const deviceState: string = action.device.state || '0';
const instance: Discovery = {
network: action.network,
xpub: action.xpub,
hdKey: action.hdKey,
basePath: action.basePath,
deviceState: action.device.state,
deviceState,
accountIndex: 0,
interrupted: false,
completed: false,
waitingForDevice: false
}
const newState: Array<Discovery> = [ ...state ];
const index: number = findIndex(state, action.network, action.device.state);
const newState: State = [ ...state ];
const index: number = findIndex(state, action.network, deviceState);
if (index >= 0) {
newState[index] = instance;
} else {
@ -48,26 +63,26 @@ const start = (state: Array<Discovery>, action: any): Array<Discovery> => {
return newState;
}
const complete = (state: Array<Discovery>, action: any): Array<Discovery> => {
const index: number = findIndex(state, action.network, action.device.state);
const newState: Array<Discovery> = [ ...state ];
const complete = (state: State, action: DiscoveryCompleteAction): State => {
const index: number = findIndex(state, action.network, action.device.state || '0');
const newState: State = [ ...state ];
newState[index].completed = true;
return newState;
}
const addressCreate = (state: Array<Discovery>, action: any): Array<Discovery> => {
const index: number = findIndex(state, action.network, action.device.state);
const newState: Array<Discovery> = [ ...state ];
const addressCreate = (state: State, action: AddressCreateAction): State => {
const index: number = findIndex(state, action.network, action.device.state || '0');
const newState: State = [ ...state ];
newState[index].accountIndex++;
return newState;
}
const forgetDiscovery = (state: Array<Discovery>, action: any): Array<Discovery> => {
return state.filter(d => d.deviceState !== action.device.state);
const forgetDiscovery = (state: State, device: TrezorDevice): State => {
return state.filter(d => d.deviceState !== device.state);
}
const stop = (state: Array<Discovery>, action: any): Array<Discovery> => {
const newState: Array<Discovery> = [ ...state ];
const stop = (state: State, action: DiscoveryStopAction): State => {
const newState: State = [ ...state ];
return newState.map( (d: Discovery) => {
if (d.deviceState === action.device.state && !d.completed) {
d.interrupted = true;
@ -77,22 +92,23 @@ const stop = (state: Array<Discovery>, action: any): Array<Discovery> => {
});
}
const waiting = (state: Array<Discovery>, action: any): Array<Discovery> => {
const waiting = (state: State, action: DiscoveryWaitingAction): State => {
const deviceState: string = action.device.state || '0';
const instance: Discovery = {
network: action.network,
deviceState: action.device.state,
deviceState,
xpub: '',
hdKey: null,
basePath: null,
basePath: [],
accountIndex: 0,
interrupted: false,
completed: false,
waitingForDevice: true
}
const index: number = findIndex(state, action.network, action.device.state);
const newState: Array<Discovery> = [ ...state ];
const index: number = findIndex(state, action.network, deviceState);
const newState: State = [ ...state ];
if (index >= 0) {
newState[index] = instance;
} else {
@ -102,7 +118,7 @@ const waiting = (state: Array<Discovery>, action: any): Array<Discovery> => {
return newState;
}
export default function discovery(state: Array<Discovery> = initialState, action: any): Array<Discovery> {
export default function discovery(state: State = initialState, action: Action): State {
switch (action.type) {
case DISCOVERY.START :
@ -125,7 +141,7 @@ export default function discovery(state: Array<Discovery> = initialState, action
})
case CONNECT.FORGET :
case CONNECT.FORGET_SINGLE :
return forgetDiscovery(state, action);
return forgetDiscovery(state, action.device);
default:
return state;

@ -6,10 +6,12 @@ import * as RECEIVE from '../actions/constants/receive';
import * as MODAL from '../actions/constants/modal';
import * as CONNECT from '../actions/constants/TrezorConnect';
import type { Action, TrezorDevice } from '../flowtype';
export type State = {
opened: boolean;
device: any;
instances: ?Array<any>;
device: ?TrezorDevice;
instances: ?Array<TrezorDevice>;
windowType: ?string;
}
@ -20,7 +22,7 @@ const initialState: State = {
windowType: null
};
export default function modal(state: State = initialState, action: any): State {
export default function modal(state: State = initialState, action: Action): State {
switch (action.type) {
@ -33,12 +35,18 @@ export default function modal(state: State = initialState, action: any): State {
}
case CONNECT.REMEMBER_REQUEST :
return {
...state,
device: action.device,
instances: action.instances,
opened: true,
windowType: action.type
};
case CONNECT.FORGET_REQUEST :
case CONNECT.DISCONNECT_REQUEST :
return {
...state,
device: action.device,
instances: action.instances,
opened: true,
windowType: action.type
};
@ -104,8 +112,6 @@ export default function modal(state: State = initialState, action: any): State {
...initialState,
};
default:
return state;
}

@ -5,22 +5,26 @@ import { LOCATION_CHANGE } from 'react-router-redux';
import * as NOTIFICATION from '../actions/constants/notification';
import { DEVICE } from 'trezor-connect';
type NotificationAction = {
import type { Action } from '../flowtype';
export type CallbackAction = {
label: string;
callback: Function;
}
type NotificationEntry = {
export type NotificationEntry = {
+id: ?string;
+devicePath: ?string;
+type: string;
+title: string;
+message: string;
+cancelable: boolean;
+actions: Array<NotificationAction>;
+actions: Array<CallbackAction>;
}
const initialState: Array<NotificationEntry> = [
export type State = Array<NotificationEntry>;
const initialState: State = [
// {
// id: undefined,
// type: "info",
@ -31,8 +35,8 @@ const initialState: Array<NotificationEntry> = [
// }
];
const addNotification = (state: Array<NotificationEntry>, payload: any): Array<NotificationEntry> => {
const newState: Array<NotificationEntry> = state.filter(e => !e.cancelable);
const addNotification = (state: State, payload: any): State => {
const newState: State = state.filter(e => !e.cancelable);
newState.push({
id: payload.id,
devicePath: payload.devicePath,
@ -47,7 +51,7 @@ const addNotification = (state: Array<NotificationEntry>, payload: any): Array<N
return newState;
}
const closeNotification = (state: Array<NotificationEntry>, payload: any): Array<NotificationEntry> => {
const closeNotification = (state: State, payload: any): State => {
if (payload && typeof payload.id === 'string') {
return state.filter(entry => entry.id !== payload.id);
} else if (payload && typeof payload.devicePath === 'string') {
@ -57,9 +61,13 @@ const closeNotification = (state: Array<NotificationEntry>, payload: any): Array
}
}
export default function notification(state: Array<NotificationEntry> = initialState, action: Object): Array<NotificationEntry> {
export default function notification(state: State = initialState, action: Action): State {
switch(action.type) {
case DEVICE.DISCONNECT :
const path: string = action.device.path; // Flow warning
return state.filter(entry => entry.devicePath !== path);
case NOTIFICATION.ADD :
return addNotification(state, action.payload);
@ -67,9 +75,6 @@ export default function notification(state: Array<NotificationEntry> = initialSt
case NOTIFICATION.CLOSE :
return closeNotification(state, action.payload);
case DEVICE.DISCONNECT :
return state.filter(entry => entry.devicePath !== action.device.path);
default:
return state;
}

@ -1,9 +1,12 @@
/* @flow */
'use strict';
import * as PENDING from '../actions/constants/pendingTx';
import * as SEND from '../actions/constants/send';
import * as WEB3 from '../actions/constants/web3';
import type { Action } from '../flowtype';
export type PendingTx = {
+id: string;
+network: string;
@ -12,9 +15,11 @@ export type PendingTx = {
+address: string;
}
const initialState: Array<PendingTx> = [];
export type State = Array<PendingTx>;
const initialState: State = [];
const add = (state: Array<PendingTx>, action: any) => {
const add = (state: State, action: any) => {
const newState = [ ...state ];
newState.push({
id: action.txid,
@ -26,25 +31,25 @@ const add = (state: Array<PendingTx>, action: any) => {
return newState;
}
const remove = (state: Array<PendingTx>, action: any) => {
const remove = (state: State, action: any) => {
return state.filter(tx => tx.id !== action.tx.id);
}
const fromStorage = (state: Array<PendingTx>, action: any) => {
const fromStorage = (state: State, action: any) => {
return state.filter(tx => tx.id !== action.tx.id);
}
export default function pending(state: Array<PendingTx> = initialState, action: any): Array<PendingTx> {
export default function pending(state: State = initialState, action: Action): State {
switch (action.type) {
case SEND.TX_COMPLETE :
return add(state, action);
case WEB3.PENDING_TX_RESOLVED :
case PENDING.TX_RESOLVED :
return remove(state, action);
case 'PENDING.FROM_STORAGE' :
case PENDING.FROM_STORAGE :
return action.payload;
default:

@ -2,6 +2,7 @@
'use strict';
import * as RECEIVE from '../actions/constants/receive';
import type { Action } from '../flowtype';
export type State = {
addressVerified: boolean;
@ -13,7 +14,7 @@ export const initialState: State = {
addressUnverified: false,
};
export default (state: State = initialState, action: any): State => {
export default (state: State = initialState, action: Action): State => {
switch (action.type) {

@ -8,6 +8,7 @@ import EthereumjsUnits from 'ethereumjs-units';
import BigNumber from 'bignumber.js';
import { getFeeLevels } from '../actions/SendFormActions';
import type { Action } from '../flowtype';
import type {
Web3CreateAction,
Web3UpdateBlockAction,
@ -122,7 +123,7 @@ const onBalanceUpdated = (state: State, action: any): State => {
}
export default (state: State = initialState, action: any): State => {
export default (state: State = initialState, action: Action): State => {
switch (action.type) {

@ -26,28 +26,18 @@ export const findToken = (state: Array<Token>, address: string, symbol: string,
return state.find(t => t.ethAddress === address && t.symbol === symbol && t.deviceState === deviceState);
}
const setBalance = (state: State, payload: any): State => {
// const setBalance = (state: State, payload: any): State => {
// const newState: Array<Token> = [ ...state ];
// let index: number = state.findIndex(t => t.address === payload.address && t.ethAddress === payload.ethAddress);
// if (index >= 0) {
// newState[index].loaded = true;
// newState[index].balance = payload.balance;
// }
// return newState;
// }
const create = (state: State, token: Token): State => {
const newState: Array<Token> = [ ...state ];
let index: number = state.findIndex(t => t.address === payload.address && t.ethAddress === payload.ethAddress);
if (index >= 0) {
newState[index].loaded = true;
newState[index].balance = payload.balance;
}
return newState;
}
const create = (state: State, payload: any): State => {
const newState: Array<Token> = [ ...state ];
const token: Token = {
loaded: false,
deviceState: payload.deviceState,
name: payload.name,
symbol: payload.symbol,
address: payload.address,
ethAddress: payload.ethAddress,
decimals: payload.decimals,
balance: '0'
}
newState.push(token);
return newState;
}
@ -74,7 +64,7 @@ export default (state: State = initialState, action: Action): State => {
case TOKEN.REMOVE :
return remove(state, action.token);
case TOKEN.SET_BALANCE :
return setBalance(state, action.payload);
return action.payload;
case CONNECT.FORGET :
case CONNECT.FORGET_SINGLE :

@ -41,24 +41,8 @@ const reducers = {
wallet
}
export type Reducers = typeof reducers;
type $ExtractFunctionReturn = <V>(v: (...args: any) => V) => V;
export type ReducersState = $ObjMap<Reducers, $ExtractFunctionReturn>;
export default combineReducers(reducers);
// export type Reducers = {
// router: any;
// log: any;
// connect: TrezorConnectState;
// accounts: Array<Account>;
// tokens: Array<Token>;
// pending: Array<PendingTx>;
// discovery: Array<Discovery>;
// localStorage: LocalStorageState;
// }

@ -11,6 +11,7 @@ import * as ADDRESS from '../actions/constants/address';
import * as DISCOVERY from '../actions/constants/discovery';
import * as SEND from '../actions/constants/send';
import * as WEB3 from '../actions/constants/web3';
import * as PENDING from '../actions/constants/pendingTx';
import { LOCATION_CHANGE } from 'react-router-redux';
import type {
@ -131,7 +132,7 @@ const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: Middlewar
break;
case SEND.TX_COMPLETE :
case WEB3.PENDING_TX_RESOLVED :
case PENDING.TX_RESOLVED :
save(api.dispatch, api.getState);
break;

@ -105,7 +105,7 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa
// TODO: move it to modal actions
const { modal } = api.getState();
if (modal.opened && modal.windowType === CONNECT.REMEMBER_REQUEST) {
if (action.device.features && modal.device.features.device_id === action.device.features.device_id) {
if (action.device.features && modal.device && modal.device.features && modal.device.features.device_id === action.device.features.device_id) {
api.dispatch({
type: MODAL.CLOSE,
});

Loading…
Cancel
Save