diff --git a/.flowconfig b/.flowconfig index a3a80352..97214ee1 100644 --- a/.flowconfig +++ b/.flowconfig @@ -6,7 +6,6 @@ .*/node_modules/react-redux/.* .*/node_modules/redux/.* .*/node_modules/react-router/.* -.*/node_modules/react-router-redux/.* .*/node_modules/oboe/test/.* .*/_old/.* .*/scripts/solidity/.* @@ -17,7 +16,7 @@ ./src/flowtype/npm/react-redux_v5.x.x.js ./src/flowtype/npm/react-router_v4.x.x.js ./src/flowtype/npm/react-router-dom_v4.x.x.js -./src/flowtype/npm/react-router-redux.js +./src/flowtype/npm/connected-react-router.js ./src/flowtype/npm/bignumber.js ./src/flowtype/npm/ethereum-types.js ./src/flowtype/npm/web3.js diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3092eec3..f0a4b250 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,9 @@ image: node:9.3 cache: + key: ${CI_COMMIT_REF_SLUG} paths: - - node_modules + - node_modules/ stages: - test @@ -18,6 +19,7 @@ lint: flow: stage: test script: + - yarn install - yarn run flow unit: diff --git a/package.json b/package.json index f5387414..11e2b53d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "bignumber.js": "2.4.0", "color-hash": "^1.0.3", "commander": "^2.19.0", + "connected-react-router": "^6.0.0", "copy-webpack-plugin": "^4.5.2", "cross-env": "^5.2.0", "date-fns": "^1.29.0", @@ -54,9 +55,9 @@ "react-hot-loader": "^4.6.2", "react-json-view": "^1.19.1", "react-qr-svg": "^2.1.0", - "react-redux": "^5.0.7", + "react-redux": "^6.0.0", + "react-router": "^4.3.1", "react-router-dom": "^4.2.2", - "react-router-redux": "next", "react-scale-text": "^1.2.2", "react-select": "2.0.0", "react-textarea-autosize": "^7.0.4", diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index 27d4c46b..6b918df8 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -4,59 +4,13 @@ import * as ACCOUNT from 'actions/constants/account'; import type { Action } from 'flowtype'; import type { Account, State } from 'reducers/AccountsReducer'; -export type AccountFromStorageAction = { +export type AccountAction = { type: typeof ACCOUNT.FROM_STORAGE, payload: State -} - -export type AccountCreateAction = { - type: typeof ACCOUNT.CREATE, +} | { + type: typeof ACCOUNT.CREATE | typeof ACCOUNT.UPDATE, payload: Account, -} - -export type AccountUpdateAction = { - type: typeof ACCOUNT.UPDATE, - payload: Account, -} - -export type AccountSetBalanceAction = { - type: typeof ACCOUNT.SET_BALANCE, - address: string, - network: string, - deviceState: string, - balance: string -} - -export type AccountSetNonceAction = { - type: typeof ACCOUNT.SET_NONCE, - address: string, - network: string, - deviceState: string, - nonce: number -} - -export type AccountAction = - AccountFromStorageAction - | AccountCreateAction - | AccountUpdateAction - | AccountSetBalanceAction - | AccountSetNonceAction; - -export const setBalance = (address: string, network: string, deviceState: string, balance: string): Action => ({ - type: ACCOUNT.SET_BALANCE, - address, - network, - deviceState, - balance, -}); - -export const setNonce = (address: string, network: string, deviceState: string, nonce: number): Action => ({ - type: ACCOUNT.SET_NONCE, - address, - network, - deviceState, - nonce, -}); +}; export const update = (account: Account): Action => ({ type: ACCOUNT.UPDATE, diff --git a/src/actions/LocalStorageActions.js b/src/actions/LocalStorageActions.js index c3380891..7742b345 100644 --- a/src/actions/LocalStorageActions.js +++ b/src/actions/LocalStorageActions.js @@ -12,7 +12,7 @@ import { httpRequest } from 'utils/networkUtils'; import * as buildUtils from 'utils/build'; import * as storageUtils from 'utils/storage'; -import { findAccountTokens } from 'reducers/TokensReducer'; +import { getAccountTokens } from 'reducers/utils'; import type { Account } from 'reducers/AccountsReducer'; import type { Token } from 'reducers/TokensReducer'; import type { Discovery } from 'reducers/DiscoveryReducer'; @@ -59,11 +59,11 @@ const KEY_BETA_MODAL: string = '/betaModalPrivacy'; // this key needs to be comp const findAccounts = (devices: Array, accounts: Array): Array => devices.reduce((arr, dev) => arr.concat(accounts.filter(a => a.deviceState === dev.state)), []); -const findTokens = (accounts: Array, tokens: Array): Array => accounts.reduce((arr, account) => arr.concat(findAccountTokens(tokens, account)), []); +const findTokens = (accounts: Array, tokens: Array): Array => accounts.reduce((arr, account) => arr.concat(getAccountTokens(tokens, account)), []); const findDiscovery = (devices: Array, discovery: Array): Array => devices.reduce((arr, dev) => arr.concat(discovery.filter(d => d.deviceState === dev.state && d.completed)), []); -const findPendingTxs = (accounts: Array, pending: Array): Array => accounts.reduce((result, account) => result.concat(pending.filter(p => p.address === account.address && p.network === account.network)), []); +const findPendingTxs = (accounts: Array, pending: Array): Array => accounts.reduce((result, account) => result.concat(pending.filter(p => p.address === account.descriptor && p.network === account.network)), []); export const save = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const devices: Array = getState().devices.filter(d => d.features && d.remember === true); diff --git a/src/actions/RouterActions.js b/src/actions/RouterActions.js index 3cb7dea1..3d501714 100644 --- a/src/actions/RouterActions.js +++ b/src/actions/RouterActions.js @@ -1,8 +1,8 @@ /* @flow */ -import { push, LOCATION_CHANGE } from 'react-router-redux'; +import { push, LOCATION_CHANGE } from 'connected-react-router'; import { CONTEXT_NONE } from 'actions/constants/modal'; -import { SET_INITIAL_URL } from 'actions/constants/wallet'; +import { SET_INITIAL_URL, SET_FIRST_LOCATION_CHANGE } from 'actions/constants/wallet'; import { routes } from 'support/routes'; import * as deviceUtils from 'utils/device'; @@ -15,7 +15,7 @@ import type { Dispatch, GetState, } from 'flowtype'; -import type { RouterAction } from 'react-router-redux'; +import type { RouterAction } from 'connected-react-router'; /* * Parse url string to RouterLocationState object (key/value) @@ -51,6 +51,7 @@ export const pathToParams = (path: string): PayloadAction = */ export const paramsValidation = (params: RouterLocationState): PayloadAction => (dispatch: Dispatch, getState: GetState): boolean => { // validate requested device + if (params.hasOwnProperty('device')) { const { devices } = getState(); @@ -105,7 +106,6 @@ export const paramsToPath = (params: RouterLocationState): PayloadAction => (dispatch: Dispatch, getState: GetState): string => { const { location } = getState().router; - + const { firstLocationChange } = getState().wallet; // redirect to landing page (loading screen) // and wait until application is ready - if (!location) return '/'; + if (firstLocationChange) { + dispatch({ + type: SET_FIRST_LOCATION_CHANGE, + }); + return '/'; + } - const requestedUrl = action.payload.pathname; + const requestedUrl = action.payload.location.pathname; // Corner case: LOCATION_CHANGE was called but pathname didn't changed (redirect action from RouterService) if (requestedUrl === location.pathname) return requestedUrl; @@ -351,10 +356,12 @@ export const setInitialUrl = (): PayloadAction => (dispatch: Dispatch, const valid = dispatch(getValidUrl({ type: LOCATION_CHANGE, payload: { - pathname: initialPathname, - hash: '', - search: '', - state: {}, + location: { + pathname: initialPathname, + hash: '', + search: '', + state: {}, + }, }, })); diff --git a/src/actions/SelectedAccountActions.js b/src/actions/SelectedAccountActions.js index fe6a0d2e..868b7155 100644 --- a/src/actions/SelectedAccountActions.js +++ b/src/actions/SelectedAccountActions.js @@ -1,5 +1,5 @@ /* @flow */ -import { LOCATION_CHANGE } from 'react-router-redux'; +import { LOCATION_CHANGE } from 'connected-react-router'; import { BLOCKCHAIN } from 'trezor-connect'; import * as WALLET from 'actions/constants/wallet'; import * as ACCOUNT from 'actions/constants/account'; @@ -210,7 +210,7 @@ export const observe = (prevState: State, action: Action): PayloadAction async name: token.name, symbol: token.symbol, address: token.address, - ethAddress: account.address, + ethAddress: account.descriptor, decimals: token.decimals, balance: '0', }; @@ -87,7 +87,7 @@ export const add = (token: NetworkToken, account: Account): AsyncAction => async }); const tokenBalance = await dispatch(BlockchainActions.getTokenBalance(tkn)); - dispatch(setBalance(token.address, account.address, tokenBalance)); + dispatch(setBalance(token.address, account.descriptor, tokenBalance)); }; export const remove = (token: Token): Action => ({ diff --git a/src/actions/WalletActions.js b/src/actions/WalletActions.js index f0d72a1b..9e5ea9f9 100644 --- a/src/actions/WalletActions.js +++ b/src/actions/WalletActions.js @@ -1,6 +1,6 @@ /* @flow */ -import { LOCATION_CHANGE } from 'react-router-redux'; +import { LOCATION_CHANGE } from 'connected-react-router'; import { DEVICE } from 'trezor-connect'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as WALLET from 'actions/constants/wallet'; @@ -39,7 +39,7 @@ export type WalletAction = { type: typeof WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA, devices: Array } | { - type: typeof WALLET.SHOW_BETA_DISCLAIMER | typeof WALLET.HIDE_BETA_DISCLAIMER, + type: typeof WALLET.SHOW_BETA_DISCLAIMER | typeof WALLET.HIDE_BETA_DISCLAIMER | typeof WALLET.SET_FIRST_LOCATION_CHANGE, } export const init = (): ThunkAction => (dispatch: Dispatch): void => { diff --git a/src/actions/Web3Actions.js b/src/actions/Web3Actions.js index dd665224..2bb0a43e 100644 --- a/src/actions/Web3Actions.js +++ b/src/actions/Web3Actions.js @@ -193,9 +193,10 @@ export const getTxInput = (): PromiseAction => async (dispatch: Dispatch): export const updateAccount = (account: Account, newAccount: EthereumAccount, network: string): PromiseAction => async (dispatch: Dispatch): Promise => { const instance: Web3Instance = await dispatch(initWeb3(network)); - const balance = await instance.web3.eth.getBalance(account.address); - const nonce = await instance.web3.eth.getTransactionCount(account.address); + const balance = await instance.web3.eth.getBalance(account.descriptor); + const nonce = await instance.web3.eth.getTransactionCount(account.descriptor); dispatch(AccountsActions.update({ + networkType: 'ethereum', ...account, ...newAccount, nonce, @@ -208,7 +209,7 @@ export const updateAccount = (account: Account, newAccount: EthereumAccount, net }; export const updateAccountTokens = (account: Account): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { - const tokens = getState().tokens.filter(t => t.network === account.network && t.ethAddress === account.address); + const tokens = getState().tokens.filter(t => t.network === account.network && t.ethAddress === account.descriptor); tokens.forEach(async (token) => { const balance = await dispatch(getTokenBalance(token)); // const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10); diff --git a/src/actions/constants/wallet.js b/src/actions/constants/wallet.js index 6f449a7a..04615371 100644 --- a/src/actions/constants/wallet.js +++ b/src/actions/constants/wallet.js @@ -2,6 +2,7 @@ export const TOGGLE_DEVICE_DROPDOWN: 'wallet__toggle_dropdown' = 'wallet__toggle_dropdown'; export const SET_INITIAL_URL: 'wallet__set_initial_url' = 'wallet__set_initial_url'; +export const SET_FIRST_LOCATION_CHANGE: 'wallet__set_first_location_change' = 'wallet__set_first_location_change'; export const ONLINE_STATUS: 'wallet__online_status' = 'wallet__online_status'; export const SET_SELECTED_DEVICE: 'wallet__set_selected_device' = 'wallet__set_selected_device'; diff --git a/src/actions/ethereum/BlockchainActions.js b/src/actions/ethereum/BlockchainActions.js index 72dec1d7..b1856d24 100644 --- a/src/actions/ethereum/BlockchainActions.js +++ b/src/actions/ethereum/BlockchainActions.js @@ -85,7 +85,7 @@ export const estimateGasLimit = (network: string, data: string, value: string, g }; export const subscribe = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { - const accounts: Array = getState().accounts.filter(a => a.network === network).map(a => a.address); // eslint-disable-line no-unused-vars + const accounts: Array = getState().accounts.filter(a => a.network === network).map(a => a.descriptor); // eslint-disable-line no-unused-vars const response = await TrezorConnect.blockchainSubscribe({ accounts, coin: network, @@ -129,7 +129,7 @@ export const onBlockMined = (network: string): PromiseAction => async (dis export const onNotification = (payload: $ElementType): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { const { notification } = payload; - const account = getState().accounts.find(a => a.address === notification.address); + const account = getState().accounts.find(a => a.descriptor === notification.address); if (!account) return; if (notification.status === 'pending') { diff --git a/src/actions/ethereum/DiscoveryActions.js b/src/actions/ethereum/DiscoveryActions.js index e4b302b2..e1f71f83 100644 --- a/src/actions/ethereum/DiscoveryActions.js +++ b/src/actions/ethereum/DiscoveryActions.js @@ -8,13 +8,13 @@ import * as BlockchainActions from 'actions/ethereum/BlockchainActions'; import type { PromiseAction, Dispatch, + GetState, TrezorDevice, Network, Account, } from 'flowtype'; import type { Discovery } from 'reducers/DiscoveryReducer'; - export type DiscoveryStartAction = { type: typeof DISCOVERY.START, networkType: 'ethereum', @@ -61,33 +61,38 @@ export const begin = (device: TrezorDevice, network: Network): PromiseAction => async (dispatch: Dispatch): Promise => { +export const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const { config } = getState().localStorage; + const network = config.networks.find(c => c.shortcut === discoveryProcess.network); + if (!network) throw new Error('Discovery network not found'); + const derivedKey = discoveryProcess.hdKey.derive(`m/${discoveryProcess.accountIndex}`); const path = discoveryProcess.basePath.concat(discoveryProcess.accountIndex); const publicAddress: string = EthereumjsUtil.publicToAddress(derivedKey.publicKey, true).toString('hex'); const ethAddress: string = EthereumjsUtil.toChecksumAddress(publicAddress); - const { network } = discoveryProcess; // TODO: check if address was created before - const account = await dispatch(BlockchainActions.discoverAccount(device, ethAddress, network)); + const account = await dispatch(BlockchainActions.discoverAccount(device, ethAddress, network.shortcut)); // const accountIsEmpty = account.transactions <= 0 && account.nonce <= 0 && account.balance === '0'; const empty = account.nonce <= 0 && account.balance === '0'; return { + imported: false, index: discoveryProcess.accountIndex, - loaded: true, - network, + network: network.shortcut, deviceID: device.features ? device.features.device_id : '0', deviceState: device.state || '0', - addressPath: path, - address: ethAddress, + accountPath: path, + descriptor: ethAddress, + balance: account.balance, availableBalance: account.balance, - sequence: account.nonce, - nonce: account.nonce, block: account.block, transactions: account.transactions, empty, + + networkType: 'ethereum', + nonce: account.nonce, }; }; \ No newline at end of file diff --git a/src/actions/ethereum/SendFormActions.js b/src/actions/ethereum/SendFormActions.js index 6ce41239..0b4be855 100644 --- a/src/actions/ethereum/SendFormActions.js +++ b/src/actions/ethereum/SendFormActions.js @@ -8,7 +8,6 @@ import * as NOTIFICATION from 'actions/constants/notification'; import * as SEND from 'actions/constants/send'; import * as WEB3 from 'actions/constants/web3'; import { initialState } from 'reducers/SendFormEthereumReducer'; -import { findToken } from 'reducers/TokensReducer'; import * as reducerUtils from 'reducers/utils'; import * as ethUtils from 'utils/ethUtils'; @@ -76,7 +75,7 @@ export const observe = (prevState: ReducersState, action: Action): ThunkAction = // make sure that this token is added into account const { account, tokens } = getState().selectedAccount; if (!account) return; - const token = findToken(tokens, account.address, currentState.sendFormEthereum.currency, account.deviceState); + const token = reducerUtils.findToken(tokens, account.descriptor, currentState.sendFormEthereum.currency, account.deviceState); if (!token) { // token not found, re-init form dispatch(init()); @@ -456,7 +455,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge pending, } = getState().selectedAccount; - if (!account || !network) return; + if (!account || account.networkType !== 'ethereum' || !network) return; const currentState: State = getState().sendFormEthereum; @@ -466,8 +465,8 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge const txData = await dispatch(prepareEthereumTx({ network: network.shortcut, - token: isToken ? findToken(getState().tokens, account.address, currentState.currency, account.deviceState) : null, - from: account.address, + token: isToken ? reducerUtils.findToken(getState().tokens, account.descriptor, currentState.currency, account.deviceState) : null, + from: account.descriptor, to: currentState.address, amount: currentState.amount, data: currentState.data, @@ -487,7 +486,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge }, // useEmptyPassphrase: !selected.instance, useEmptyPassphrase: selected.useEmptyPassphrase, - path: account.addressPath, + path: account.accountPath, transaction: txData, }); @@ -533,10 +532,10 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge type: 'send', status: 'pending', confirmations: 0, - address: account.address, + address: account.descriptor, inputs: [ { - addresses: [account.address], + addresses: [account.descriptor], amount: currentState.amount, fee, total: currentState.total, diff --git a/src/actions/ethereum/SendFormValidationActions.js b/src/actions/ethereum/SendFormValidationActions.js index b7985b09..46451fb5 100644 --- a/src/actions/ethereum/SendFormValidationActions.js +++ b/src/actions/ethereum/SendFormValidationActions.js @@ -3,8 +3,7 @@ import BigNumber from 'bignumber.js'; import EthereumjsUtil from 'ethereumjs-util'; import EthereumjsUnits from 'ethereumjs-units'; -import { findToken } from 'reducers/TokensReducer'; -import { findDevice, getPendingAmount } from 'reducers/utils'; +import { findDevice, getPendingAmount, findToken } from 'reducers/utils'; import * as SEND from 'actions/constants/send'; import * as ethUtils from 'utils/ethUtils'; @@ -114,7 +113,7 @@ export const recalculateTotalAmount = ($state: State): PayloadAction => ( if (state.setMax) { const pendingAmount = getPendingAmount(pending, state.currency, isToken); if (isToken) { - const token = findToken(tokens, account.address, state.currency, account.deviceState); + const token = findToken(tokens, account.descriptor, state.currency, account.deviceState); if (token) { state.amount = new BigNumber(token.balance).minus(pendingAmount).toString(10); } @@ -173,7 +172,7 @@ export const addressLabel = ($state: State): PayloadAction => (dispatch: if (!account || !network) return state; const { address } = state; - const savedAccounts = getState().accounts.filter(a => a.address.toLowerCase() === address.toLowerCase()); + const savedAccounts = getState().accounts.filter(a => a.descriptor.toLowerCase() === address.toLowerCase()); if (savedAccounts.length > 0) { // check if found account belongs to this network const currentNetworkAccount = savedAccounts.find(a => a.network === network.shortcut); @@ -221,7 +220,7 @@ export const amountValidation = ($state: State): PayloadAction => (dispat const pendingAmount: BigNumber = getPendingAmount(pending, state.currency, isToken); if (isToken) { - const token = findToken(tokens, account.address, state.currency, account.deviceState); + const token = findToken(tokens, account.descriptor, state.currency, account.deviceState); if (!token) return state; const decimalRegExp = dynamicRegexp(parseInt(token.decimals, 0)); @@ -304,7 +303,7 @@ export const nonceValidation = ($state: State): PayloadAction => (dispatc const { account, } = getState().selectedAccount; - if (!account) return state; + if (!account || account.networkType !== 'ethereum') return state; const { nonce } = state; if (nonce.length < 1) { diff --git a/src/actions/ripple/BlockchainActions.js b/src/actions/ripple/BlockchainActions.js index 5cb6cede..5d73bd8b 100644 --- a/src/actions/ripple/BlockchainActions.js +++ b/src/actions/ripple/BlockchainActions.js @@ -16,7 +16,7 @@ import type { const DECIMALS: number = 6; export const subscribe = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { - const accounts: Array = getState().accounts.filter(a => a.network === network).map(a => a.address); + const accounts: Array = getState().accounts.filter(a => a.network === network).map(a => a.descriptor); await TrezorConnect.blockchainSubscribe({ accounts, coin: network, @@ -68,7 +68,7 @@ export const onBlockMined = (network: string): PromiseAction => async (dis export const onNotification = (payload: $ElementType): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { const { notification } = payload; - const account = getState().accounts.find(a => a.address === notification.address); + const account = getState().accounts.find(a => a.descriptor === notification.address); if (!account) return; if (notification.status === 'pending') { @@ -95,7 +95,7 @@ export const onNotification = (payload: $ElementType async (dispatch: Dispatch, getState: Ge const selected: ?TrezorDevice = getState().wallet.selectedDevice; if (!selected) return; - if (!account || !network) return; + if (!account || account.networkType !== 'ripple' || !network) return; const blockchain = getState().blockchain.find(b => b.shortcut === account.network); if (!blockchain) return; @@ -188,7 +188,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge state: selected.state, }, useEmptyPassphrase: selected.useEmptyPassphrase, - path: account.addressPath, + path: account.accountPath, transaction: { fee: blockchain.fee, // Fee must be in the range of 10 to 10,000 drops flags: 0x80000000, diff --git a/src/actions/ripple/SendFormValidationActions.js b/src/actions/ripple/SendFormValidationActions.js index 9c5f1b01..fd473181 100644 --- a/src/actions/ripple/SendFormValidationActions.js +++ b/src/actions/ripple/SendFormValidationActions.js @@ -115,7 +115,7 @@ const addressValidation = ($state: State): PayloadAction => (dispatch: Di state.errors.address = 'Address is not set'; } else if (!AddressValidator.validate(address, 'XRP')) { state.errors.address = 'Address is not valid'; - } else if (address.toLowerCase() === account.address.toLowerCase()) { + } else if (address.toLowerCase() === account.descriptor.toLowerCase()) { state.errors.address = 'Cannot send to myself'; } return state; @@ -135,7 +135,7 @@ const addressLabel = ($state: State): PayloadAction => (dispatch: Dispatc if (!account || !network) return state; const { address } = state; - const savedAccounts = getState().accounts.filter(a => a.address.toLowerCase() === address.toLowerCase()); + const savedAccounts = getState().accounts.filter(a => a.descriptor.toLowerCase() === address.toLowerCase()); if (savedAccounts.length > 0) { // check if found account belongs to this network const currentNetworkAccount = savedAccounts.find(a => a.network === network.shortcut); diff --git a/src/components/modals/confirm/Address/index.js b/src/components/modals/confirm/Address/index.js index d3b0f1cf..97538a97 100644 --- a/src/components/modals/confirm/Address/index.js +++ b/src/components/modals/confirm/Address/index.js @@ -45,7 +45,7 @@ const ConfirmAddress = (props: Props) => {

Please compare your address on device with address shown bellow.

-

{ account.address }

+

{ account.descriptor }

diff --git a/src/components/modals/confirm/UnverifiedAddress/index.js b/src/components/modals/confirm/UnverifiedAddress/index.js index cb7c7e7b..2246cdf1 100644 --- a/src/components/modals/confirm/UnverifiedAddress/index.js +++ b/src/components/modals/confirm/UnverifiedAddress/index.js @@ -71,7 +71,7 @@ class ConfirmUnverifiedAddress extends PureComponent { const { account, onCancel, showAddress } = this.props; if (!account) return; onCancel(); - showAddress(account.addressPath); + showAddress(account.accountPath); } showUnverifiedAddress() { diff --git a/src/flowtype/index.js b/src/flowtype/index.js index 68a8cfee..28d23197 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -47,7 +47,7 @@ import type { BlockchainLinkTransaction, } from 'trezor-connect'; -import type { RouterAction, LocationState } from 'react-router-redux'; +import type { RouterAction, LocationState } from 'connected-react-router'; export type AcquiredDevice = $Exact<{ +type: 'acquired', diff --git a/src/flowtype/npm/react-router-redux.js b/src/flowtype/npm/connected-react-router.js similarity index 87% rename from src/flowtype/npm/react-router-redux.js rename to src/flowtype/npm/connected-react-router.js index 81c9a297..44b48659 100644 --- a/src/flowtype/npm/react-router-redux.js +++ b/src/flowtype/npm/connected-react-router.js @@ -3,7 +3,7 @@ import type { Location as RouterLocation, } from 'react-router'; -declare module 'react-router-redux' { +declare module 'connected-react-router' { // custom state for location declare export type LocationState = {[key: string]: string}; @@ -19,7 +19,9 @@ declare module 'react-router-redux' { declare export type RouterAction = { type: typeof LOCATION_CHANGE, - payload: Location; + payload: { + location: Location, + }, } declare export type State = { @@ -35,8 +37,9 @@ declare module 'react-router-redux' { //declare export function routerReducer(state?: S, action: A): S; declare export function routerReducer(state?: State, action: any): State; declare export function routerMiddleware(history: any): any; + declare export function connectRouter(history: any): any; declare export class ConnectedRouter extends React$Component<{ history: any - }> {} + }> {} } \ No newline at end of file diff --git a/src/reducers/AccountsReducer.js b/src/reducers/AccountsReducer.js index e2fb75f3..f52f22c8 100644 --- a/src/reducers/AccountsReducer.js +++ b/src/reducers/AccountsReducer.js @@ -6,27 +6,35 @@ import * as WALLET from 'actions/constants/wallet'; import * as ACCOUNT from 'actions/constants/account'; import type { Action, TrezorDevice } from 'flowtype'; -import type { - AccountSetBalanceAction, - AccountSetNonceAction, -} from 'actions/AccountsActions'; -export type Account = { - loaded: boolean; - +network: string; - +deviceID: string; - +deviceState: string; - +index: number; - +addressPath: Array; - +address: string; - balance: string; - availableBalance: string; - sequence: number; - nonce: number; - block: number; - transactions: number; - empty: boolean; -} +type AccountCommon = { + +imported: boolean, + +index: number, + +network: string, // network id (shortcut) + +deviceID: string, // empty for imported accounts + +deviceState: string, // empty for imported accounts + +accountPath: Array, // empty for imported accounts + +descriptor: string, // address or xpub + + balance: string, + availableBalance: string, // balance - pending + block: number, // last known (synchronized) block + empty: boolean, // account without transactions + + transactions: number, // deprecated +}; + +export type Account = AccountCommon & { + networkType: 'ethereum', + nonce: number, +} | AccountCommon & { + networkType: 'ripple', + sequence: number, + reserve: string, +} | AccountCommon & { + networkType: 'bitcoin', + addressIndex: number, +}; export type State = Array; @@ -44,7 +52,7 @@ export const findDeviceAccounts = (state: State, device: TrezorDevice, network: const createAccount = (state: State, account: Account): State => { // TODO check with device_id // check if account was created before - const exist: ?Account = state.find(a => a.address === account.address && a.network === account.network && a.deviceState === account.deviceState); + const exist: ?Account = state.find(a => a.descriptor === account.descriptor && a.network === account.network && a.deviceState === account.deviceState); if (exist) { return state; } @@ -55,7 +63,6 @@ const createAccount = (state: State, account: Account): State => { const removeAccounts = (state: State, device: TrezorDevice): State => state.filter(account => account.deviceState !== device.state); - const clear = (state: State, devices: Array): State => { let newState: State = [...state]; devices.forEach((d) => { @@ -65,29 +72,12 @@ const clear = (state: State, devices: Array): State => { }; const updateAccount = (state: State, account: Account): State => { - const index: number = state.findIndex(a => a.address === account.address && a.network === account.network && a.deviceState === account.deviceState); + const index: number = state.findIndex(a => a.descriptor === account.descriptor && a.network === account.network && a.deviceState === account.deviceState); const newState: State = [...state]; newState[index] = account; return newState; }; -const setBalance = (state: State, action: AccountSetBalanceAction): State => { - // const index: number = state.findIndex(account => account.address === action.address && account.network === action.network && account.deviceState === action.deviceState); - const index: number = state.findIndex(account => account.address === action.address && account.network === action.network); - const newState: State = [...state]; - newState[index].loaded = true; - newState[index].balance = action.balance; - return newState; -}; - -const setNonce = (state: State, action: AccountSetNonceAction): State => { - const index: number = state.findIndex(account => account.address === action.address && account.network === action.network && account.deviceState === action.deviceState); - const newState: State = [...state]; - newState[index].loaded = true; - newState[index].nonce = action.nonce; - return newState; -}; - export default (state: State = initialState, action: Action): State => { switch (action.type) { case ACCOUNT.CREATE: @@ -108,11 +98,6 @@ export default (state: State = initialState, action: Action): State => { case ACCOUNT.UPDATE: return updateAccount(state, action.payload); - case ACCOUNT.SET_BALANCE: - return setBalance(state, action); - case ACCOUNT.SET_NONCE: - return setNonce(state, action); - case ACCOUNT.FROM_STORAGE: return action.payload; diff --git a/src/reducers/NotificationReducer.js b/src/reducers/NotificationReducer.js index 34274aea..46b1aea9 100644 --- a/src/reducers/NotificationReducer.js +++ b/src/reducers/NotificationReducer.js @@ -1,7 +1,7 @@ /* @flow */ import * as React from 'react'; -import { LOCATION_CHANGE } from 'react-router-redux'; +import { LOCATION_CHANGE } from 'connected-react-router'; import * as NOTIFICATION from 'actions/constants/notification'; import { DEVICE } from 'trezor-connect'; diff --git a/src/reducers/TokensReducer.js b/src/reducers/TokensReducer.js index c880c588..f9d00f12 100644 --- a/src/reducers/TokensReducer.js +++ b/src/reducers/TokensReducer.js @@ -6,7 +6,6 @@ import * as WALLET from 'actions/constants/wallet'; import * as TOKEN from 'actions/constants/token'; import type { Action, TrezorDevice } from 'flowtype'; -import type { Account } from './AccountsReducer'; export type Token = { loaded: boolean; @@ -24,21 +23,6 @@ export type State = Array; const initialState: State = []; -// Helper for actions -export const findToken = (state: Array, address: string, symbol: string, deviceState: string): ?Token => state.find(t => t.ethAddress === address && t.symbol === symbol && t.deviceState === deviceState); - -export const findAccountTokens = (state: Array, account: Account): Array => state.filter(t => t.ethAddress === account.address && t.network === account.network && t.deviceState === account.deviceState); - -// const setBalance = (state: State, payload: any): State => { -// const newState: Array = [ ...state ]; -// let index: number = state.findIndex(t => t.address === payload.address && t.ethAddress === payload.ethAddress); -// if (index >= 0) { -// newState[index].loaded = true; -// newState[index].balance = payload.balance; -// } -// return newState; -// } - const create = (state: State, token: Token): State => { const newState: State = [...state]; newState.push(token); diff --git a/src/reducers/WalletReducer.js b/src/reducers/WalletReducer.js index 37fd38fd..8f07dc6e 100644 --- a/src/reducers/WalletReducer.js +++ b/src/reducers/WalletReducer.js @@ -1,7 +1,7 @@ /* @flow */ -import { LOCATION_CHANGE } from 'react-router-redux'; +import { LOCATION_CHANGE } from 'connected-react-router'; import { DEVICE, TRANSPORT } from 'trezor-connect'; import * as MODAL from 'actions/constants/modal'; import * as WALLET from 'actions/constants/wallet'; @@ -16,6 +16,7 @@ type State = { showBetaDisclaimer: boolean; initialParams: ?RouterLocationState; initialPathname: ?string; + firstLocationChange: boolean; disconnectRequest: ?TrezorDevice; selectedDevice: ?TrezorDevice; } @@ -24,6 +25,7 @@ const initialState: State = { ready: false, online: navigator.onLine, dropdownOpened: false, + firstLocationChange: true, showBetaDisclaimer: false, initialParams: null, initialPathname: null, @@ -39,6 +41,11 @@ export default function wallet(state: State = initialState, action: Action): Sta initialParams: action.state, initialPathname: action.pathname, }; + case WALLET.SET_FIRST_LOCATION_CHANGE: + return { + ...state, + firstLocationChange: false, + }; case TRANSPORT.START: return { diff --git a/src/reducers/index.js b/src/reducers/index.js index 498e5a70..2e10d00a 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,6 +1,7 @@ /* @flow */ import { combineReducers } from 'redux'; -import { routerReducer } from 'react-router-redux'; +import { connectRouter } from 'connected-react-router'; +import type { State } from 'connected-react-router'; import log from 'reducers/LogReducer'; import localStorage from 'reducers/LocalStorageReducer'; @@ -24,7 +25,6 @@ import blockchain from 'reducers/BlockchainReducer'; import signVerify from 'reducers/SignVerifyReducer'; const reducers = { - router: routerReducer, log, localStorage, connect, @@ -45,10 +45,18 @@ const reducers = { devices, blockchain, signVerify, + router: () => ({ + location: { + pathname: '', hash: '', search: '', state: {}, + }, + }: State), }; export type Reducers = typeof reducers; type $ExtractFunctionReturn = (v: (...args: any) => V) => V; export type ReducersState = $ObjMap; -export default combineReducers(reducers); +export default (history: any) => combineReducers({ + ...reducers, + router: connectRouter(history), +}); \ No newline at end of file diff --git a/src/reducers/utils/index.js b/src/reducers/utils/index.js index f3734dad..7104ca8e 100644 --- a/src/reducers/utils/index.js +++ b/src/reducers/utils/index.js @@ -86,7 +86,7 @@ export const getDiscoveryProcess = (state: State): ?Discovery => { export const getAccountPendingTx = (pending: Array, account: ?Account): Array => { const a = account; if (!a) return []; - return pending.filter(p => p.network === a.network && p.address === a.address); + return pending.filter(p => p.network === a.network && p.address === a.descriptor); }; export const getPendingSequence = (pending: Array): number => pending.reduce((value: number, tx: Transaction) => { @@ -101,10 +101,12 @@ export const getPendingAmount = (pending: Array, currency: string, return value; }, new BigNumber('0')); -export const getAccountTokens = (state: State, account: ?Account): Array => { +export const findToken = (state: Array, address: string, symbol: string, deviceState: string): ?Token => state.find(t => t.ethAddress === address && t.symbol === symbol && t.deviceState === deviceState); + +export const getAccountTokens = (tokens: Array, account: ?Account): Array => { const a = account; if (!a) return []; - return state.tokens.filter(t => t.ethAddress === a.address && t.network === a.network && t.deviceState === a.deviceState); + return tokens.filter(t => t.ethAddress === a.descriptor && t.network === a.network && t.deviceState === a.deviceState); }; export const getWeb3 = (state: State): ?Web3Instance => { diff --git a/src/services/LocalStorageService.js b/src/services/LocalStorageService.js index 3f9775be..7719120e 100644 --- a/src/services/LocalStorageService.js +++ b/src/services/LocalStorageService.js @@ -37,8 +37,7 @@ const LocalStorageService: Middleware = (api: MiddlewareAPI) => (next: Middlewar break; case ACCOUNT.CREATE: - case ACCOUNT.SET_BALANCE: - case ACCOUNT.SET_NONCE: + case ACCOUNT.UPDATE: api.dispatch(LocalStorageActions.save()); break; diff --git a/src/services/RouterService.js b/src/services/RouterService.js index 202165af..66fa821b 100644 --- a/src/services/RouterService.js +++ b/src/services/RouterService.js @@ -1,5 +1,5 @@ /* @flow */ -import { LOCATION_CHANGE, replace } from 'react-router-redux'; +import { LOCATION_CHANGE, replace } from 'connected-react-router'; import * as RouterActions from 'actions/RouterActions'; import type { @@ -25,11 +25,11 @@ const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa const validUrl = api.dispatch(RouterActions.getValidUrl(action)); // override action state (to be stored in RouterReducer) const override = action; - override.payload.state = api.dispatch(RouterActions.pathToParams(validUrl)); - const redirect = action.payload.pathname !== validUrl; + override.payload.location.state = api.dispatch(RouterActions.pathToParams(validUrl)); + const redirect = action.payload.location.pathname !== validUrl; if (redirect) { // override action pathname - override.payload.pathname = validUrl; + override.payload.location.pathname = validUrl; } // pass action diff --git a/src/services/WalletService.js b/src/services/WalletService.js index 0c44a3a3..95890b0c 100644 --- a/src/services/WalletService.js +++ b/src/services/WalletService.js @@ -1,6 +1,6 @@ /* @flow */ import { DEVICE } from 'trezor-connect'; -import { LOCATION_CHANGE } from 'react-router-redux'; +import { LOCATION_CHANGE } from 'connected-react-router'; import * as WALLET from 'actions/constants/wallet'; import * as CONNECT from 'actions/constants/TrezorConnect'; @@ -25,17 +25,16 @@ import type { */ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => async (action: Action): Promise => { 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.router.location) { + 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 api.dispatch({ type: WALLET.SET_INITIAL_URL, - pathname: action.payload.pathname, + pathname: action.payload.location.pathname, state: {}, }); // pass action and break process diff --git a/src/store.js b/src/store.js index 78fce246..678148ed 100644 --- a/src/store.js +++ b/src/store.js @@ -1,11 +1,11 @@ /* @flow */ import { createStore, applyMiddleware, compose } from 'redux'; -import { routerMiddleware } from 'react-router-redux'; +import { routerMiddleware } from 'connected-react-router'; import thunk from 'redux-thunk'; import createHistory from 'history/createHashHistory'; import { createLogger } from 'redux-logger'; -import reducers from 'reducers'; +import createRootReducer from 'reducers'; import services from 'services'; import Raven from 'raven-js'; @@ -65,7 +65,7 @@ if (buildUtils.isDev()) { } export default createStore( - reducers, + createRootReducer(history), initialState, composedEnhancers, ); diff --git a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js index 3e500e3c..202632b5 100644 --- a/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js +++ b/src/views/Wallet/components/LeftNavigation/components/AccountMenu/index.js @@ -161,10 +161,8 @@ const AccountMenu = (props: Props) => { const discovery = props.discovery.find(d => d.deviceState === selected.state && d.network === location.state.network); if (discovery && discovery.completed) { - // TODO: add only if last one is not empty - //if (selectedAccounts.length > 0 && selectedAccounts[selectedAccounts.length - 1]) const lastAccount = deviceAccounts[deviceAccounts.length - 1]; - if (lastAccount && (new BigNumber(lastAccount.balance).greaterThan(0) || lastAccount.nonce > 0)) { + if (lastAccount && !lastAccount.empty) { discoveryStatus = ( diff --git a/src/views/Wallet/views/Account/Receive/ethereum/index.js b/src/views/Wallet/views/Account/Receive/ethereum/index.js index 5646b7ed..34109886 100644 --- a/src/views/Wallet/views/Account/Receive/ethereum/index.js +++ b/src/views/Wallet/views/Account/Receive/ethereum/index.js @@ -111,9 +111,9 @@ const AccountReceive = (props: Props) => { const isAddressVerifying = props.modal.context === CONTEXT_DEVICE && props.modal.windowType === 'ButtonRequest_Address'; const isAddressHidden = !isAddressVerifying && !addressVerified && !addressUnverified; - let address = `${account.address.substring(0, 20)}...`; + let address = `${account.descriptor.substring(0, 20)}...`; if (addressVerified || addressUnverified || isAddressVerifying) { - ({ address } = account); + address = account.descriptor; } return ( @@ -149,7 +149,7 @@ const AccountReceive = (props: Props) => { /> )} > - props.showAddress(account.addressPath)}> + props.showAddress(account.accountPath)}> { )} /> {!(addressVerified || addressUnverified) && ( - props.showAddress(account.addressPath)} isDisabled={device.connected && !discovery.completed}> + props.showAddress(account.accountPath)} isDisabled={device.connected && !discovery.completed}> Show full address )} @@ -172,7 +172,7 @@ const AccountReceive = (props: Props) => { fgColor="#000000" level="Q" style={{ width: 150 }} - value={account.address} + value={account.descriptor} /> )} diff --git a/src/views/Wallet/views/Account/Receive/ripple/index.js b/src/views/Wallet/views/Account/Receive/ripple/index.js index c308eafd..e439466a 100644 --- a/src/views/Wallet/views/Account/Receive/ripple/index.js +++ b/src/views/Wallet/views/Account/Receive/ripple/index.js @@ -111,9 +111,9 @@ const AccountReceive = (props: Props) => { const isAddressVerifying = props.modal.context === CONTEXT_DEVICE && props.modal.windowType === 'ButtonRequest_Address'; const isAddressHidden = !isAddressVerifying && !addressVerified && !addressUnverified; - let address = `${account.address.substring(0, 20)}...`; + let address = `${account.descriptor.substring(0, 20)}...`; if (addressVerified || addressUnverified || isAddressVerifying) { - ({ address } = account); + address = account.descriptor; } return ( @@ -149,7 +149,7 @@ const AccountReceive = (props: Props) => { /> )} > - props.showAddress(account.addressPath)}> + props.showAddress(account.accountPath)}> { )} /> {!(addressVerified || addressUnverified) && ( - props.showAddress(account.addressPath)} isDisabled={device.connected && !discovery.completed}> + props.showAddress(account.accountPath)} isDisabled={device.connected && !discovery.completed}> Show full address )} @@ -172,7 +172,7 @@ const AccountReceive = (props: Props) => { fgColor="#000000" level="Q" style={{ width: 150 }} - value={account.address} + value={account.descriptor} /> )} diff --git a/src/views/Wallet/views/Account/SignVerify/index.js b/src/views/Wallet/views/Account/SignVerify/index.js index 937294ba..11e9b0fe 100644 --- a/src/views/Wallet/views/Account/SignVerify/index.js +++ b/src/views/Wallet/views/Account/SignVerify/index.js @@ -104,7 +104,7 @@ class SignVerify extends Component { { >Clear signVerifyActions.sign(account.addressPath, signMessage)} + onClick={() => signVerifyActions.sign(account.accountPath, signMessage)} >Sign diff --git a/src/views/Wallet/views/Account/Summary/ethereum/index.js b/src/views/Wallet/views/Account/Summary/ethereum/index.js index fe9aed68..e7cc7cc2 100644 --- a/src/views/Wallet/views/Account/Summary/ethereum/index.js +++ b/src/views/Wallet/views/Account/Summary/ethereum/index.js @@ -84,7 +84,7 @@ const AccountSummary = (props: Props) => { return ; } - const explorerLink: string = `${network.explorer.address}${account.address}`; + const explorerLink: string = `${network.explorer.address}${account.descriptor}`; const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol); const balance: string = new BigNumber(account.balance).minus(pendingAmount).toString(10); diff --git a/src/views/Wallet/views/Account/Summary/ripple/index.js b/src/views/Wallet/views/Account/Summary/ripple/index.js index fd4d4a77..260e2685 100644 --- a/src/views/Wallet/views/Account/Summary/ripple/index.js +++ b/src/views/Wallet/views/Account/Summary/ripple/index.js @@ -74,7 +74,7 @@ const AccountSummary = (props: Props) => { return ; } - const explorerLink: string = `${network.explorer.address}${account.address}`; + const explorerLink: string = `${network.explorer.address}${account.descriptor}`; const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol); const balance: string = new BigNumber(account.balance).minus(pendingAmount).toString(10); diff --git a/src/views/index.js b/src/views/index.js index 6e37aef5..62221dce 100644 --- a/src/views/index.js +++ b/src/views/index.js @@ -2,7 +2,7 @@ import React from 'react'; import { hot } from 'react-hot-loader'; import { Route, Switch } from 'react-router-dom'; import { Provider } from 'react-redux'; -import { ConnectedRouter } from 'react-router-redux'; +import { ConnectedRouter } from 'connected-react-router'; // general import ErrorBoundary from 'support/ErrorBoundary'; diff --git a/yarn.lock b/yarn.lock index bd1dec40..8abb1c76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -127,6 +127,13 @@ version "7.0.0-rc.1" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-rc.1.tgz#d009a9bba8175d7b971e30cd03535b278c44082d" +"@babel/runtime@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f" + integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg== + dependencies: + regenerator-runtime "^0.12.0" + "@babel/template@7.0.0-beta.44": version "7.0.0-beta.44" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" @@ -2611,6 +2618,14 @@ connect-history-api-fallback@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" +connected-react-router@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.0.0.tgz#cb7ccbbc5ed353832ecd91d68289c916e8aba734" + integrity sha512-TarPqf2wY3cz993Mw3eBg2U12M5OmaGwKzJsinvRQh61nKb8WMUvimyhu6u2HeWS8625PHFXjNOU0OIAMWj/bQ== + dependencies: + immutable "^3.8.1" + seamless-immutable "^7.1.3" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -4822,6 +4837,13 @@ hoist-non-react-statics@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40" +hoist-non-react-statics@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.2.1.tgz#c09c0555c84b38a7ede6912b61efddafd6e75e1e" + integrity sha512-TFsu3TV3YLY+zFTZDrN8L2DTFanObwmBLpWvJs1qfUuEQ5bTAdFcwfx2T/bsCXfM9QHSLvjfP+nihEl0yvozxw== + dependencies: + react-is "^16.3.2" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -5009,6 +5031,11 @@ ignore@^3.3.5: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" +immutable@^3.8.1: + version "3.8.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" + integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM= + import-local@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" @@ -5111,15 +5138,16 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" +invariant@^2.2.0, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: loose-envify "^1.0.0" -invariant@^2.2.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" +invariant@^2.2.1, invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + integrity sha1-nh9WrArNtr8wMwbzOL47IErmA2A= dependencies: loose-envify "^1.0.0" @@ -5872,6 +5900,11 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" @@ -6227,10 +6260,6 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash-es@^4.17.5: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.5.tgz#9fc6e737b1c4d151d8f9cae2247305d552ce748f" - lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -6331,6 +6360,13 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3 dependencies: js-tokens "^3.0.0" +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + loud-rejection@^1.0.0, loud-rejection@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -7986,7 +8022,7 @@ react-input-autosize@^2.2.1: dependencies: prop-types "^15.5.8" -react-is@^16.6.0: +react-is@^16.3.2, react-is@^16.6.0, react-is@^16.6.3: version "16.6.3" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0" @@ -8010,16 +8046,17 @@ react-qr-svg@^2.1.0: prop-types "^15.5.8" qr.js "0.0.0" -react-redux@^5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8" +react-redux@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-6.0.0.tgz#09e86eeed5febb98e9442458ad2970c8f1a173ef" + integrity sha512-EmbC3uLl60pw2VqSSkj6HpZ6jTk12RMrwXMBdYtM6niq0MdEaRq9KYCwpJflkOZj349BLGQm1MI/JO1W96kLWQ== dependencies: - hoist-non-react-statics "^2.5.0" - invariant "^2.0.0" - lodash "^4.17.5" - lodash-es "^4.17.5" - loose-envify "^1.1.0" - prop-types "^15.6.0" + "@babel/runtime" "^7.2.0" + hoist-non-react-statics "^3.2.1" + invariant "^2.2.4" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-is "^16.6.3" react-router-dom@^4.2.2: version "4.2.2" @@ -8032,14 +8069,6 @@ react-router-dom@^4.2.2: react-router "^4.2.0" warning "^3.0.0" -react-router-redux@next: - version "5.0.0-alpha.8" - resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-5.0.0-alpha.8.tgz#5242c705730b2ac862aff7a8e90f870d0cf45e12" - dependencies: - history "^4.7.2" - prop-types "^15.6.0" - react-router "^4.2.0" - react-router@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986" @@ -8052,6 +8081,19 @@ react-router@^4.2.0: prop-types "^15.5.4" warning "^3.0.0" +react-router@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e" + integrity sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg== + dependencies: + history "^4.7.2" + hoist-non-react-statics "^2.5.0" + invariant "^2.2.4" + loose-envify "^1.3.1" + path-to-regexp "^1.7.0" + prop-types "^15.6.1" + warning "^4.0.1" + react-scale-text@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/react-scale-text/-/react-scale-text-1.2.2.tgz#4a56e1d2fd4e4582d2ad472c003ee12f51cbf2ae" @@ -8320,6 +8362,11 @@ regenerator-runtime@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -8781,6 +8828,11 @@ scryptsy@^1.2.1: dependencies: pbkdf2 "^3.0.3" +seamless-immutable@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/seamless-immutable/-/seamless-immutable-7.1.4.tgz#6e9536def083ddc4dea0207d722e0e80d0f372f8" + integrity sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A== + secp256k1@^3.0.1: version "3.4.0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.4.0.tgz#1c905b256fa4ae5b9cc170e672dd59b4c5de46a4" @@ -10304,6 +10356,13 @@ warning@^3.0.0: dependencies: loose-envify "^1.0.0" +warning@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.2.tgz#aa6876480872116fa3e11d434b0d0d8d91e44607" + integrity sha512-wbTp09q/9C+jJn4KKJfJfoS6VleK/Dti0yqWSm6KMvJ4MRCXFQNapHuJXutJIrWV0Cf4AhTdeIe4qdKHR1+Hug== + dependencies: + loose-envify "^1.0.0" + watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986"