/* @flow */ import * as BLOCKCHAIN from 'actions/constants/blockchain'; import * as EthereumBlockchainActions from 'actions/ethereum/BlockchainActions'; import * as RippleBlockchainActions from 'actions/ripple/BlockchainActions'; import type { Dispatch, GetState, PromiseAction, BlockchainFeeLevel } from 'flowtype'; import type { BlockchainBlock, BlockchainNotification, BlockchainError } from 'trezor-connect'; export type BlockchainAction = | { type: typeof BLOCKCHAIN.READY, } | { type: typeof BLOCKCHAIN.UPDATE_FEE, shortcut: string, feeLevels: Array, } | { type: typeof BLOCKCHAIN.START_SUBSCRIBE, shortcut: string, }; // Conditionally subscribe to blockchain backend // called after TrezorConnect.init successfully emits TRANSPORT.START event // checks if there are discovery processes loaded from LocalStorage // if so starts subscription to proper networks export const init = (): PromiseAction => async ( dispatch: Dispatch, getState: GetState ): Promise => { if (getState().discovery.length > 0) { // get unique networks const networks: Array = []; getState().discovery.forEach(discovery => { if (networks.indexOf(discovery.network) < 0) { networks.push(discovery.network); } }); // subscribe const results = networks.map(n => dispatch(subscribe(n))); // wait for all subscriptions await Promise.all(results); } // continue wallet initialization dispatch({ type: BLOCKCHAIN.READY, }); }; export const subscribe = (networkName: string): PromiseAction => async ( dispatch: Dispatch, getState: GetState ): Promise => { const { config } = getState().localStorage; const network = config.networks.find(c => c.shortcut === networkName); if (!network) return; dispatch({ type: BLOCKCHAIN.START_SUBSCRIBE, shortcut: network.shortcut, }); switch (network.type) { case 'ethereum': await dispatch(EthereumBlockchainActions.subscribe(networkName)); break; case 'ripple': await dispatch(RippleBlockchainActions.subscribe(networkName)); break; default: break; } }; export const onBlockMined = ( payload: $ElementType ): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { const shortcut = payload.coin.shortcut.toLowerCase(); if (getState().router.location.state.network !== shortcut) return; const { config } = getState().localStorage; const network = config.networks.find(c => c.shortcut === shortcut); if (!network) return; switch (network.type) { case 'ethereum': await dispatch(EthereumBlockchainActions.onBlockMined(shortcut)); break; case 'ripple': await dispatch(RippleBlockchainActions.onBlockMined(shortcut)); break; default: break; } }; export const onNotification = ( payload: $ElementType ): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { const shortcut = payload.coin.shortcut.toLowerCase(); const { config } = getState().localStorage; const network = config.networks.find(c => c.shortcut === shortcut); if (!network) return; switch (network.type) { case 'ethereum': // this is not working until blockchain-link will start support blockbook backends await dispatch(EthereumBlockchainActions.onNotification(payload)); break; case 'ripple': await dispatch(RippleBlockchainActions.onNotification(payload)); break; default: break; } }; // Handle BLOCKCHAIN.ERROR event from TrezorConnect // disconnect and remove Web3 websocket instance if exists export const onError = ( payload: $ElementType ): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { const shortcut = payload.coin.shortcut.toLowerCase(); const { config } = getState().localStorage; const network = config.networks.find(c => c.shortcut === shortcut); if (!network) return; switch (network.type) { case 'ethereum': await dispatch(EthereumBlockchainActions.onError(shortcut)); break; case 'ripple': // this error is handled in BlockchainReducer // await dispatch(RippleBlockchainActions.onBlockMined(shortcut)); break; default: break; } };