diff --git a/.flowconfig b/.flowconfig index 6a2dc2fa..59038724 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,3 +1,5 @@ +[include] + [ignore] .*/node_modules/bitcoinjs-lib-zcash/.* .*/node_modules/bitcoinjs-lib/.* @@ -9,7 +11,13 @@ .*/src/solidity/.* [libs] +./src/js/flowtype/redux_v3.x.x.js +./src/js/flowtype/react-redux_v5.x.x.js +./src/js/flowtype/react-router_v4.x.x.js +./src/js/flowtype/react-router-dom_v4.x.x.js +./src/js/flowtype/react-router-redux.js ./src/js/flowtype/css.js +./src/js/flowtype/trezor-connect.js [options] diff --git a/package.json b/package.json index 031b6c05..c9a6db25 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "bugs": { "url": "https://github.com/szymonlesisz/trezor-connect-react-boilerplate/issues" }, + "bin": { + "flow": "./node_modules/flow-bin" + }, "license": "LGPL-3.0+", "scripts": { "dev": "babel-node ./webpack/server.js --connect", @@ -48,6 +51,7 @@ "redux-logger": "^3.0.6", "redux-raven-middleware": "^1.2.0", "redux-thunk": "^2.2.0", + "trezor-connect": "^5.0.10", "web3": "^0.19.0" }, "devDependencies": { @@ -65,6 +69,7 @@ "extract-text-webpack-plugin": "^3.0.0", "file-loader": "^1.1.9", "flow-bin": "^0.69.0", + "flow-typed": "^2.4.0", "html-webpack-plugin": "^2.29.0", "json-loader": "^0.5.7", "less": "^3.0.1", diff --git a/src/data/appConfig.json b/src/data/appConfig.json index b8525626..7578c0cf 100644 --- a/src/data/appConfig.json +++ b/src/data/appConfig.json @@ -117,19 +117,6 @@ } ], - - - - "bridge": { - "url": "https://localback.net:21324", - "configUrl": "data/config_signed.bin", - "latestUrl": "data/bridge/latest.txt" - }, - "extensionId": "jcjjhjgimijdkoamemaghajlhegmoclj", - "storageVersion": "1.1.0", - "metadataVersion": "1.0.0", - - "supportedBrowsers": { "chrome": { "version": 59, diff --git a/src/js/actions/AbstractAccountActions.js b/src/js/actions/AbstractAccountActions.js index ad39e3de..343905bd 100644 --- a/src/js/actions/AbstractAccountActions.js +++ b/src/js/actions/AbstractAccountActions.js @@ -5,35 +5,51 @@ import * as ACCOUNT from './constants/account'; import { initialState } from '../reducers/AbstractAccountReducer'; import { findSelectedDevice } from '../reducers/TrezorConnectReducer'; + +import type { AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '../flowtype'; import type { State } from '../reducers/AbstractAccountReducer'; +import type { Coin } from '../reducers/LocalStorageReducer'; + +export type AbstractAccountAction = { + type: typeof ACCOUNT.INIT, + state: State +} | { + type: typeof ACCOUNT.DISPOSE, +}; -export const init = (): any => { - return (dispatch, getState): void => { +export const init = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const { location } = getState().router; - const urlParams = location.params; + const urlParams = location.state; - const selected = findSelectedDevice( getState().connect ); + const selected: ?TrezorDevice = findSelectedDevice( getState().connect ); if (!selected) return; + const { config } = getState().localStorage; + const coin: ?Coin = config.coins.find(c => c.network === urlParams.network); + if (!coin) return; + const state: State = { index: parseInt(urlParams.address), - deviceState: selected.state, - deviceId: selected.features.device_id, + deviceState: selected.state || '0', + deviceId: selected.features ? selected.features.device_id : '0', deviceInstance: selected.instance, network: urlParams.network, - location: location.pathname + coin, + location: location.pathname, }; dispatch({ type: ACCOUNT.INIT, state: state }); + } } -export const update = (): any => { - return (dispatch, getState): void => { +export const update = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const { abstractAccount, router @@ -46,10 +62,14 @@ export const update = (): any => { } } -export const dispose = (): any => { - return (dispatch, getState): void => { - dispatch({ - type: ACCOUNT.DISPOSE, - }); +export const dispose = (): Action => { + return { + type: ACCOUNT.DISPOSE } +} + +export default { + init, + update, + dispose } \ No newline at end of file diff --git a/src/js/actions/AddressActions.js b/src/js/actions/AddressActions.js new file mode 100644 index 00000000..0310d32e --- /dev/null +++ b/src/js/actions/AddressActions.js @@ -0,0 +1,15 @@ +/* @flow */ +'use strict'; + +import * as ADDRESS from './constants/address'; + +export type AddressAction = { + type: typeof ADDRESS.CREATE, + payload: any +} | { + type: typeof ADDRESS.SET_BALANCE, + payload: any +} | { + type: typeof ADDRESS.SET_NONCE, + payload: any +} \ No newline at end of file diff --git a/src/js/actions/DiscoveryActions.js b/src/js/actions/DiscoveryActions.js index 65561412..62399cd2 100644 --- a/src/js/actions/DiscoveryActions.js +++ b/src/js/actions/DiscoveryActions.js @@ -13,6 +13,16 @@ import HDKey from 'hdkey'; import EthereumjsUtil from 'ethereumjs-util'; import { getNonceAsync, getBalanceAsync, getTokenBalanceAsync } from './Web3Actions'; + + +export type DiscoveryAction = { + type: typeof DISCOVERY.START, +} | { + type: typeof DISCOVERY.STOP, +} | { + type: typeof DISCOVERY.COMPLETE, +}; + export const start = (device: any, network: string, ignoreCompleted?: boolean): any => { return (dispatch, getState) => { @@ -310,7 +320,7 @@ export const check = (): any => { const selected = findSelectedDevice(getState().connect); if (!selected) return; - const urlParams = getState().router.location.params; + const urlParams = getState().router.location.state; if (urlParams.network) { const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.network === urlParams.network); if (!discoveryProcess) { diff --git a/src/js/actions/HistoryActions.js b/src/js/actions/HistoryActions.js index 31e1b803..0f324a80 100644 --- a/src/js/actions/HistoryActions.js +++ b/src/js/actions/HistoryActions.js @@ -1,10 +1,2 @@ /* @flow */ 'use strict'; - - -export const onGasPriceChange2 = (gasPrice: string): void => { - return { - type: '', - gasPrice - } -} \ No newline at end of file diff --git a/src/js/actions/LocalStorageActions.js b/src/js/actions/LocalStorageActions.js index 60315ac1..24ad696f 100644 --- a/src/js/actions/LocalStorageActions.js +++ b/src/js/actions/LocalStorageActions.js @@ -6,10 +6,26 @@ 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 { httpRequest } from '../utils/networkUtils'; +import { JSONRequest, httpRequest } from '../utils/networkUtils'; -export function loadData(): any { - return async (dispatch, getState) => { +import type { AsyncAction, GetState, Dispatch } from '../flowtype'; +import type { Config, Coin, TokensCollection } from '../reducers/LocalStorageReducer'; + +export type StorageAction = { + type: typeof STORAGE.READY, + config: any, + tokens: any, + ERC20Abi: any +} | { + type: typeof STORAGE.SAVE, + network: string, +} | { + type: typeof STORAGE.ERROR, + error: string, +}; + +export const loadData = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { // check if local storage is available // let available: boolean = true; @@ -27,16 +43,51 @@ export function loadData(): any { } } -export function loadTokensFromJSON(): any { - return async (dispatch, getState) => { +// const parseConfig = (json: JSON): Config => { + +// if (json['coins']) { + +// } + +// for (let key in json) { +// if (key === 'coins') { + +// } +// } + +// const coins: Array = json.coins || []; + +// if ("coins" in json){ +// json.coins +// } +// if (!json.hasOwnProperty("fiatValueTickers")) throw new Error(`Property "fiatValueTickers" is missing in appConfig.json`); +// if (json.config && json.hasOwnProperty('coins') && Array.isArray(json.coins)) { +// json.coins.map(c => { +// return { + +// } +// }) +// } else { +// throw new Error(`Property "coins" is missing in appConfig.json`); +// } + + +// return { +// coins: [], +// fiatValueTickers: [] +// } +// } + +export function loadTokensFromJSON(): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { try { - const config = await httpRequest('data/appConfig.json', 'json'); + const config: Config = await httpRequest('data/appConfig.json', 'json'); const ERC20Abi = await httpRequest('data/ERC20Abi.json', 'json'); // load tokens - const tokens = await config.coins.reduce(async (promise: Promise, coin: any): Promise => { - const collection = await promise; - const json: JSON = await httpRequest(coin.tokens, 'json'); + const tokens = await config.coins.reduce(async (promise: Promise, coin: Coin): Promise => { + const collection: TokensCollection = await promise; + const json = await httpRequest(coin.tokens, 'json'); collection[ coin.network ] = json; return collection; }, Promise.resolve({})); @@ -99,8 +150,8 @@ export function loadTokensFromJSON(): any { } -export const save = (key: string, value: string): any => { - return (dispatch, getState) => { +export const save = (key: string, value: string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState) => { if (typeof window.localStorage !== 'undefined') { try { window.localStorage.setItem(key, value); diff --git a/src/js/actions/LogActions.js b/src/js/actions/LogActions.js index 216f88e6..970471ea 100644 --- a/src/js/actions/LogActions.js +++ b/src/js/actions/LogActions.js @@ -1,15 +1,25 @@ /* @flow */ 'use strict'; -export const toggle = (): any => { - return (dispatch, getState) => { +import * as LOG from './constants/log'; + +import type { AsyncAction, GetState, Dispatch } from '../flowtype'; + +export type LogAction = { + type: typeof LOG.OPEN, +} | { + type: typeof LOG.CLOSE, +}; + +export const toggle = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { if (!getState().log.opened) { window.scrollTo(0, 0); } dispatch({ - type: getState().log.opened ? 'log__close' : 'log__open' + type: getState().log.opened ? LOG.CLOSE : LOG.OPEN }); } } diff --git a/src/js/actions/ModalActions.js b/src/js/actions/ModalActions.js index 186349fb..281f1d3b 100644 --- a/src/js/actions/ModalActions.js +++ b/src/js/actions/ModalActions.js @@ -5,16 +5,24 @@ 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'; -export function onPinSubmit(value: string): any { +export type ModalAction = { + type: typeof MODAL.CLOSE +} | { + type: typeof MODAL.REMEMBER, + device: any +}; + +export const onPinSubmit = (value: string): Action => { TrezorConnect.uiResponse({ type: UI.RECEIVE_PIN, payload: value }); return { type: MODAL.CLOSE } } -export function onPassphraseSubmit(passphrase: string): any { - return async (dispatch, getState): Promise => { +export const onPassphraseSubmit = (passphrase: string): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { const resp = await TrezorConnect.uiResponse({ type: UI.RECEIVE_PASSPHRASE, payload: { @@ -29,42 +37,42 @@ export function onPassphraseSubmit(passphrase: string): any { } } -export const askForRemember = (device: any) => { +export const askForRemember = (device: any): Action => { return { type: MODAL.REMEMBER, device } } -export const onRememberDevice = (device: any) => { +export const onRememberDevice = (device: any): Action => { return { type: CONNECT.REMEMBER, device } } -export const onForgetDevice = (device: any) => { +export const onForgetDevice = (device: any): Action => { return { type: CONNECT.FORGET, device, } } -export const onForgetSingleDevice = (device: any) => { +export const onForgetSingleDevice = (device: any): Action => { return { type: CONNECT.FORGET_SINGLE, device, } } -export const onCancel = () => { +export const onCancel = (): Action => { return { type: MODAL.CLOSE } } -export const onDuplicateDevice = (device: any): any => { - return (dispatch: any, getState: any): void => { +export const onDuplicateDevice = (device: any): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { dispatch( onCancel() ); @@ -73,4 +81,15 @@ export const onDuplicateDevice = (device: any): any => { device }); } +} + +export default { + onPinSubmit, + onPassphraseSubmit, + askForRemember, + onRememberDevice, + onForgetDevice, + onForgetSingleDevice, + onCancel, + onDuplicateDevice } \ No newline at end of file diff --git a/src/js/actions/NotificationActions.js b/src/js/actions/NotificationActions.js index 6e2151f8..e4d455f8 100644 --- a/src/js/actions/NotificationActions.js +++ b/src/js/actions/NotificationActions.js @@ -3,10 +3,33 @@ import * as NOTIFICATION from './constants/notification'; +import type { AsyncAction, GetState, Dispatch, RouterLocationState } from '../flowtype'; + +export type NotificationAction = { + type: typeof NOTIFICATION.ADD, + payload: { + +type: string, + +title: string, + +message?: string, + +cancelable: boolean, + actions?: Array + } +} | { + type: typeof NOTIFICATION.CLOSE, + payload?: { + id?: string; + devicePath?: string + } +} + +export const close = () => { + +} + // called from RouterService -export const clear = (currentParams, requestedParams): any => { - return async (dispatch, getState) => { +export const clear = (currentParams: RouterLocationState, requestedParams: RouterLocationState): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { // if route has been changed from device view into something else (like other device, settings...) // try to remove all Notifications which are linked to previous device (they are not cancelable by user) if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) { diff --git a/src/js/actions/ReceiveActions.js b/src/js/actions/ReceiveActions.js index 4fa54bd2..bcc6b05b 100644 --- a/src/js/actions/ReceiveActions.js +++ b/src/js/actions/ReceiveActions.js @@ -9,9 +9,24 @@ import { initialState } from '../reducers/ReceiveReducer'; import type { State } from '../reducers/ReceiveReducer'; import { findSelectedDevice } from '../reducers/TrezorConnectReducer'; +import type { TrezorDevice, AsyncAction, Action, GetState, Dispatch } from '../flowtype'; -export const init = (): any => { - return (dispatch, getState): void => { +export type ReceiveAction = { + type: typeof RECEIVE.INIT, + state: State +} | { + type: typeof RECEIVE.DISPOSE, +} | { + type: typeof RECEIVE.REQUEST_UNVERIFIED, + device: TrezorDevice +} | { + type: typeof RECEIVE.SHOW_ADDRESS +} | { + type: typeof RECEIVE.SHOW_UNVERIFIED_ADDRESS +} + +export const init = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const state: State = { ...initialState, @@ -25,8 +40,8 @@ export const init = (): any => { } -export const update = (newProps: any): any => { - return (dispatch, getState): void => { +export const update = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const { abstractAccount, router @@ -39,20 +54,20 @@ export const update = (newProps: any): any => { } } -export const dispose = (address: string): any => { +export const dispose = (): Action => { return { type: RECEIVE.DISPOSE } } -export const showUnverifiedAddress = () => { +export const showUnverifiedAddress = (): Action => { return { type: RECEIVE.SHOW_UNVERIFIED_ADDRESS } } -export const showAddress = (address_n: string): any => { - return async (dispatch, getState) => { +export const showAddress = (address_n: string): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { const selected = findSelectedDevice(getState().connect); if (!selected) return; @@ -99,4 +114,12 @@ export const showAddress = (address_n: string): any => { }) } } +} + +export default { + init, + update, + dispose, + showAddress, + showUnverifiedAddress } \ No newline at end of file diff --git a/src/js/actions/SendFormActions.js b/src/js/actions/SendFormActions.js index 2f9f3fe1..b7081450 100644 --- a/src/js/actions/SendFormActions.js +++ b/src/js/actions/SendFormActions.js @@ -16,12 +16,72 @@ import BigNumber from 'bignumber.js'; import { initialState } from '../reducers/SendFormReducer'; import { findAccount } from '../reducers/AccountsReducer'; +import { findToken } from '../reducers/TokensReducer'; +import { findSelectedDevice } from '../reducers/TrezorConnectReducer'; + +import type { + Dispatch, + GetState, + Action, + AsyncAction, + RouterLocationState, + TrezorDevice +} from '../flowtype'; +import type { State as AccountState } from '../reducers/AbstractAccountReducer'; +import type { Web3Instance } from '../reducers/Web3Reducer'; +import type { Config, Coin } from '../reducers/LocalStorageReducer'; +import type { Token } from '../reducers/TokensReducer'; import type { State, FeeLevel } from '../reducers/SendFormReducer'; import type { Account } from '../reducers/AccountsReducer'; -import { findSelectedDevice } from '../reducers/TrezorConnectReducer'; + +export type SendFormAction = { + type: typeof SEND.TX_COMPLETE, +} | { + type: typeof SEND.INIT, + state: State +} | { + type: typeof SEND.DISPOSE +} | { + type: typeof SEND.TOGGLE_ADVANCED +} | { + type: typeof SEND.VALIDATION, + errors: {[k: string]: string}, + warnings: {[k: string]: string}, + infos: {[k: string]: string} +} | { + type: typeof SEND.ADDRESS_CHANGE, + state: State +} | { + type: typeof SEND.AMOUNT_CHANGE, + state: State +} | { + type: typeof SEND.CURRENCY_CHANGE, + state: State +} | { + type: typeof SEND.SET_MAX, + state: State +} | { + type: typeof SEND.FEE_LEVEL_CHANGE, + state: State +} | { + type: typeof SEND.UPDATE_FEE_LEVELS, + state: State +} | { + type: typeof SEND.FEE_LEVEL_CHANGE, + state: State +} | { + type: typeof SEND.GAS_PRICE_CHANGE, + state: State +} | { + type: typeof SEND.GAS_LIMIT_CHANGE, + state: State +} | { + type: typeof SEND.DATA_CHANGE, + state: State +}; //const numberRegExp = new RegExp('^([0-9]{0,10}\\.)?[0-9]{1,18}$'); -const numberRegExp = new RegExp('^(0|0\\.([0-9]+)?|[1-9]+\\.?([0-9]+)?|\\.[0-9]+)$'); +const numberRegExp: RegExp = new RegExp('^(0|0\\.([0-9]+)?|[1-9]+\\.?([0-9]+)?|\\.[0-9]+)$'); const calculateFee = (gasPrice: string, gasLimit: string): string => { return EthereumjsUnits.convert( new BigNumber(gasPrice).times(gasLimit), 'gwei', 'ether'); @@ -82,38 +142,43 @@ export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLi ] } -export const findBalance = (getState: any): string => { - const accountState = getState().abstractAccount; - const { token } = getState().sendForm; - const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); +// export const findBalance = (getState: GetState): string => { +// const accountState = getState().abstractAccount; +// const { token } = getState().sendForm; +// const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); - if (token !== state.network) { - return getState().tokens.find(t => t.ethAddress === account.address && t.symbol === token).balance; - } else { - return account.balance; - } -} +// if (token !== state.network) { +// return getState().tokens.find(t => t.ethAddress === account.address && t.symbol === token).balance; +// } else { +// return account.balance; +// } +// } // initialize component -export const init = (): any => { - return (dispatch, getState): void => { +export const init = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + + const accountState: AccountState = getState().abstractAccount; const { location } = getState().router; - const urlParams = location.params; + const urlParams: RouterLocationState = location.state; - const selected = findSelectedDevice( getState().connect ); + const selected: ?TrezorDevice = findSelectedDevice( getState().connect ); if (!selected) return; - const web3instance = getState().web3.find(w3 => w3.network === urlParams.network); + const web3instance: ?Web3Instance = getState().web3.find(w3 => w3.network === urlParams.network); if (!web3instance) { // no backend for this network - //return; + return; } // TODO: check if there are some unfinished tx in localStorage const { config } = getState().localStorage; - const coin = config.coins.find(c => c.network === urlParams.network); + if (!config) return; + + const coin: ?Coin = config.coins.find(c => c.network === urlParams.network); + if (!coin) return; const gasPrice: BigNumber = new BigNumber( EthereumjsUnits.convert(web3instance.gasPrice, 'wei', 'gwei') ) || new BigNumber(coin.defaultGasPrice); const gasLimit: string = coin.defaultGasLimit.toString(); @@ -123,9 +188,9 @@ export const init = (): any => { const state: State = { ...initialState, + network: coin.network, coinSymbol: coin.symbol, token: coin.network, - feeLevels, selectedFeeLevel: feeLevels.find(f => f.value === 'Normal'), recommendedGasPrice: gasPrice.toString(), @@ -141,8 +206,8 @@ export const init = (): any => { } } -export const update = (): any => { - return (dispatch, getState): void => { +export const update = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const { abstractAccount, router @@ -156,29 +221,29 @@ export const update = (): any => { } } -export const dispose = (): any => { +export const dispose = (): Action => { return { type: SEND.DISPOSE } } -export const toggleAdvanced = (address: string): any => { +export const toggleAdvanced = (address: string): Action => { return { type: SEND.TOGGLE_ADVANCED } } -export const validation = (): any => { - return (dispatch, getState): void => { +export const validation = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { - const accountState = getState().abstractAccount; + const accountState: AccountState = getState().abstractAccount; const state: State = getState().sendForm; + const errors: {[k: string]: string} = {}; const warnings: {[k: string]: string} = {}; const infos: {[k: string]: string} = {}; if (!state.untouched) { - // valid address if (state.touched.address) { @@ -208,8 +273,11 @@ export const validation = (): any => { } else if (state.amount.length > 0 && !state.amount.match(numberRegExp)) { errors.amount = 'Amount is not a number'; } else { + const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); - let decimalRegExp; + if (!account) return; // this should not happen + + let decimalRegExp: RegExp; if (state.token !== accountState.network) { const token: any = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === state.token); @@ -296,8 +364,8 @@ export const validation = (): any => { } -export const onAddressChange = (address: string): any => { - return (dispatch, getState): void => { +export const onAddressChange = (address: string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const currentState: State = getState().sendForm; const touched = { ...currentState.touched }; @@ -318,10 +386,10 @@ export const onAddressChange = (address: string): any => { } } -export const onAmountChange = (amount: string): any => { - return (dispatch, getState): void => { +export const onAmountChange = (amount: string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { - const accountState = getState().abstractAccount; + const accountState: AccountState = getState().abstractAccount; const currentState: State = getState().sendForm; const isToken: boolean = currentState.token !== accountState.network; const touched = { ...currentState.touched }; @@ -345,11 +413,10 @@ export const onAmountChange = (amount: string): any => { } } -export const onCurrencyChange = (currency: any): any => { - - return (dispatch, getState): void => { - const accountState = getState().abstractAccount; - const currentState = getState().sendForm; +export const onCurrencyChange = (currency: any): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const accountState: AccountState = getState().abstractAccount; + const currentState: State = getState().sendForm; const isToken: boolean = currency.value !== accountState.network; const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); @@ -359,7 +426,9 @@ export const onCurrencyChange = (currency: any): any => { } const { config } = getState().localStorage; - const coin = config.coins.find(c => c.network === accountState.network); + if (!config) return; + const coin: ?Coin = config.coins.find(c => c.network === accountState.network); + if (!coin) return; let gasLimit: string = ''; let amount: string = currentState.amount; @@ -368,8 +437,9 @@ export const onCurrencyChange = (currency: any): any => { if (isToken) { gasLimit = coin.defaultGasLimitTokens.toString(); if (currentState.setMax) { - const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currency.value).balance; - amount = tokenBalance; + const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState); + if (!token) return; + amount = token.balance; } total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit); } else { @@ -381,6 +451,8 @@ export const onCurrencyChange = (currency: any): any => { } const feeLevels: Array = getFeeLevels(currentState.coinSymbol, currentState.gasPrice, gasLimit); + const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value); + if (!selectedFeeLevel) return; const state: State = { ...currentState, @@ -388,7 +460,7 @@ export const onCurrencyChange = (currency: any): any => { amount, total, feeLevels, - selectedFeeLevel: feeLevels.find(f => f.value === currentState.selectedFeeLevel.value), + selectedFeeLevel, gasLimit, }; @@ -402,10 +474,10 @@ export const onCurrencyChange = (currency: any): any => { -export const onSetMax = (): any => { - return (dispatch, getState): void => { - const accountState = getState().abstractAccount; - const currentState = getState().sendForm; +export const onSetMax = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const accountState: AccountState = getState().abstractAccount; + const currentState: State = getState().sendForm; const isToken: boolean = currentState.token !== accountState.network; const touched = { ...currentState.touched }; touched.amount = true; @@ -420,8 +492,9 @@ export const onSetMax = (): any => { let total: string = currentState.total; if (!currentState.setMax) { if (isToken) { - const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance; - amount = tokenBalance; + const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState); + if (!token) return; + amount = token.balance; total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit); } else { amount = calculateMaxAmount(account.balance, currentState.gasPrice, currentState.gasLimit); @@ -446,12 +519,17 @@ export const onSetMax = (): any => { } } -export const onFeeLevelChange = (feeLevel: any): any => { - return (dispatch, getState): void => { - const accountState = getState().abstractAccount; - const currentState = getState().sendForm; +export const onFeeLevelChange = (feeLevel: FeeLevel): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const accountState: AccountState = getState().abstractAccount; + const currentState: State = getState().sendForm; const isToken: boolean = currentState.token !== accountState.network; + const { config } = getState().localStorage; + if (!config) return; + const coin: ?Coin = config.coins.find(c => c.network === accountState.network); + if (!coin) return; + const state: State = { ...currentState, untouched: false, @@ -464,16 +542,22 @@ export const onFeeLevelChange = (feeLevel: any): any => { feeLevel.gasPrice = state.gasPrice; feeLevel.label = `${ calculateFee(state.gasPrice, state.gasLimit) } ${ state.coinSymbol }`; } else { - const customLevel = state.feeLevels.find(f => f.value === 'Custom'); - customLevel.label = ''; + const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom'); + if (customLevel) + customLevel.label = ''; state.gasPrice = feeLevel.gasPrice; + state.gasLimit = isToken ? coin.defaultGasLimitTokens.toString() : coin.defaultGasLimit.toString(); + // reset custom gasLimit } if (currentState.setMax) { const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); + if (!account) return; + if (isToken) { - const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance; - state.amount = tokenBalance; + const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState); + if (!token) return; + state.amount = token.balance; } else { state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit); } @@ -488,14 +572,16 @@ export const onFeeLevelChange = (feeLevel: any): any => { } } -export const updateFeeLevels = (): any => { - return (dispatch, getState): void => { - const accountState = getState().abstractAccount; - const currentState = getState().sendForm; +export const updateFeeLevels = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const accountState: AccountState = getState().abstractAccount; + const currentState: State = getState().sendForm; const isToken: boolean = currentState.token !== accountState.network; const feeLevels: Array = getFeeLevels(currentState.coinSymbol, currentState.recommendedGasPrice, currentState.gasLimit); - const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value) + const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value); + if (!selectedFeeLevel) return; + const state: State = { ...currentState, feeLevels, @@ -507,8 +593,11 @@ export const updateFeeLevels = (): any => { if (currentState.setMax) { const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); + if (!account) return; if (isToken) { - const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance; + const token: ?Token = findToken(getState().tokens, account.address, state.token, accountState.deviceState); + if (!token) return; + const tokenBalance: string = token.balance; state.amount = tokenBalance; } else { state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit); @@ -524,10 +613,10 @@ export const updateFeeLevels = (): any => { } } -export const onGasPriceChange = (gasPrice: string): any => { - return (dispatch, getState): void => { - const accountState = getState().abstractAccount; - const currentState = getState().sendForm; +export const onGasPriceChange = (gasPrice: string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const accountState: AccountState = getState().abstractAccount; + const currentState: State = getState().sendForm; const isToken: boolean = currentState.token !== accountState.network; const touched = { ...currentState.touched }; @@ -542,6 +631,7 @@ export const onGasPriceChange = (gasPrice: string): any => { if (gasPrice.match(numberRegExp) && state.gasLimit.match(numberRegExp)) { const customLevel = currentState.feeLevels.find(f => f.value === 'Custom'); + if (!customLevel) return; customLevel.gasPrice = gasPrice; customLevel.label = `${ calculateFee(gasPrice, state.gasLimit) } ${ state.coinSymbol }`; @@ -549,8 +639,11 @@ export const onGasPriceChange = (gasPrice: string): any => { if (currentState.setMax) { const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); + if (!account) return; if (isToken) { - const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance; + const token: ?Token = findToken(getState().tokens, account.address, state.token, accountState.deviceState); + if (!token) return; + const tokenBalance: string = token.balance; state.amount = tokenBalance; } else { state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit); @@ -568,10 +661,10 @@ export const onGasPriceChange = (gasPrice: string): any => { } } -export const onGasLimitChange = (gasLimit: string): any => { - return (dispatch, getState): void => { - const accountState = getState().abstractAccount; - const currentState = getState().sendForm; +export const onGasLimitChange = (gasLimit: string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const accountState: AccountState = getState().abstractAccount; + const currentState: State = getState().sendForm; const isToken: boolean = currentState.token !== accountState.network; const touched = { ...currentState.touched }; @@ -585,15 +678,20 @@ export const onGasLimitChange = (gasLimit: string): any => { }; if (gasLimit.match(numberRegExp) && state.gasPrice.match(numberRegExp)) { - const customLevel = state.feeLevels.find(f => f.value === 'Custom'); + const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom'); + if (!customLevel) return; customLevel.label = `${ calculateFee(currentState.gasPrice, gasLimit) } ${ state.coinSymbol }`; state.selectedFeeLevel = customLevel; if (state.setMax) { const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); + if (!account) return; + if (isToken) { - const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === state.token).balance; + const token: ?Token = findToken(getState().tokens, account.address, state.token, accountState.deviceState); + if (!token) return; + const tokenBalance: string = token.balance; state.amount = tokenBalance; } else { state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit); @@ -611,9 +709,9 @@ export const onGasLimitChange = (gasLimit: string): any => { } } -export const onDataChange = (data: string): any => { - return (dispatch, getState): void => { - const currentState = getState().sendForm; +export const onDataChange = (data: string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const currentState: State = getState().sendForm; const touched = { ...currentState.touched }; touched.data = true; @@ -632,33 +730,37 @@ export const onDataChange = (data: string): any => { } } -export const onSend = (): any => { +export const onSend = (): AsyncAction => { //return onSendERC20(); + return async (dispatch: Dispatch, getState: GetState): Promise => { - return async (dispatch, getState): Promise => { - - const accountState = getState().abstractAccount; + const accountState: AccountState = getState().abstractAccount; const currentState: State = getState().sendForm; - const web3instance = getState().web3.filter(w3 => w3.network === accountState.network)[0]; - const web3 = web3instance.web3; + const web3instance: ?Web3Instance = getState().web3.filter(w3 => w3.network === accountState.network)[0]; const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network); + if (!account || !web3instance) return; + const isToken: boolean = currentState.token !== accountState.network; + const web3 = web3instance.web3; const address_n = account.addressPath; let data: string = ''; - let txAmount = web3.toHex(web3.toWei(currentState.amount, 'ether')); - let txAddress = currentState.address; + let txAmount: string = web3.toHex(web3.toWei(currentState.amount, 'ether')); + let txAddress: string = currentState.address; if (isToken) { - const t = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token); - const contract = web3instance.erc20.at(t.address); + // const t = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token); + const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState); + if (!token) return; + + const contract = web3instance.erc20.at(token.address); data = contract.transfer.getData(currentState.address, currentState.amount, { from: account.address, gasLimit: currentState.gasLimit, gasPrice: currentState.gasPrice }); txAmount = '0x00'; - txAddress = t.address; + txAddress = token.address; } const txData = { @@ -693,7 +795,7 @@ export const onSend = (): any => { // console.log("---->GASSS", txData, gasLimit, gasPrice, EthereumjsUnits.convert(gasPrice, 'gwei', 'wei')); - const selected = findSelectedDevice(getState().connect); + const selected: ?TrezorDevice = findSelectedDevice(getState().connect); if (!selected) return; let signedTransaction = await TrezorConnect.ethereumSignTransaction({ @@ -736,7 +838,9 @@ export const onSend = (): any => { // console.log("---->GASSS", txData, gasLimit2.toString() ); const { config } = getState().localStorage; - const selectedCoin = config.coins.find(c => c.network === currentState.network); + if (!config) return; + const selectedCoin: ?Coin = config.coins.find(c => c.network === currentState.network); + if (!selectedCoin) return; try { const tx = new EthereumjsTx(txData); @@ -778,3 +882,21 @@ export const onSend = (): any => { } } } + +export default { + init, + update, + dispose, + + toggleAdvanced, + onAddressChange, + onAmountChange, + onCurrencyChange, + onSetMax, + onFeeLevelChange, + updateFeeLevels, + onGasPriceChange, + onGasLimitChange, + onDataChange, + onSend, +} diff --git a/src/js/actions/SummaryActions.js b/src/js/actions/SummaryActions.js index 3faf89c9..39716f81 100644 --- a/src/js/actions/SummaryActions.js +++ b/src/js/actions/SummaryActions.js @@ -7,14 +7,24 @@ import * as TOKEN from './constants/token'; import * as ADDRESS from './constants/address'; import { resolveAfter } from '../utils/promiseUtils'; import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions'; - import { initialState } from '../reducers/SummaryReducer'; -import type { State } from '../reducers/SummaryReducer'; import { findSelectedDevice } from '../reducers/TrezorConnectReducer'; +import type { AsyncAction, Action, GetState, Dispatch } from '../flowtype'; +import type { State } from '../reducers/SummaryReducer'; +import type { Token } from '../reducers/TokensReducer'; + +export type SummaryAction = { + type: typeof SUMMARY.INIT, + state: State +} | { + type: typeof SUMMARY.DISPOSE, +} | { + type: typeof SUMMARY.DETAILS_TOGGLE +} -export const init = (): any => { - return (dispatch, getState): void => { +export const init = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const state: State = { ...initialState, @@ -28,8 +38,8 @@ export const init = (): any => { } -export const update = (newProps: any): any => { - return (dispatch, getState): void => { +export const update = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const { abstractAccount, router @@ -43,87 +53,15 @@ export const update = (newProps: any): any => { } } -export const dispose = (address: string): any => { +export const dispose = (): Action => { return { type: SUMMARY.DISPOSE } } -export const onDetailsToggle = (): any => { +export const onDetailsToggle = (): Action => { return { type: SUMMARY.DETAILS_TOGGLE } } - -export const loadTokens = (input: string, account: any): any => { - return async (dispatch, getState): Promise => { - - if (input.length < 1) return null; - - const tokens = getState().localStorage.tokens[ account.network ]; - const value = input.toLowerCase(); - const result = tokens.filter(t => - t.symbol.toLowerCase().indexOf(value) >= 0 || - t.address.toLowerCase().indexOf(value) >= 0 || - t.name.toLowerCase().indexOf(value) >= 0 - ); - - if (result.length > 0) { - return { options: result }; - } else { - const web3instance = getState().web3.find(w3 => w3.network === account.network); - - const info = await getTokenInfoAsync(web3instance.erc20, input); - info.address = input; - - if (info) { - return { - options: [ info ] - } - } else { - return { - - } - } - - //await resolveAfter(300000); - //await resolveAfter(3000); - - } - - } -} - -export const selectToken = (token: any, account: any): any => { - return async (dispatch, getState): Promise => { - - const web3instance = getState().web3.find(w3 => w3.network === account.network); - dispatch({ - type: TOKEN.ADD, - payload: { - ...token, - ethAddress: account.address, - deviceState: account.deviceState - } - }); - - const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, token.address, account.address); - dispatch({ - type: TOKEN.SET_BALANCE, - payload: { - ethAddress: account.address, - address: token.address, - balance: tokenBalance.toString() - } - }) - - } -} - -export const removeToken = (token: any): any => { - return { - type: TOKEN.REMOVE, - token - } -} diff --git a/src/js/actions/TokenActions.js b/src/js/actions/TokenActions.js new file mode 100644 index 00000000..668e4d5f --- /dev/null +++ b/src/js/actions/TokenActions.js @@ -0,0 +1,113 @@ +/* @flow */ +'use strict'; + +import * as TOKEN from './constants/token'; +import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions'; + +import type { GetState, AsyncAction, Action } from '../flowtype'; +import type { State, Token } from '../reducers/TokensReducer'; +import type { Account } from '../reducers/AccountsReducer'; +import type { NetworkToken } from '../reducers/LocalStorageReducer'; + +export type TokenAction = { + type: typeof TOKEN.FROM_STORAGE, + payload: State +} | { + type: typeof TOKEN.ADD, + payload: Token +} | { + type: typeof TOKEN.REMOVE, + 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 => { + } +} + +type SelectOptions = { + options?: Array +} + + +// action from component +export const load = (input: string, network: string): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { + + if (input.length < 1) return; + + const tokens = getState().localStorage.tokens[ network ]; + const value = input.toLowerCase(); + const result = tokens.filter(t => + t.symbol.toLowerCase().indexOf(value) >= 0 || + t.address.toLowerCase().indexOf(value) >= 0 || + t.name.toLowerCase().indexOf(value) >= 0 + ); + + if (result.length > 0) { + return { options: result }; + } else { + const web3instance = getState().web3.find(w3 => w3.network === network); + if (!web3instance) return; + + const info = await getTokenInfoAsync(web3instance.erc20, input); + info.address = input; + + if (info) { + return { + options: [ info ] + } + } + //await resolveAfter(300000); + //await resolveAfter(3000); + + } + return; + } +} + +export const add = (token: NetworkToken, account: Account): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { + + const web3instance = getState().web3.find(w3 => w3.network === account.network); + if (!web3instance) return; + + dispatch({ + type: TOKEN.ADD, + payload: { + loaded: false, + deviceState: account.deviceState, + name: token.name, + symbol: token.symbol, + address: token.address, + ethAddress: account.address, + decimals: token.decimals, + balance: '0' + } + }); + + const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, token.address, account.address); + dispatch({ + type: TOKEN.SET_BALANCE, + payload: { + ethAddress: account.address, + address: token.address, + balance: tokenBalance.toString() + } + }) + + } +} + +export const remove = (token: Token): Action => { + return { + type: TOKEN.REMOVE, + token + } +} \ No newline at end of file diff --git a/src/js/actions/TrezorConnectActions.js b/src/js/actions/TrezorConnectActions.js index 3c47333a..18ea6aa8 100644 --- a/src/js/actions/TrezorConnectActions.js +++ b/src/js/actions/TrezorConnectActions.js @@ -14,29 +14,107 @@ import { resolveAfter } from '../utils/promiseUtils'; import { getAccounts } from '../utils/reducerUtils'; import { findSelectedDevice } from '../reducers/TrezorConnectReducer'; -export const init = (): any => { - return async (dispatch, getState): Promise => { + +import type { + Device, + ResponseMessage, + DeviceMessage, + UiMessage, + TransportMessage, + DeviceMessageType, + TransportMessageType, + UiMessageType +} from 'trezor-connect'; + +import type { + Dispatch, + GetState, + Action, + AsyncAction, + TrezorDevice, + RouterLocationState +} from '../flowtype'; + + +export type TrezorConnectAction = { + type: typeof CONNECT.INITIALIZATION_ERROR, + error: any +} | { + type: typeof CONNECT.SELECT_DEVICE, + payload: ?{ + id: string, + instance: string + } +} | { + type: typeof CONNECT.COIN_CHANGED, + payload: { + network: string + } +} | { + type: typeof CONNECT.AUTH_DEVICE, + device: any +} | { + type: typeof CONNECT.DUPLICATE, + device: any +} | { + type: typeof CONNECT.REMEMBER_REQUEST, + device: any +} | { + type: typeof CONNECT.DISCONNECT_REQUEST, + device: any +} | { + type: typeof CONNECT.FORGET_REQUEST, + device: any +} | { + type: typeof CONNECT.FORGET, + device: any +} | { + type: typeof CONNECT.FORGET_SINGLE, + device: any +} | { + type: typeof CONNECT.REMEMBER, + device: any +} | { + type: typeof CONNECT.TRY_TO_DUPLICATE, + device: any +} | { + type: typeof CONNECT.DEVICE_FROM_STORAGE, + payload: Array +} | { + type: typeof CONNECT.START_ACQUIRING, + device: any +} | { + type: typeof CONNECT.STOP_ACQUIRING, + device: any +}; + + +export const init = (): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { // set listeners TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => { + // post event to reducers + const type: DeviceMessageType = event.type; // assert flow type dispatch({ - type: event.type, + type, device: event.payload }); }); - const version: Object = TrezorConnect.getVersion(); TrezorConnect.on(UI_EVENT, (event: UiMessage): void => { // post event to reducers + const type: UiMessageType = event.type; // assert flow type dispatch({ - type: event.type, + type, payload: event.payload }); }); - TrezorConnect.on(TRANSPORT_EVENT, (event: UiMessage): void => { + TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => { // post event to reducers + const type: TransportMessageType = event.type; // assert flow type dispatch({ - type: event.type, + type, payload: event.payload }); }); @@ -47,7 +125,7 @@ export const init = (): any => { connectSrc: 'https://localhost:8088/', // connectSrc: 'https://connect.trezor.io/tpm/', // connectSrc: 'https://sisyfos.trezor.io/', - debug: true, + debug: false, popup: false, webusb: true }); @@ -62,10 +140,10 @@ export const init = (): any => { // called after backend was initialized // set listeners for connect/disconnect -export const postInit = (): any => { - return (dispatch, getState): void => { +export const postInit = (): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { - const handleDeviceConnect = (device) => { + const handleDeviceConnect = (device: Device) => { dispatch( initConnectedDevice(device) ); } @@ -75,9 +153,11 @@ export const postInit = (): any => { TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect); TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect); - const { devices } = getState().connect; + // const devices: Array = getState().connect.devices; + const devices: Array = getState().connect.devices; + + const { initialPathname, initialParams } = getState().wallet; - const { initialPathname, initialParams } = getState().wallet if (initialPathname) { dispatch({ type: WALLET.SET_INITIAL_URL, @@ -87,7 +167,7 @@ export const postInit = (): any => { } if (devices.length > 0) { - const unacquired = devices.find(d => d.unacquired); + const unacquired: ?TrezorDevice = devices.find(d => d.unacquired); if (unacquired) { dispatch( onSelectDevice(unacquired) ); } else { @@ -118,8 +198,8 @@ const sortDevices = (devices: Array): Array => { }); } -export const initConnectedDevice = (device: any, force): any => { - return (dispatch, getState): void => { +export const initConnectedDevice = (device: any): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { const selected = findSelectedDevice(getState().connect); if (!selected || (selected && selected.state)) { @@ -137,27 +217,26 @@ export const initConnectedDevice = (device: any, force): any => { // after device_connect event // or after acquiring device // device type could be local TrezorDevice or Device (from trezor-connect device_connect event) -export const onSelectDevice = (device: any): any => { - return (dispatch, getState): void => { +export const onSelectDevice = (device: TrezorDevice | Device): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { // || device.isUsedElsewhere - console.log("------> REDITTO", device, getState().wallet.initialUrl); - // switch to initial url and reset this value - if (device.unacquired) { + if (!device.features) { dispatch( push(`/device/${ device.path }/acquire`) ); } else if (device.features.bootloader_mode) { dispatch( push(`/device/${ device.path }/bootloader`) ); - } else if (device.instance) { + } else if (typeof device.instance === 'number') { dispatch( push(`/device/${ device.features.device_id }:${ device.instance }`) ); } else { - const urlParams: any = getState().router.location.params; + const deviceId: string = device.features.device_id; + const urlParams: RouterLocationState = getState().router.location.state; // let url: string = `/device/${ device.features.device_id }/network/ethereum/address/0`; - let url: string = `/device/${ device.features.device_id }`; - let instance: ?string; + let url: string = `/device/${ deviceId }`; + let instance: ?number; // check if device is not TrezorDevice type if (!device.hasOwnProperty('ts')) { // its device from trezor-connect (called in initConnectedDevice triggered by device_connect event) @@ -173,15 +252,15 @@ export const onSelectDevice = (device: any): any => { // check if current location is not set to this device //dispatch( push(`/device/${ device.features.device_id }/network/etc/address/0`) ); - if (urlParams.deviceInstance !== instance || urlParams.device !== device.features.device_id) { + if (urlParams.deviceInstance !== instance || urlParams.device !== deviceId) { dispatch( push(url) ); } } } } -export const switchToFirstAvailableDevice = (): any => { - return async (dispatch, getState): Promise => { +export const switchToFirstAvailableDevice = (): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { const { devices } = getState().connect; if (devices.length > 0) { @@ -208,8 +287,8 @@ export const switchToFirstAvailableDevice = (): any => { } -export const getSelectedDeviceState = (): any => { - return async (dispatch, getState): Promise => { +export const getSelectedDeviceState = (): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { const selected = findSelectedDevice(getState().connect); console.warn("init selected", selected) if (selected @@ -260,13 +339,13 @@ export const getSelectedDeviceState = (): any => { } } -export const deviceDisconnect = (device: any): any => { - return async (dispatch, getState): Promise => { +export const deviceDisconnect = (device: Device): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { - const selected = findSelectedDevice(getState().connect); + const selected: ?TrezorDevice = findSelectedDevice(getState().connect); if (device && device.features) { - if (selected && selected.features.device_id === device.features.device_id) { + if (selected && selected.features && selected.features.device_id === device.features.device_id) { dispatch( DiscoveryActions.stop(selected) ); } @@ -287,9 +366,11 @@ export const deviceDisconnect = (device: any): any => { } } -export const coinChanged = (network: ?string): any => { - return (dispatch, getState): void => { - const selected = findSelectedDevice(getState().connect); +export const coinChanged = (network: ?string): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { + const selected: ?TrezorDevice = findSelectedDevice(getState().connect); + if (!selected) return; + dispatch( DiscoveryActions.stop(selected) ); if (network) { @@ -298,15 +379,16 @@ export const coinChanged = (network: ?string): any => { } } -export function reload(): any { - return async (dispatch, getState) => { +export function reload(): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { } } -export function acquire(): any { - return async (dispatch, getState) => { +export function acquire(): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { - const selected = findSelectedDevice(getState().connect); + const selected: ?TrezorDevice = findSelectedDevice(getState().connect); + if (!selected) return; // const saved = getState().connect.devices.map(d => { // if (d.state) { @@ -341,10 +423,11 @@ export function acquire(): any { if (response && response.success) { dispatch({ type: DEVICE.ACQUIRED, + device: null }) } else { // TODO: handle invalid pin? - console.log("-errror ack", response) + console.log("-error ack", response) dispatch({ type: NOTIFICATION.ADD, @@ -367,35 +450,34 @@ export function acquire(): any { } } -export const forgetDevice = (device: any) => { - return (dispatch: any, getState: any): any => { - +export const forgetDevice = (device: any): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { // find accounts associated with this device - const accounts: Array = getState().accounts.find(a => a.deviceState === device.state); + // const accounts: Array = getState().accounts.find(a => a.deviceState === device.state); // find discovery processes associated with this device - const discovery: Array = getState().discovery.find(d => d.deviceState === device.state); + // const discovery: Array = getState().discovery.find(d => d.deviceState === device.state); } } -export const gotoDeviceSettings = (device: any) => { - return (dispatch: any, getState: any): any => { +export const gotoDeviceSettings = (device: any): AsyncAction => { + return (dispatch: Dispatch, getState: GetState): void => { dispatch( push(`/device/${ device.features.device_id }/settings`) ); } } // called from Aside - device menu (forget single instance) -export const forget = (device: any) => { +export const forget = (device: any): Action => { return { type: CONNECT.FORGET_REQUEST, device }; } -export const duplicateDevice = (device: any) => { - return async (dispatch: any, getState: any): Promise => { +export const duplicateDevice = (device: any): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { dispatch({ type: CONNECT.TRY_TO_DUPLICATE, device @@ -403,17 +485,18 @@ export const duplicateDevice = (device: any) => { } } -export const onDuplicateDevice = () => { - return async (dispatch: any, getState: any): Promise => { - const selected = findSelectedDevice(getState().connect); - dispatch(onSelectDevice(selected)); +export const onDuplicateDevice = (): AsyncAction => { + return async (dispatch: Dispatch, getState: GetState): Promise => { + const selected: ?TrezorDevice = findSelectedDevice(getState().connect); + if (selected) + dispatch(onSelectDevice(selected)); } } -export function addAddress(): any { - return (dispatch, getState) => { +export function addAddress(): AsyncAction { + return (dispatch: Dispatch, getState: GetState): void => { const selected = findSelectedDevice(getState().connect); - dispatch( DiscoveryActions.start(selected, getState().router.location.params.network, true) ); // TODO: network nicer + dispatch( DiscoveryActions.start(selected, getState().router.location.state.network, true) ); // TODO: network nicer } } diff --git a/src/js/actions/WalletActions.js b/src/js/actions/WalletActions.js index 10649ef8..589e1dad 100644 --- a/src/js/actions/WalletActions.js +++ b/src/js/actions/WalletActions.js @@ -1,23 +1,28 @@ /* @flow */ 'use strict'; -export const ON_RESIZE: string = 'ON_RESIZE'; -export const TOGGLE_DEVICE_DROPDOWN: string = 'TOGGLE_DEVICE_DROPDOWN'; import * as WALLET from './constants/wallet'; -export const onResize = (): any => { - return { - type: ON_RESIZE - } +import type { RouterLocationState } from '../flowtype'; + +export type WalletAction = { + type: typeof WALLET.SET_INITIAL_URL, + state?: RouterLocationState, + pathname?: string +} | { + type: typeof WALLET.TOGGLE_DEVICE_DROPDOWN, + opened: boolean +} | { + type: typeof WALLET.ON_BEFORE_UNLOAD } -export const onBeforeUnload = (): any => { +export const onBeforeUnload = (): WalletAction => { return { type: WALLET.ON_BEFORE_UNLOAD } } -export const toggleDeviceDropdown = (opened: boolean): any => { +export const toggleDeviceDropdown = (opened: boolean): WalletAction => { return { type: WALLET.TOGGLE_DEVICE_DROPDOWN, opened diff --git a/src/js/actions/Web3Actions.js b/src/js/actions/Web3Actions.js index 4ead2c7e..1b2de3d4 100644 --- a/src/js/actions/Web3Actions.js +++ b/src/js/actions/Web3Actions.js @@ -1,7 +1,7 @@ /* @flow */ 'use strict'; -import Web3 from 'web3'; +import Web3, { ContractFactory, Contract } from 'web3'; import HDKey from 'hdkey'; import EthereumjsUtil from 'ethereumjs-util'; import EthereumjsTx from 'ethereumjs-tx'; @@ -9,48 +9,47 @@ import TrezorConnect from 'trezor-connect'; import { strip } from '../utils/ethUtils'; import * as ADDRESS from './constants/address'; import * as WEB3 from './constants/web3'; -import { httpRequest } from '../utils/networkUtils'; -type ActionMethod = (dispatch: any, getState: any) => Promise; +import type { + Dispatch, + GetState, + Action, + AsyncAction, +} from '../flowtype'; + +import type { Account } from '../reducers/AccountsReducer'; + +export type Web3Action = { + type: typeof WEB3.READY, +} | { + type: typeof WEB3.PENDING_TX_RESOLVED +} | Web3CreateAction + | Web3UpdateBlockAction + | Web3UpdateGasPriceAction; + +export type Web3CreateAction = { + type: typeof WEB3.CREATE, + network: string, + web3: any, //(web3instance) + erc20: any, + chainId: string; +}; -type Web3Payload = -| { - name: string; - instance: Web3; - chainId: number; - erc20abi: any; -} -| { - network: string; - blockHash: string; -} -| { - network: string; - gasPrice: string; -} -| { - network: string; - address: string; - balance: string; -} -| { - network: string; - address: string; - nonce: string; -} -| { - network: string; - blockHash: string; +export type Web3UpdateBlockAction = { + type: typeof WEB3.BLOCK_UPDATED, + network: string, + blockHash: any }; -type Web3Action = { - type: string, - payload?: Web3Payload +export type Web3UpdateGasPriceAction = { + type: typeof WEB3.GAS_PRICE_UPDATED, + network: string, + gasPrice: any }; -export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod { - return async (dispatch, getState) => { +export function init(web3: ?Web3, coinIndex: number = 0): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { const { config, ERC20Abi } = getState().localStorage; @@ -191,48 +190,48 @@ export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod { } -export function initContracts(): ActionMethod { - return async (dispatch, getState) => { - const { web3, abi, tokens } = getState().web3; - - const contracts = []; - for (let token of tokens) { - contracts.push({ - contract: web3.eth.contract(abi).at(token.address), - name: token.name, - symbol: token.symbol, - decimal: token.decimal - }); - - // web3.eth.contract(abi).at(token.address).balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => { - // console.warn('contrR', e, r.toString(10)); - // }); - } - - const contract = web3.eth.contract(abi).at('0x58cda554935e4a1f2acbe15f8757400af275e084'); - - contract.name.call((error, name) => { - if (error) { - // TODO: skip - } - contract.symbol.call((error, symbol) => { - if (error) { - // TODO: skip - } - - contract.decimals.call((error, decimals) => { - console.log("nameeeee", name, symbol, decimals) - }) - }); +// export function initContracts(): AsyncAction { +// return async (dispatch: Dispatch, getState: GetState): Promise => { +// const { web3, abi, tokens } = getState().web3; + +// const contracts = []; +// for (let token of tokens) { +// contracts.push({ +// contract: web3.eth.contract(abi).at(token.address), +// name: token.name, +// symbol: token.symbol, +// decimal: token.decimal +// }); + +// // web3.eth.contract(abi).at(token.address).balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => { +// // console.warn('contrR', e, r.toString(10)); +// // }); +// } + +// const contract = web3.eth.contract(abi).at('0x58cda554935e4a1f2acbe15f8757400af275e084'); + +// contract.name.call((error, name) => { +// if (error) { +// // TODO: skip +// } +// contract.symbol.call((error, symbol) => { +// if (error) { +// // TODO: skip +// } + +// contract.decimals.call((error, decimals) => { +// console.log("nameeeee", name, symbol, decimals) +// }) +// }); - }) - } -} +// }) +// } +// } -export function getGasPrice(network: string): ActionMethod { - return async (dispatch, getState) => { +export function getGasPrice(network: string): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { const index: number = getState().web3.findIndex(w3 => w3.network === network); @@ -252,20 +251,20 @@ export function getGasPrice(network: string): ActionMethod { } } -export function getBalance(addr: Address): ActionMethod { - return async (dispatch, getState) => { +export function getBalance(account: Account): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === addr.network)[0]; - const web3 = web3instance.web3; + const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0]; + const web3: Web3 = web3instance.web3; - web3.eth.getBalance(addr.address, (error, balance) => { + web3.eth.getBalance(account.address, (error, balance) => { if (!error) { const newBalance: string = web3.fromWei(balance.toString(), 'ether'); - if (addr.balance !== newBalance) { + if (account.balance !== newBalance) { dispatch({ type: ADDRESS.SET_BALANCE, - address: addr.address, - network: addr.network, + address: account.address, + network: account.network, balance: newBalance }); @@ -276,20 +275,20 @@ export function getBalance(addr: Address): ActionMethod { } } -export function getNonce(addr: Address) { +export function getNonce(account: Account): AsyncAction { - return async (dispatch, getState) => { + return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === addr.network)[0]; + const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0]; const web3 = web3instance.web3; - web3.eth.getTransactionCount(addr.address, (error, result) => { + web3.eth.getTransactionCount(account.address, (error, result) => { if (!error) { - if (addr.nonce !== result) { + if (account.nonce !== result) { dispatch({ type: ADDRESS.SET_NONCE, - address: addr.address, - network: addr.network, + address: account.address, + network: account.network, nonce: result }); } @@ -298,8 +297,8 @@ export function getNonce(addr: Address) { } } -export function getTransactionReceipt(tx: any): any { - return async (dispatch, getState) => { +export function getTransactionReceipt(tx: any): AsyncAction { + return async (dispatch: Dispatch, getState: GetState): Promise => { const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0]; const web3 = web3instance.web3; @@ -323,14 +322,14 @@ export function getTransactionReceipt(tx: any): any { } -export function updateLastBlock(hash: string) { - return { - type: 'web3__update_last_block', - hash - } -} +// export function updateLastBlock(hash: string): Action { +// return { +// type: 'web3__update_last_block', +// hash +// } +// } -export function getTransaction(web3, txid) { +export const getTransaction = (web3: Web3, txid: string): Promise => { return new Promise((resolve, reject) => { web3.eth.getTransaction(txid, (error, result) => { if (error) { @@ -344,7 +343,7 @@ export function getTransaction(web3, txid) { -export function getBalanceAsync(web3, address) { +export const getBalanceAsync = (web3: Web3, address: string): Promise => { return new Promise((resolve, reject) => { web3.eth.getBalance(address, (error, result) => { if (error) { @@ -356,7 +355,7 @@ export function getBalanceAsync(web3, address) { }); } -export const getTokenBalanceAsync = (erc20: any, token: any, address: any): Promise => { +export const getTokenBalanceAsync = (erc20: any, token: string, address: string): Promise => { return new Promise((resolve, reject) => { const contr = erc20.at(token); @@ -370,7 +369,7 @@ export const getTokenBalanceAsync = (erc20: any, token: any, address: any): Prom }); } -export function getNonceAsync(web3, address) { +export const getNonceAsync = (web3: Web3, address: string): Promise => { return new Promise((resolve, reject) => { web3.eth.getTransactionCount(address, (error, result) => { if (error) { @@ -383,7 +382,7 @@ export function getNonceAsync(web3, address) { } -export function getTokenInfoAsync(erc20: any, address: string): Promise { +export const getTokenInfoAsync = (erc20: any, address: string): Promise => { return new Promise((resolve, reject) => { const contract = erc20.at(address); @@ -417,7 +416,7 @@ export function getTokenInfoAsync(erc20: any, address: string): Promise { }); } -export function estimateGas(web3, gasOptions) { +export const estimateGas = (web3: Web3, gasOptions: any): Promise => { return new Promise((resolve, reject) => { web3.eth.estimateGas(gasOptions, (error, result) => { if (error) { @@ -429,7 +428,7 @@ export function estimateGas(web3, gasOptions) { }) } -export function getGasPrice2(web3) { +export const getGasPrice2 = (web3: Web3): Promise => { return new Promise((resolve, reject) => { web3.eth.getGasPrice((error, result) => { if (error) { @@ -441,7 +440,7 @@ export function getGasPrice2(web3) { }) } -export function pushTx(web3, tx) { +export const pushTx = (web3: Web3, tx: any): Promise => { return new Promise((resolve, reject) => { web3.eth.sendRawTransaction(tx, (error, result) => { if (error) { @@ -452,7 +451,3 @@ export function pushTx(web3, tx) { }); }) } - - - - diff --git a/src/js/actions/constants/TrezorConnect.js b/src/js/actions/constants/TrezorConnect.js index 06b0a4b4..db6cc452 100644 --- a/src/js/actions/constants/TrezorConnect.js +++ b/src/js/actions/constants/TrezorConnect.js @@ -1,26 +1,29 @@ /* @flow */ 'use strict'; -export const READY: string = 'trezorconnect__ready'; -export const INITIALIZATION_ERROR: string = 'trezorconnect__init_error'; -export const SELECT_DEVICE: string = 'trezorconnect__select_device'; +//regExp1 : string = '(.*)' +//regExp2 : '$1' = '$1' +export const READY: 'trezorconnect__ready' = 'trezorconnect__ready'; +export const INITIALIZATION_ERROR: 'trezorconnect__init_error' = 'trezorconnect__init_error'; +export const SELECT_DEVICE: 'trezorconnect__select_device' = 'trezorconnect__select_device'; -export const DEVICE_FROM_STORAGE: string = 'trezorconnect__device_from_storage'; -export const AUTH_DEVICE: string = 'trezorconnect__auth_device'; -export const COIN_CHANGED: string = 'trezorconnect__coin_changed'; -export const REMEMBER_REQUEST: string = 'trezorconnect__remember_request'; -export const FORGET_REQUEST: string = 'trezorconnect__forget_request'; -export const FORGET: string = 'trezorconnect__forget'; -export const FORGET_SINGLE: string = 'trezorconnect__forget_single'; -export const DISCONNECT_REQUEST: string = 'trezorconnect__disconnect_request'; -export const REMEMBER: string = 'trezorconnect__remember'; +export const DEVICE_FROM_STORAGE: 'trezorconnect__device_from_storage' = 'trezorconnect__device_from_storage'; +export const AUTH_DEVICE: 'trezorconnect__auth_device' = 'trezorconnect__auth_device'; +export const COIN_CHANGED: 'trezorconnect__coin_changed' = 'trezorconnect__coin_changed'; -export const START_ACQUIRING: string = 'trezorconnect__start_acquiring'; -export const STOP_ACQUIRING: string = 'trezorconnect__stop_acquiring'; +export const REMEMBER_REQUEST: 'trezorconnect__remember_request' = 'trezorconnect__remember_request'; +export const FORGET_REQUEST: 'trezorconnect__forget_request' = 'trezorconnect__forget_request'; +export const FORGET: 'trezorconnect__forget' = 'trezorconnect__forget'; +export const FORGET_SINGLE: 'trezorconnect__forget_single' = 'trezorconnect__forget_single'; +export const DISCONNECT_REQUEST: 'trezorconnect__disconnect_request' = 'trezorconnect__disconnect_request'; +export const REMEMBER: 'trezorconnect__remember' = 'trezorconnect__remember'; -export const TRY_TO_DUPLICATE: string = 'trezorconnect__try_to_duplicate'; -export const DUPLICATE: string = 'trezorconnect__duplicate'; +export const START_ACQUIRING: 'trezorconnect__start_acquiring' = 'trezorconnect__start_acquiring'; +export const STOP_ACQUIRING: 'trezorconnect__stop_acquiring' = 'trezorconnect__stop_acquiring'; -export const DEVICE_STATE_EXCEPTION: string = 'trezorconnect__device_state_exception'; \ No newline at end of file +export const TRY_TO_DUPLICATE: 'trezorconnect__try_to_duplicate' = 'trezorconnect__try_to_duplicate'; +export const DUPLICATE: 'trezorconnect__duplicate' = 'trezorconnect__duplicate'; + +export const DEVICE_STATE_EXCEPTION: 'trezorconnect__device_state_exception' = 'trezorconnect__device_state_exception'; \ No newline at end of file diff --git a/src/js/actions/constants/account.js b/src/js/actions/constants/account.js index d6bcb858..36ae5327 100644 --- a/src/js/actions/constants/account.js +++ b/src/js/actions/constants/account.js @@ -1,11 +1,11 @@ /* @flow */ 'use strict'; -export const INIT: string = 'account__init'; -export const DISPOSE: string = 'account__dispose'; +export const INIT: 'account__init' = 'account__init'; +export const DISPOSE: 'account__dispose' = 'account__dispose'; -export const CREATE: string = 'address__create'; -export const REMOVE: string = 'address__remove'; -export const SET_BALANCE: string = 'address__set_balance'; -export const SET_NONCE: string = 'address__set_nonce'; -export const FROM_STORAGE: string = 'address__from_storage'; \ No newline at end of file +// export const CREATE: 'address__create' = 'address__create'; +// export const REMOVE: 'address__remove' = 'address__remove'; +// export const SET_BALANCE: 'address__set_balance' = 'address__set_balance'; +// export const SET_NONCE: 'address__set_nonce' = 'address__set_nonce'; +// export const FROM_STORAGE: 'address__from_storage' = 'address__from_storage'; \ No newline at end of file diff --git a/src/js/actions/constants/address.js b/src/js/actions/constants/address.js index 23e87cd0..03c1931f 100644 --- a/src/js/actions/constants/address.js +++ b/src/js/actions/constants/address.js @@ -1,9 +1,9 @@ /* @flow */ 'use strict'; -export const CREATE: string = 'address__create'; -export const REMOVE: string = 'address__remove'; -export const SET_BALANCE: string = 'address__set_balance'; -export const SET_NONCE: string = 'address__set_nonce'; -export const FROM_STORAGE: string = 'address__from_storage'; +export const CREATE: 'address__create' = 'address__create'; +export const REMOVE: 'address__remove' = 'address__remove'; +export const SET_BALANCE: 'address__set_balance' = 'address__set_balance'; +export const SET_NONCE: 'address__set_nonce' = 'address__set_nonce'; +export const FROM_STORAGE: 'address__from_storage' = 'address__from_storage'; diff --git a/src/js/actions/constants/discovery.js b/src/js/actions/constants/discovery.js index 152f43d3..e43bc4c7 100644 --- a/src/js/actions/constants/discovery.js +++ b/src/js/actions/constants/discovery.js @@ -1,8 +1,8 @@ /* @flow */ 'use strict'; -export const START: string = 'discovery__start'; -export const STOP: string = 'discovery__stop'; -export const COMPLETE: string = 'discovery__complete'; -export const WAITING: string = 'discovery__waiting'; -export const FROM_STORAGE: string = 'discovery__from_storage'; \ No newline at end of file +export const START: 'discovery__start' = 'discovery__start'; +export const STOP: 'discovery__stop' = 'discovery__stop'; +export const COMPLETE: 'discovery__complete' = 'discovery__complete'; +export const WAITING: 'discovery__waiting' = 'discovery__waiting'; +export const FROM_STORAGE: 'discovery__from_storage' = 'discovery__from_storage'; \ No newline at end of file diff --git a/src/js/actions/constants/localStorage.js b/src/js/actions/constants/localStorage.js index 479d9672..9c73badd 100644 --- a/src/js/actions/constants/localStorage.js +++ b/src/js/actions/constants/localStorage.js @@ -1,6 +1,6 @@ /* @flow */ 'use strict'; -export const SAVE: string = 'storage__save'; -export const READY: string = 'storage__ready'; -export const ERROR: string = 'storage__error'; \ No newline at end of file +export const SAVE: 'storage__save' = 'storage__save'; +export const READY: 'storage__ready' = 'storage__ready'; +export const ERROR: 'storage__error' = 'storage__error'; \ No newline at end of file diff --git a/src/js/actions/constants/log.js b/src/js/actions/constants/log.js new file mode 100644 index 00000000..de85d8eb --- /dev/null +++ b/src/js/actions/constants/log.js @@ -0,0 +1,5 @@ +/* @flow */ +'use strict'; + +export const OPEN: 'log__open' = 'log__open'; +export const CLOSE: 'log__close' = 'log__close'; \ No newline at end of file diff --git a/src/js/actions/constants/modal.js b/src/js/actions/constants/modal.js index 4f20c0fe..a0949ebd 100644 --- a/src/js/actions/constants/modal.js +++ b/src/js/actions/constants/modal.js @@ -1,14 +1,17 @@ -export const ON_PASSPHRASE_CHANGE: string = 'action__on_passphrase_change'; -export const ON_PASSPHRASE_SHOW: string = 'action__on_passphrase_show'; -export const ON_PASSPHRASE_HIDE: string = 'action__on_passphrase_hide'; -export const ON_PASSPHRASE_SAVE: string = 'action__on_passphrase_save'; -export const ON_PASSPHRASE_FORGET: string = 'action__on_passphrase_forget'; -export const ON_PASSPHRASE_FOCUS: string = 'action__on_passphrase_focus'; -export const ON_PASSPHRASE_BLUR: string = 'action__on_passphrase_blur'; -export const ON_PASSPHRASE_SUBMIT: string = 'action__on_passphrase_submit'; +/* @flow */ +'use strict'; -export const FORGET: string = 'modal__forget'; -export const REMEMBER: string = 'modal__remember'; -export const ON_FORGET: string = 'modal__on_forget'; -export const ON_REMEMBER: string = 'modal__on_remember'; -export const CLOSE: string = 'modal__close'; +export const ON_PASSPHRASE_CHANGE: 'action__on_passphrase_change' = 'action__on_passphrase_change'; +export const ON_PASSPHRASE_SHOW: 'action__on_passphrase_show' = 'action__on_passphrase_show'; +export const ON_PASSPHRASE_HIDE: 'action__on_passphrase_hide' = 'action__on_passphrase_hide'; +export const ON_PASSPHRASE_SAVE: 'action__on_passphrase_save' = 'action__on_passphrase_save'; +export const ON_PASSPHRASE_FORGET: 'action__on_passphrase_forget' = 'action__on_passphrase_forget'; +export const ON_PASSPHRASE_FOCUS: 'action__on_passphrase_focus' = 'action__on_passphrase_focus'; +export const ON_PASSPHRASE_BLUR: 'action__on_passphrase_blur' = 'action__on_passphrase_blur'; +export const ON_PASSPHRASE_SUBMIT: 'action__on_passphrase_submit' = 'action__on_passphrase_submit'; + +export const FORGET: 'modal__forget' = 'modal__forget'; +export const REMEMBER: 'modal__remember' = 'modal__remember'; +export const ON_FORGET: 'modal__on_forget' = 'modal__on_forget'; +export const ON_REMEMBER: 'modal__on_remember' = 'modal__on_remember'; +export const CLOSE: 'modal__close' = 'modal__close'; diff --git a/src/js/actions/constants/notification.js b/src/js/actions/constants/notification.js index d1acbcc5..0b14d504 100644 --- a/src/js/actions/constants/notification.js +++ b/src/js/actions/constants/notification.js @@ -1,6 +1,6 @@ /* @flow */ 'use strict'; -export const ADD: string = 'notification__add'; -export const CLOSE: string = 'notification__close'; -export const REMOVE: string = 'account__remove'; \ No newline at end of file +export const ADD: 'notification__add' = 'notification__add'; +export const CLOSE: 'notification__close' = 'notification__close'; +export const REMOVE: 'account__remove' = 'account__remove'; \ No newline at end of file diff --git a/src/js/actions/constants/receive.js b/src/js/actions/constants/receive.js index 49c0f5cd..0cb397aa 100644 --- a/src/js/actions/constants/receive.js +++ b/src/js/actions/constants/receive.js @@ -1,8 +1,8 @@ /* @flow */ 'use strict'; -export const INIT: string = 'receive__init'; -export const DISPOSE: string = 'receive__dispose'; -export const REQUEST_UNVERIFIED: string = 'receive__request_unverified'; -export const SHOW_ADDRESS: string = 'receive__show_address'; -export const SHOW_UNVERIFIED_ADDRESS: string = 'receive__show_unverified'; +export const INIT: 'receive__init' = 'receive__init'; +export const DISPOSE: 'receive__dispose' = 'receive__dispose'; +export const REQUEST_UNVERIFIED: 'receive__request_unverified' = 'receive__request_unverified'; +export const SHOW_ADDRESS: 'receive__show_address' = 'receive__show_address'; +export const SHOW_UNVERIFIED_ADDRESS: 'receive__show_unverified' = 'receive__show_unverified'; diff --git a/src/js/actions/constants/send.js b/src/js/actions/constants/send.js index 7e33336b..15c65690 100644 --- a/src/js/actions/constants/send.js +++ b/src/js/actions/constants/send.js @@ -1,19 +1,19 @@ /* @flow */ 'use strict'; -export const INIT: string = 'send__init'; -export const DISPOSE: string = 'send__dispose'; -export const VALIDATION: string = 'send__validation'; -export const ADDRESS_CHANGE: string = 'send__address_change'; -export const AMOUNT_CHANGE: string = 'send__amount_change'; -export const SET_MAX: string = 'send__set_max'; -export const CURRENCY_CHANGE: string = 'send__currency_change'; -export const FEE_LEVEL_CHANGE: string = 'send__fee_level_change'; -export const GAS_PRICE_CHANGE: string = 'send__gas_price_change'; -export const GAS_LIMIT_CHANGE: string = 'send__gas_limit_change'; -export const UPDATE_FEE_LEVELS: string = 'send__update_fee_levels'; -export const DATA_CHANGE: string = 'send__data_change'; -export const SEND: string = 'send__submit'; -export const TX_COMPLETE: string = 'send__tx_complete'; -export const TX_ERROR: string = 'send__tx_error'; -export const TOGGLE_ADVANCED: string = 'send__toggle_advanced'; \ No newline at end of file +export const INIT: 'send__init' = 'send__init'; +export const DISPOSE: 'send__dispose' = 'send__dispose'; +export const VALIDATION: 'send__validation' = 'send__validation'; +export const ADDRESS_CHANGE: 'send__address_change' = 'send__address_change'; +export const AMOUNT_CHANGE: 'send__amount_change' = 'send__amount_change'; +export const SET_MAX: 'send__set_max' = 'send__set_max'; +export const CURRENCY_CHANGE: 'send__currency_change' = 'send__currency_change'; +export const FEE_LEVEL_CHANGE: 'send__fee_level_change' = 'send__fee_level_change'; +export const GAS_PRICE_CHANGE: 'send__gas_price_change' = 'send__gas_price_change'; +export const GAS_LIMIT_CHANGE: 'send__gas_limit_change' = 'send__gas_limit_change'; +export const UPDATE_FEE_LEVELS: 'send__update_fee_levels' = 'send__update_fee_levels'; +export const DATA_CHANGE: 'send__data_change' = 'send__data_change'; +export const SEND: 'send__submit' = 'send__submit'; +export const TX_COMPLETE: 'send__tx_complete' = 'send__tx_complete'; +export const TX_ERROR: 'send__tx_error' = 'send__tx_error'; +export const TOGGLE_ADVANCED: 'send__toggle_advanced' = 'send__toggle_advanced'; \ No newline at end of file diff --git a/src/js/actions/constants/summary.js b/src/js/actions/constants/summary.js index 02dae814..ebb82c95 100644 --- a/src/js/actions/constants/summary.js +++ b/src/js/actions/constants/summary.js @@ -1,7 +1,7 @@ /* @flow */ 'use strict'; -export const INIT: string = 'summary__init'; -export const DISPOSE: string = 'summary__dispose'; -export const ADD_TOKEN: string = 'summary__add_token'; -export const DETAILS_TOGGLE: string = 'summary__details_toggle'; +export const INIT: 'summary__init' = 'summary__init'; +export const DISPOSE: 'summary__dispose' = 'summary__dispose'; +export const ADD_TOKEN: 'summary__add_token' = 'summary__add_token'; +export const DETAILS_TOGGLE: 'summary__details_toggle' = 'summary__details_toggle'; diff --git a/src/js/actions/constants/token.js b/src/js/actions/constants/token.js index ed88dc03..5878c5b5 100644 --- a/src/js/actions/constants/token.js +++ b/src/js/actions/constants/token.js @@ -1,7 +1,7 @@ /* @flow */ 'use strict'; -export const ADD: string = 'token__add'; -export const REMOVE: string = 'token__remove'; -export const SET_BALANCE: string = 'token__set_balance'; -export const FROM_STORAGE: string = 'token__from_storage'; \ No newline at end of file +export const ADD: 'token__add' = 'token__add'; +export const REMOVE: 'token__remove' = 'token__remove'; +export const SET_BALANCE: 'token__set_balance' = 'token__set_balance'; +export const FROM_STORAGE: 'token__from_storage' = 'token__from_storage'; \ No newline at end of file diff --git a/src/js/actions/constants/wallet.js b/src/js/actions/constants/wallet.js index 675a0fc8..fd93b50a 100644 --- a/src/js/actions/constants/wallet.js +++ b/src/js/actions/constants/wallet.js @@ -1,6 +1,6 @@ /* @flow */ 'use strict'; -export const ON_BEFORE_UNLOAD: string = 'wallet__on_before_unload'; -export const TOGGLE_DEVICE_DROPDOWN: string = 'wallet_toggle_dropdown'; -export const SET_INITIAL_URL: string = 'wallet_set_initial_url'; \ No newline at end of file +export const ON_BEFORE_UNLOAD: 'wallet__on_before_unload' = 'wallet__on_before_unload'; +export const TOGGLE_DEVICE_DROPDOWN: 'wallet_toggle_dropdown' = 'wallet_toggle_dropdown'; +export const SET_INITIAL_URL: 'wallet_set_initial_url' = 'wallet_set_initial_url'; \ No newline at end of file diff --git a/src/js/actions/constants/web3.js b/src/js/actions/constants/web3.js index f1e3eee8..ad55001f 100644 --- a/src/js/actions/constants/web3.js +++ b/src/js/actions/constants/web3.js @@ -1,10 +1,10 @@ /* @flow */ 'use strict'; -export const START: string = 'web3__start'; -export const STOP: string = 'web3__stop'; -export const CREATE: string = 'web3__create'; -export const READY: string = 'web3__ready'; -export const BLOCK_UPDATED: string = 'web3__block_updated'; -export const GAS_PRICE_UPDATED: string = 'web3__gas_price_updated'; -export const PENDING_TX_RESOLVED: string = 'web3__pending_tx_resolved'; \ No newline at end of file +export const START: 'web3__start' = 'web3__start'; +export const STOP: 'web3__stop' = 'web3__stop'; +export const CREATE: 'web3__create' = 'web3__create'; +export const READY: 'web3__ready' = 'web3__ready'; +export const BLOCK_UPDATED: 'web3__block_updated' = 'web3__block_updated'; +export const GAS_PRICE_UPDATED: 'web3__gas_price_updated' = 'web3__gas_price_updated'; +export const PENDING_TX_RESOLVED: 'web3__pending_tx_resolved' = 'web3__pending_tx_resolved'; \ No newline at end of file diff --git a/src/js/components/common/Footer.js b/src/js/components/common/Footer.js index 552d68f3..84165aef 100644 --- a/src/js/components/common/Footer.js +++ b/src/js/components/common/Footer.js @@ -6,8 +6,13 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import * as LogActions from '../../actions/LogActions'; +import type { State, Dispatch } from '../../flowtype'; -const Footer = (props: any): any => { +type Props = { + toggle: typeof LogActions.toggle +} + +const Footer = (props: Props): React$Element => { return (