diff --git a/package.json b/package.json index ebede7ea..9f764b5f 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "redux-thunk": "^2.2.0", "styled-components": "^3.3.3", "styled-normalize": "^8.0.0", - "trezor-connect": "^5.0.28", + "trezor-connect": "5.0.30", "web3": "^0.19.0", "webpack": "^4.16.3", "whatwg-fetch": "^2.0.4", diff --git a/src/flowtype/index.js b/src/flowtype/index.js index 635c1557..56e8c40e 100644 --- a/src/flowtype/index.js +++ b/src/flowtype/index.js @@ -78,6 +78,7 @@ export type UnknownDevice = $Exact<{ ts: number; }> +export type { Device } from 'trezor-connect'; export type TrezorDevice = AcquiredDevice | UnknownDevice; export type RouterLocationState = LocationState; diff --git a/src/js/actions/ModalActions.js b/src/js/actions/ModalActions.js index c4e75f56..35266e27 100644 --- a/src/js/actions/ModalActions.js +++ b/src/js/actions/ModalActions.js @@ -2,7 +2,6 @@ import TrezorConnect, { UI, UI_EVENT } from 'trezor-connect'; -import type { Device } from 'trezor-connect'; import * as MODAL from 'actions/constants/modal'; import * as CONNECT from 'actions/constants/TrezorConnect'; diff --git a/src/js/actions/SelectedAccountActions.js b/src/js/actions/SelectedAccountActions.js index 99be257f..18056b55 100644 --- a/src/js/actions/SelectedAccountActions.js +++ b/src/js/actions/SelectedAccountActions.js @@ -67,7 +67,7 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct const web3 = stateUtils.getWeb3(state); const payload: $ElementType = { - // location: location.pathname, + location: location.pathname, account, network, discovery, diff --git a/src/js/actions/TokenActions.js b/src/js/actions/TokenActions.js index b0306ba4..a986ac76 100644 --- a/src/js/actions/TokenActions.js +++ b/src/js/actions/TokenActions.js @@ -32,7 +32,7 @@ type SelectOptions = { // action from component export const load = (input: string, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { - if (input.length < 1) return; + if (input.length < 1) input = '0x'; const tokens = getState().localStorage.tokens[network]; const value = input.toLowerCase(); diff --git a/src/js/actions/TrezorConnectActions.js b/src/js/actions/TrezorConnectActions.js index 16d784f2..528041dd 100644 --- a/src/js/actions/TrezorConnectActions.js +++ b/src/js/actions/TrezorConnectActions.js @@ -8,13 +8,12 @@ import * as TOKEN from 'actions/constants/token'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as NOTIFICATION from 'actions/constants/notification'; import * as WALLET from 'actions/constants/wallet'; +import { getDuplicateInstanceNumber } from 'reducers/utils'; import { push } from 'react-router-redux'; -import { resolveAfter } from 'utils/promiseUtils'; import type { - Device, DeviceMessage, UiMessage, TransportMessage, @@ -29,6 +28,7 @@ import type { Action, ThunkAction, AsyncAction, + Device, TrezorDevice, RouterLocationState, } from 'flowtype'; @@ -112,8 +112,9 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS }); // $FlowIssue LOCAL not declared + 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://sisyfos.trezor.io/connect/'; // window.__TREZOR_CONNECT_SRC = 'https://localhost:8088/'; try { @@ -401,9 +402,16 @@ export const forget = (device: TrezorDevice): Action => ({ }); export const duplicateDevice = (device: TrezorDevice): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise => { + // dispatch({ + // type: CONNECT.TRY_TO_DUPLICATE, + // device, + // }); + + const instance: number = getDuplicateInstanceNumber(getState().devices, device); + const extended: Object = { instance }; dispatch({ - type: CONNECT.TRY_TO_DUPLICATE, - device, + type: CONNECT.DUPLICATE, + device: { ...device, ...extended }, }); }; diff --git a/src/js/actions/WalletActions.js b/src/js/actions/WalletActions.js index 82c529b7..8eeea9b2 100644 --- a/src/js/actions/WalletActions.js +++ b/src/js/actions/WalletActions.js @@ -6,7 +6,6 @@ import * as WALLET from 'actions/constants/wallet'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as stateUtils from 'reducers/utils'; -import type { Device } from 'trezor-connect'; import type { Account, @@ -14,6 +13,7 @@ import type Discovery, Token, Web3Instance, + Device, TrezorDevice, RouterLocationState, ThunkAction, diff --git a/src/js/components/landing/ConnectDevice.js b/src/js/components/landing/ConnectDevice.js new file mode 100644 index 00000000..f1034ecd --- /dev/null +++ b/src/js/components/landing/ConnectDevice.js @@ -0,0 +1,114 @@ +/* @flow */ + + +import React, { Component } from 'react'; +import TrezorConnect from 'trezor-connect'; + +import type { State, TrezorDevice } from '~/flowtype'; + +type Props = { + transport: $PropertyType<$ElementType, 'transport'>; + disconnectRequest: ?TrezorDevice; +} + +const DisconnectDevice = (props: Props) => { + if (!props.disconnectRequest) return null; + return ( +
+

The private bank in your hands.

+

TREZOR Wallet is an easy-to-use interface for your TREZOR.

+

TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.

+
+

+ + Unplug { props.disconnectRequest.label } device. + +

+
+
+
+ ); +}; + +const ConnectHIDDevice = (props: Props) => ( +
+

The private bank in your hands.

+

TREZOR Wallet is an easy-to-use interface for your TREZOR.

+

TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.

+
+

+ + + + + + + + + + Connect TREZOR to continue + +

+
+
+

+ Don't have TREZOR? Get one +

+
+
+); + +class ConnectWebUsbDevice extends Component { + componentDidMount(): void { + TrezorConnect.renderWebUSBButton(); + } + + componentDidUpdate() { + TrezorConnect.renderWebUSBButton(); + } + + render() { + return ( +
+

The private bank in your hands.

+

TREZOR Wallet is an easy-to-use interface for your TREZOR.

+

TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.

+
+

+ + + + + + + + + + Connect TREZOR + +

+

and

+ +
+
+

+ Device not recognized? Try installing the TREZOR Bridge. + Don't have TREZOR? Get one +

+
+
+ ); + } +} + +const ConnectDevice = (props: Props) => { + const { transport, disconnectRequest } = props; + if (disconnectRequest) { + return ; + } if (transport && transport.version.indexOf('webusb') >= 0) { + return ; + } + return ; +}; + +export default ConnectDevice; \ No newline at end of file diff --git a/src/js/components/modal/DuplicateDevice.js b/src/js/components/modal/DuplicateDevice.js index 5d5de6e0..d707eb84 100644 --- a/src/js/components/modal/DuplicateDevice.js +++ b/src/js/components/modal/DuplicateDevice.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; -import { getNewInstance } from 'reducers/DevicesReducer'; +import { getDuplicateInstanceNumber } from 'reducers/utils'; import type { Props } from './index'; type State = { @@ -25,7 +25,7 @@ export default class DuplicateDevice extends Component { const device = props.modal.opened ? props.modal.device : null; if (!device) return; - const instance = getNewInstance(props.devices, device); + const instance = getDuplicateInstanceNumber(props.devices, device); this.state = { defaultName: `${device.label} (${instance.toString()})`, diff --git a/src/js/components/modal/Passphrase.js b/src/js/components/modal/Passphrase.js index 92010cbf..007f1e2f 100644 --- a/src/js/components/modal/Passphrase.js +++ b/src/js/components/modal/Passphrase.js @@ -39,7 +39,7 @@ export default class PinModal extends Component { let singleInput = false; if (selected && selected.path === device.path) { deviceLabel = selected.instanceLabel; - singleInput = selected.remember; + singleInput = selected.remember || selected.state !== null; } this.state = { diff --git a/src/js/reducers/DevicesReducer.js b/src/js/reducers/DevicesReducer.js index 59ed5c8d..9c150ecd 100644 --- a/src/js/reducers/DevicesReducer.js +++ b/src/js/reducers/DevicesReducer.js @@ -1,10 +1,11 @@ /* @flow */ -import { TRANSPORT, DEVICE } from 'trezor-connect'; +import { DEVICE } from 'trezor-connect'; import type { Device } from 'trezor-connect'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as WALLET from 'actions/constants/wallet'; +import { getDuplicateInstanceNumber } from 'reducers/utils'; import type { Action, TrezorDevice } from 'flowtype'; @@ -121,7 +122,7 @@ const addDevice = (state: State, device: Device): State => { // edge case: freshly connected device has different "passphrase_protection" than saved instances // need to automatically create another instance with default instance name // if (hasDifferentPassphraseSettings && !hasInstancesWithPassphraseSettings) { - // const instance = getNewInstance(affectedDevices, device); + // const instance = getDuplicateInstanceNumber(affectedDevices, device); // newDevice.instance = instance; // newDevice.instanceLabel = `${device.label} (${instance})`; @@ -149,7 +150,7 @@ const duplicate = (state: State, device: TrezorDevice): State => { const newState: State = [...state]; - const instance: number = getNewInstance(state, device); + const instance: number = getDuplicateInstanceNumber(state, device); const newDevice: TrezorDevice = { ...device, @@ -295,20 +296,4 @@ export default function devices(state: State = initialState, action: Action): St default: return state; } -} - -// UTILS - -export const getNewInstance = (devices: State, device: Device | TrezorDevice): number => { - const affectedDevices: State = devices.filter(d => d.features && device.features && d.features.device_id === device.features.device_id) - .sort((a, b) => { - if (!a.instance) { - return -1; - } - return !b.instance || a.instance > b.instance ? 1 : -1; - }); - - const instance: number = affectedDevices.reduce((inst, dev) => (dev.instance ? dev.instance + 1 : inst + 1), 0); - - return instance; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/js/reducers/TrezorConnectReducer.js b/src/js/reducers/TrezorConnectReducer.js index bf8c66bd..16e24057 100644 --- a/src/js/reducers/TrezorConnectReducer.js +++ b/src/js/reducers/TrezorConnectReducer.js @@ -2,11 +2,10 @@ import { TRANSPORT, DEVICE, UI } from 'trezor-connect'; -import type { Device } from 'trezor-connect'; import * as CONNECT from 'actions/constants/TrezorConnect'; import * as WALLET from 'actions/constants/wallet'; -import type { Action, TrezorDevice } from 'flowtype'; +import type { Action } from 'flowtype'; export type SelectedDevice = { id: string; // could be device path if unacquired or features.device_id diff --git a/src/js/reducers/utils/index.js b/src/js/reducers/utils/index.js index e088d5fa..67bed35c 100644 --- a/src/js/reducers/utils/index.js +++ b/src/js/reducers/utils/index.js @@ -15,6 +15,7 @@ import type { Action, AsyncAction, GetState, + Device, TrezorDevice, Account, Coin, @@ -53,6 +54,23 @@ export const findDevice = (devices: Array, deviceId: string, devic return false; }); +// get next instance number +export const getDuplicateInstanceNumber = (devices: Array, device: Device | TrezorDevice): number => { + // find device(s) with the same features.device_id + // and sort them by instance number + const affectedDevices: Array = devices.filter(d => d.features && device.features && d.features.device_id === device.features.device_id) + .sort((a, b) => { + if (!a.instance) { + return -1; + } + return !b.instance || a.instance > b.instance ? 1 : -1; + }); + + // calculate new instance number + const instance: number = affectedDevices.reduce((inst, dev) => (dev.instance ? dev.instance + 1 : inst + 1), 0); + return instance; +}; + export const getSelectedAccount = (state: State): ?Account => { const device = state.wallet.selectedDevice; const locationState = state.router.location.state; diff --git a/src/js/views/Landing/components/ConnectDevice/components/DisconnectDevice.js b/src/js/views/Landing/components/ConnectDevice/components/DisconnectDevice.js index e26db268..2d3c01ef 100644 --- a/src/js/views/Landing/components/ConnectDevice/components/DisconnectDevice.js +++ b/src/js/views/Landing/components/ConnectDevice/components/DisconnectDevice.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { H2 } from 'components/Heading'; -const DisconnectDevice = ({ instanceLabel }) => ( +const DisconnectDevice = ({ label }) => (

The private bank in your hands.

TREZOR Wallet is an easy-to-use interface for your TREZOR.

@@ -10,7 +10,7 @@ const DisconnectDevice = ({ instanceLabel }) => (

- Unplug { instanceLabel } device. + Unplug { label } device.

@@ -19,7 +19,7 @@ const DisconnectDevice = ({ instanceLabel }) => ( ); DisconnectDevice.propTypes = { - instanceLabel: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, }; export default DisconnectDevice; \ No newline at end of file diff --git a/src/js/views/Landing/components/ConnectDevice/index.js b/src/js/views/Landing/components/ConnectDevice/index.js index f2d7bc2e..f108be1b 100644 --- a/src/js/views/Landing/components/ConnectDevice/index.js +++ b/src/js/views/Landing/components/ConnectDevice/index.js @@ -18,7 +18,7 @@ type Props = { const ConnectDevice = (props: Props) => { const { transport, disconnectRequest } = props; if (disconnectRequest) { - return ; + return ; } if (transport && transport.version.indexOf('webusb') >= 0) { return ; } diff --git a/src/js/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js b/src/js/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js index fb73650b..10f1214f 100644 --- a/src/js/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js +++ b/src/js/views/Wallet/components/LeftNavigation/components/DeviceMenu/index.js @@ -152,7 +152,7 @@ export class DeviceDropdown extends Component { deviceMenuItems.push({ type: 'settings', label: 'Device settings' }); if (selected.features.passphrase_protection && selected.connected && selected.available) { - deviceMenuItems.push({ type: 'clone', label: 'Clone device' }); + deviceMenuItems.push({ type: 'clone', label: 'Create hidden wallet' }); } //if (selected.remember) { deviceMenuItems.push({ type: 'forget', label: 'Forget device' }); @@ -169,7 +169,11 @@ export class DeviceDropdown extends Component { ); } - const deviceList = devices.map((dev, index) => { + const sortByInstance = (a: TrezorDevice, b: TrezorDevice) => { + if (!a.instance || !b.instance) return -1; + return a.instance > b.instance ? 1 : -1; + } + const deviceList = devices.sort(sortByInstance).map((dev, index) => { if (dev === selected) return null; let deviceStatus: string = 'Connected'; diff --git a/src/js/views/Wallet/components/Summary/components/Tokens/index.js b/src/js/views/Wallet/components/Summary/components/Tokens/index.js index c6dc05c6..e0f99b52 100644 --- a/src/js/views/Wallet/components/Summary/components/Tokens/index.js +++ b/src/js/views/Wallet/components/Summary/components/Tokens/index.js @@ -18,14 +18,14 @@ type Props = { const SummaryTokens = (props: Props) => { if (!props.tokens || props.tokens.length < 1) return null; - const bgColor = new ColorHash({ lightness: 0.7 }); + const bgColor = new ColorHash({ lightness: 0.16 } ); const textColor = new ColorHash(); const tokens = props.tokens.map((token, index) => { const iconColor = { - color: textColor.hex(token.name), - background: bgColor.hex(token.name), - borderColor: bgColor.hex(token.name), + color: textColor.hex(token.address), + background: bgColor.hex(token.address), + borderColor: bgColor.hex(token.address), }; const pendingAmount: BigNumber = stateUtils.getPendingAmount(props.pending, token.symbol, true); diff --git a/src/js/views/Wallet/components/Summary/index.js b/src/js/views/Wallet/components/Summary/index.js index c64dc3c0..6877fe23 100644 --- a/src/js/views/Wallet/components/Summary/index.js +++ b/src/js/views/Wallet/components/Summary/index.js @@ -75,7 +75,7 @@ const Summary = (props: Props) => {