diff --git a/package.json b/package.json index 3c57abf3..14e4102a 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "react-router-redux": "next", "react-scale-text": "^1.2.2", "react-select": "2.0.0", + "react-sticky-el": "^1.0.20", "react-transition-group": "^2.2.1", "redbox-react": "^1.6.0", "redux": "4.0.0", @@ -56,8 +57,8 @@ "styled-components": "^3.3.3", "styled-media-query": "^2.0.2", "styled-normalize": "^8.0.0", - "trezor-connect": "5.0.30", - "web3": "^0.19.0", + "trezor-connect": "5.0.31", + "web3": "1.0.0-beta.35", "webpack": "^4.16.3", "webpack-bundle-analyzer": "^2.13.1", "whatwg-fetch": "^2.0.4", diff --git a/public/data/appConfig.json b/public/data/appConfig.json index bf0d4277..c9c3ca0c 100644 --- a/public/data/appConfig.json +++ b/public/data/appConfig.json @@ -3,21 +3,15 @@ { "name": "Ethereum", "symbol": "ETH", - "network": "ethereum", + "network": "eth", "bip44": "m/44'/60'/0'/0", "chainId": 1, "defaultGasPrice": 64, "defaultGasLimit": 21000, "defaultGasLimitTokens": 200000, "tokens": "./data/ethereumTokens.json", - "backends": [ - { - "name": "TREZOR Wallet - Ethereum", - "urls": [ - "https://mainnet.infura.io/QGyVKozSUEh2YhL4s2G4", - "http://88.208.115.69" - ] - } + "web3": [ + "wss://eth2.trezor.io/geth" ], "explorer": { "tx": "https://etherscan.io/tx/", @@ -27,21 +21,15 @@ { "name": "Ethereum Classic", "symbol": "ETC", - "network": "ethereum-classic", + "network": "etc", "chainId": 61, "bip44": "m/44'/61'/0'/0", "defaultGasPrice": 64, "defaultGasLimit": 21000, "defaultGasLimitTokens": 200000, "tokens": "./data/ethereumClassicTokens.json", - "backends": [ - { - "name": "TREZOR Wallet - Ethereum", - "urls": [ - "https://etc-geth.0xinfra.com/", - "https://mew.epool.io/" - ] - } + "web3": [ + "wss://etc2.trezor.io/geth" ], "explorer": { "tx": "https://gastracker.io/tx/", @@ -50,50 +38,21 @@ }, { "name": "Ethereum Ropsten", - "symbol": "tETH", - "network": "ropsten", + "symbol": "tROP", + "network": "trop", "chainId": 3, "bip44": "m/44'/60'/0'/0", "defaultGasPrice": 64, "defaultGasLimit": 21000, "defaultGasLimitTokens": 200000, "tokens": "./data/ropstenTokens.json", - "backends": [ - { - "name": "TREZOR Wallet - Ethereum", - "urls": [ - "https://ropsten.infura.io/QGyVKozSUEh2YhL4s2G4", - "http://10.34.2.5:8545" - ] - } + "web3": [ + "wss://ropsten1.trezor.io/geth" ], "explorer": { "tx": "https://ropsten.etherscan.io/tx/", "address": "https://ropsten.etherscan.io/address/" } - }, - { - "name": "Ethereum Rinkeby", - "symbol": "tETH", - "network": "rinkeby", - "chainId": 4, - "bip44": "m/44'/61'/0'/0", - "defaultGasPrice": 64, - "defaultGasLimit": 21000, - "defaultGasLimitTokens": 200000, - "tokens": "./data/rinkebyTokens.json", - "backends": [ - { - "name": "TREZOR Wallet - Ethereum", - "urls": [ - "https://rinkeby.infura.io/QGyVKozSUEh2YhL4s2G4" - ] - } - ], - "explorer": { - "tx": "https://rinkeby.etherscan.io/tx/", - "address": "https://rinkeby.etherscan.io/address/" - } } ], diff --git a/public/data/ropstenTokens.json b/public/data/ropstenTokens.json index 082693ce..f4d716ae 100644 --- a/public/data/ropstenTokens.json +++ b/public/data/ropstenTokens.json @@ -4,5 +4,17 @@ "name": "PLASMA", "symbol" :"PLASMA", "decimals": 6 + }, + { + "address": "0x58cda554935e4a1f2acbe15f8757400af275e084", + "name": "Trezor01", + "symbol": "T01", + "decimals": 0 + }, + { + "address": "0xa04761a776af2bed654a041430a063fd9d20fad4", + "name": "Trezor13", + "symbol": "T013", + "decimals": 13 } ] \ No newline at end of file diff --git a/src/actions/AccountsActions.js b/src/actions/AccountsActions.js index 2bc3a8f1..8c14e594 100644 --- a/src/actions/AccountsActions.js +++ b/src/actions/AccountsActions.js @@ -2,7 +2,7 @@ import * as ACCOUNT from 'actions/constants/account'; import type { Action, TrezorDevice } from 'flowtype'; -import type { State } from 'reducers/AccountsReducer'; +import type { Account, State } from 'reducers/AccountsReducer'; export type AccountFromStorageAction = { type: typeof ACCOUNT.FROM_STORAGE, @@ -11,11 +11,12 @@ export type AccountFromStorageAction = { export type AccountCreateAction = { type: typeof ACCOUNT.CREATE, - device: TrezorDevice, - network: string, - index: number, - path: Array, - address: string + payload: Account, +} + +export type AccountUpdateAction = { + type: typeof ACCOUNT.UPDATE, + payload: Account, } export type AccountSetBalanceAction = { @@ -36,9 +37,10 @@ export type AccountSetNonceAction = { export type AccountAction = AccountFromStorageAction - | AccountCreateAction - | AccountSetBalanceAction - | AccountSetNonceAction; + | AccountCreateAction + | AccountUpdateAction + | AccountSetBalanceAction + | AccountSetNonceAction; export const setBalance = (address: string, network: string, deviceState: string, balance: string): Action => ({ type: ACCOUNT.SET_BALANCE, @@ -55,3 +57,8 @@ export const setNonce = (address: string, network: string, deviceState: string, deviceState, nonce, }); + +export const update = (account: Account): Action => ({ + type: ACCOUNT.UPDATE, + payload: account +}); diff --git a/src/actions/BlockchainActions.js b/src/actions/BlockchainActions.js new file mode 100644 index 00000000..353cd345 --- /dev/null +++ b/src/actions/BlockchainActions.js @@ -0,0 +1,210 @@ +/* @flow */ + +import Web3 from 'web3'; +import HDKey from 'hdkey'; + +import EthereumjsUtil from 'ethereumjs-util'; +import EthereumjsUnits from 'ethereumjs-units'; +import EthereumjsTx from 'ethereumjs-tx'; +import TrezorConnect from 'trezor-connect'; +import BigNumber from 'bignumber.js'; + +import type { EstimateGasOptions } from 'web3'; +import type { TransactionStatus, TransactionReceipt } from 'web3'; +import { strip } from 'utils/ethUtils'; +import * as BLOCKCHAIN from 'actions/constants/blockchain'; +import * as WEB3 from 'actions/constants/web3'; +import * as PENDING from 'actions/constants/pendingTx'; + +import * as AccountsActions from './AccountsActions'; +import * as Web3Actions from './Web3Actions'; + +import type { + TrezorDevice, + Dispatch, + GetState, + Action, + AsyncAction, + PromiseAction, + ThunkAction, +} from 'flowtype'; +import type { EthereumAccount } from 'trezor-connect'; +import type { Token } from 'reducers/TokensReducer'; +import type { NetworkToken } from 'reducers/LocalStorageReducer'; + +export type BlockchainAction = { + type: typeof BLOCKCHAIN.READY, +} + +export const discoverAccount = (device: TrezorDevice, address: string, network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + // get data from connect + // Temporary disabled, enable after trezor-connect@5.0.32 release + const txs = await TrezorConnect.ethereumGetAccountInfo({ + account: { + address, + block: 0, + transactions: 0, + balance: "0", + nonce: 0 + }, + coin: network, + }); + + if (!txs.success) { + throw new Error(txs.payload.error); + } + + // blockbook web3 fallback + const web3account = await dispatch( Web3Actions.discoverAccount(address, network) ); + // return { transactions: txs.payload, ...web3account }; + return { + address, + transactions: txs.payload.transactions, + block: txs.payload.block, + balance: web3account.balance, + nonce: web3account.nonce, + }; +}; + +export const getTokenInfo = (input: string, network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + return await dispatch( Web3Actions.getTokenInfo(input, network) ); +} + +export const getTokenBalance = (token: Token): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + return await dispatch( Web3Actions.getTokenBalance(token) ); +} + +export const getGasPrice = (network: string, defaultGasPrice: number): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + try { + const gasPrice = await dispatch( Web3Actions.getCurrentGasPrice(network) ); + return new BigNumber(gasPrice); + } catch (error) { + return new BigNumber(defaultGasPrice); + } +} + +export const estimateGasLimit = (network: string, data: string, value: string, gasPrice: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + return await dispatch( Web3Actions.estimateGasLimit(network, { to: '', data, value, gasPrice }) ); +} + +export const onBlockMined = (coinInfo: any): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + // incoming "coinInfo" from TrezorConnect is CoinInfo | EthereumNetwork type + const network: string = coinInfo.shortcut.toLowerCase(); + + // try to resolve pending transactions + await dispatch( Web3Actions.resolvePendingTransactions(network) ); + + await dispatch( Web3Actions.updateGasPrice(network) ); + + const accounts: Array = getState().accounts.filter(a => a.network === network); + if (accounts.length > 0) { + // find out which account changed + const response = await TrezorConnect.ethereumGetAccountInfo({ + accounts, + coin: network, + }); + + if (response.success) { + response.payload.forEach((a, i) => { + if (a.transactions > 0) { + // load additional data from Web3 (balance, nonce, tokens) + dispatch( Web3Actions.updateAccount(accounts[i], a, network) ) + } else { + // there are no new txs, just update block + dispatch( AccountsActions.update( { ...accounts[i], ...a }) ); + + // HACK: since blockbook can't work with smart contracts for now + // try to update tokens balances added to this account using Web3 + dispatch( Web3Actions.updateAccountTokens(accounts[i]) ); + } + }); + } + } +} + + +// not used for now, waiting for fix in blockbook +export const onNotification = (payload: any): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + + // this event can be triggered multiple times + // 1. check if pair [txid + address] is already in reducer + const network: string = payload.coin.shortcut.toLowerCase(); + const address: string = EthereumjsUtil.toChecksumAddress(payload.tx.address); + const txInfo = await dispatch( Web3Actions.getPendingInfo(network, payload.tx.txid) ); + + // const exists = getState().pending.filter(p => p.id === payload.tx.txid && p.address === address); + const exists = getState().pending.filter(p => { + return p.address === address; + }); + if (exists.length < 1) { + if (txInfo) { + dispatch({ + type: PENDING.ADD, + payload: { + type: 'send', + id: payload.tx.txid, + network, + currency: "tETH", + amount: txInfo.value, + total: "0", + tx: {}, + nonce: txInfo.nonce, + address, + rejected: false + } + }); + } else { + // tx info not found (yet?) + // dispatch({ + // type: PENDING.ADD_UNKNOWN, + // payload: { + // network, + // ...payload.tx, + // } + // }); + } + } +} + + +export const subscribe = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const addresses: Array = getState().accounts.filter(a => a.network === network).map(a => a.address); + // $FlowIssue: trezor-connect@5.0.32 + return await TrezorConnect.blockchainSubscribe({ + // accounts: addresses, + accounts: [], + coin: network + }); +} + +// Conditionally subscribe to blockchain backend +// called after TrezorConnect.init successfully emits TRANSPORT.START event +// checks if there are discovery processes loaded from LocalStorage +// if so starts subscription to proper networks +export const init = (): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + if (getState().discovery.length > 0) { + // get unique networks + const networks: Array = []; + getState().discovery.forEach(discovery => { + if (networks.indexOf(discovery.network) < 0) { + networks.push(discovery.network); + } + }); + + // subscribe + for (let i = 0; i < networks.length; i++) { + await dispatch( subscribe(networks[i]) ); + } + } + + // continue wallet initialization + dispatch({ + type: BLOCKCHAIN.READY + }); +} + +// Handle BLOCKCHAIN.ERROR event from TrezorConnect +// disconnect and remove Web3 webscocket instance if exists +export const error = (payload: any): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + dispatch( Web3Actions.disconnect(payload.coin) ); +} \ No newline at end of file diff --git a/src/actions/DiscoveryActions.js b/src/actions/DiscoveryActions.js index b31534a0..0daea108 100644 --- a/src/actions/DiscoveryActions.js +++ b/src/actions/DiscoveryActions.js @@ -6,12 +6,12 @@ import * as DISCOVERY from 'actions/constants/discovery'; import * as ACCOUNT from 'actions/constants/account'; import * as NOTIFICATION from 'actions/constants/notification'; import type { - ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice, + ThunkAction, AsyncAction, PromiseAction, Action, GetState, Dispatch, TrezorDevice, } from 'flowtype'; import type { Discovery, State } from 'reducers/DiscoveryReducer'; import * as AccountsActions from './AccountsActions'; - -import { getNonceAsync, getBalanceAsync } from './Web3Actions'; +import * as BlockchainActions from './BlockchainActions'; +import { setBalance as setTokenBalance } from './TokenActions'; export type DiscoveryStartAction = { @@ -24,7 +24,7 @@ export type DiscoveryStartAction = { } export type DiscoveryWaitingAction = { - type: typeof DISCOVERY.WAITING_FOR_DEVICE | typeof DISCOVERY.WAITING_FOR_BACKEND, + type: typeof DISCOVERY.WAITING_FOR_DEVICE | typeof DISCOVERY.WAITING_FOR_BLOCKCHAIN, device: TrezorDevice, network: string } @@ -44,147 +44,9 @@ export type DiscoveryAction = { type: typeof DISCOVERY.FROM_STORAGE, payload: State } | DiscoveryStartAction - | DiscoveryWaitingAction - | DiscoveryStopAction - | DiscoveryCompleteAction; - - -// Because start() is calling begin() and begin() is calling start() one of them must be declared first -// otherwise eslint will start complaining -let begin; - - -const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { - const { completed } = discoveryProcess; - discoveryProcess.completed = false; - - 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 - - // verify address with TREZOR - const verifyAddress = await TrezorConnect.ethereumGetAddress({ - device: { - path: device.path, - instance: device.instance, - state: device.state, - }, - path, - showOnTrezor: false, - keepSession: true, - useEmptyPassphrase: !device.instance, - }); - if (discoveryProcess.interrupted) return; - - // TODO: with block-book (Martin) - // const discoveryA = await TrezorConnect.accountDiscovery({ - // device: { - // path: device.path, - // instance: device.instance, - // state: device.state - // }, - // }); - // if (discoveryProcess.interrupted) return; - - if (verifyAddress && verifyAddress.success) { - //const trezorAddress: string = '0x' + verifyAddress.payload.address; - const trezorAddress: string = EthereumjsUtil.toChecksumAddress(verifyAddress.payload.address); - if (trezorAddress !== ethAddress) { - // throw inconsistent state error - console.warn('Inconsistent state', trezorAddress, ethAddress); - - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Address validation error', - message: `Addresses are different. TREZOR: ${trezorAddress} HDKey: ${ethAddress}`, - cancelable: true, - actions: [ - { - label: 'Try again', - callback: () => { - dispatch(start(device, discoveryProcess.network)); - }, - }, - ], - }, - }); - return; - } - } else { - // handle TREZOR communication error - dispatch({ - type: NOTIFICATION.ADD, - payload: { - type: 'error', - title: 'Address validation error', - message: verifyAddress.payload.error, - cancelable: true, - actions: [ - { - label: 'Try again', - callback: () => { - dispatch(start(device, discoveryProcess.network)); - }, - }, - ], - }, - }); - return; - } - - const web3instance = getState().web3.find(w3 => w3.network === network); - if (!web3instance) return; - - const balance = await getBalanceAsync(web3instance.web3, ethAddress); - if (discoveryProcess.interrupted) return; - const nonce: number = await getNonceAsync(web3instance.web3, ethAddress); - if (discoveryProcess.interrupted) return; - - const addressIsEmpty = nonce < 1 && !balance.greaterThan(0); - - if (!addressIsEmpty || (addressIsEmpty && completed) || (addressIsEmpty && discoveryProcess.accountIndex === 0)) { - dispatch({ - type: ACCOUNT.CREATE, - device, - network, - index: discoveryProcess.accountIndex, - path, - address: ethAddress, - }); - dispatch( - AccountsActions.setBalance(ethAddress, network, device.state || 'undefined', web3instance.web3.fromWei(balance.toString(), 'ether')), - ); - dispatch(AccountsActions.setNonce(ethAddress, network, device.state || 'undefined', nonce)); - - if (!completed) { dispatch(discoverAccount(device, discoveryProcess)); } - } - - if (addressIsEmpty) { - // release acquired sesssion - await TrezorConnect.getFeatures({ - device: { - path: device.path, - instance: device.instance, - state: device.state, - }, - keepSession: false, - useEmptyPassphrase: !device.instance, - }); - if (discoveryProcess.interrupted) return; - - dispatch({ - type: DISCOVERY.COMPLETE, - device, - network, - }); - } -}; + | DiscoveryWaitingAction + | DiscoveryStopAction + | DiscoveryCompleteAction; export const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const selected = getState().wallet.selectedDevice; @@ -203,26 +65,9 @@ export const start = (device: TrezorDevice, network: string, ignoreCompleted?: b return; } - const web3 = getState().web3.find(w3 => w3.network === network); - if (!web3) { - console.error('Start discovery: Web3 does not exist', network); - return; - } - - if (!web3.web3.currentProvider.isConnected()) { - console.error('Start discovery: Web3 is not connected', network); - dispatch({ - type: DISCOVERY.WAITING_FOR_BACKEND, - device, - network, - }); - return; - } - - const { discovery }: { discovery: State } = getState(); + const discovery: State = getState().discovery; const discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network); - if (!selected.connected && (!discoveryProcess || !discoveryProcess.completed)) { dispatch({ type: DISCOVERY.WAITING_FOR_DEVICE, @@ -232,15 +77,25 @@ export const start = (device: TrezorDevice, network: string, ignoreCompleted?: b return; } + const blockchain = getState().blockchain.find(b => b.name === network); + if (blockchain && !blockchain.connected && (!discoveryProcess || !discoveryProcess.completed)) { + dispatch({ + type: DISCOVERY.WAITING_FOR_BLOCKCHAIN, + device, + network, + }); + return; + } + if (!discoveryProcess) { - dispatch(begin(device, network)); + dispatch(begin(device, network)) } else if (discoveryProcess.completed && !ignoreCompleted) { dispatch({ type: DISCOVERY.COMPLETE, device, network, }); - } else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice) { + } else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice || discoveryProcess.waitingForBlockchain) { // discovery cycle was interrupted // start from beginning dispatch(begin(device, network)); @@ -249,7 +104,10 @@ export const start = (device: TrezorDevice, network: string, ignoreCompleted?: b } }; -begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { +// first iteration +// generate public key for this account +// start discovery process +const begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { const { config } = getState().localStorage; const coinToDiscover = config.coins.find(c => c.network === network); if (!coinToDiscover) return; @@ -272,10 +130,8 @@ begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: useEmptyPassphrase: !device.instance, }); - // handle TREZOR response error + // handle TREZOR response error if (!response.success) { - // TODO: check message - console.warn('DISCOVERY ERROR', response); dispatch({ type: NOTIFICATION.ADD, payload: { @@ -312,14 +168,113 @@ begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: basePath, }); + // next iteration dispatch(start(device, network)); }; +const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const { completed } = discoveryProcess; + discoveryProcess.completed = false; + + 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 + + try { + const account = await dispatch( BlockchainActions.discoverAccount(device, ethAddress, network) ); + if (discoveryProcess.interrupted) return; + + // const accountIsEmpty = account.transactions <= 0 && account.nonce <= 0 && account.balance === '0'; + const accountIsEmpty = account.nonce <= 0 && account.balance === '0'; + if (!accountIsEmpty || (accountIsEmpty && completed) || (accountIsEmpty && discoveryProcess.accountIndex === 0)) { + + dispatch({ + type: ACCOUNT.CREATE, + payload: { + index: discoveryProcess.accountIndex, + loaded: true, + network, + deviceID: device.features ? device.features.device_id : '0', + deviceState: device.state || '0', + addressPath: path, + address: ethAddress, + balance: account.balance, + nonce: account.nonce, + block: account.block, + transactions: account.transactions + } + }); + } + + if (accountIsEmpty) { + dispatch( finish(device, discoveryProcess) ); + } else { + if (!completed) { dispatch( discoverAccount(device, discoveryProcess) ); } + } + + } catch (error) { + + dispatch({ + type: DISCOVERY.STOP, + device + }); + + dispatch({ + type: NOTIFICATION.ADD, + payload: { + type: 'error', + title: 'Account discovery error', + message: error.message, + cancelable: true, + actions: [ + { + label: 'Try again', + callback: () => { + dispatch(start(device, discoveryProcess.network)); + }, + }, + ], + }, + }); + } +}; + +const finish = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + await TrezorConnect.getFeatures({ + device: { + path: device.path, + instance: device.instance, + state: device.state, + }, + keepSession: false, + useEmptyPassphrase: !device.instance, + }); + + await dispatch( BlockchainActions.subscribe(discoveryProcess.network) ); + + if (discoveryProcess.interrupted) return; + + dispatch({ + type: DISCOVERY.COMPLETE, + device, + network: discoveryProcess.network, + }); + +} + +export const reconnect = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + await dispatch(BlockchainActions.subscribe(network)); + dispatch(restore()); +} + export const restore = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { const selected = getState().wallet.selectedDevice; - if (selected && selected.connected && selected.features) { - const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.waitingForDevice); + const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && (d.interrupted || d.waitingForDevice || d.waitingForBlockchain)); if (discoveryProcess) { dispatch(start(selected, discoveryProcess.network)); } diff --git a/src/actions/PendingTxActions.js b/src/actions/PendingTxActions.js index f9ebb839..b4f398d3 100644 --- a/src/actions/PendingTxActions.js +++ b/src/actions/PendingTxActions.js @@ -7,6 +7,9 @@ import type { State, PendingTx } from 'reducers/PendingTxReducer'; export type PendingTxAction = { type: typeof PENDING.FROM_STORAGE, payload: State +} | { + type: typeof PENDING.ADD, + payload: PendingTx } | { type: typeof PENDING.TX_RESOLVED, tx: PendingTx, diff --git a/src/actions/SelectedAccountActions.js b/src/actions/SelectedAccountActions.js index cb426256..0bacf1b3 100644 --- a/src/actions/SelectedAccountActions.js +++ b/src/actions/SelectedAccountActions.js @@ -47,8 +47,7 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct || prevState.accounts !== state.accounts || prevState.discovery !== state.discovery || prevState.tokens !== state.tokens - || prevState.pending !== state.pending - || prevState.web3 !== state.web3) { + || prevState.pending !== state.pending) { if (locationChange) { // dispose current account view dispatch(dispose()); @@ -59,7 +58,6 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct const discovery = stateUtils.getDiscoveryProcess(state); const tokens = stateUtils.getAccountTokens(state, account); const pending = stateUtils.getAccountPendingTx(state.pending, account); - const web3 = stateUtils.getWeb3(state); const payload: $ElementType = { location: location.pathname, @@ -68,7 +66,6 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct discovery, tokens, pending, - web3, }; let needUpdate: boolean = false; diff --git a/src/actions/SendFormActions.js b/src/actions/SendFormActions.js index ae2189bd..6288c9d6 100644 --- a/src/actions/SendFormActions.js +++ b/src/actions/SendFormActions.js @@ -12,6 +12,7 @@ import * as SEND from 'actions/constants/send'; import { initialState } from 'reducers/SendFormReducer'; import { findToken } from 'reducers/TokensReducer'; import { findDevice, getPendingAmount, getPendingNonce } from 'reducers/utils'; +import * as stateUtils from 'reducers/utils'; import type { Dispatch, @@ -27,7 +28,8 @@ import type { State, FeeLevel } from 'reducers/SendFormReducer'; import type { Account } from 'reducers/AccountsReducer'; import type { Props } from 'views/Wallet/views/AccountSend/Container'; import * as SessionStorageActions from './SessionStorageActions'; -import { estimateGas, pushTx } from './Web3Actions'; +import { prepareEthereumTx, serializeEthereumTx } from './TxActions'; +import * as BlockchainActions from './BlockchainActions'; export type SendTxAction = { type: typeof SEND.TX_COMPLETE, @@ -223,14 +225,13 @@ export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLi // initialize component -export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { +export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { const { account, network, - web3, } = getState().selectedAccount; - if (!account || !network || !web3) return; + if (!account || !network) return; const stateFromStorage = SessionStorageActions.load(getState().router.location.pathname); if (stateFromStorage) { @@ -243,7 +244,10 @@ export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): // TODO: check if there are some unfinished tx in localStorage - const gasPrice: BigNumber = new BigNumber(EthereumjsUnits.convert(web3.gasPrice, 'wei', 'gwei')) || new BigNumber(network.defaultGasPrice); + + // const gasPrice: BigNumber = new BigNumber(EthereumjsUnits.convert(web3.gasPrice, 'wei', 'gwei')) || new BigNumber(network.defaultGasPrice); + const gasPrice: BigNumber = await dispatch( BlockchainActions.getGasPrice(network.network, network.defaultGasPrice) ); + // const gasPrice: BigNumber = new BigNumber(network.defaultGasPrice); const gasLimit: string = network.defaultGasLimit.toString(); const feeLevels: Array = getFeeLevels(network.symbol, gasPrice, gasLimit); @@ -709,12 +713,9 @@ export const onNonceChange = (nonce: string): AsyncAction => async (dispatch: Di const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { const { - web3, network, } = getState().selectedAccount; - if (!web3 || !network) return; - - const w3 = web3.web3; + if (!network) return; const state: State = getState().sendForm; const requestedData = state.data; @@ -732,14 +733,7 @@ const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState: return; } - // TODO: allow data starting with 0x ... - const data: string = `0x${state.data.length % 2 === 0 ? state.data : `0${state.data}`}`; - const gasLimit = await estimateGas(w3, { - to: '0x0000000000000000000000000000000000000000', - data, - value: w3.toHex(w3.toWei(state.amount, 'ether')), - gasPrice: w3.toHex(EthereumjsUnits.convert(state.gasPrice, 'gwei', 'wei')), - }); + const gasLimit: number = await dispatch( BlockchainActions.estimateGasLimit(network.network, state.data, state.amount, state.gasPrice) ); if (getState().sendForm.data === requestedData) { dispatch(onGasLimitChange(gasLimit.toString())); @@ -777,56 +771,29 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge const { account, network, - web3, pending, } = getState().selectedAccount; - if (!account || !web3 || !network) return; + + if (!account || !network) return; const currentState: State = getState().sendForm; const isToken: boolean = currentState.currency !== currentState.networkSymbol; - const w3 = web3.web3; - const address_n = account.addressPath; - - let data: string = `0x${currentState.data}`; - let txAmount: string = w3.toHex(w3.toWei(currentState.amount, 'ether')); - let txAddress: string = currentState.address; - if (isToken) { - const token: ?Token = findToken(getState().tokens, account.address, currentState.currency, account.deviceState); - if (!token) return; - - const contract = web3.erc20.at(token.address); - const amountValue: string = new BigNumber(currentState.amount).times(Math.pow(10, token.decimals)).toString(10); - - data = contract.transfer.getData(currentState.address, amountValue, { - from: account.address, - gasLimit: currentState.gasLimit, - gasPrice: currentState.gasPrice, - }); - txAmount = '0x00'; - txAddress = token.address; - } - - const pendingNonce: number = getPendingNonce(pending); + const pendingNonce: number = stateUtils.getPendingNonce(pending); const nonce = pendingNonce > 0 && pendingNonce >= account.nonce ? pendingNonce : account.nonce; - console.warn('NONCE', nonce, account.nonce, pendingNonce); - - const txData = { - address_n, - // from: currentAddress.address - to: txAddress, - value: txAmount, - data, - chainId: web3.chainId, - nonce: w3.toHex(nonce), - gasLimit: w3.toHex(currentState.gasLimit), - gasPrice: w3.toHex(EthereumjsUnits.convert(currentState.gasPrice, 'gwei', 'wei')), - r: '', - s: '', - v: '', - }; + const txData = await dispatch( prepareEthereumTx({ + network: network.network, + token: isToken ? findToken(getState().tokens, account.address, currentState.currency, account.deviceState) : null, + from: account.address, + to: currentState.address, + amount: currentState.amount, + data: currentState.data, + gasLimit: currentState.gasLimit, + gasPrice: currentState.gasPrice, + nonce + }) ); const selected: ?TrezorDevice = getState().wallet.selectedDevice; if (!selected) return; @@ -861,9 +828,17 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge txData.v = signedTransaction.payload.v; try { - const tx = new EthereumjsTx(txData); - const serializedTx = `0x${tx.serialize().toString('hex')}`; - const txid: string = await pushTx(w3, serializedTx); + const serializedTx: string = await dispatch( serializeEthereumTx(txData) ); + const push = await TrezorConnect.pushTransaction({ + tx: serializedTx, + coin: network.network + }); + + if (!push.success) { + throw new Error( push.payload.error ); + } + + const txid = push.payload.txid; dispatch({ type: SEND.TX_COMPLETE, @@ -871,7 +846,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge selectedCurrency: currentState.currency, amount: currentState.amount, total: currentState.total, - tx, + tx: txData, nonce, txid, txData, diff --git a/src/actions/TokenActions.js b/src/actions/TokenActions.js index bac9ce9d..68860968 100644 --- a/src/actions/TokenActions.js +++ b/src/actions/TokenActions.js @@ -9,7 +9,7 @@ import type { import type { State, Token } from 'reducers/TokensReducer'; import type { Account } from 'reducers/AccountsReducer'; import type { NetworkToken } from 'reducers/LocalStorageReducer'; -import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions'; +import * as BlockchainActions from './BlockchainActions'; export type TokenAction = { type: typeof TOKEN.FROM_STORAGE, @@ -42,15 +42,11 @@ export const load = (input: string, network: string): AsyncAction => async (disp // when options is a large list (>200 items) return result.slice(0, 100); } - const web3instance = getState().web3.find(w3 => w3.network === network); - if (!web3instance) return; - const info = await getTokenInfoAsync(web3instance.erc20, input); + const info = await dispatch( BlockchainActions.getTokenInfo(input, network) ); if (info) { return [info]; } - //await resolveAfter(300000); - //await resolveAfter(3000); }; export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { @@ -68,9 +64,6 @@ export const setBalance = (tokenAddress: string, ethAddress: string, balance: st }; export const add = (token: NetworkToken, account: Account): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.find(w3 => w3.network === account.network); - if (!web3instance) return; - const tkn: Token = { loaded: false, deviceState: account.deviceState, @@ -88,7 +81,7 @@ export const add = (token: NetworkToken, account: Account): AsyncAction => async payload: tkn, }); - const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, tkn); + const tokenBalance = await dispatch( BlockchainActions.getTokenBalance(tkn) ); dispatch(setBalance(token.address, account.address, tokenBalance)); }; diff --git a/src/actions/TrezorConnectActions.js b/src/actions/TrezorConnectActions.js index f4b9925e..eeef3218 100644 --- a/src/actions/TrezorConnectActions.js +++ b/src/actions/TrezorConnectActions.js @@ -1,6 +1,6 @@ /* @flow */ import TrezorConnect, { - DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, + UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT } from 'trezor-connect'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as NOTIFICATION from 'actions/constants/notification'; @@ -9,14 +9,15 @@ import { getDuplicateInstanceNumber } from 'reducers/utils'; import { push } from 'react-router-redux'; - import type { DeviceMessage, - UiMessage, - TransportMessage, DeviceMessageType, - TransportMessageType, + UiMessage, UiMessageType, + TransportMessage, + TransportMessageType, + BlockchainMessage, + BlockchainMessageType, } from 'trezor-connect'; import type { @@ -115,11 +116,18 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS }); }); + TrezorConnect.on(BLOCKCHAIN_EVENT, (event: BlockchainMessage): void => { + // post event to reducers + const type: BlockchainMessageType = event.type; // assert flow type + dispatch({ + type, + payload: event.payload, + }); + }); + // $FlowIssue LOCAL not declared + window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/'; // window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/'; - // window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/'; - //window.__TREZOR_CONNECT_SRC = 'https://sisyfos.trezor.io/connect/'; - // window.__TREZOR_CONNECT_SRC = 'https://localhost:8088/'; try { await TrezorConnect.init({ diff --git a/src/actions/TxActions.js b/src/actions/TxActions.js new file mode 100644 index 00000000..8bdaed0e --- /dev/null +++ b/src/actions/TxActions.js @@ -0,0 +1,69 @@ +/* @flow */ + +import EthereumjsTx from 'ethereumjs-tx'; +import EthereumjsUnits from 'ethereumjs-units'; +import BigNumber from 'bignumber.js'; +import { toHex } from 'web3-utils'; +import { initWeb3 } from './Web3Actions'; + +import type { + Dispatch, + GetState, + PromiseAction, +} from 'flowtype'; + +import type { + EthereumTransaction +} from 'trezor-connect'; + +import type { Token } from 'reducers/TokensReducer'; + +type EthereumTxRequest = { + network: string; + token: ?Token; + from: string; + to: string; + amount: string; + data: string; + gasLimit: string; + gasPrice: string; + nonce: number; +} + + +export const prepareEthereumTx = (tx: EthereumTxRequest): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance = await dispatch( initWeb3(tx.network) ); + const token = tx.token; + let data: string = `0x${tx.data}`; // TODO: check if already prefixed + let value: string = toHex( EthereumjsUnits.convert(tx.amount, 'ether', 'wei') ); + let to: string = tx.to; + + if (token) { + // smart contract transaction + const contract = instance.erc20.clone(); + contract.options.address = token.address; + const tokenAmount: string = new BigNumber(tx.amount).times(Math.pow(10, token.decimals)).toString(10); + data = instance.erc20.methods.transfer(to, tokenAmount).encodeABI(); + value = '0x00'; + to = token.address; + } + + return { + to, + value, + data, + chainId: instance.chainId, + nonce: toHex(tx.nonce), + gasLimit: toHex(tx.gasLimit), + gasPrice: toHex( EthereumjsUnits.convert(tx.gasPrice, 'gwei', 'wei') ), + r: '', + s: '', + v: '', + } +}; + +export const serializeEthereumTx = (tx: EthereumTransaction): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const ethTx = new EthereumjsTx(tx); + return `0x${ ethTx.serialize().toString('hex') }`; + // return toHex( ethTx.serialize() ); +} \ No newline at end of file diff --git a/src/actions/WalletActions.js b/src/actions/WalletActions.js index a4bb0040..32830e26 100644 --- a/src/actions/WalletActions.js +++ b/src/actions/WalletActions.js @@ -5,8 +5,11 @@ import { LOCATION_CHANGE } from 'react-router-redux'; import * as WALLET from 'actions/constants/wallet'; import * as stateUtils from 'reducers/utils'; -import type -{ +import type { + Account, + Coin, + Discovery, + Token, Device, TrezorDevice, RouterLocationState, diff --git a/src/actions/Web3Actions.js b/src/actions/Web3Actions.js index e1c1b73e..b4611bd3 100644 --- a/src/actions/Web3Actions.js +++ b/src/actions/Web3Actions.js @@ -1,22 +1,27 @@ /* @flow */ import Web3 from 'web3'; +import HDKey from 'hdkey'; +import BigNumber from 'bignumber.js'; -import type { - ContractFactory, - EstimateGasOptions, - TransactionStatus, - TransactionReceipt, -} from 'web3'; -import type BigNumber from 'bignumber.js'; +import EthereumjsUtil from 'ethereumjs-util'; +import EthereumjsUnits from 'ethereumjs-units'; +import EthereumjsTx from 'ethereumjs-tx'; +// import InputDataDecoder from 'ethereum-input-data-decoder'; +import TrezorConnect from 'trezor-connect'; +import type { EstimateGasOptions, TransactionStatus, TransactionReceipt } from 'web3'; +import { strip } from 'utils/ethUtils'; import * as WEB3 from 'actions/constants/web3'; import * as PENDING from 'actions/constants/pendingTx'; import type { Dispatch, GetState, + ThunkAction, AsyncAction, + PromiseAction, } from 'flowtype'; +import type { EthereumAccount } from 'trezor-connect'; import type { Account } from 'reducers/AccountsReducer'; import type { PendingTx } from 'reducers/PendingTxReducer'; import type { Web3Instance } from 'reducers/Web3Reducer'; @@ -40,379 +45,266 @@ export type Web3UpdateGasPriceAction = { export type Web3Action = { type: typeof WEB3.READY, } | { - type: typeof WEB3.CREATE, + type: typeof WEB3.START, +} | { + type: typeof WEB3.CREATE | typeof WEB3.DISCONNECT, instance: Web3Instance -} - | Web3UpdateBlockAction - | Web3UpdateGasPriceAction; +} | Web3UpdateBlockAction + | Web3UpdateGasPriceAction; -export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { +export const initWeb3 = (network: string, urlIndex: number = 0): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + return new Promise(async (resolve, reject) => { + // check if requested web was initialized before + const instance = getState().web3.find(w3 => w3.network === network); + if (instance && instance.web3.currentProvider.connected) { + resolve(instance); + return; + } + + // requested web3 wasn't initialized or is disconnected + // initialize again const { config, ERC20Abi } = getState().localStorage; - - const coin = config.coins[coinIndex]; + const coin = config.coins.find(c => c.network === network); if (!coin) { - // all instances done - dispatch({ - type: WEB3.READY, - }); + // coin not found + reject(new Error(`Network ${ network} not found in application config.`)); return; } - const { network } = coin; - const urls = coin.backends[0].urls; - - let web3host: string = urls[0]; - - if (instance) { - const currentHost = instance.currentProvider.host; - const currentHostIndex: number = urls.indexOf(currentHost); - - if (currentHostIndex + 1 < urls.length) { - web3host = urls[currentHostIndex + 1]; - } else { - console.error(`TODO: Backend ${network} not working`, instance.currentProvider); - - dispatch({ - type: WEB3.CREATE, - instance: { - network, - web3: instance, - chainId: coin.chainId, - erc20: instance.eth.contract(ERC20Abi), - latestBlock: '0', - gasPrice: '0', - }, - }); - - // try next coin - dispatch(init(null, coinIndex + 1)); - return; - } - } - - //const instance = new Web3(window.web3.currentProvider); - const web3 = new Web3(new Web3.providers.HttpProvider(web3host)); - - // instance = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') ); // UBQ - //instance = new Web3( new Web3.providers.HttpProvider('https://node.expanse.tech/') ); // EXP - //instance = new Web3( new Web3.providers.HttpProvider('http://10.34.0.91:8545/') ); - - //web3 = new Web3(new Web3.providers.HttpProvider("https://api.myetherapi.com/rop")); - //instance = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io2/QGyVKozSUEh2YhL4s2G4")); - //web3 = new Web3( new Web3.providers.HttpProvider("ws://34.230.234.51:30303") ); - - - // initial check if backend is running - if (!web3.currentProvider.isConnected()) { - // try different url - dispatch(init(web3, coinIndex)); + // get first url + const url = coin.web3[ urlIndex ]; + if (!url) { + reject(new Error('Web3 backend is not responding')); return; } - const erc20 = web3.eth.contract(ERC20Abi); + const web3 = new Web3( new Web3.providers.WebsocketProvider(url) ); - dispatch({ - type: WEB3.CREATE, - instance: { + const onConnect = async () => { + + const latestBlock = await web3.eth.getBlockNumber(); + const gasPrice = await web3.eth.getGasPrice(); + + const instance = { network, web3, chainId: coin.chainId, - erc20, - latestBlock: '0', - gasPrice: '0', - }, - }); - - // dispatch({ - // type: WEB3.GAS_PRICE_UPDATED, - // network, - // gasPrice - // }); - - - // console.log("GET CHAIN", instance.version.network) - - // instance.version.getWhisper((err, shh) => { - // console.log("-----whisperrr", error, shh) - // }) - - - // const sshFilter = instance.ssh.filter('latest'); - // sshFilter.watch((error, blockHash) => { - // console.warn("SSH", error, blockHash); - // }); - - //const shh = instance.shh.newIdentity(); - - // const latestBlockFilter = web3.eth.filter('latest'); - - const onBlockMined = async (error: ?Error, blockHash: ?string) => { - if (error) { - window.setTimeout(() => { - // try again - onBlockMined(new Error('manually_triggered_error'), undefined); - }, 30000); + erc20: new web3.eth.Contract(ERC20Abi), + latestBlock, + gasPrice, } - if (blockHash) { - dispatch({ - type: WEB3.BLOCK_UPDATED, - network, - blockHash, - }); - } + dispatch({ + type: WEB3.CREATE, + instance, + }); - // TODO: filter only current device - const accounts = getState().accounts.filter(a => a.network === network); - for (const account of accounts) { - const nonce = await getNonceAsync(web3, account.address); - if (nonce !== account.nonce) { - dispatch(AccountsActions.setNonce(account.address, account.network, account.deviceState, nonce)); + resolve(instance); + } - // dispatch( getBalance(account) ); - // TODO: check if nonce was updated, - // update tokens balance, - // update account balance, - // update pending transactions + const onEnd = async () => { + + web3.currentProvider.reset(); + const instance = getState().web3.find(w3 => w3.network === network); + + if (instance && instance.web3.currentProvider.connected) { + // backend disconnects + // dispatch({ + // type: 'WEB3.DISCONNECT', + // network + // }); + } else { + // backend initialization error for given url, try next one + try { + const web3 = await dispatch( initWeb3(network, urlIndex + 1) ); + resolve(web3); + } catch (error) { + reject(error); } - dispatch(getBalance(account)); - // dispatch( getNonce(account) ); } + } - const tokens = getState().tokens.filter(t => t.network === network); - tokens.forEach(token => dispatch(getTokenBalance(token))); + web3.currentProvider.on('connect', onConnect); + web3.currentProvider.on('end', onEnd); + web3.currentProvider.on('error', onEnd); + }); +} - dispatch(getGasPrice(network)); - - const pending = getState().pending.filter(p => p.network === network); - pending.forEach(pendingTx => dispatch(getTransactionReceipt(pendingTx))); - }; - - // latestBlockFilter.watch(onBlockMined); - onBlockMined(new Error('manually_triggered_error'), undefined); - - - // init next coin - dispatch(init(web3, coinIndex + 1)); - - - // let instance2 = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') ); - // console.log("INIT WEB3", instance, instance2); - // instance2.eth.getGasPrice((error, gasPrice) => { - // console.log("---gasss price from UBQ", gasPrice) - // }); +export const discoverAccount = (address: string, network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance: Web3Instance = await dispatch( initWeb3(network) ); + const balance = await instance.web3.eth.getBalance(address); + const nonce = await instance.web3.eth.getTransactionCount(address); + return { + address, + transactions: 0, + block: 0, + balance: EthereumjsUnits.convert(balance, 'wei', 'ether'), + nonce }; } - -export function getGasPrice(network: string): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const index: number = getState().web3.findIndex(w3 => w3.network === network); - - const web3instance = getState().web3[index]; - const { web3 } = web3instance; - web3.eth.getGasPrice((error, gasPrice) => { - if (!error) { - if (web3instance.gasPrice && web3instance.gasPrice.toString() !== gasPrice.toString()) { - dispatch({ - type: WEB3.GAS_PRICE_UPDATED, - network, - gasPrice, - }); - } - } - }); - }; -} - -export function getBalance(account: Account): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0]; - const { web3 } = web3instance; - - web3.eth.getBalance(account.address, (error: Error, balance: BigNumber) => { - if (!error) { - const newBalance: string = web3.fromWei(balance.toString(), 'ether'); - if (account.balance !== newBalance) { - dispatch(AccountsActions.setBalance( - account.address, - account.network, - account.deviceState, - newBalance, - )); - - // dispatch( loadHistory(addr) ); - } - } - }); - }; -} - -export function getTokenBalance(token: Token): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === token.network)[0]; - const contract = web3instance.erc20.at(token.address); - - contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => { - if (balance) { - const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10); - if (newBalance !== token.balance) { - dispatch(TokenActions.setBalance( - token.address, - token.ethAddress, - newBalance, - )); - } - } - }); - }; -} - -export function getNonce(account: Account): AsyncAction { - return async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0]; - const { web3 } = web3instance; - - web3.eth.getTransactionCount(account.address, (error: Error, result: number) => { - if (!error) { - if (account.nonce !== result) { - dispatch(AccountsActions.setNonce(account.address, account.network, account.deviceState, result)); - } - } - }); - }; -} - -export const getTransactionReceipt = (tx: PendingTx): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { - const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0]; - const { web3 } = web3instance; - - web3.eth.getTransaction(tx.id, (error: Error, status: TransactionStatus) => { - if (!error && !status) { +export const resolvePendingTransactions = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance: Web3Instance = await dispatch( initWeb3(network) ); + const pending = getState().pending.filter(p => p.network === network); + for (const tx of pending) { + const status = await instance.web3.eth.getTransaction(tx.id); + if (!status) { dispatch({ type: PENDING.TX_NOT_FOUND, tx, }); - } else if (status && status.blockNumber) { - web3.eth.getTransactionReceipt(tx.id, (error: Error, receipt: TransactionReceipt) => { - if (receipt) { - if (status.gas !== receipt.gasUsed) { - dispatch({ - type: PENDING.TX_TOKEN_ERROR, - tx, - }); - } + } else { + const receipt = await instance.web3.eth.getTransactionReceipt(tx.id); + if (receipt) { + if (status.gas !== receipt.gasUsed) { dispatch({ - type: PENDING.TX_RESOLVED, + type: PENDING.TX_TOKEN_ERROR, tx, - receipt, }); } - }); + dispatch({ + type: PENDING.TX_RESOLVED, + tx, + receipt, + }); + } } - }); + } +} + +export const getPendingInfo = (network: string, txid: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance: Web3Instance = await dispatch( initWeb3(network) ); + const tx = await instance.web3.eth.getTransaction(txid); + + /* + if (tx.input !== "0x") { + // find token: + // tx.to <= smart contract address + + // smart contract data + const decoder = new InputDataDecoder(instance.erc20.options.jsonInterface); + const data = decoder.decodeData(tx.input); + if (data.name === 'transfer') { + console.warn("DATA!", data.inputs[0], data.inputs[1].toString(10)); + } + + + } + */ + // return tx; +} + +export const getTxInput = (): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance: Web3Instance = await dispatch( initWeb3("ropsten") ); + // const inputData = instance.web3.utils.hexToAscii("0xa9059cbb00000000000000000000000073d0385f4d8e00c5e6504c6030f47bf6212736a80000000000000000000000000000000000000000000000000000000000000001"); + // console.warn("input data!", inputData); +} + + +export const updateAccount = (account: Account, newAccount: EthereumAccount, network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): 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); + dispatch( AccountsActions.update( { ...account, ...newAccount, balance: EthereumjsUnits.convert(balance, 'wei', 'ether'), nonce }) ); + + // update tokens for this account + dispatch( updateAccountTokens(account) ); +} + +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); + for (const token of tokens) { + const balance = await dispatch( getTokenBalance(token) ); + // const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10); + if (balance !== token.balance) { + dispatch(TokenActions.setBalance( + token.address, + token.ethAddress, + balance, + )); + } + } +} + +export const getTokenInfo = (address: string, network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance: Web3Instance = await dispatch( initWeb3(network) ); + const contract = instance.erc20.clone(); + contract.options.address = address; + + const name = await contract.methods.name().call(); + const symbol = await contract.methods.symbol().call(); + const decimals = await contract.methods.decimals().call(); + + return { + address, + name, + symbol, + decimals, + }; }; -export const getTransaction = (web3: Web3, txid: string): Promise => new Promise((resolve, reject) => { - web3.eth.getTransaction(txid, (error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); -}); +export const getTokenBalance = (token: Token): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance = await dispatch( initWeb3(token.network) ); + const contract = instance.erc20.clone(); + contract.options.address = token.address; -export const getBalanceAsync = (web3: Web3, address: string): Promise => new Promise((resolve, reject) => { - web3.eth.getBalance(address, (error: Error, result: BigNumber) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); -}); + const balance = await contract.methods.balanceOf(token.ethAddress).call(); + return new BigNumber(balance).dividedBy(Math.pow(10, token.decimals)).toString(10); +}; -export const getTokenBalanceAsync = (erc20: ContractFactory, token: Token): Promise => new Promise((resolve, reject) => { - const contract = erc20.at(token.address); - contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => { - if (error) { - reject(error); - } else { - const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10); - resolve(newBalance); - } - }); -}); +export const getCurrentGasPrice = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance = getState().web3.find(w3 => w3.network === network); + if (instance) { + return EthereumjsUnits.convert(instance.gasPrice, 'wei', 'gwei'); + } else { + throw "0"; + } +} -export const getNonceAsync = (web3: Web3, address: string): Promise => new Promise((resolve, reject) => { - web3.eth.getTransactionCount(address, (error: Error, result: number) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); -}); - - -export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise => new Promise((resolve) => { - const contract = erc20.at(address, (error/* , res */) => { - // console.warn("callback", error, res) - }); - - const info: NetworkToken = { - address, - name: '', - symbol: '', - decimals: 0, - }; - - contract.name.call((error: Error, name: string) => { - if (error) { - resolve(null); - return; - } - info.name = name; - - - contract.symbol.call((error: Error, symbol: string) => { - if (error) { - resolve(null); - return; - } - info.symbol = symbol; - - - contract.decimals.call((error: Error, decimals: BigNumber) => { - if (decimals) { - info.decimals = decimals.toNumber(); - resolve(info); - } else { - resolve(null); - } +export const updateGasPrice = (network: string): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + try { + const instance = await dispatch( initWeb3(network) ); + const gasPrice = await instance.web3.eth.getGasPrice(); + if (instance.gasPrice !== gasPrice) { + dispatch({ + type: WEB3.GAS_PRICE_UPDATED, + network, + gasPrice }); + } + } catch (e) { + // silent action + // nothing happens if this fails + } +} + + +export const estimateGasLimit = (network: string, options: EstimateGasOptions): PromiseAction => async (dispatch: Dispatch, getState: GetState): Promise => { + const instance = await dispatch( initWeb3(network) ); + // TODO: allow data starting with 0x ... + options.to = '0x0000000000000000000000000000000000000000'; + options.data = `0x${options.data.length % 2 === 0 ? options.data : `0${options.data}`}`; + options.value = instance.web3.utils.toHex( EthereumjsUnits.convert(options.value || '0', 'ether', 'wei') ); + options.gasPrice = instance.web3.utils.toHex( EthereumjsUnits.convert(options.gasPrice, 'gwei', 'wei') ); + + const limit = await instance.web3.eth.estimateGas(options); + return limit; +}; + +export const disconnect = (coinInfo: any): ThunkAction => (dispatch: Dispatch, getState: GetState): void => { + // incoming "coinInfo" from TrezorConnect is CoinInfo | EthereumNetwork type + const network: string = coinInfo.shortcut.toLowerCase(); + // check if Web3 was already initialized + const instance = getState().web3.find(w3 => w3.network === network); + if (instance) { + // reset current connection + instance.web3.currentProvider.reset(); + instance.web3.currentProvider.connection.close(); + + // remove instance from reducer + dispatch({ + type: WEB3.DISCONNECT, + instance }); - }); -}); - -export const estimateGas = (web3: Web3, options: EstimateGasOptions): Promise => new Promise((resolve, reject) => { - web3.eth.estimateGas(options, (error: ?Error, gas: ?number) => { - if (error) { - reject(error); - } else if (typeof gas === 'number') { - resolve(gas); - } - }); -}); - -export const pushTx = (web3: Web3, tx: any): Promise => new Promise((resolve, reject) => { - web3.eth.sendRawTransaction(tx, (error: Error, result: string) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); -}); \ No newline at end of file + } +}; diff --git a/src/actions/constants/account.js b/src/actions/constants/account.js index 18075a00..d1baa199 100644 --- a/src/actions/constants/account.js +++ b/src/actions/constants/account.js @@ -6,6 +6,7 @@ export const DISPOSE: 'account__dispose' = 'account__dispose'; export const CREATE: 'account__create' = 'account__create'; export const REMOVE: 'account__remove' = 'account__remove'; +export const UPDATE: 'account__update' = 'account__update'; export const SET_BALANCE: 'account__set_balance' = 'account__set_balance'; export const SET_NONCE: 'account__set_nonce' = 'account__set_nonce'; export const FROM_STORAGE: 'account__from_storage' = 'account__from_storage'; diff --git a/src/actions/constants/blockchain.js b/src/actions/constants/blockchain.js new file mode 100644 index 00000000..ff0d9b36 --- /dev/null +++ b/src/actions/constants/blockchain.js @@ -0,0 +1,6 @@ +/* @flow */ + +export const READY: 'blockchain__ready' = 'blockchain__ready'; +export const CONNECTING: 'blockchain__connecting' = 'blockchain__connecting'; +export const CONNECTED: 'blockchain__connected' = 'blockchain__connected'; +export const DISCONNECTED: 'blockchain__disconnected' = 'blockchain__disconnected'; \ No newline at end of file diff --git a/src/actions/constants/discovery.js b/src/actions/constants/discovery.js index 1fca3045..e7287b1e 100644 --- a/src/actions/constants/discovery.js +++ b/src/actions/constants/discovery.js @@ -5,5 +5,5 @@ export const START: 'discovery__start' = 'discovery__start'; export const STOP: 'discovery__stop' = 'discovery__stop'; export const COMPLETE: 'discovery__complete' = 'discovery__complete'; export const WAITING_FOR_DEVICE: 'discovery__waiting_for_device' = 'discovery__waiting_for_device'; -export const WAITING_FOR_BACKEND: 'discovery__waiting_for_backend' = 'discovery__waiting_for_backend'; +export const WAITING_FOR_BLOCKCHAIN: 'discovery__waiting_for_blockchain' = 'discovery__waiting_for_blockchain'; export const FROM_STORAGE: 'discovery__from_storage' = 'discovery__from_storage'; \ No newline at end of file diff --git a/src/actions/constants/pendingTx.js b/src/actions/constants/pendingTx.js index c2cfc0c2..04f8ef91 100644 --- a/src/actions/constants/pendingTx.js +++ b/src/actions/constants/pendingTx.js @@ -2,6 +2,7 @@ export const FROM_STORAGE: 'pending__from_storage' = 'pending__from_storage'; +export const ADD: 'pending__add' = 'pending__add'; export const TX_RESOLVED: 'pending__tx_resolved' = 'pending__tx_resolved'; export const TX_NOT_FOUND: 'pending__tx_not_found' = 'pending__tx_not_found'; export const TX_TOKEN_ERROR: 'pending__tx_token_error' = 'pending__tx_token_error'; \ No newline at end of file diff --git a/src/actions/constants/web3.js b/src/actions/constants/web3.js index 232db739..54b8836f 100644 --- a/src/actions/constants/web3.js +++ b/src/actions/constants/web3.js @@ -7,4 +7,5 @@ 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 +export const PENDING_TX_RESOLVED: 'web3__pending_tx_resolved' = 'web3__pending_tx_resolved'; +export const DISCONNECT: 'web3__disconnect' = 'web3__disconnect'; \ No newline at end of file diff --git a/src/flowtype/index.js b/src/flowtype/index.js index 025df015..ece6a996 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -7,6 +7,8 @@ import type { Middleware as ReduxMiddleware, ThunkAction as ReduxThunkAction, AsyncAction as ReduxAsyncAction, + PromiseAction as ReduxPromiseAction, + ThunkDispatch as ReduxThunkDispatch, PlainDispatch as ReduxPlainDispatch, } from 'redux'; @@ -15,6 +17,7 @@ import type { ReducersState } from 'reducers'; // Actions import type { SelectedAccountAction } from 'actions/SelectedAccountActions'; import type { AccountAction } from 'actions/AccountsActions'; +import type { BlockchainAction } from 'actions/BlockchainActions'; import type { DiscoveryAction } from 'actions/DiscoveryActions'; import type { StorageAction } from 'actions/LocalStorageActions'; import type { LogAction } from 'actions/LogActions'; @@ -37,6 +40,7 @@ import type { DeviceFirmwareStatus, DeviceMessageType, TransportMessageType, + BlockchainMessageType, UiMessageType, } from 'trezor-connect'; @@ -102,6 +106,11 @@ type UiEventAction = { // }, } +type BlockchainEventAction = { + type: BlockchainMessageType, + payload: any, +} + // TODO: join this message with uiMessage type IFrameHandshake = { type: 'iframe_handshake', @@ -114,9 +123,11 @@ export type Action = | TransportEventAction | DeviceEventAction | UiEventAction + | BlockchainEventAction | SelectedAccountAction | AccountAction + | BlockchainAction | DiscoveryAction | StorageAction | LogAction @@ -154,6 +165,7 @@ export type Middleware = ReduxMiddleware; export type ThunkAction = ReduxThunkAction; export type AsyncAction = ReduxAsyncAction; +export type PromiseAction = ReduxPromiseAction; export type Store = ReduxStore; export type GetState = () => State; diff --git a/src/flowtype/npm/bignumber.js b/src/flowtype/npm/bignumber.js index 5fa3a6fe..9f34ac28 100644 --- a/src/flowtype/npm/bignumber.js +++ b/src/flowtype/npm/bignumber.js @@ -1,3 +1,5 @@ +/* @flow */ + declare module 'bignumber.js' { declare type $npm$big$number$object = number | string | T_BigNumber declare type $npm$cmp$result = -1 | 0 | 1 @@ -24,7 +26,7 @@ declare module 'bignumber.js' { constructor(value: $npm$big$number$object): T_BigNumber; // Methods - abs(): BigNumber; + abs(): T_BigNumber; cmp(n: $npm$big$number$object): $npm$cmp$result; div(n: $npm$big$number$object): T_BigNumber; dividedBy(n: $npm$big$number$object): T_BigNumber; diff --git a/src/flowtype/npm/redux_v3.x.x.js b/src/flowtype/npm/redux_v3.x.x.js index d0717bdf..cdd88212 100644 --- a/src/flowtype/npm/redux_v3.x.x.js +++ b/src/flowtype/npm/redux_v3.x.x.js @@ -1,10 +1,12 @@ +/* @flow */ + declare module 'redux' { /* S = State A = Action D = Dispatch - + R = Promise response */ declare export type DispatchAPI = (action: A) => A; @@ -13,12 +15,14 @@ declare module 'redux' { declare export type ThunkAction = (dispatch: ReduxDispatch, getState: () => S) => void; declare export type AsyncAction = (dispatch: ReduxDispatch, getState: () => S) => Promise; + declare export type PromiseAction = (dispatch: ReduxDispatch, getState: () => S) => Promise; declare export type ThunkDispatch = (action: ThunkAction) => void; declare export type AsyncDispatch = (action: AsyncAction) => Promise; + declare export type PromiseDispatch = (action: PromiseAction) => Promise; declare export type PlainDispatch}> = DispatchAPI; /* NEW: Dispatch is now a combination of these different dispatch types */ - declare export type ReduxDispatch = PlainDispatch & ThunkDispatch & AsyncDispatch; + declare export type ReduxDispatch = PlainDispatch & ThunkDispatch & AsyncDispatch & PromiseDispatch; declare export type MiddlewareAPI = { // dispatch: Dispatch; diff --git a/src/flowtype/npm/web3.js b/src/flowtype/npm/web3.js index 81e27543..1b04d7d4 100644 --- a/src/flowtype/npm/web3.js +++ b/src/flowtype/npm/web3.js @@ -1,8 +1,10 @@ +/* @flow */ + import type BigNumber from 'bignumber.js'; import type { EthereumUnitT, EthereumAddressT } from 'ethereum-types'; declare module 'web3' { - declare type ProviderT = { + declare type HttpProviderT = { host: string; timeout: number; isConnected: () => boolean; @@ -10,14 +12,28 @@ declare module 'web3' { sendAsync: (payload: any, callback: (error: Error, result: any) => void) => any; }; + declare type WebsocketProviderT = { + connection: { + close: () => void; + }; // WebSocket type + on: (type: string, callback: () => any) => void; + removeAllListeners: (type: string) => void; + reset: () => void; + connected: boolean; + } + declare class Web3T { static providers: { - HttpProvider: (host: string, timeout?: number) => ProviderT; + HttpProvider: (host: string, timeout?: number) => HttpProviderT; + WebsocketProvider: (host: string, options?: any) => WebsocketProviderT; }; - constructor(ProviderT): Web3T; - currentProvider: ProviderT; + // constructor(HttpProviderT): Web3T; + constructor(WebsocketProviderT): Web3T; + // currentProvider: HttpProviderT; + currentProvider: WebsocketProviderT; eth: Eth; + utils: Utils; toHex: (str: string | number) => string; isAddress: (address: string) => boolean; @@ -78,20 +94,33 @@ declare module 'web3' { transactionIndex: number } + //declare function F_CardanoGetAddress(params: (P.$Common & CARDANO.$CardanoGetAddress)): Promise; + //declare function F_CardanoGetAddress(params: (P.$Common & { bundle: Array })): Promise; + + declare type PromiseEvent = { + once: typeof F_PromiseEventOn; + on: typeof F_PromiseEventOn; + off: (type: string, callback: Function) => PromiseEvent; + then: () => (result: T) => PromiseEvent; + catch: () => (error: Error) => PromiseEvent; + } + + declare function F_PromiseEventOn(type: 'transactionHash', callback: (hash: string) => void): PromiseEvent; + declare function F_PromiseEventOn(type: 'receipt', callback: (receipt: TransactionReceipt) => void): PromiseEvent; + declare function F_PromiseEventOn(type: 'confirmation', callback: (confirmations: number, receipt: TransactionReceipt) => void): PromiseEvent; + declare function F_PromiseEventOn(type: 'error', callback: (error: Error) => void): PromiseEvent; + declare class Eth { - getGasPrice: (callback: (error: Error, gasPrice: string) => void) => void, - getBalance: (address: string, callback: (error: Error, balance: BigNumber) => void) => void, - getTransactionCount: (address: string, callback: (error: Error, result: number) => void) => void, - getTransaction: (txid: string, callback: (error: Error, result: TransactionStatus) => void) => void, - getTransactionReceipt: (txid: string, callback: (error: Error, result: TransactionReceipt) => void) => void, - getBlockNumber: (callback: (error: Error, blockNumber: number) => void) => void, - getBlock: (hash: string, callback: (error: Error, result: any) => void) => void, - // getAccounts: (callback: (error: Error, accounts: Array) => void) => void, - // sign: (payload: string, signer: EthereumAddressT) => Promise, - contract: (abi: Array) => ContractFactory, - estimateGas: (options: EstimateGasOptions, callback: (error: ?Error, gas: ?number) => void) => void, - sendRawTransaction: (tx: any, callback: (error: Error, result: string) => void) => void, - filter: (type: string) => Filter; // return intance with "watch" + getBalance: (address: string) => Promise; + getTransactionCount: (address: string) => Promise; + estimateGas: (options: EstimateGasOptions) => Promise; + getGasPrice: () => Promise; + getBlockNumber: () => Promise; + Contract: (abi: Array, options?: any) => Contract; + sendSignedTransaction: (tx: string) => PromiseEvent; + getTransaction: (txid: string) => Promise; + getTransactionReceipt: (txid: string) => Promise; + subscribe: (type: string, callback: Function) => any; } declare export class Filter { @@ -99,108 +128,40 @@ declare module 'web3' { stopWatching: (callback: any) => void, } - declare export class ContractFactory { - // constructor(abi: Array); - eth: Eth; - abi: Array; - at: (address: string, callback: ?(error: Error, contract: Contract) => void) => Contract; // TODO + declare type ContractMethod = { + call: () => Promise; } declare export class Contract { - name: { - call: (callback: (error: Error, name: string) => void) => void; - }, - symbol: { - call: (callback: (error: Error, symbol: string) => void) => void; - }, - decimals: { - call: (callback: (error: Error, decimals: BigNumber) => void) => void; - }, - balanceOf: (address: string, callback: (error: Error, balance: BigNumber) => void) => void, - transfer: any, + clone: () => Contract; + + options: { + address: string; + jsonInterface: JSON; + }; + + methods: { + name: () => ContractMethod; + symbol: () => ContractMethod; + decimals: () => ContractMethod; + balanceOf: (address: string) => ContractMethod; + transfer: (to: string, amount: any) => { + encodeABI: () => string; + } + }; + } + + declare class Utils { + toHex: (str: string | number) => string; + hexToNumberString: (str: string) => string; + + isAddress: (address: string) => boolean; + toWei: (number: BigNumber, unit?: EthereumUnitT) => BigNumber; + toWei: (number: string, unit?: EthereumUnitT) => string; + toDecimal: (number: BigNumber) => number; + toDecimal: (number: string) => number; + soliditySha3: (payload: string | number | BigNumber | Object) => String; } declare export default typeof Web3T; -} - - -// -// - - -/*declare module 'web3' { - - module.exports = { - eth: { - _requestManager: any; - iban: { - (iban: string): void; - fromAddress: (address: string) => any; - fromBban: (bban: string) => any; - createIndirect: (options: any) => any; - isValid: (iban: string) => boolean; - }; - sendIBANTransaction: any; - contract: (abi: any) => { - eth: any; - abi: any[]; - new: (...args: any[]) => { - _eth: any; - transactionHash: any; - address: any; - abi: any[]; - }; - at: (address: any, callback: Function) => any; - getData: (...args: any[]) => any; - }; - filter: (fil: any, callback: any, filterCreationErrorCallback: any) => { - requestManager: any; - options: any; - implementation: { - [x: string]: any; - }; - filterId: any; - callbacks: any[]; - getLogsCallbacks: any[]; - pollFilters: any[]; - formatter: any; - watch: (callback: any) => any; - stopWatching: (callback: any) => any; - get: (callback: any) => any; - }; - namereg: () => { - eth: any; - abi: any[]; - new: (...args: any[]) => { - _eth: any; - transactionHash: any; - address: any; - abi: any[]; - }; - at: (address: any, callback: Function) => any; - getData: (...args: any[]) => any; - }; - icapNamereg: () => { - eth: any; - abi: any[]; - new: (...args: any[]) => { - _eth: any; - transactionHash: any; - address: any; - abi: any[]; - }; - at: (address: any, callback: Function) => any; - getData: (...args: any[]) => any; - }; - isSyncing: (callback: any) => { - requestManager: any; - pollId: string; - callbacks: any[]; - lastSyncState: boolean; - addCallback: (callback: any) => any; - stopWatching: () => void; - }; - } - } -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/images/ropsten-logo.png b/src/images/trop-logo.png similarity index 100% rename from src/images/ropsten-logo.png rename to src/images/trop-logo.png diff --git a/src/reducers/AccountsReducer.js b/src/reducers/AccountsReducer.js index c601424f..df05ff00 100644 --- a/src/reducers/AccountsReducer.js +++ b/src/reducers/AccountsReducer.js @@ -7,7 +7,6 @@ import * as ACCOUNT from 'actions/constants/account'; import type { Action, TrezorDevice } from 'flowtype'; import type { - AccountCreateAction, AccountSetBalanceAction, AccountSetNonceAction, } from 'actions/AccountsActions'; @@ -22,6 +21,8 @@ export type Account = { +address: string; balance: string; nonce: number; + block: number; + transactions: number; } export type State = Array; @@ -37,28 +38,14 @@ export const findDeviceAccounts = (state: State, device: TrezorDevice, network: return state.filter(addr => addr.deviceState === device.state); }; -const createAccount = (state: State, action: AccountCreateAction): State => { +const createAccount = (state: State, account: Account): State => { // TODO check with device_id // check if account was created before - // const exist: ?Account = state.find(account => account.address === action.address && account.network === action.network && action.device.features && account.deviceID === action.device.features.device_id); - const exist: ?Account = state.find(account => account.address === action.address && account.network === action.network && account.deviceState === action.device.state); + const exist: ?Account = state.find(a => a.address === account.address && a.network === account.network && a.deviceState === account.deviceState); if (exist) { return state; } - - const account: Account = { - loaded: false, - network: action.network, - deviceID: action.device.features ? action.device.features.device_id : '0', - deviceState: action.device.state || 'undefined', - index: action.index, - addressPath: action.path, - address: action.address, - balance: '0', - nonce: 0, - }; - - const newState: State = [...state]; + const newState: State = [ ...state ]; newState.push(account); return newState; }; @@ -74,8 +61,16 @@ const clear = (state: State, devices: Array): State => { return newState; }; +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 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 && 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; @@ -93,7 +88,7 @@ const setNonce = (state: State, action: AccountSetNonceAction): State => { export default (state: State = initialState, action: Action): State => { switch (action.type) { case ACCOUNT.CREATE: - return createAccount(state, action); + return createAccount(state, action.payload); case CONNECT.FORGET: case CONNECT.FORGET_SINGLE: @@ -105,6 +100,9 @@ export default (state: State = initialState, action: Action): State => { //case CONNECT.FORGET_SINGLE : // return forgetAccounts(state, action); + case ACCOUNT.UPDATE : + return updateAccount(state, action.payload); + case ACCOUNT.SET_BALANCE: return setBalance(state, action); case ACCOUNT.SET_NONCE: diff --git a/src/reducers/BlockchainReducer.js b/src/reducers/BlockchainReducer.js new file mode 100644 index 00000000..b4d4a12b --- /dev/null +++ b/src/reducers/BlockchainReducer.js @@ -0,0 +1,64 @@ +/* @flow */ + +import { BLOCKCHAIN } from 'trezor-connect'; + +import type { Action } from 'flowtype'; + +export type BlockchainNetwork = { + +name: string; + connected: boolean; +} + +export type State = Array; + +export const initialState: State = []; + +const find = (state: State, name: string): number => { + return state.findIndex(b => b.name === name); +} + +const connect = (state: State, action: any): State => { + const name = action.payload.coin.shortcut.toLowerCase(); + const network: BlockchainNetwork = { + name, + connected: true, + } + const newState: State = [...state]; + const index: number = find(newState, name); + if (index >= 0) { + newState[index] = network; + } else { + newState.push(network); + } + return newState; +}; + +const disconnect = (state: State, action: any): State => { + const name = action.payload.coin.shortcut.toLowerCase(); + const network: BlockchainNetwork = { + name, + connected: false, + } + const newState: State = [...state]; + const index: number = find(newState, name); + if (index >= 0) { + newState[index] = network; + } else { + newState.push(network); + } + return newState; +}; + + +export default (state: State = initialState, action: Action): State => { + switch (action.type) { + + case BLOCKCHAIN.CONNECT: + return connect(state, action); + case BLOCKCHAIN.ERROR: + return disconnect(state, action); + + default: + return state; + } +}; \ No newline at end of file diff --git a/src/reducers/DiscoveryReducer.js b/src/reducers/DiscoveryReducer.js index 81e8ffb7..aebb392e 100644 --- a/src/reducers/DiscoveryReducer.js +++ b/src/reducers/DiscoveryReducer.js @@ -16,9 +16,7 @@ import type { DiscoveryCompleteAction, } from 'actions/DiscoveryActions'; -import type { - AccountCreateAction, -} from 'actions/AccountsActions'; +import type { Account } from './AccountsReducer'; export type Discovery = { network: string; @@ -31,7 +29,7 @@ export type Discovery = { interrupted: boolean; completed: boolean; waitingForDevice: boolean; - waitingForBackend: boolean; + waitingForBlockchain: boolean; } export type State = Array; @@ -55,7 +53,7 @@ const start = (state: State, action: DiscoveryStartAction): State => { interrupted: false, completed: false, waitingForDevice: false, - waitingForBackend: false, + waitingForBlockchain: false, }; const newState: State = [...state]; @@ -75,8 +73,8 @@ const complete = (state: State, action: DiscoveryCompleteAction): State => { return newState; }; -const accountCreate = (state: State, action: AccountCreateAction): State => { - const index: number = findIndex(state, action.network, action.device.state || '0'); +const accountCreate = (state: State, account: Account): State => { + const index: number = findIndex(state, account.network, account.deviceState); const newState: State = [...state]; newState[index].accountIndex++; return newState; @@ -98,6 +96,7 @@ const stop = (state: State, action: DiscoveryStopAction): State => { if (d.deviceState === action.device.state && !d.completed) { d.interrupted = true; d.waitingForDevice = false; + d.waitingForBlockchain = false; } return d; }); @@ -116,7 +115,7 @@ const waitingForDevice = (state: State, action: DiscoveryWaitingAction): State = interrupted: false, completed: false, waitingForDevice: true, - waitingForBackend: false, + waitingForBlockchain: false, }; const index: number = findIndex(state, action.network, deviceState); @@ -130,7 +129,7 @@ const waitingForDevice = (state: State, action: DiscoveryWaitingAction): State = return newState; }; -const waitingForBackend = (state: State, action: DiscoveryWaitingAction): State => { +const waitingForBlockchain = (state: State, action: DiscoveryWaitingAction): State => { const deviceState: string = action.device.state || '0'; const instance: Discovery = { network: action.network, @@ -143,7 +142,7 @@ const waitingForBackend = (state: State, action: DiscoveryWaitingAction): State interrupted: false, completed: false, waitingForDevice: false, - waitingForBackend: true, + waitingForBlockchain: true, }; const index: number = findIndex(state, action.network, deviceState); @@ -162,15 +161,15 @@ export default function discovery(state: State = initialState, action: Action): case DISCOVERY.START: return start(state, action); case ACCOUNT.CREATE: - return accountCreate(state, action); + return accountCreate(state, action.payload); case DISCOVERY.STOP: return stop(state, action); case DISCOVERY.COMPLETE: return complete(state, action); case DISCOVERY.WAITING_FOR_DEVICE: return waitingForDevice(state, action); - case DISCOVERY.WAITING_FOR_BACKEND: - return waitingForBackend(state, action); + case DISCOVERY.WAITING_FOR_BLOCKCHAIN: + return waitingForBlockchain(state, action); case DISCOVERY.FROM_STORAGE: return action.payload.map((d) => { const hdKey: HDKey = new HDKey(); @@ -181,7 +180,7 @@ export default function discovery(state: State = initialState, action: Action): hdKey, interrupted: false, waitingForDevice: false, - waitingForBackend: false, + waitingForBlockchain: false, }; }); case CONNECT.FORGET: diff --git a/src/reducers/LocalStorageReducer.js b/src/reducers/LocalStorageReducer.js index bfbc3491..47e1c9d4 100644 --- a/src/reducers/LocalStorageReducer.js +++ b/src/reducers/LocalStorageReducer.js @@ -22,7 +22,8 @@ export type Coin = { backends: Array<{ name: string; urls: Array; - }> + }>; + web3: Array; } export type NetworkToken = { diff --git a/src/reducers/PendingTxReducer.js b/src/reducers/PendingTxReducer.js index c6108d74..b8c80f57 100644 --- a/src/reducers/PendingTxReducer.js +++ b/src/reducers/PendingTxReducer.js @@ -6,6 +6,7 @@ import type { Action } from 'flowtype'; import type { SendTxAction } from 'actions/SendFormActions'; export type PendingTx = { + +type: 'send' | 'recv'; +id: string; +network: string; +currency: string; @@ -24,6 +25,7 @@ const initialState: State = []; const add = (state: State, action: SendTxAction): State => { const newState = [...state]; newState.push({ + type: 'send', id: action.txid, network: action.account.network, currency: action.selectedCurrency, @@ -37,6 +39,12 @@ const add = (state: State, action: SendTxAction): State => { return newState; }; +const add_NEW = (state: State, payload: any): State => { + const newState = [...state]; + newState.push(payload); + return newState; +}; + const remove = (state: State, id: string): State => state.filter(tx => tx.id !== id); const reject = (state: State, id: string): State => state.map((tx) => { @@ -51,6 +59,8 @@ export default function pending(state: State = initialState, action: Action): St case SEND.TX_COMPLETE: return add(state, action); + // case PENDING.ADD: + // return add(state, action.payload); case PENDING.TX_RESOLVED: return remove(state, action.tx.id); case PENDING.TX_NOT_FOUND: diff --git a/src/reducers/SelectedAccountReducer.js b/src/reducers/SelectedAccountReducer.js index a83b2dca..0500fb13 100644 --- a/src/reducers/SelectedAccountReducer.js +++ b/src/reducers/SelectedAccountReducer.js @@ -10,7 +10,6 @@ import type { Token, PendingTx, Discovery, - Web3Instance, } from 'flowtype'; export type State = { @@ -20,7 +19,6 @@ export type State = { network: ?Coin; tokens: Array, pending: Array, - web3: ?Web3Instance, discovery: ?Discovery }; @@ -30,7 +28,6 @@ export const initialState: State = { network: null, tokens: [], pending: [], - web3: null, discovery: null, }; diff --git a/src/reducers/WalletReducer.js b/src/reducers/WalletReducer.js index aa4f6d26..5eb5698c 100644 --- a/src/reducers/WalletReducer.js +++ b/src/reducers/WalletReducer.js @@ -2,9 +2,8 @@ import { LOCATION_CHANGE } from 'react-router-redux'; -import { DEVICE } from 'trezor-connect'; +import { DEVICE, TRANSPORT } from 'trezor-connect'; import * as MODAL from 'actions/constants/modal'; -import * as WEB3 from 'actions/constants/web3'; import * as WALLET from 'actions/constants/wallet'; import * as CONNECT from 'actions/constants/TrezorConnect'; @@ -41,7 +40,7 @@ export default function wallet(state: State = initialState, action: Action): Sta initialPathname: action.pathname, }; - case WEB3.READY: + case TRANSPORT.START: return { ...state, ready: true, diff --git a/src/reducers/Web3Reducer.js b/src/reducers/Web3Reducer.js index 40903eec..9c25d9c8 100644 --- a/src/reducers/Web3Reducer.js +++ b/src/reducers/Web3Reducer.js @@ -3,7 +3,8 @@ import Web3 from 'web3'; -import type { ContractFactory } from 'web3'; +import type { Contract } from 'web3'; +import * as STORAGE from 'actions/constants/localStorage'; import * as WEB3 from 'actions/constants/web3'; import type { Action } from 'flowtype'; @@ -18,7 +19,7 @@ export type Web3Instance = { chainId: number; latestBlock: any; gasPrice: string; - erc20: ContractFactory; + erc20: Contract; } export type State = Array; @@ -26,8 +27,13 @@ export type State = Array; const initialState: State = []; const createWeb3 = (state: State, instance: Web3Instance): State => { + const index: number = state.findIndex(w3 => w3.network === instance.network); const newState: Array = [...state]; - newState.push(instance); + if (index >= 0) { + newState[index] = instance; + } else { + newState.push(instance); + } return newState; }; @@ -45,6 +51,13 @@ const updateGasPrice = (state: State, action: Web3UpdateGasPriceAction): State = return newState; }; +const disconnect = (state: State, instance: Web3Instance): State => { + const index: number = state.indexOf(instance); + const newState: Array = [...state]; + newState.splice(index, 1); + return newState; +}; + export default function web3(state: State = initialState, action: Action): State { switch (action.type) { case WEB3.CREATE: @@ -53,6 +66,8 @@ export default function web3(state: State = initialState, action: Action): State return updateLatestBlock(state, action); case WEB3.GAS_PRICE_UPDATED: return updateGasPrice(state, action); + case WEB3.DISCONNECT: + return disconnect(state, action.instance); default: return state; } diff --git a/src/reducers/index.js b/src/reducers/index.js index 1d0be6a7..ed6f1aa6 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -19,6 +19,7 @@ import pending from 'reducers/PendingTxReducer'; import fiat from 'reducers/FiatRateReducer'; import wallet from 'reducers/WalletReducer'; import devices from 'reducers/DevicesReducer'; +import blockchain from 'reducers/BlockchainReducer'; const reducers = { router: routerReducer, @@ -39,6 +40,7 @@ const reducers = { fiat, wallet, devices, + blockchain }; export type Reducers = typeof reducers; diff --git a/src/services/RouterService.js b/src/services/RouterService.js index db3157cd..92ba3b4d 100644 --- a/src/services/RouterService.js +++ b/src/services/RouterService.js @@ -72,7 +72,6 @@ const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa __unloading = true; } else if (action.type === LOCATION_CHANGE && !__unloading) { const { location } = api.getState().router; - const { web3 } = api.getState(); const { devices } = api.getState(); const { error } = api.getState().connect; @@ -92,8 +91,8 @@ const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa redirectPath = '/'; } else { const isModalOpened: boolean = api.getState().modal.opened; - // if web3 wasn't initialized yet or there are no devices attached or initialization error occurs - const landingPage: boolean = web3.length < 1 || devices.length < 1 || error !== null; + // there are no devices attached or initialization error occurs + const landingPage: boolean = devices.length < 1 || error !== null; // modal is still opened and currentPath is still valid // example 1 (valid blocking): url changes while passphrase modal opened but device is still connected (we want user to finish this action) diff --git a/src/services/TrezorConnectService.js b/src/services/TrezorConnectService.js index f69f5b13..5a4255c2 100644 --- a/src/services/TrezorConnectService.js +++ b/src/services/TrezorConnectService.js @@ -1,16 +1,16 @@ /* @flow */ import { push } from 'react-router-redux'; -import { - TRANSPORT, DEVICE, +import TrezorConnect, { + TRANSPORT, DEVICE_EVENT, UI_EVENT, UI, DEVICE, BLOCKCHAIN } from 'trezor-connect'; import * as TrezorConnectActions from 'actions/TrezorConnectActions'; import * as DiscoveryActions from 'actions/DiscoveryActions'; +import * as BlockchainActions from 'actions/BlockchainActions'; import * as ModalActions from 'actions/ModalActions'; -import { init as initWeb3 } from 'actions/Web3Actions'; -import * as WEB3 from 'actions/constants/web3'; import * as STORAGE from 'actions/constants/localStorage'; import * as CONNECT from 'actions/constants/TrezorConnect'; +import { READY as BLOCKCHAIN_READY } from 'actions/constants/blockchain'; import type { Middleware, @@ -32,9 +32,9 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa } else if (action.type === TRANSPORT.ERROR) { // TODO: check if modal is open // api.dispatch( push('/') ); - } else if (action.type === TRANSPORT.START && api.getState().web3.length < 1) { - api.dispatch(initWeb3()); - } else if (action.type === WEB3.READY) { + } else if (action.type === TRANSPORT.START) { + api.dispatch(BlockchainActions.init()); + } else if (action.type === BLOCKCHAIN_READY) { api.dispatch(TrezorConnectActions.postInit()); } else if (action.type === DEVICE.DISCONNECT) { api.dispatch(TrezorConnectActions.deviceDisconnect(action.device)); @@ -63,6 +63,12 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa api.dispatch(TrezorConnectActions.onSelectDevice(action.device)); } else if (action.type === CONNECT.COIN_CHANGED) { api.dispatch(TrezorConnectActions.coinChanged(action.payload.network)); + } else if (action.type === BLOCKCHAIN.BLOCK) { + api.dispatch(BlockchainActions.onBlockMined(action.payload.coin)); + } else if (action.type === BLOCKCHAIN.NOTIFICATION) { + // api.dispatch(BlockchainActions.onNotification(action.payload)); + } else if (action.type === BLOCKCHAIN.ERROR) { + api.dispatch( BlockchainActions.error(action.payload) ); } return action; diff --git a/src/store.js b/src/store.js index b69d1243..30e78995 100644 --- a/src/store.js +++ b/src/store.js @@ -6,13 +6,14 @@ import thunk from 'redux-thunk'; // import createHistory from 'history/createBrowserHistory'; // import { useRouterHistory } from 'react-router'; import createHistory from 'history/createHashHistory'; +import { createLogger } from 'redux-logger'; import reducers from 'reducers'; import services from 'services'; import Raven from 'raven-js'; import RavenMiddleware from 'redux-raven-middleware'; -// import type { Action, GetState, Store } from 'flowtype'; +import type { Action, GetState, Store } from 'flowtype'; export const history: History = createHistory({ queryKey: false }); @@ -30,17 +31,29 @@ const middleware = [ let composedEnhancers: any; if (process.env.NODE_ENV === 'development') { - // const excludeLogger = (getState: GetState, action: Action): boolean => { - // //'@@router/LOCATION_CHANGE' - // const excluded: Array = ['LOG_TO_EXCLUDE', 'log__add']; - // const pass: Array = excluded.filter(act => action.type === act); - // return pass.length === 0; - // }; + const excludeLogger = (getState: GetState, action: Action): boolean => { + //'@@router/LOCATION_CHANGE' + const excluded: Array = ['LOG_TO_EXCLUDE', 'log__add', undefined]; + const pass: Array = excluded.filter(act => action.type === act); + return pass.length === 0; + }; + + const logger = createLogger({ + level: 'info', + predicate: excludeLogger, + collapsed: true, + }); + + const devToolsExtension: ?Function = window.devToolsExtension; + if (typeof devToolsExtension === 'function') { + enhancers.push(devToolsExtension()); + } composedEnhancers = compose( - applyMiddleware(...middleware, ...services), + applyMiddleware(logger, ...middleware, ...services), ...enhancers, ); + } else { composedEnhancers = compose( applyMiddleware(...middleware, ...services), diff --git a/src/views/Landing/Container.js b/src/views/Landing/Container.js index da89a4b0..6c891761 100644 --- a/src/views/Landing/Container.js +++ b/src/views/Landing/Container.js @@ -8,7 +8,6 @@ import LandingPage from './index'; export type StateProps = { localStorage: $ElementType, modal: $ElementType, - web3: $ElementType, wallet: $ElementType, connect: $ElementType, router: $ElementType, @@ -29,7 +28,6 @@ export type Props = StateProps & DispatchProps; const mapStateToProps: MapStateToProps = (state: State): StateProps => ({ localStorage: state.localStorage, modal: state.modal, - web3: state.web3, wallet: state.wallet, connect: state.connect, router: state.router, diff --git a/src/views/Landing/components/InstallBridge/index.js b/src/views/Landing/components/InstallBridge/index.js index ecf72ebf..67177f79 100644 --- a/src/views/Landing/components/InstallBridge/index.js +++ b/src/views/Landing/components/InstallBridge/index.js @@ -103,7 +103,6 @@ export default class InstallBridge extends Component { } onChange(value: InstallTarget) { - console.warn(value); this.setState({ target: value, }); diff --git a/src/views/Wallet/components/SelectedAccount/index.js b/src/views/Wallet/components/SelectedAccount/index.js index 98f5c092..9067b6b1 100644 --- a/src/views/Wallet/components/SelectedAccount/index.js +++ b/src/views/Wallet/components/SelectedAccount/index.js @@ -1,6 +1,7 @@ /* @flow */ import * as React from 'react'; import { Notification } from 'components/Notification'; +import { reconnect } from 'actions/DiscoveryActions'; import type { State } from 'flowtype'; @@ -8,11 +9,12 @@ export type StateProps = { className: string; selectedAccount: $ElementType, wallet: $ElementType, + blockchain: $ElementType, children?: React.Node } export type DispatchProps = { - + blockchainReconnect: typeof reconnect; } export type Props = StateProps & DispatchProps; @@ -28,8 +30,28 @@ const SelectedAccount = (props: Props) => { const { account, discovery, + network } = accountState; + if (!network) return; // TODO: this shouldn't happen. change accountState reducer? + + const blockchain = props.blockchain.find(b => b.name === network.network); + if (blockchain && !blockchain.connected) { + return ( + { + await props.blockchainReconnect(network.network); + } + }] + } /> + ); + } + // account not found (yet). checking why... if (!account) { if (!discovery || discovery.waitingForDevice) { @@ -57,11 +79,6 @@ const SelectedAccount = (props: Props) => { message="Connect device to load accounts" /> ); - } if (discovery.waitingForBackend) { - // case 4: backend is not working - return ( - - ); } if (discovery.completed) { // case 5: account not found and discovery is completed return ( diff --git a/src/views/Wallet/views/AccountReceive/Container.js b/src/views/Wallet/views/AccountReceive/Container.js index 5695877b..22f5eda6 100644 --- a/src/views/Wallet/views/AccountReceive/Container.js +++ b/src/views/Wallet/views/AccountReceive/Container.js @@ -2,6 +2,7 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import { reconnect } from 'actions/DiscoveryActions'; import { showAddress } from 'actions/ReceiveActions'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; import type { State, Dispatch } from 'flowtype'; @@ -28,12 +29,14 @@ const mapStateToProps: MapStateToProps = (state: St className: 'receive', selectedAccount: state.selectedAccount, wallet: state.wallet, + blockchain: state.blockchain, receive: state.receive, modal: state.modal, }); const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ + blockchainReconnect: bindActionCreators(reconnect, dispatch), showAddress: bindActionCreators(showAddress, dispatch), }); diff --git a/src/views/Wallet/views/AccountSend/Container.js b/src/views/Wallet/views/AccountSend/Container.js index 847bac63..0dee8fbc 100644 --- a/src/views/Wallet/views/AccountSend/Container.js +++ b/src/views/Wallet/views/AccountSend/Container.js @@ -5,6 +5,7 @@ import * as React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import { reconnect } from 'actions/DiscoveryActions'; import SendFormActions from 'actions/SendFormActions'; import * as SessionStorageActions from 'actions/SessionStorageActions'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; @@ -12,7 +13,6 @@ import type { State, Dispatch } from 'flowtype'; import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps } from 'views/Wallet/components/SelectedAccount'; import AccountSend from './index'; - type OwnProps = { } export type StateProps = BaseStateProps & { @@ -33,6 +33,7 @@ const mapStateToProps: MapStateToProps = (state: St className: 'send-from', selectedAccount: state.selectedAccount, wallet: state.wallet, + blockchain: state.blockchain, sendForm: state.sendForm, fiat: state.fiat, @@ -40,6 +41,7 @@ const mapStateToProps: MapStateToProps = (state: St }); const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ + blockchainReconnect: bindActionCreators(reconnect, dispatch), sendFormActions: bindActionCreators(SendFormActions, dispatch), saveSessionStorage: bindActionCreators(SessionStorageActions.save, dispatch), }); diff --git a/src/views/Wallet/views/AccountSummary/Container.js b/src/views/Wallet/views/AccountSummary/Container.js index e7239ebb..5163b737 100644 --- a/src/views/Wallet/views/AccountSummary/Container.js +++ b/src/views/Wallet/views/AccountSummary/Container.js @@ -3,6 +3,7 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; +import { reconnect } from 'actions/DiscoveryActions'; import * as TokenActions from 'actions/TokenActions'; import type { State, Dispatch } from 'flowtype'; @@ -30,6 +31,7 @@ const mapStateToProps: MapStateToProps = (state: St className: 'summary', selectedAccount: state.selectedAccount, wallet: state.wallet, + blockchain: state.blockchain, tokens: state.tokens, summary: state.summary, @@ -38,6 +40,7 @@ const mapStateToProps: MapStateToProps = (state: St }); const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({ + blockchainReconnect: bindActionCreators(reconnect, dispatch), addToken: bindActionCreators(TokenActions.add, dispatch), loadTokens: bindActionCreators(TokenActions.load, dispatch), removeToken: bindActionCreators(TokenActions.remove, dispatch), diff --git a/src/views/Wallet/views/AccountSummary/index.js b/src/views/Wallet/views/AccountSummary/index.js index 1996fc99..67d976db 100644 --- a/src/views/Wallet/views/AccountSummary/index.js +++ b/src/views/Wallet/views/AccountSummary/index.js @@ -69,7 +69,7 @@ const AccountSummary = (props: Props) => { } = props.selectedAccount; // flow - if (!device || !account || !network) return null; + if (!device || !account || !network) return ; const explorerLink: string = `${network.explorer.address}${account.address}`; const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, network.symbol); diff --git a/webpack/local.babel.js b/webpack/local.babel.js index c62b2e08..92930de8 100644 --- a/webpack/local.babel.js +++ b/webpack/local.babel.js @@ -2,6 +2,7 @@ import webpack from 'webpack'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin'; +import MiniCssExtractPlugin from '../../trezor-connect/node_modules/mini-css-extract-plugin'; import { TREZOR_CONNECT_ROOT, @@ -47,20 +48,17 @@ module.exports = { { test: /\.js?$/, exclude: /node_modules/, + use: ['babel-loader'], + }, + { + test: /\.less$/, use: [ - 'babel-loader', { - loader: 'eslint-loader', - options: { - emitWarning: true, - }, - }, - { - loader: 'stylelint-custom-processor-loader', - options: { - configPath: '.stylelintrc', - }, + loader: MiniCssExtractPlugin.loader, + options: { publicPath: '../' }, }, + `${TREZOR_CONNECT_ROOT}/node_modules/css-loader`, + `${TREZOR_CONNECT_ROOT}/node_modules/less-loader`, ], }, { @@ -113,6 +111,11 @@ module.exports = { hints: false, }, plugins: [ + new MiniCssExtractPlugin({ + filename: '[name].css', + chunkFilename: '[id].css', + }), + new HtmlWebpackPlugin({ chunks: ['index'], template: `${SRC}index.html`, diff --git a/yarn.lock b/yarn.lock index b45b201c..6f485cac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -558,6 +558,10 @@ any-observable@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" +any-promise@1.3.0, any-promise@^1.0.0, any-promise@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -805,6 +809,10 @@ aws4@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + axobject-query@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.1.tgz#05dfa705ada8ad9db993fa6896f22d395b0b0a07" @@ -1678,6 +1686,10 @@ balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base64-js@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" + base64-js@^1.0.2: version "1.3.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" @@ -1720,10 +1732,6 @@ bignumber.js@2.4.0, bignumber.js@^2.3.0: version "2.4.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-2.4.0.tgz#838a992da9f9d737e0f4b2db0be62bb09dd0c5e8" -bignumber.js@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" - binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" @@ -1742,17 +1750,32 @@ bip66@^1.1.3: dependencies: safe-buffer "^5.0.1" +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" dependencies: inherits "~2.0.0" -bluebird@^3.5.1: +bluebird@^2.9.34: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + +bluebird@^3.5.0, bluebird@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.0, bn.js@^4.11.3, bn.js@^4.4.0, bn.js@^4.8.0: +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.0, bn.js@^4.11.3, bn.js@^4.11.6, bn.js@^4.4.0, bn.js@^4.8.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -1771,6 +1794,21 @@ body-parser@1.18.2: raw-body "2.3.2" type-is "~1.6.15" +body-parser@^1.16.0: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" @@ -1882,6 +1920,12 @@ browserify-rsa@^4.0.0: bn.js "^4.1.0" randombytes "^2.0.1" +browserify-sha3@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/browserify-sha3/-/browserify-sha3-0.0.1.tgz#3ff34a3006ef15c0fb3567e541b91a2340123d11" + dependencies: + js-sha3 "^0.3.1" + browserify-sign@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" @@ -1931,6 +1975,25 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + +buffer-alloc@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" @@ -1939,10 +2002,22 @@ buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" +buffer@^3.0.1: + version "3.6.0" + resolved "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb" + dependencies: + base64-js "0.0.8" + ieee754 "^1.1.4" + isarray "^1.0.0" + buffer@^4.3.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" @@ -1958,6 +2033,13 @@ buffer@^5.0.3: base64-js "^1.0.2" ieee754 "^1.1.4" +buffer@^5.0.5: + version "5.2.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -2454,7 +2536,7 @@ colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" -combined-stream@1.0.6: +combined-stream@1.0.6, combined-stream@~1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" dependencies: @@ -2475,6 +2557,10 @@ commander@^2.11.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.1.tgz#468635c4168d06145b9323356d1da84d14ac4a7a" commander@^2.13.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" + +commander@^2.8.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" @@ -2482,6 +2568,12 @@ commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -2585,6 +2677,10 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +cookiejar@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -2629,6 +2725,13 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cors@^2.8.1: + version "2.8.4" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397" @@ -2727,7 +2830,7 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" -crypto-browserify@^3.11.0: +crypto-browserify@3.12.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" dependencies: @@ -2743,10 +2846,6 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^3.1.4: - version "3.1.8" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.8.tgz#715f070bf6014f2ae992a98b3929258b713f08d5" - css-animation@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.4.1.tgz#5b8813125de0fbbbb0bbe1b472ae84221469b7a8" @@ -2955,6 +3054,54 @@ decompress-response@^3.2.0, decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d" + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + deep-diff@^0.3.5: version "0.3.8" resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84" @@ -3280,6 +3427,18 @@ elliptic@^6.0.0, elliptic@^6.2.3: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +elliptic@^6.4.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + emoji-regex@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" @@ -3643,6 +3802,26 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" +eth-lib@0.1.27, eth-lib@^0.1.26: + version "0.1.27" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.27.tgz#f0b0fd144f865d2d6bf8257a40004f2e75ca1dd6" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + keccakjs "^0.2.1" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +eth-lib@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + ethereum-common@^0.0.18: version "0.0.18" resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" @@ -3685,6 +3864,13 @@ ethereumjs-util@^5.1.4: safe-buffer "^5.1.1" secp256k1 "^3.0.1" +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + ethjs-util@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.4.tgz#1c8b6879257444ef4d3f3fbbac2ded12cd997d93" @@ -3704,6 +3890,10 @@ event-stream@~3.3.0: stream-combiner "~0.0.4" through "~2.3.1" +eventemitter3@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.1.1.tgz#47786bdaa087caf7b1b75e73abc5c7d540158cd0" + eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -3798,7 +3988,7 @@ expect@^23.4.0: jest-message-util "^23.4.0" jest-regex-util "^23.3.0" -express@^4.16.2: +express@^4.14.0, express@^4.16.2: version "4.16.3" resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" dependencies: @@ -3846,7 +4036,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0, extend@~3.0.1: +extend@^3.0.0, extend@~3.0.1, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -3958,6 +4148,12 @@ fbjs@^0.8.5: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + dependencies: + pend "~1.2.0" + figures@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -3985,6 +4181,18 @@ file-loader@1.1.11: loader-utils "^1.0.2" schema-utils "^0.4.5" +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + +file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -4111,6 +4319,12 @@ follow-redirects@^1.0.0: dependencies: debug "^3.1.0" +for-each@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + dependencies: + is-callable "^1.1.3" + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -4137,7 +4351,7 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" -form-data@~2.3.1: +form-data@~2.3.1, form-data@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" dependencies: @@ -4170,12 +4384,32 @@ from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + +fs-extra@^2.0.0, fs-extra@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" dependencies: minipass "^2.2.1" +fs-promise@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-2.0.3.tgz#f64e4f854bcf689aa8bddcba268916db3db46854" + dependencies: + any-promise "^1.3.0" + fs-extra "^2.0.0" + mz "^2.6.0" + thenify-all "^1.6.0" + fs-readdir-recursive@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -4215,7 +4449,7 @@ fstream-ignore@^1.0.5: inherits "2" minimatch "^3.0.0" -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2, fstream@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" dependencies: @@ -4261,6 +4495,13 @@ get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -4344,7 +4585,7 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -global@^4.3.0: +global@^4.3.0, global@~4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" dependencies: @@ -4413,7 +4654,7 @@ gonzales-pe@^4.0.3: dependencies: minimist "1.1.x" -got@^7.0.0: +got@7.1.0, got@^7.0.0, got@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" dependencies: @@ -4454,10 +4695,14 @@ got@^8.2.0: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4: +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + grouped-queue@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c" @@ -4511,6 +4756,13 @@ har-validator@~5.0.3: ajv "^5.1.0" har-schema "^2.0.0" +har-validator@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + dependencies: + ajv "^5.3.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -4766,6 +5018,19 @@ http-errors@1.6.2, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-errors@1.6.3, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + http-parser-js@>=0.4.0: version "0.4.12" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.12.tgz#b9cfbf4a2cf26f0fc34b10ca1489a27771e3474f" @@ -4811,7 +5076,7 @@ iconv-lite@0.4.19, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.17, iconv-lite@^0.4.4: +iconv-lite@0.4.23, iconv-lite@^0.4.17, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: @@ -5120,6 +5385,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + is-generator-fn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" @@ -5150,6 +5419,10 @@ is-hexadecimal@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz#b6e710d7d07bb66b98cb8cece5c9b4921deeb835" +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -5266,7 +5539,7 @@ is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" -is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -5698,6 +5971,10 @@ js-base64@^2.1.9: version "2.3.2" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" +js-sha3@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.3.1.tgz#86122802142f0828502a0d1dee1d95e253bb0243" + 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" @@ -5845,6 +6122,12 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -5873,6 +6156,13 @@ keccak@^1.0.2: nan "^2.2.1" safe-buffer "^5.1.0" +keccakjs@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/keccakjs/-/keccakjs-0.2.1.tgz#1d633af907ef305bbf9f2fa616d56c44561dfa4d" + dependencies: + browserify-sha3 "^0.0.1" + sha3 "^1.1.0" + keyv@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" @@ -6406,12 +6696,22 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" +mime-db@~1.36.0: + version "1.36.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" + mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.7: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: mime-db "~1.30.0" +mime-types@^2.1.16, mime-types@~2.1.19: + version "2.1.20" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" + dependencies: + mime-db "~1.36.0" + mime-types@~2.1.17, mime-types@~2.1.18: version "2.1.18" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" @@ -6516,12 +6816,26 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + dependencies: + mkdirp "*" + +mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" +mock-fs@^4.1.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.6.0.tgz#d944ef4c3e03ceb4e8332b4b31b8ac254051c8ae" + +mout@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/mout/-/mout-0.11.1.tgz#ba3611df5f0e5b1ffbfd01166b8f02d1f5fa2b99" + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -6561,13 +6875,29 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" +mz@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@2.10.0, nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nan@^2.0.8, nan@^2.3.3: + version "2.11.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" + nan@^2.2.1, nan@^2.3.0: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" -nan@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" nanomatch@^1.2.9: version "1.2.9" @@ -6821,6 +7151,13 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + nwsapi@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.7.tgz#6fc54c254621f10cac5225b76e81c74120139b78" @@ -6829,7 +7166,11 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.x, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + +object-assign@4.x, object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6893,6 +7234,12 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" +oboe@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.3.tgz#2b4865dbd46be81225713f4e9bfe4bcf4f680a4f" + dependencies: + http-https "^1.0.0" + obuf@^1.0.0, obuf@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -7115,6 +7462,13 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" +parse-headers@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" + dependencies: + for-each "^0.3.2" + trim "0.0.1" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -7230,6 +7584,10 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" @@ -7693,6 +8051,13 @@ prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, pr loose-envify "^1.3.1" object-assign "^4.1.1" +prop-types@>=15.5.10, prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + prop-types@^15.6.1: version "15.6.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" @@ -7701,13 +8066,6 @@ prop-types@^15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" -prop-types@^15.6.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" - dependencies: - loose-envify "^1.3.1" - object-assign "^4.1.1" - proxy-addr@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" @@ -7782,14 +8140,14 @@ qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +qs@6.5.2, qs@~6.5.1, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" -qs@~6.5.1: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" @@ -7851,6 +8209,10 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +randomhex@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" + range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -7868,6 +8230,15 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + rc-align@2.x: version "2.3.5" resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.3.5.tgz#5085cfa4d685ee9d030b9afd2971eb370c5e80a1" @@ -8027,6 +8398,12 @@ react-select@2.0.0: react-input-autosize "^2.2.1" react-transition-group "^2.2.1" +react-sticky-el@^1.0.20: + version "1.0.20" + resolved "https://registry.yarnpkg.com/react-sticky-el/-/react-sticky-el-1.0.20.tgz#b3c5e7128218633f440dc67aec239d1cd078342d" + dependencies: + prop-types ">=15.5.10" + react-transition-group@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10" @@ -8129,7 +8506,7 @@ readable-stream@1.0: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.1, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: +readable-stream@^2.0.1, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -8444,6 +8821,31 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@^2.79.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + request@^2.87.0: version "2.87.0" resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" @@ -8683,6 +9085,25 @@ scoped-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" +scrypt.js@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada" + dependencies: + scrypt "^6.0.2" + scryptsy "^1.2.1" + +scrypt@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/scrypt/-/scrypt-6.0.3.tgz#04e014a5682b53fa50c2d5cce167d719c06d870d" + dependencies: + nan "^2.0.8" + +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + dependencies: + pbkdf2 "^3.0.3" + secp256k1@^3.0.1: version "3.4.0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.4.0.tgz#1c905b256fa4ae5b9cc170e672dd59b4c5de46a4" @@ -8696,6 +9117,12 @@ secp256k1@^3.0.1: nan "^2.2.1" safe-buffer "^5.1.0" +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + dependencies: + commander "~2.8.1" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -8757,6 +9184,16 @@ serve-static@1.13.2: parseurl "~1.3.2" send "0.16.2" +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -8802,6 +9239,12 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +sha3@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" + dependencies: + nan "2.10.0" + shallowequal@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e" @@ -8851,6 +9294,18 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + sisteransi@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" @@ -9095,6 +9550,10 @@ static-extend@^0.1.1: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -9239,6 +9698,12 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + dependencies: + is-natural-number "^4.0.1" + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -9429,6 +9894,24 @@ svgo@^0.7.0: sax "~1.2.1" whet.extend "~0.9.9" +swarm-js@0.1.37: + version "0.1.37" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.37.tgz#27d485317a340bbeec40292af783cc10acfa4663" + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + decompress "^4.0.0" + eth-lib "^0.1.26" + fs-extra "^2.1.2" + fs-promise "^2.0.0" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar.gz "^1.0.5" + xhr-request-promise "^0.1.2" + symbol-observable@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" @@ -9484,7 +9967,29 @@ tar-pack@^3.4.0: tar "^2.2.1" uid-number "^0.0.6" -tar@^2.2.1: +tar-stream@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395" + dependencies: + bl "^1.0.0" + buffer-alloc "^1.1.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.0" + xtend "^4.0.0" + +tar.gz@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/tar.gz/-/tar.gz-1.0.7.tgz#577ef2c595faaa73452ef0415fed41113212257b" + dependencies: + bluebird "^2.9.34" + commander "^2.8.1" + fstream "^1.0.8" + mout "^0.11.0" + tar "^2.1.1" + +tar@^2.1.1, tar@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" dependencies: @@ -9529,6 +10034,18 @@ textextensions@2: version "2.2.0" resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" +thenify-all@^1.0.0, thenify-all@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + dependencies: + any-promise "^1.0.0" + throat@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" @@ -9572,6 +10089,10 @@ to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" +to-buffer@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -9612,7 +10133,7 @@ touch@^1.0.0: dependencies: nopt "~1.0.10" -tough-cookie@>=2.3.3, tough-cookie@^2.3.4: +tough-cookie@>=2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" dependencies: @@ -9637,9 +10158,9 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" -trezor-connect@5.0.30: - version "5.0.30" - resolved "https://registry.yarnpkg.com/trezor-connect/-/trezor-connect-5.0.30.tgz#3a71613a6d6e63532c7880c1dc25abca18f0b0e7" +trezor-connect@5.0.31: + version "5.0.31" + resolved "https://registry.yarnpkg.com/trezor-connect/-/trezor-connect-5.0.31.tgz#7ecf5e26e154962b638ddc35e68a52d57f4cc107" dependencies: babel-runtime "^6.26.0" events "^1.1.1" @@ -9711,6 +10232,12 @@ type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" +typedarray-to-buffer@^3.1.2: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + dependencies: + is-typedarray "^1.0.0" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -9767,6 +10294,21 @@ uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + +unbzip2-stream@^1.0.9: + version "1.2.5" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47" + dependencies: + buffer "^3.0.1" + through "^2.3.6" + +underscore@1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + underscore@~1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" @@ -9918,6 +10460,10 @@ url-parse@^1.1.8, url-parse@~1.4.0: querystringify "^2.0.0" requires-port "^1.0.0" +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" @@ -9939,9 +10485,9 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -utf8@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" +utf8@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.1.tgz#2e01db02f7d8d0944f77104f1609eb0c304cf768" util-deprecate@~1.0.1: version "1.0.2" @@ -9978,6 +10524,10 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" +uuid@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" + uuid@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -9986,6 +10536,10 @@ uuid@^3.0.1, uuid@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" +uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + v8-compile-cache@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" @@ -10007,7 +10561,7 @@ value-equal@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -10117,15 +10671,200 @@ wbuf@^1.1.0, wbuf@^1.7.2: dependencies: minimalistic-assert "^1.0.0" -web3@^0.19.0: - version "0.19.1" - resolved "https://registry.yarnpkg.com/web3/-/web3-0.19.1.tgz#e763d5b1107c4bc24abd4f8cbee1ba3659e6eb31" +web3-bzz@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.35.tgz#9d5e1362b3db2afd77d65619b7cd46dd5845c192" dependencies: - bignumber.js "^4.0.2" - crypto-js "^3.1.4" - utf8 "^2.1.1" - xhr2 "*" - xmlhttprequest "*" + got "7.1.0" + swarm-js "0.1.37" + underscore "1.8.3" + +web3-core-helpers@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz#d681d218a0c6e3283ee1f99a078ab9d3eef037f1" + dependencies: + underscore "1.8.3" + web3-eth-iban "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-core-method@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz#fc10e2d546cf4886038e6130bd5726b0952a4e5f" + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.35" + web3-core-promievent "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-core-promievent@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz#4f1b24737520fa423fee3afee110fbe82bcb8691" + dependencies: + any-promise "1.3.0" + eventemitter3 "1.1.1" + +web3-core-requestmanager@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz#2b77cbf6303720ad68899b39fa7f584dc03dbc8f" + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.35" + web3-providers-http "1.0.0-beta.35" + web3-providers-ipc "1.0.0-beta.35" + web3-providers-ws "1.0.0-beta.35" + +web3-core-subscriptions@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz#c1b76a2ad3c6e80f5d40b8ba560f01e0f4628758" + dependencies: + eventemitter3 "1.1.1" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.35" + +web3-core@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.35.tgz#0c44d3c50d23219b0b1531d145607a9bc7cd4b4f" + dependencies: + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-requestmanager "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-eth-abi@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz#2eb9c1c7c7233db04010defcb192293e0db250e6" + dependencies: + bn.js "4.11.6" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-eth-accounts@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.35.tgz#7d0e5a69f510dc93874471599eb7abfa9ddf3e63" + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + scrypt.js "0.2.0" + underscore "1.8.3" + uuid "2.0.1" + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-eth-contract@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.35.tgz#5276242d8a3358d9f1ce92b71575c74f9015935c" + dependencies: + underscore "1.8.3" + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-promievent "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-eth-abi "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-eth-iban@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz#5aa10327a9abb26bcfc4ba79d7bad18a002b332c" + dependencies: + bn.js "4.11.6" + web3-utils "1.0.0-beta.35" + +web3-eth-personal@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz#ecac95b7a53d04a567447062d5cae5f49879e89f" + dependencies: + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-eth@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.35.tgz#c52c804afb95e6624b6f5e72a9af90fbf5005b68" + dependencies: + underscore "1.8.3" + web3-core "1.0.0-beta.35" + web3-core-helpers "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-eth-abi "1.0.0-beta.35" + web3-eth-accounts "1.0.0-beta.35" + web3-eth-contract "1.0.0-beta.35" + web3-eth-iban "1.0.0-beta.35" + web3-eth-personal "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-net@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.35.tgz#5c6688e0dea71fcd910ee9dc5437b94b7f6b3354" + dependencies: + web3-core "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" + +web3-providers-http@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.0.0-beta.35.tgz#92059d9d6de6e9f82f4fae30b743efd841afc1e1" + dependencies: + web3-core-helpers "1.0.0-beta.35" + xhr2-cookies "1.1.0" + +web3-providers-ipc@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz#031afeb10fade2ebb0ef2fb82f5e58c04be842d9" + dependencies: + oboe "2.1.3" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.35" + +web3-providers-ws@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz#5d38603fd450243a26aae0ff7f680644e77fa240" + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.35" + websocket "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + +web3-shh@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.35.tgz#7e4a585f8beee0c1927390937c6537748a5d1a58" + dependencies: + web3-core "1.0.0-beta.35" + web3-core-method "1.0.0-beta.35" + web3-core-subscriptions "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + +web3-utils@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.35.tgz#ced9e1df47c65581c441c5f2af76b05a37a273d7" + dependencies: + bn.js "4.11.6" + eth-lib "0.1.27" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randomhex "0.1.5" + underscore "1.8.3" + utf8 "2.1.1" + +web3@1.0.0-beta.35: + version "1.0.0-beta.35" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.35.tgz#6475095bd451a96e50a32b997ddee82279292f11" + dependencies: + web3-bzz "1.0.0-beta.35" + web3-core "1.0.0-beta.35" + web3-eth "1.0.0-beta.35" + web3-eth-personal "1.0.0-beta.35" + web3-net "1.0.0-beta.35" + web3-shh "1.0.0-beta.35" + web3-utils "1.0.0-beta.35" webidl-conversions@^4.0.2: version "4.0.2" @@ -10287,6 +11026,15 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" +"websocket@git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible": + version "1.0.26" + resolved "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + dependencies: + debug "^2.2.0" + nan "^2.3.3" + typedarray-to-buffer "^3.1.2" + yaeti "^0.0.6" + whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" @@ -10394,6 +11142,14 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + ws@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" @@ -10411,18 +11167,43 @@ x-is-string@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" -xhr2@*: - version "0.1.4" - resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" +xhr-request-promise@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz#343c44d1ee7726b8648069682d0f840c83b4261d" + dependencies: + xhr-request "^1.0.1" + +xhr-request@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + dependencies: + cookiejar "^2.1.1" + +xhr@^2.0.4, xhr@^2.3.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" -xmlhttprequest@*: - version "1.8.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -10435,6 +11216,10 @@ y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -10513,6 +11298,13 @@ yarn-run-all@^3.1.1: shell-quote "^1.6.1" string.prototype.padend "^3.0.0" +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yeoman-environment@^2.0.0, yeoman-environment@^2.0.5: version "2.1.1" resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.1.1.tgz#10a045f7fc4397873764882eae055a33e56ee1c5"