You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-wallet/src/services/WalletService.js

145 lines
5.6 KiB

/* @flow */
import { DEVICE, BLOCKCHAIN } from 'trezor-connect';
import { LOCATION_CHANGE } from 'connected-react-router';
import * as WALLET from 'actions/constants/wallet';
import * as CONNECT from 'actions/constants/TrezorConnect';
import * as WalletActions from 'actions/WalletActions';
import * as NotificationActions from 'actions/NotificationActions';
import * as LocalStorageActions from 'actions/LocalStorageActions';
import * as TrezorConnectActions from 'actions/TrezorConnectActions';
import * as SelectedAccountActions from 'actions/SelectedAccountActions';
import * as SendFormActions from 'actions/SendFormActions';
import * as DiscoveryActions from 'actions/DiscoveryActions';
import * as RouterActions from 'actions/RouterActions';
import type { Middleware, MiddlewareAPI, MiddlewareDispatch, Action } from 'flowtype';
/**
* Middleware
*/
const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => async (
action: Action
): Promise<Action> => {
const prevState = api.getState();
// Application live cycle starts HERE!
// when first LOCATION_CHANGE is called router does not have "location" set yet
if (action.type === LOCATION_CHANGE && prevState.wallet.firstLocationChange) {
// initialize wallet
api.dispatch(WalletActions.init());
// set initial url
// TODO: validate if initial url is potentially correct
// exclude landing page url
const { pathname } = action.payload.location;
const isValidPath = !api.dispatch(RouterActions.isLandingPageUrl(pathname, true));
if (isValidPath) {
api.dispatch({
type: WALLET.SET_INITIAL_URL,
pathname,
state: {},
});
}
// pass action and break process
return next(action);
}
// pass action
next(action);
switch (action.type) {
case WALLET.SET_FIRST_LOCATION_CHANGE:
api.dispatch(LocalStorageActions.loadData());
break;
case WALLET.SET_SELECTED_DEVICE:
// try to authorize device
// api.dispatch(TrezorConnectActions.authorizeDevice());
api.dispatch(TrezorConnectActions.requestWalletType());
break;
case DEVICE.CONNECT:
api.dispatch(WalletActions.clearUnavailableDevicesData(prevState, action.device));
break;
default: {
break;
}
}
// update common values ONLY if application is ready
if (!api.getState().wallet.ready) return action;
// check for "selectedDevice" change before any action
const selectedDeviceDidChange = await api.dispatch(WalletActions.observe(prevState, action));
// double verification needed
// Corner case: LOCATION_CHANGE was called but pathname didn't changed (redirection from RouterService)
const prevLocation = prevState.router.location;
const currentLocation = api.getState().router.location;
if (action.type === LOCATION_CHANGE && prevLocation.pathname !== currentLocation.pathname) {
// watch for network change
if (prevLocation.state.network !== currentLocation.state.network) {
api.dispatch({
type: CONNECT.NETWORK_CHANGED,
payload: {
network: currentLocation.state.network,
},
});
// try to stop currently running discovery on previous network
api.dispatch(DiscoveryActions.stop());
// try to start new discovery on new network
api.dispatch(DiscoveryActions.restore());
}
// watch for account change
if (
prevLocation.state.network !== currentLocation.state.network ||
prevLocation.state.account !== currentLocation.state.account
) {
api.dispatch(SelectedAccountActions.dispose());
}
// clear notifications
api.dispatch(NotificationActions.clear(prevLocation.state, currentLocation.state));
}
// if "selectedDevice" didn't change observe common values in SelectedAccountReducer
if (!selectedDeviceDidChange) {
if (!(await api.dispatch(SelectedAccountActions.observe(prevState, action)))) {
// if "selectedAccount" didn't change observe send form props changes
api.dispatch(SendFormActions.observe(prevState, action));
}
} else {
// no changes in common values
if (action.type === CONNECT.RECEIVE_WALLET_TYPE) {
if (action.device.state) {
// redirect to root view (Dashboard) if device was authenticated before
api.dispatch(RouterActions.selectFirstAvailableDevice(true));
}
api.dispatch(TrezorConnectActions.authorizeDevice());
}
if (action.type === CONNECT.AUTH_DEVICE) {
// selected device did changed
// try to restore discovery after device authentication
api.dispatch(DiscoveryActions.restore());
}
}
// even if "selectedDevice" didn't change because it was updated on DEVICE.CHANGED before DEVICE.CONNECT action
// try to restore discovery
if (action.type === DEVICE.CONNECT) {
api.dispatch(DiscoveryActions.restore());
} else if (action.type === DEVICE.DISCONNECT) {
api.dispatch(DiscoveryActions.stop());
}
// try to restore discovery on BLOCKCHAIN.CONNECT event
// edge case when backend throws error during discovery
if (action.type === BLOCKCHAIN.CONNECT) {
api.dispatch(DiscoveryActions.restore());
}
return action;
};
export default WalletService;