1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-28 03:08:30 +00:00

corrupted

This commit is contained in:
Szymon Lesisz 2018-04-23 12:20:15 +02:00
parent c597f482dc
commit 15505ff263
25 changed files with 420 additions and 233 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,8 @@
import * as NOTIFICATION from './constants/notification'; 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 = { export type NotificationAction = {
type: typeof NOTIFICATION.ADD, type: typeof NOTIFICATION.ADD,
@ -12,7 +13,7 @@ export type NotificationAction = {
+title: string, +title: string,
+message?: string, +message?: string,
+cancelable: boolean, +cancelable: boolean,
actions?: Array<any> actions?: Array<CallbackAction>
} }
} | { } | {
type: typeof NOTIFICATION.CLOSE, 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
}
} }

View File

@ -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
}

View File

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

View File

@ -20,15 +20,7 @@ export type TokenAction = {
token: Token token: Token
} | { } | {
type: typeof TOKEN.SET_BALANCE, type: typeof TOKEN.SET_BALANCE,
payload: { payload: State
ethAddress: string,
address: string,
}
}
export const setBalance = (web3: any, coinIndex: number = 0): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
}
} }
type SelectOptions = { type SelectOptions = {
@ -93,15 +85,23 @@ export const add = (token: NetworkToken, account: Account): AsyncAction => {
}); });
const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, token.address, account.address); 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({ dispatch({
type: TOKEN.SET_BALANCE, type: TOKEN.SET_BALANCE,
payload: { payload: newState
ethAddress: account.address,
address: token.address,
balance: tokenBalance.toString()
}
}) })
} }
} }

View File

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

View File

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

View File

@ -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';

View File

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

View File

@ -3,10 +3,9 @@
import type { import type {
Store as ReduxStore, Store as ReduxStore,
StoreEnhancer as ReduxStoreEnhancer,
Dispatch as ReduxDispatch, Dispatch as ReduxDispatch,
Middleware as ReduxMiddleware,
MiddlewareAPI as ReduxMiddlewareAPI, MiddlewareAPI as ReduxMiddlewareAPI,
Middleware as ReduxMiddleware,
ThunkAction as ReduxThunkAction, ThunkAction as ReduxThunkAction,
ThunkDispatch as ReduxThunkDispatch, ThunkDispatch as ReduxThunkDispatch,
PlainDispatch as ReduxPlainDispatch PlainDispatch as ReduxPlainDispatch
@ -22,6 +21,7 @@ import type { StorageAction } from '../actions/LocalStorageActions';
import type { LogAction } from '../actions/LogActions'; import type { LogAction } from '../actions/LogActions';
import type { ModalAction } from '../actions/ModalActions'; import type { ModalAction } from '../actions/ModalActions';
import type { NotificationAction } from '../actions/NotificationActions'; import type { NotificationAction } from '../actions/NotificationActions';
import type { PendingTxAction } from '../actions/PendingTxActions';
import type { ReceiveAction } from '../actions/ReceiveActions'; import type { ReceiveAction } from '../actions/ReceiveActions';
import type { SendFormAction } from '../actions/SendFormActions'; import type { SendFormAction } from '../actions/SendFormActions';
import type { SummaryAction } from '../actions/SummaryActions'; import type { SummaryAction } from '../actions/SummaryActions';
@ -58,6 +58,22 @@ export type TrezorDevice = {
ts: number; 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; export type RouterLocationState = LocationState;
// Cast event from TrezorConnect event listener to react Action // Cast event from TrezorConnect event listener to react Action
@ -96,6 +112,7 @@ export type Action =
| LogAction | LogAction
| ModalAction | ModalAction
| NotificationAction | NotificationAction
| PendingTxAction
| ReceiveAction | ReceiveAction
| SendFormAction | SendFormAction
| SummaryAction | SummaryAction
@ -111,7 +128,6 @@ export type Accounts = $ElementType<State, 'accounts'>;
export type LocalStorage = $ElementType<State, 'localStorage'>; export type LocalStorage = $ElementType<State, 'localStorage'>;
export type Config = $PropertyType<$ElementType<State, 'localStorage'>, 'config'>; export type Config = $PropertyType<$ElementType<State, 'localStorage'>, 'config'>;
export type Dispatch = ReduxDispatch<State, Action>; export type Dispatch = ReduxDispatch<State, Action>;
export type MiddlewareDispatch = ReduxPlainDispatch<Action>; export type MiddlewareDispatch = ReduxPlainDispatch<Action>;
@ -119,8 +135,5 @@ export type MiddlewareAPI = ReduxMiddlewareAPI<State, Action>;
export type Middleware = ReduxMiddleware<State, Action>; export type Middleware = ReduxMiddleware<State, Action>;
export type Store = ReduxStore<State, Action>; export type Store = ReduxStore<State, Action>;
export type StoreEnhancer = ReduxStoreEnhancer<State, Action>;
export type GetState = () => State; export type GetState = () => State;
export type AsyncAction = ReduxThunkAction<State, Action>; export type AsyncAction = ReduxThunkAction<State, Action>;

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,6 +8,7 @@ import EthereumjsUnits from 'ethereumjs-units';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { getFeeLevels } from '../actions/SendFormActions'; import { getFeeLevels } from '../actions/SendFormActions';
import type { Action } from '../flowtype';
import type { import type {
Web3CreateAction, Web3CreateAction,
Web3UpdateBlockAction, 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) { switch (action.type) {

View File

@ -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); 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 ]; // const newState: Array<Token> = [ ...state ];
let index: number = state.findIndex(t => t.address === payload.address && t.ethAddress === payload.ethAddress); // let index: number = state.findIndex(t => t.address === payload.address && t.ethAddress === payload.ethAddress);
if (index >= 0) { // if (index >= 0) {
newState[index].loaded = true; // newState[index].loaded = true;
newState[index].balance = payload.balance; // newState[index].balance = payload.balance;
} // }
return newState; // return newState;
} // }
const create = (state: State, payload: any): State => { const create = (state: State, token: Token): State => {
const newState: Array<Token> = [ ...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); newState.push(token);
return newState; return newState;
} }
@ -74,7 +64,7 @@ export default (state: State = initialState, action: Action): State => {
case TOKEN.REMOVE : case TOKEN.REMOVE :
return remove(state, action.token); return remove(state, action.token);
case TOKEN.SET_BALANCE : case TOKEN.SET_BALANCE :
return setBalance(state, action.payload); return action.payload;
case CONNECT.FORGET : case CONNECT.FORGET :
case CONNECT.FORGET_SINGLE : case CONNECT.FORGET_SINGLE :

View File

@ -41,24 +41,8 @@ const reducers = {
wallet wallet
} }
export type Reducers = typeof reducers; export type Reducers = typeof reducers;
type $ExtractFunctionReturn = <V>(v: (...args: any) => V) => V; type $ExtractFunctionReturn = <V>(v: (...args: any) => V) => V;
export type ReducersState = $ObjMap<Reducers, $ExtractFunctionReturn>; export type ReducersState = $ObjMap<Reducers, $ExtractFunctionReturn>;
export default combineReducers(reducers); 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;
// }

View File

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

View File

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