before testing

pull/2/merge
Szymon Lesisz 6 years ago
parent 0bc4dd3cf9
commit 1c89f3e975

@ -18,6 +18,9 @@
./src/js/flowtype/react-router-redux.js ./src/js/flowtype/react-router-redux.js
./src/js/flowtype/css.js ./src/js/flowtype/css.js
./src/js/flowtype/trezor-connect.js ./src/js/flowtype/trezor-connect.js
./src/js/flowtype/bignumber.js
./src/js/flowtype/ethereum-types.js
./src/js/flowtype/web3.js
[options] [options]

@ -1,27 +1,4 @@
{ {
"coins1": [
{
"name": "Ethereum Ropsten",
"symbol": "eth",
"network": "ropsten-eth",
"shortcut": "eth",
"bip44": "m/44'/60'/0'/0",
"defaultGasPrice": 64,
"defaultGasLimit": 21000,
"defaultGasLimitTokens": 200000,
"backends": [
{
"name": "TREZOR Wallet - Ethereum",
"urls": [
"https://ropsten.infura.io/QGyVKozSUEh2YhL4s2G4",
"http://10.34.2.5:8545"
],
"explorer": "https://blockexplorer.com"
}
]
}
],
"coins": [ "coins": [
{ {
"name": "Ethereum", "name": "Ethereum",
@ -41,7 +18,10 @@
] ]
} }
], ],
"explorer": "https://etherscan.io" "explorer": {
"tx": "https://etherscan.io/tx/",
"address": "https://etherscan.io/address/"
}
}, },
{ {
"name": "Ethereum Classic", "name": "Ethereum Classic",
@ -63,7 +43,10 @@
] ]
} }
], ],
"explorer": "https://etherscan.io" "explorer": {
"tx": "https://gastracker.io/tx/",
"address": "https://gastracker.io/addr/"
}
}, },
{ {
"name": "Ethereum Ropsten", "name": "Ethereum Ropsten",
@ -83,7 +66,10 @@
] ]
} }
], ],
"explorer": "https://ropsten.etherscan.io" "explorer": {
"tx": "https://ropsten.etherscan.io/tx/",
"address": "https://ropsten.etherscan.io/tx/"
}
}, },
{ {
"name": "Ethereum Rinkeby", "name": "Ethereum Rinkeby",
@ -102,7 +88,10 @@
] ]
} }
], ],
"explorer": "https://rinkeby.etherscan.io" "explorer": {
"tx": "https://rinkeby.etherscan.io/tx/",
"tx": "https://rinkeby.etherscan.io/address/"
}
} }
], ],

@ -3,12 +3,16 @@
import * as LOG from './constants/log'; import * as LOG from './constants/log';
import type { ThunkAction, GetState, Dispatch } from '../flowtype'; import type { Action, ThunkAction, GetState, Dispatch } from '../flowtype';
import type { LogEntry } from '../reducers/LogReducer';
export type LogAction = { export type LogAction = {
type: typeof LOG.OPEN, type: typeof LOG.OPEN,
} | { } | {
type: typeof LOG.CLOSE, type: typeof LOG.CLOSE,
} | {
type: typeof LOG.ADD,
payload: LogEntry
}; };
export const toggle = (): ThunkAction => { export const toggle = (): ThunkAction => {
@ -18,12 +22,24 @@ export const toggle = (): ThunkAction => {
window.scrollTo(0, 0); window.scrollTo(0, 0);
dispatch({ dispatch({
type: LOG.CLOSE type: LOG.OPEN
}); });
} else { } else {
dispatch({ dispatch({
type: LOG.OPEN type: LOG.CLOSE
}); });
} }
} }
} }
// export const add = (type: string, message: string): Action => {
export const add = (type: string, message: any): Action => {
return {
type: LOG.ADD,
payload: {
time: new Date().getTime(),
type,
message
}
}
}

@ -66,7 +66,8 @@ export const showUnverifiedAddress = (): Action => {
} }
} }
export const showAddress = (address_n: string): AsyncAction => { //export const showAddress = (address_n: string): AsyncAction => {
export const showAddress = (address_n: Array<number>): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => { return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected = findSelectedDevice(getState().connect); const selected = findSelectedDevice(getState().connect);

@ -118,10 +118,10 @@ const getMaxAmount = () => {
} }
export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLimit: string): Array<FeeLevel> => { export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLimit: string): Array<FeeLevel> => {
if (typeof gasPrice === 'string') gasPrice = new BigNumber(gasPrice); const price: BigNumber = typeof gasPrice === 'string' ? new BigNumber(gasPrice) : gasPrice
const quarter: BigNumber = gasPrice.dividedBy(4); const quarter: BigNumber = price.dividedBy(4);
const high: string = gasPrice.plus(quarter.times(2)).toString(); const high: string = price.plus(quarter.times(2)).toString();
const low: string = gasPrice.minus(quarter.times(2)).toString(); const low: string = price.minus(quarter.times(2)).toString();
return [ return [
{ {
@ -132,7 +132,7 @@ export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLi
{ {
value: 'Normal', value: 'Normal',
gasPrice: gasPrice.toString(), gasPrice: gasPrice.toString(),
label: `${ calculateFee(gasPrice.toString(), gasLimit) } ${ symbol }` label: `${ calculateFee(price.toString(), gasLimit) } ${ symbol }`
}, },
{ {
value: 'Low', value: 'Low',
@ -798,8 +798,6 @@ export const onSend = (): AsyncAction => {
// txData.gasLimit = web3.toHex(gasLimit); // txData.gasLimit = web3.toHex(gasLimit);
// txData.gasPrice = web3.toHex( EthereumjsUnits.convert(gasPrice, 'gwei', 'wei') ); // txData.gasPrice = web3.toHex( EthereumjsUnits.convert(gasPrice, 'gwei', 'wei') );
// console.log("---->GASSS", txData, gasLimit, gasPrice, EthereumjsUnits.convert(gasPrice, 'gwei', 'wei'));
const selected: ?TrezorDevice = findSelectedDevice(getState().connect); const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
if (!selected) return; if (!selected) return;
@ -840,7 +838,6 @@ export const onSend = (): AsyncAction => {
txData.v = web3.toHex(signedTransaction.payload.v); txData.v = web3.toHex(signedTransaction.payload.v);
// const gasLimit2 = await estimateGas(web3, txData); // const gasLimit2 = await estimateGas(web3, txData);
// console.log("---->GASSS", txData, gasLimit2.toString() );
const { config } = getState().localStorage; const { config } = getState().localStorage;
if (!config) return; if (!config) return;
@ -866,7 +863,7 @@ export const onSend = (): AsyncAction => {
payload: { payload: {
type: 'success', type: 'success',
title: 'Transaction success', title: 'Transaction success',
message: `<a href="${ selectedCoin.explorer }/tx/${txid}" class="green" target="_blank" rel="noreferrer noopener">See transaction detail</a>`, message: `<a href="${selectedCoin.explorer.tx}${txid}" class="green" target="_blank" rel="noreferrer noopener">See transaction detail</a>`,
cancelable: true, cancelable: true,
actions: [] actions: []
} }

@ -135,10 +135,10 @@ export const init = (): AsyncAction => {
webusb: true webusb: true
}); });
} catch (error) { } catch (error) {
dispatch({ // dispatch({
type: CONNECT.INITIALIZATION_ERROR, // type: CONNECT.INITIALIZATION_ERROR,
error // error
}) // })
} }
} }
} }
@ -227,7 +227,6 @@ export const onSelectDevice = (device: TrezorDevice | Device): ThunkAction => {
// || device.isUsedElsewhere // || device.isUsedElsewhere
// switch to initial url and reset this value // switch to initial url and reset this value
console.warn("ON SELECT DEV d", device);
if (!device.features) { if (!device.features) {
dispatch( push(`/device/${ device.path }/acquire`) ); dispatch( push(`/device/${ device.path }/acquire`) );
@ -295,7 +294,6 @@ export const switchToFirstAvailableDevice = (): AsyncAction => {
export const getSelectedDeviceState = (): AsyncAction => { export const getSelectedDeviceState = (): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => { return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected = findSelectedDevice(getState().connect); const selected = findSelectedDevice(getState().connect);
console.warn("init selected", selected)
if (selected if (selected
&& selected.connected && selected.connected
&& selected.features && selected.features

@ -1,7 +1,7 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
import Web3, { ContractFactory, Contract } from 'web3'; import Web3 from 'web3';
import HDKey from 'hdkey'; import HDKey from 'hdkey';
import EthereumjsUtil from 'ethereumjs-util'; import EthereumjsUtil from 'ethereumjs-util';
import EthereumjsTx from 'ethereumjs-tx'; import EthereumjsTx from 'ethereumjs-tx';
@ -21,6 +21,7 @@ import type {
import type { Account } from '../reducers/AccountsReducer'; import type { Account } from '../reducers/AccountsReducer';
import type { PendingTx } from '../reducers/PendingTxReducer'; import type { PendingTx } from '../reducers/PendingTxReducer';
import type { Web3Instance } from '../reducers/Web3Reducer';
export type Web3Action = { export type Web3Action = {
type: typeof WEB3.READY, type: typeof WEB3.READY,
@ -31,7 +32,7 @@ export type Web3Action = {
export type Web3CreateAction = { export type Web3CreateAction = {
type: typeof WEB3.CREATE, type: typeof WEB3.CREATE,
network: string, network: string,
web3: any, //(web3instance) web3: Web3, //(web3instance)
erc20: any, erc20: any,
chainId: string; chainId: string;
}; };
@ -45,7 +46,7 @@ export type Web3UpdateBlockAction = {
export type Web3UpdateGasPriceAction = { export type Web3UpdateGasPriceAction = {
type: typeof WEB3.GAS_PRICE_UPDATED, type: typeof WEB3.GAS_PRICE_UPDATED,
network: string, network: string,
gasPrice: any gasPrice: string
}; };
@ -94,12 +95,8 @@ export function init(web3: ?Web3, coinIndex: number = 0): AsyncAction {
//web3 = new Web3( new Web3.providers.HttpProvider("ws://34.230.234.51:30303") ); //web3 = new Web3( new Web3.providers.HttpProvider("ws://34.230.234.51:30303") );
// initial check if backend is running // initial check if backend is running
// instance.version.getNetwork(function(error, chainId){
// if (!error) {
instance.eth.getGasPrice((error, gasPrice) => { instance.eth.getGasPrice((error: Error, gasPrice: string) => {
if (error) { if (error) {
// try different url // try different url
dispatch( init(instance, coinIndex) ); dispatch( init(instance, coinIndex) );
@ -140,12 +137,12 @@ export function init(web3: ?Web3, coinIndex: number = 0): AsyncAction {
const latestBlockFilter = instance.eth.filter('latest'); const latestBlockFilter = instance.eth.filter('latest');
const onBlockMined = async (error, blockHash) => { const onBlockMined = async (error: ?Error, blockHash: ?string) => {
if (error) { if (error) {
window.setTimeout(() => { window.setTimeout(() => {
// try again // try again
onBlockMined("manually_triggered_error", undefined); onBlockMined(new Error("manually_triggered_error"), undefined);
}, 30000); }, 30000);
} }
@ -221,7 +218,6 @@ export function init(web3: ?Web3, coinIndex: number = 0): AsyncAction {
// } // }
// contract.decimals.call((error, decimals) => { // contract.decimals.call((error, decimals) => {
// console.log("nameeeee", name, symbol, decimals)
// }) // })
// }); // });
@ -353,7 +349,7 @@ export const getBalanceAsync = (web3: Web3, address: string): Promise<any> => {
}); });
} }
export const getTokenBalanceAsync = (erc20: any, token: string, address: string): Promise<any> => { export const getTokenBalanceAsync = (erc20: any, token: string, address: string): Promise<string> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const contr = erc20.at(token); const contr = erc20.at(token);
@ -383,26 +379,27 @@ export const getNonceAsync = (web3: Web3, address: string): Promise<number> => {
export const getTokenInfoAsync = (erc20: any, address: string): Promise<any> => { export const getTokenInfoAsync = (erc20: any, address: string): Promise<any> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const contract = erc20.at(address); const contract = erc20.at(address, (error, res) => {
console.warn("callack", error, res)
});
console.warn("AT", contract)
const info = {}; const info = {};
// TODO: handle errors // TODO: handle errors
contract.name.call((e, name) => { contract.name.call((e, name) => {
if (e) { if (e) {
//console.log("1", address, e)
//resolve(null); //resolve(null);
//return; //return;
} }
info.name = name; info.name = name;
contract.symbol.call((e, symbol) => { contract.symbol.call((e, symbol) => {
if (e) { if (e) {
console.log("2", e)
resolve(null); resolve(null);
return; return;
} }
info.symbol = symbol; info.symbol = symbol;
contract.decimals.call((e, decimals) => { contract.decimals.call((e, decimals) => {
if (e) { if (e) {
console.log("3", e)
resolve(null); resolve(null);
return; return;
} }

@ -2,4 +2,5 @@
'use strict'; 'use strict';
export const OPEN: 'log__open' = 'log__open'; export const OPEN: 'log__open' = 'log__open';
export const CLOSE: 'log__close' = 'log__close'; export const CLOSE: 'log__close' = 'log__close';
export const ADD: 'log__add' = 'log__add';

@ -16,13 +16,19 @@ type Props = {
const Log = (props: Props): ?React$Element<string> => { const Log = (props: Props): ?React$Element<string> => {
if (!props.log.opened) if (!props.log.opened)
return null; return null;
// const entries = props.log.entries.map(entry => {
// return (
// )
// })
return ( return (
<div className="log"> <div className="log">
<button className="log-close transparent" onClick={ props.toggle }></button> <button className="log-close transparent" onClick={ props.toggle }></button>
<h2>Log</h2> <h2>Log</h2>
<p>Attention: The log contains your XPUBs. Anyone with your XPUBs can see your account history.</p> <p>Attention: The log contains your XPUBs. Anyone with your XPUBs can see your account history.</p>
<textarea></textarea> <textarea value={ JSON.stringify(props.log.entries) } readOnly></textarea>
</div> </div>
) )
} }

@ -4,45 +4,79 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import TrezorConnect from 'trezor-connect'; import TrezorConnect from 'trezor-connect';
import type { State, TrezorDevice } from '../../flowtype';
type Props = { type Props = {
transport: any; transport: $PropertyType<$ElementType<State, 'connect'>, 'transport'>;
disconnectRequest: ?TrezorDevice;
} }
export default class InstallBridge extends Component<Props> { const DisconnectDevice = (props: Props) => {
if (!props.disconnectRequest) return null;
return (
<main>
<h2 className="claim">The private bank in your hands.</h2>
<p>TREZOR Wallet is an easy-to-use interface for your TREZOR.</p>
<p>TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.</p>
<div className="row">
<p className="connect">
<span>
Unplug { props.disconnectRequest.instanceLabel } device.
</span>
</p>
</div>
<div className="image">
</div>
</main>
)
}
const ConnectHIDDevice = (props: Props) => {
return (
<main>
<h2 className="claim">The private bank in your hands.</h2>
<p>TREZOR Wallet is an easy-to-use interface for your TREZOR.</p>
<p>TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.</p>
<div className="row">
<p className="connect">
<span>
<svg width="12px" height="35px" viewBox="0 0 20 57">
<g stroke="none" strokeWidth="1" fill="none" transform="translate(1, 1)">
<rect className="connect-usb-pin" fill="#01B757" x="6" y="39" width="6" height="5"></rect>
<rect className="connect-usb-cable" stroke="#01B757" strokeWidth="1" x="8.5" y="44.5" width="1" height="11"></rect>
<path stroke="#01B757" d="M8.90856859,33.9811778 L6.43814432,33.9811778 C5.45301486,34.0503113 4.69477081,33.6889084 4.1634122,32.8969691 C3.36637428,31.7090602 -0.000402169348,26.3761977 0.0748097911,23.2982514 C0.124878873,21.2492429 0.0999525141,14.5598149 3.07156595e-05,3.22996744 C-0.000274213164,3.1963928 0.00243636275,3.162859 0.00812115776,3.12976773 C0.28477346,1.51937083 1.22672004,0.617538852 2.8339609,0.424271782 C4.45813658,0.228968338 6.54411954,0.0875444105 9.09190977,0 L9.09190977,0.0169167084 C11.5566027,0.104886477 13.5814718,0.244169993 15.1665175,0.434768145 C16.7530267,0.625542287 17.6912941,1.50671985 17.9813196,3.07830083 C17.9943481,3.14889902 18.0005888,3.22058224 17.9999563,3.29236974 L17.9999901,3.29237004 C17.9004498,14.5907444 17.875676,21.2628703 17.9256686,23.3087478 C18.0008805,26.3866941 14.6341041,31.7195566 13.8370662,32.9074655 C13.3057075,33.6994047 12.5474635,34.0608076 11.562334,33.9916742 L8.90856859,33.9916742 L8.90856859,33.9811778 Z"></path>
<rect fill="#01B757" x="2" y="7" width="14" height="7" rx="0.5625"></rect>
</g>
</svg>
Connect TREZOR to continue
</span>
</p>
</div>
<div className="image">
<p>
<span>Don't have TREZOR? <a href="https://trezor.io/" className="green" target="_blank" rel="noreferrer noopener">Get one</a></span>
</p>
</div>
</main>
);
}
class ConnectWebUsbDevice extends Component<Props> {
componentDidMount(): void { componentDidMount(): void {
const transport: any = this.props.transport; TrezorConnect.renderWebUSBButton();
if (transport && transport.version.indexOf('webusb') >= 0)
TrezorConnect.renderWebUSBButton();
} }
componentDidUpdate() { componentDidUpdate() {
const transport = this.props.transport; TrezorConnect.renderWebUSBButton();
if (transport && transport.version.indexOf('webusb') >= 0)
TrezorConnect.renderWebUSBButton();
} }
render() { render() {
let css = 'row';
let webusb = null;
let connectClaim = 'Connect TREZOR to continue';
let and = null;
let bridgeClaim = null;
const transport = this.props.transport;
if (transport && transport.version.indexOf('webusb') >= 0) {
css = 'row webusb'
webusb = <button className="trezor-webusb-button">Check for devices</button>;
connectClaim = 'Connect TREZOR';
and = <p>and</p>;
bridgeClaim = <span>Device not recognized? <a href="#/bridge" className="green">Try installing the TREZOR Bridge.</a></span>;
}
return ( return (
<main> <main>
<h2 className="claim">The private bank in your hands.</h2> <h2 className="claim">The private bank in your hands.</h2>
<p>TREZOR Wallet is an easy-to-use interface for your TREZOR.</p> <p>TREZOR Wallet is an easy-to-use interface for your TREZOR.</p>
<p>TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.</p> <p>TREZOR Wallet allows you to easily control your funds, manage your balance and initiate transfers.</p>
<div className={ css }> <div className="row webusb">
<p className="connect"> <p className="connect">
<span> <span>
<svg width="12px" height="35px" viewBox="0 0 20 57"> <svg width="12px" height="35px" viewBox="0 0 20 57">
@ -53,7 +87,7 @@ export default class InstallBridge extends Component<Props> {
<rect fill="#01B757" x="2" y="7" width="14" height="7" rx="0.5625"></rect> <rect fill="#01B757" x="2" y="7" width="14" height="7" rx="0.5625"></rect>
</g> </g>
</svg> </svg>
{ connectClaim } Connect TREZOR
</span> </span>
</p> </p>
<p className="webusb-and">and</p> <p className="webusb-and">and</p>
@ -61,11 +95,24 @@ export default class InstallBridge extends Component<Props> {
</div> </div>
<div className="image"> <div className="image">
<p> <p>
{ bridgeClaim } <span>Device not recognized? <a href="#/bridge" className="green">Try installing the TREZOR Bridge.</a></span>
<span>Don't have TREZOR? <a href="https://trezor.io/" className="green" target="_blank" rel="noreferrer noopener">Get one</a></span> <span>Don't have TREZOR? <a href="https://trezor.io/" className="green" target="_blank" rel="noreferrer noopener">Get one</a></span>
</p> </p>
</div> </div>
</main> </main>
); );
} }
} }
const ConnectDevice = (props: Props) => {
const { transport, disconnectRequest } = props;
if (disconnectRequest) {
return <DisconnectDevice {...props} />
} else if (transport && transport.version.indexOf('webusb') >= 0) {
return <ConnectWebUsbDevice {...props} />
} else {
return <ConnectHIDDevice {...props} />
}
}
export default ConnectDevice;

@ -43,7 +43,7 @@ export default class InstallBridge extends Component<Props, State> {
this.state = { this.state = {
version: '2.0.12', version: '2.0.12',
url: 'https://wallet.trezor.io/data/bridge/2.0.12/', url: 'https://wallet.trezor.io/data/bridge/2.0.12/',
target: null, target: currentTarget,
}; };
} }
@ -53,7 +53,6 @@ export default class InstallBridge extends Component<Props, State> {
}); });
} }
componentWillUpdate() { componentWillUpdate() {
if (this.props.browserState.osname && !this.state.target) { if (this.props.browserState.osname && !this.state.target) {
const currentTarget: ?InstallTarget = installers.find(i => i.id === this.props.browserState.osname); const currentTarget: ?InstallTarget = installers.find(i => i.id === this.props.browserState.osname);

@ -10,7 +10,6 @@ import TrezorConnectError from './TrezorConnectError';
import Header from '../common/Header'; import Header from '../common/Header';
import Footer from '../common/Footer'; import Footer from '../common/Footer';
import Log from '../common/Log'; import Log from '../common/Log';
// import { Notification } from '../common/Notification';
import Notifications, { Notification } from '../common/Notification'; import Notifications, { Notification } from '../common/Notification';
import type { Props } from './index'; import type { Props } from './index';
@ -63,7 +62,7 @@ export default (props: Props) => {
body = <InstallBridge browserState={ browserState } />; body = <InstallBridge browserState={ browserState } />;
} else if (props.wallet.ready && devices.length < 1) { } else if (props.wallet.ready && devices.length < 1) {
css += ' connect-device'; css += ' connect-device';
body = <ConnectDevice transport={ transport } />; body = <ConnectDevice transport={ transport } disconnectRequest={ props.wallet.disconnectRequest } />;
} }
if (notification || body) { if (notification || body) {

@ -2,13 +2,16 @@
'use strict'; 'use strict';
import React from 'react'; import React from 'react';
import { findAccount } from '../../reducers/AccountsReducer';
import { findSelectedDevice } from '../../reducers/TrezorConnectReducer'; import { findSelectedDevice } from '../../reducers/TrezorConnectReducer';
const ConfirmAddress = (props: any): any => { import type { Props } from './index';
const account = props.accounts.find(a => a.deviceState === props.receive.deviceState && a.index === props.receive.accountIndex && a.network === props.receive.network); const ConfirmAddress = (props: Props) => {
const { config } = props.localStorage;
const selectedCoin = config.coins.find(c => c.network === account.network); const { accounts, abstractAccount } = props;
const account = findAccount(accounts, abstractAccount.index, abstractAccount.deviceState, abstractAccount.network);
if (!account) return null;
return ( return (
<div className="confirm-address"> <div className="confirm-address">
@ -18,16 +21,21 @@ const ConfirmAddress = (props: any): any => {
</div> </div>
<div className="content"> <div className="content">
<p>{ account.address }</p> <p>{ account.address }</p>
<label>{ selectedCoin.symbol } account #{ (account.index + 1) }</label> <label>{ abstractAccount.coin.symbol } account #{ (account.index + 1) }</label>
</div> </div>
</div> </div>
); );
} }
export default ConfirmAddress; export default ConfirmAddress;
export const ConfirmUnverifiedAddress = (props: any): any => { export const ConfirmUnverifiedAddress = (props: Props): any => {
if (!props.modal.opened) return null;
const {
device
} = props.modal;
const account = props.accounts.find(a => a.deviceState === props.receive.deviceState && a.index === props.receive.accountIndex && a.network === props.receive.network); const { accounts, abstractAccount } = props;
const { const {
onCancel onCancel
@ -38,10 +46,9 @@ export const ConfirmUnverifiedAddress = (props: any): any => {
showAddress showAddress
} = props.receiveActions; } = props.receiveActions;
const { const account = findAccount(accounts, abstractAccount.index, abstractAccount.deviceState, abstractAccount.network);
device if (!account) return null;
} = props.modal;
if (!device.connected) { if (!device.connected) {
return ( return (
<div className="confirm-address-unverified"> <div className="confirm-address-unverified">
@ -59,7 +66,8 @@ export const ConfirmUnverifiedAddress = (props: any): any => {
</div> </div>
); );
} else { } else {
const enable: string = device.features.passphrase_protection ? 'Enable' : 'Disable'; // corner-case where device is connected but it is unavailable because it was created with different "passphrase_protection" settings
const enable: string = device.features && device.features.passphrase_protection ? 'Enable' : 'Disable';
return ( return (
<div className="confirm-address-unverified"> <div className="confirm-address-unverified">
<button className="close-modal transparent" onClick={ onCancel }></button> <button className="close-modal transparent" onClick={ onCancel }></button>

@ -2,8 +2,10 @@
'use strict'; 'use strict';
import React from 'react'; import React from 'react';
import type { Props } from './index';
const RememberDevice = (props: any): any => { const RememberDevice = (props: Props) => {
if (!props.modal.opened) return null;
const { device } = props.modal; const { device } = props.modal;
const { onCancel, onDuplicateDevice } = props.modalActions; const { onCancel, onDuplicateDevice } = props.modalActions;
return ( return (

@ -67,17 +67,21 @@ export default class RememberDevice extends Component<Props, State> {
const { onForgetDevice, onRememberDevice } = this.props.modalActions; const { onForgetDevice, onRememberDevice } = this.props.modalActions;
let label = device.label; let label = device.label;
let devicePlural = false; let devicePlural: string = "device or to remember it";
if (instances && instances.length > 0) { if (instances && instances.length > 1) {
label = instances.map((instance, index) => { label = instances.map((instance, index) => {
return (<span key={index}>{instance.instanceLabel}</span>); let comma: string = '';
if (index > 0) comma = ', ';
return (
<span key={ index }>{ comma }{ instance.instanceLabel }</span>
);
}) })
devicePlural = instances.length > 1; devicePlural = "devices or to remember them";
} }
return ( return (
<div className="remember"> <div className="remember">
<h3>Forget {label}?</h3> <h3>Forget {label}?</h3>
<p>Would you like TREZOR Wallet to forget your device or to remember it, so that it is still visible even while disconnected?</p> <p>Would you like TREZOR Wallet to forget your { devicePlural }, so that it is still visible even while disconnected?</p>
<button onClick={ event => onForgetDevice(device) }>Forget</button> <button onClick={ event => onForgetDevice(device) }>Forget</button>
<button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size="28" label={ this.state.countdown.toString() } /></span></button> <button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size="28" label={ this.state.countdown.toString() } /></span></button>
</div> </div>
@ -92,22 +96,9 @@ export const ForgetDevice = (props: Props) => {
return ( return (
<div className="remember"> <div className="remember">
<h3>Forget { device.instanceLabel } ?</h3> <h3>Forget { device.instanceLabel } ?</h3>
<p>Forgetting only removes the device from the list on the left, your bitcoins are still safe and you can access them by reconnecting your TREZOR again.</p> <p>Forgetting only removes the device from the list on the left, your coins are still safe and you can access them by reconnecting your TREZOR again.</p>
<button onClick={ event => onForgetSingleDevice(device) }>Forget</button> <button onClick={ (event) => onForgetSingleDevice(device) }>Forget</button>
<button className="white" onClick={ onCancel }>Don't forget</button> <button className="white" onClick={ onCancel }>Don't forget</button>
</div> </div>
); );
} }
export const DisconnectDevice = (props: Props) => {
if (!props.modal.opened) return null;
const { device } = props.modal;
const { onForgetSingleDevice, onCancel } = props.modalActions;
return (
<div className="remember">
<h3>Unplug { device.instanceLabel }</h3>
<p>TREZOR Wallet will forget your TREZOR right after you disconnect it.</p>
<b>TODO: its not true, actually i've already forget those data!!!</b>
</div>
);
}

@ -19,7 +19,7 @@ import Passphrase from './Passphrase';
import PassphraseType from './PassphraseType'; import PassphraseType from './PassphraseType';
import ConfirmSignTx from './ConfirmSignTx'; import ConfirmSignTx from './ConfirmSignTx';
import ConfirmAddress, { ConfirmUnverifiedAddress } from './ConfirmAddress'; import ConfirmAddress, { ConfirmUnverifiedAddress } from './ConfirmAddress';
import RememberDevice, { ForgetDevice, DisconnectDevice } from './RememberDevice'; import RememberDevice, { ForgetDevice } from './RememberDevice';
import DuplicateDevice from './DuplicateDevice'; import DuplicateDevice from './DuplicateDevice';
import * as RECEIVE from '../../actions/constants/receive'; import * as RECEIVE from '../../actions/constants/receive';
@ -36,6 +36,7 @@ type StateProps = {
accounts: $ElementType<State, 'accounts'>, accounts: $ElementType<State, 'accounts'>,
devices: $PropertyType<$ElementType<State, 'connect'>, 'devices'>, devices: $PropertyType<$ElementType<State, 'connect'>, 'devices'>,
connect: $ElementType<State, 'connect'>, connect: $ElementType<State, 'connect'>,
abstractAccount: $ElementType<State, 'abstractAccount'>,
sendForm: $ElementType<State, 'sendForm'>, sendForm: $ElementType<State, 'sendForm'>,
receive: $ElementType<State, 'receive'>, receive: $ElementType<State, 'receive'>,
localStorage: $ElementType<State, 'localStorage'>, localStorage: $ElementType<State, 'localStorage'>,
@ -99,10 +100,6 @@ class Modal extends Component<Props> {
component = (<ForgetDevice { ...this.props } />) component = (<ForgetDevice { ...this.props } />)
break; break;
case CONNECT.DISCONNECT_REQUEST :
component = (<DisconnectDevice { ...this.props } />)
break;
case CONNECT.TRY_TO_DUPLICATE : case CONNECT.TRY_TO_DUPLICATE :
component = (<DuplicateDevice { ...this.props } />) component = (<DuplicateDevice { ...this.props } />)
break; break;
@ -131,6 +128,7 @@ const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: St
accounts: state.accounts, accounts: state.accounts,
devices: state.connect.devices, devices: state.connect.devices,
connect: state.connect, connect: state.connect,
abstractAccount: state.abstractAccount,
sendForm: state.sendForm, sendForm: state.sendForm,
receive: state.receive, receive: state.receive,
localStorage: state.localStorage localStorage: state.localStorage

@ -45,7 +45,7 @@ export default connect(
}, },
(dispatch: Dispatch) => { (dispatch: Dispatch) => {
return { return {
toggle: bindActionCreators(TrezorConnectActions.acquire, dispatch), acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
}; };
} }
)(Acquire); )(Acquire);

@ -15,13 +15,13 @@ import { default as AbstractAccountActions } from '../../actions/AbstractAccount
import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
import type { State, Dispatch } from '../../flowtype'; import type { State, Dispatch } from '../../flowtype';
import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps, Props as BaseProps} from './account/AbstractAccount'; import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps } from './account/AbstractAccount';
import type { AccountState } from './account/AbstractAccount'; import type { AccountState } from './account/AbstractAccount';
type OwnProps = { } type OwnProps = { }
type StateProps = StateProps & { type StateProps = BaseStateProps & {
receive: $ElementType<State, 'receive'>, receive: $ElementType<State, 'receive'>,
} }
@ -29,7 +29,7 @@ type DispatchProps = BaseDispatchProps & {
showAddress: typeof ReceiveActions.showAddress showAddress: typeof ReceiveActions.showAddress
} }
type Props = BaseProps & StateProps & DispatchProps; type Props = StateProps & DispatchProps;
class Receive extends AbstractAccount<Props> { class Receive extends AbstractAccount<Props> {
@ -43,21 +43,22 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
const { const {
device, device,
account, account,
discovery,
deviceStatusNotification deviceStatusNotification
} = state; } = state;
if (!device || !account) return <section></section>;
const { const {
addressVerified, addressVerified,
addressUnverified, addressUnverified,
} = props.receive; } = props.receive;
if (!device || !account || !discovery) return <section></section>;
let qrCode = null; let qrCode = null;
let address = `${account.address.substring(0, 20)}...`; let address = `${account.address.substring(0, 20)}...`;
let className = 'address hidden'; let className = 'address hidden';
let button = ( let button = (
<button onClick={ event => props.showAddress(account.addressPath) }> <button disabled={ !discovery.completed } onClick={ event => props.showAddress(account.addressPath) }>
<span>Show full address</span> <span>Show full address</span>
</button> </button>
); );

@ -58,7 +58,9 @@ export default class AbstractAccount<P> extends Component<Props & P, AccountStat
const device = findDevice(props.devices, currentState.deviceState, currentState.deviceId, currentState.deviceInstance); const device = findDevice(props.devices, currentState.deviceState, currentState.deviceId, currentState.deviceInstance);
if (!device) return; if (!device) return;
const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === currentState.network); const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === currentState.network);
if (!discovery) return;
const account = props.accounts.find(a => a.deviceState === currentState.deviceState && a.index === currentState.index && a.network === currentState.network); const account = props.accounts.find(a => a.deviceState === currentState.deviceState && a.index === currentState.index && a.network === currentState.network);
let deviceStatusNotification: ?React$Element<typeof Notification> = null; let deviceStatusNotification: ?React$Element<typeof Notification> = null;
if (account) { if (account) {
@ -66,6 +68,8 @@ export default class AbstractAccount<P> extends Component<Props & P, AccountStat
deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />; deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />;
} else if (!device.available) { } else if (!device.available) {
deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is unavailable` } message="Change passphrase settings to use this device" />; deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is unavailable` } message="Change passphrase settings to use this device" />;
} else if (!discovery.completed) {
deviceStatusNotification = <Notification className="info" title="Loading accounts" />;
} }
} }
this.setState({ this.setState({
@ -108,7 +112,7 @@ export default class AbstractAccount<P> extends Component<Props & P, AccountStat
if (device.available) { if (device.available) {
return ( return (
<section> <section>
<Notification className="info" title="Loading account" /> <Notification className="info" title="Loading accounts" />
</section> </section>
); );
} else { } else {
@ -128,7 +132,7 @@ export default class AbstractAccount<P> extends Component<Props & P, AccountStat
<Notification <Notification
className="info" className="info"
title={ `Device ${ device.instanceLabel } is disconnected` } title={ `Device ${ device.instanceLabel } is disconnected` }
message="Connect to load accounts" message="Connect device to load accounts"
/> />
</section> </section>
); );

@ -29,8 +29,6 @@ const AccountSelection = (props: Props): ?React$Element<string> => {
const fiatRate = props.fiat.find(f => f.network === selectedCoin.network); const fiatRate = props.fiat.find(f => f.network === selectedCoin.network);
// console.warn("AccountSelectionRender", selected, props);
const deviceAddresses: Array<any> = getAccounts(accounts, selected, location.state.network); const deviceAddresses: Array<any> = getAccounts(accounts, selected, location.state.network);
let selectedAccounts = deviceAddresses.map((address, i) => { let selectedAccounts = deviceAddresses.map((address, i) => {
// const url: string = `${baseUrl}/network/${location.state.network}/address/${i}`; // const url: string = `${baseUrl}/network/${location.state.network}/address/${i}`;

@ -11,8 +11,11 @@ const CoinSelection = (props: Props): React$Element<string> => {
const { location } = props.router; const { location } = props.router;
const { config } = props.localStorage; const { config } = props.localStorage;
const urlParams = location.state;
const baseUrl: string = urlParams.deviceInstance ? `/device/${urlParams.device}:${urlParams.deviceInstance}` : `/device/${urlParams.device}`;
const walletCoins = config.coins.map(item => { const walletCoins = config.coins.map(item => {
const url = `${ location.pathname }/network/${ item.network }/address/0`; const url = `${ baseUrl }/network/${ item.network }/address/0`;
const className = `coin ${ item.network }` const className = `coin ${ item.network }`
return ( return (
<NavLink key={ item.network } to={ url } className={ className }> <NavLink key={ item.network } to={ url } className={ className }>

@ -104,11 +104,11 @@ const Value = (props: any): any => {
export const DeviceSelect = (props: Props) => { export const DeviceSelect = (props: Props) => {
const { devices, transport } = props.connect; const { devices, transport } = props.connect;
const selected: ?TrezorDevice = findSelectedDevice(props.connect); const selected: ?TrezorDevice = findSelectedDevice(props.connect);
if (!selected) return null; if (!selected) return null;
const handleMenuClick = (type, device) => { const handleMenuClick = (type: string, device: TrezorDevice) => {
console.log("handleMenuClick", type, device)
if (type === 'acquire') { if (type === 'acquire') {
props.acquireDevice(); props.acquireDevice();
} else if (type === 'forget') { } else if (type === 'forget') {
@ -118,7 +118,8 @@ export const DeviceSelect = (props: Props) => {
} }
} }
const disabled: boolean = (devices.length < 1 && transport && transport.version.indexOf('webusb') < 0); const webusb: boolean = (transport && transport.version.indexOf('webusb') >= 0) ? true : false;
const disabled: boolean = (devices.length < 1 && !webusb);
return ( return (
<Value <Value
@ -150,7 +151,7 @@ export class DeviceDropdown extends Component<Props> {
} }
componentDidUpdate() { componentDidUpdate() {
const transport: any = this.props.connect.transport; const { transport } = this.props.connect;
if (transport && transport.version.indexOf('webusb') >= 0) if (transport && transport.version.indexOf('webusb') >= 0)
TrezorConnect.renderWebUSBButton(); TrezorConnect.renderWebUSBButton();
} }
@ -163,6 +164,7 @@ export class DeviceDropdown extends Component<Props> {
block = true; block = true;
break; break;
} }
elem = elem.parentElement; elem = elem.parentElement;
} }
@ -178,7 +180,7 @@ export class DeviceDropdown extends Component<Props> {
componentDidMount(): void { componentDidMount(): void {
window.addEventListener('mousedown', this.mouseDownHandler, false); window.addEventListener('mousedown', this.mouseDownHandler, false);
// window.addEventListener('blur', this.blurHandler, false); // window.addEventListener('blur', this.blurHandler, false);
const transport: any = this.props.connect.transport; const { transport } = this.props.connect;
if (transport && transport.version.indexOf('webusb') >= 0) if (transport && transport.version.indexOf('webusb') >= 0)
TrezorConnect.renderWebUSBButton(); TrezorConnect.renderWebUSBButton();
} }
@ -192,7 +194,6 @@ export class DeviceDropdown extends Component<Props> {
if (item.type === 'reload') { if (item.type === 'reload') {
this.props.acquireDevice(); this.props.acquireDevice();
} else if (item.type === 'forget') { } else if (item.type === 'forget') {
// this.props.toggleDeviceDropdown(false);
this.props.forgetDevice(device); this.props.forgetDevice(device);
} else if (item.type === 'clone') { } else if (item.type === 'clone') {
this.props.duplicateDevice(device); this.props.duplicateDevice(device);
@ -244,14 +245,6 @@ export class DeviceDropdown extends Component<Props> {
); );
} }
// const currentDeviceMenu = (
// <div className="device-menu">
// <div className="settings">Device settings</div>
// <div className="clone">Clone device</div>
// <div className="forget">Forget device</div>
// </div>
// );
const deviceList: Array<any> = devices.map((dev, index) => { const deviceList: Array<any> = devices.map((dev, index) => {
if (dev === selected) return null; if (dev === selected) return null;

@ -5,7 +5,6 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import raf from 'raf'; import raf from 'raf';
import { DeviceSelect } from './DeviceSelection';
import { getViewportHeight, getScrollY } from '../../../utils/windowUtils'; import { getViewportHeight, getScrollY } from '../../../utils/windowUtils';
type Props = { type Props = {

@ -58,7 +58,7 @@ const PendingTransactions = (props: Props) => {
</div> </div>
</div> </div>
<div className="name"> <div className="name">
<a href={ `${props.selectedCoin.explorer}/tx/${tx.id}`} target="_blank" rel="noreferrer noopener">{ name }</a> <a href={ `${props.selectedCoin.explorer.tx}${tx.id}`} target="_blank" rel="noreferrer noopener">{ name }</a>
</div> </div>
<div className="amount">{ tx.amount } { symbol }</div> <div className="amount">{ tx.amount } { symbol }</div>
</div> </div>

@ -24,10 +24,11 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
const { const {
device, device,
account, account,
discovery,
deviceStatusNotification deviceStatusNotification
} = state; } = state;
if (!device || !account) return <section></section>; if (!device || !account || !discovery) return <section></section>;
const addressTokens = props.tokens.filter(t => t.ethAddress === account.address); const addressTokens = props.tokens.filter(t => t.ethAddress === account.address);
const { network } = props.abstractAccount; const { network } = props.abstractAccount;
@ -95,7 +96,7 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
buttonLabel += ` ${total} ${ selectedCoin.symbol }`; buttonLabel += ` ${total} ${ selectedCoin.symbol }`;
} }
if (device) { //if (device) {
if (!device.connected){ if (!device.connected){
buttonLabel = 'Device is not connected'; buttonLabel = 'Device is not connected';
@ -103,9 +104,12 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
} else if (!device.available) { } else if (!device.available) {
buttonLabel = 'Device is unavailable'; buttonLabel = 'Device is unavailable';
buttonDisabled = true; buttonDisabled = true;
} else if (!discovery.completed) {
buttonLabel = 'Loading accounts';
buttonDisabled = true;
} }
} //}
let notification = null; let notification = null;

@ -44,8 +44,11 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
{ deviceStatusNotification } { deviceStatusNotification }
<h2 className={ `summary-header ${abstractAccount.network}` }>Address #{ parseInt(abstractAccount.index) + 1 }</h2> <h2 className={ `summary-header ${abstractAccount.network}` }>Address #{ parseInt(abstractAccount.index) + 1 }</h2>
<SummaryDetails <SummaryDetails
explorer={ `${abstractAccount.coin.explorer.address}${account.address}` }
coin={ abstractAccount.coin }
summary={ props.summary } summary={ props.summary }
balance={ account.balance } balance={ account.balance }
network={ abstractAccount.network } network={ abstractAccount.network }
@ -54,7 +57,8 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
onToggle={ props.onDetailsToggle } /> onToggle={ props.onDetailsToggle } />
<h2>Tokens</h2> <h2>Tokens</h2>
{/* 0x58cda554935e4a1f2acbe15f8757400af275e084 */} {/* 0x58cda554935e4a1f2acbe15f8757400af275e084 Lahod */}
{/* 0x58cda554935e4a1f2acbe15f8757400af275e084 T01 */}
<div className="filter"> <div className="filter">
<Async <Async
className="token-select" className="token-select"
@ -81,7 +85,7 @@ const _render = (props: Props, state: AccountState): React$Element<string> => {
/> />
</div> </div>
<SummaryTokens tokens={ tokens } removeToken={ props.removeToken } /> <SummaryTokens tokens={ tokens } removeToken={ props.removeToken } />
</section> </section>

@ -7,11 +7,12 @@ import BigNumber from 'bignumber.js';
import type { Props as BaseProps } from './index'; import type { Props as BaseProps } from './index';
type Props = { type Props = {
explorer: string,
coin: $PropertyType<$ElementType<BaseProps, 'abstractAccount'>, 'coin'>,
summary: $ElementType<BaseProps, 'summary'>, summary: $ElementType<BaseProps, 'summary'>,
balance: string, balance: string,
network: string, network: string,
fiat: $ElementType<BaseProps, 'fiat'>, fiat: $ElementType<BaseProps, 'fiat'>,
localStorage: $ElementType<BaseProps, 'localStorage'>,
onToggle: $ElementType<BaseProps, 'onDetailsToggle'> onToggle: $ElementType<BaseProps, 'onDetailsToggle'>
} }
@ -23,8 +24,7 @@ const SummaryDetails = (props: Props): ?React$Element<string> => {
</div> </div>
); );
const { config } = props.localStorage; const selectedCoin = props.coin;
const selectedCoin = config.coins.find(c => c.network === props.network);
const fiatRate = props.fiat.find(f => f.network === selectedCoin.network); const fiatRate = props.fiat.find(f => f.network === selectedCoin.network);
let balanceColumn = null; let balanceColumn = null;
@ -63,6 +63,7 @@ const SummaryDetails = (props: Props): ?React$Element<string> => {
return ( return (
<div className="summary-details opened"> <div className="summary-details opened">
<div className="toggle" onClick={ props.onToggle }></div> <div className="toggle" onClick={ props.onToggle }></div>
<a href={ props.explorer } className="green" target="_blank" rel="noreferrer noopener">See full transaction history</a>
<div className="content"> <div className="content">
{ balanceColumn } { balanceColumn }
{ rateColumn } { rateColumn }

@ -5,11 +5,11 @@ import React from 'react';
import ColorHash from 'color-hash'; import ColorHash from 'color-hash';
import ScaleText from 'react-scale-text'; import ScaleText from 'react-scale-text';
import type { Token } from '../../../reducers/TokensReducer'; import type { Props as BaseProps } from './index';
type Props = { type Props = {
tokens: Array<Token>, tokens: $ElementType<BaseProps, 'tokens'>,
removeToken: (token: Token) => void removeToken: $ElementType<BaseProps, 'removeToken'>
} }
const SummaryTokens = (props: Props) => { const SummaryTokens = (props: Props) => {

@ -13,11 +13,11 @@ import * as TokenActions from '../../../actions/TokenActions';
import type { ActionCreators } from 'redux'; import type { ActionCreators } from 'redux';
import type { MapStateToProps, MapDispatchToProps } from 'react-redux'; import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
import type { State, Dispatch } from '../../../flowtype'; import type { State, Dispatch } from '../../../flowtype';
import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps, Props as BaseProps} from '../account/AbstractAccount'; import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps } from '../account/AbstractAccount';
type OwnProps = { } type OwnProps = { }
type StateProps = StateProps & { type StateProps = BaseStateProps & {
tokens: $ElementType<State, 'tokens'>, tokens: $ElementType<State, 'tokens'>,
summary: $ElementType<State, 'summary'>, summary: $ElementType<State, 'summary'>,
fiat: $ElementType<State, 'fiat'>, fiat: $ElementType<State, 'fiat'>,
@ -34,7 +34,7 @@ type DispatchProps = BaseDispatchProps & {
removeToken: typeof TokenActions.remove, removeToken: typeof TokenActions.remove,
} }
export type Props = BaseProps & StateProps & DispatchProps; export type Props = StateProps & DispatchProps;
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => { const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => {
return { return {

@ -0,0 +1,55 @@
declare module 'bignumber.js' {
declare type $npm$big$number$object = number | string | BigNumber
declare type $npm$cmp$result = -1 | 0 | 1
declare type DIGIT = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
declare type ROUND_DOWN = 0
declare type ROUND_HALF_UP = 1
declare type ROUND_HALF_EVEN = 2
declare type ROUND_UP = 3
declare type RM = ROUND_DOWN | ROUND_HALF_UP | ROUND_HALF_EVEN | ROUND_UP
declare class BigNumber {
// Properties
static DP: number;
static RM: RM;
static E_NEG: number;
static E_POS: number;
c: Array<DIGIT>;
e: number;
s: -1 | 1;
// Constructors
static (value: $npm$big$number$object): BigNumber;
constructor(value: $npm$big$number$object): BigNumber;
// Methods
abs(): BigNumber;
cmp(n: $npm$big$number$object): $npm$cmp$result;
div(n: $npm$big$number$object): BigNumber;
dividedBy(n: $npm$big$number$object): BigNumber;
eq(n: $npm$big$number$object): boolean;
gt(n: $npm$big$number$object): boolean;
greaterThan(n: $npm$big$number$object): boolean;
gte(n: $npm$big$number$object): boolean;
lt(n: $npm$big$number$object): boolean;
lessThan(n: $npm$big$number$object): boolean;
lte(n: $npm$big$number$object): boolean;
lessThanOrEqualTo(n: $npm$big$number$object): boolean;
minus(n: $npm$big$number$object): BigNumber;
mod(n: $npm$big$number$object): BigNumber;
plus(n: $npm$big$number$object): BigNumber;
pow(exp: number): BigNumber;
round(dp: ?number, rm: ?RM): BigNumber;
sqrt(): BigNumber;
times(n: $npm$big$number$object): BigNumber;
toExponential(dp: ?number): string;
toFixed(dp: ?number): string;
toPrecision(sd: ?number): string;
toString(): string;
valueOf(): string;
toJSON(): string;
}
declare module.exports: typeof BigNumber
}

@ -0,0 +1,72 @@
declare module 'ethereum-types' {
// start data types
declare export type EthereumUnitT =
| 'kwei'
| 'ada'
| 'mwei'
| 'babbage'
| 'gwei'
| 'shannon'
| 'szabo'
| 'finney'
| 'ether'
| 'kether'
| 'grand'
| 'einstein'
| 'mether'
| 'gether'
| 'tether'
declare export type EthereumAddressT = string
declare export type EthereumBlockNumberT = number
declare export type EthereumBlockHashT = string
declare export type EthereumTransactionHashT = string
// end data types
// start contract types
declare export type EthereumWatchErrorT = ?Object
declare export type EthereumEventT<A> = {
address: EthereumAddressT,
args: A,
blockHash: EthereumBlockHashT,
blockNumber: number,
event: string,
logIndex: number,
transactionHash: EthereumTransactionHashT,
transactionIndex: number,
transactionLogIndex: string,
type: 'mined' // TODO: what other types are there?
}
// this represents the setup object returned from truffle-contract
// we use it to get a known contact `at(address)` (ie. for POATokenContract addresses)
declare export type EthereumContractSetupT<A> = {
at: EthereumAddressT => Promise<A>
}
declare export type EthereumSendTransactionOptionsT = {
from: EthereumAddressT,
gas: number,
value?: number
}
declare export type EthereumSendTransactionT = EthereumSendTransactionOptionsT => Promise<
EthereumTransactionHashT
>
// TODO(mattgstevens): it would be nice to have an Generic type for a Contract instance
// similar to the EthererumWatchEventT
//
// declare export type SendTransactionContractT = interface .sendTransaction(EthereumAddressT)
// declare export type WatchableContractT = <A>(error: Object, response: A)
// declare export type EthereumContractWatcherT = (options: {
// fromBlock?: EthereumBlockNumberT,
// toBlock?: EthereumBlockNumberT,
// address?: EthereumAddressT
// }) => *
// end contract data
}

@ -92,7 +92,11 @@ declare module 'trezor-connect' {
declare export type UiMessage = { declare export type UiMessage = {
event: string; event: string;
type: UiMessageType; type: UiMessageType;
payload: Object; // payload: Object;
payload: {
device: Device;
code?: string;
}
} }
declare export type DeviceMessageType = $Values<T_DEVICE>; declare export type DeviceMessageType = $Values<T_DEVICE>;

@ -1,4 +1,81 @@
import type BigNumber from 'bignumber.js';
import type { EthereumUnitT, EthereumAddressT } from 'ethereum-types';
declare module 'web3' { declare module 'web3' {
declare type ProviderT = Object;
declare class Web3T {
static providers: {
HttpProvider: (url: string) => ProviderT;
};
constructor(ProviderT): Web3T;
currentProvider: ProviderT;
eth: Eth;
toHex: (str: string | number) => 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;
fromWei: (number: string, unit?: EthereumUnitT) => string;
version: {
api: string;
network: string;
// and many more
}
}
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: any) => 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<EthereumAddressT>) => void) => void,
sign: (payload: string, signer: EthereumAddressT) => Promise<string>,
contract: (abi: Array<Object>) => ContractFactory,
estimateGas: (options: any, callback: (error: Error, result: any) => void) => void,
sendRawTransaction: (tx: any, callback: (error: Error, result: any) => void) => void,
filter: (type: string) => Filter; // return intance with "watch"
}
declare export class Filter {
watch: (callback: (error: ?Error, blockHash: ?string) => void | Promise<void>) => void,
stopWatching: (callback: any) => void,
}
declare export class ContractFactory {
// constructor(abi: Array<Object>);
eth: Eth;
abi: Array<Object>;
at: (address: string, callback: (error: Error, contract: Contract) => void) => Contract;
}
declare export class Contract {
name: (callback: (error: Error, name: string) => void) => void;
symbol: (callback: (error: Error, symbol: string) => void) => void;
decimals: (callback: (error: Error, decimals: BigNumber) => void) => void;
balanceOf: (address: string, callback: (error: Error, balance: BigNumber) => void) => void;
transfer: any;
}
declare export default typeof Web3T;
}
//
//
/*declare module 'web3' {
module.exports = { module.exports = {
eth: { eth: {
@ -72,4 +149,5 @@ declare module 'web3' {
}; };
} }
} }
} }
*/

@ -31,7 +31,10 @@ export const initialState: State = {
defaultGasLimit: 0, defaultGasLimit: 0,
defaultGasLimitTokens: 0, defaultGasLimitTokens: 0,
defaultGasPrice: 0, defaultGasPrice: 0,
explorer: '', explorer: {
tx: '',
address: ''
},
tokens: '', tokens: '',
backends: [] backends: []
}, },

@ -13,9 +13,15 @@ export type Coin = {
defaultGasLimit: number; defaultGasLimit: number;
defaultGasLimitTokens: number; defaultGasLimitTokens: number;
defaultGasPrice: number; defaultGasPrice: number;
explorer: string; explorer: {
tx: string;
address: string;
};
tokens: string; tokens: string;
backends: Array<any> backends: Array<{
name: string;
urls: Array<string>;
}>
} }
export type NetworkToken = { export type NetworkToken = {

@ -4,10 +4,11 @@
import * as LOG from '../actions/constants/log'; import * as LOG from '../actions/constants/log';
import type { Action } from '../flowtype'; import type { Action } from '../flowtype';
type LogEntry = { export type LogEntry = {
time: number; time: number;
type: string; type: string;
messgage: string; // message: string;
message: any;
} }
export type State = { export type State = {
@ -25,22 +26,23 @@ export default (state: State = initialState, action: Action): State => {
switch (action.type) { switch (action.type) {
case LOG.OPEN: case LOG.OPEN :
return { return {
...state, ...state,
opened: true opened: true
} }
case LOG.CLOSE: case LOG.CLOSE :
return { return {
...state, ...state,
opened: false opened: false
} }
// case 'log__add': case LOG.ADD :
// return { return {
// ...state, ...state,
// } entries: state.entries.concat([ action.payload ])
}
default: default:
return state; return state;

@ -42,7 +42,6 @@ export default function modal(state: State = initialState, action: Action): Stat
windowType: action.type windowType: action.type
}; };
case CONNECT.FORGET_REQUEST : case CONNECT.FORGET_REQUEST :
case CONNECT.DISCONNECT_REQUEST :
return { return {
opened: true, opened: true,
device: action.device, device: action.device,
@ -88,7 +87,6 @@ export default function modal(state: State = initialState, action: Action): Stat
}; };
case UI.REQUEST_BUTTON : case UI.REQUEST_BUTTON :
console.log("REQBUT", action)
return { return {
opened: true, opened: true,
device: action.payload.device, device: action.payload.device,

@ -17,7 +17,17 @@ export type State = {
selectedDevice: ?SelectedDevice; selectedDevice: ?SelectedDevice;
discoveryComplete: boolean; discoveryComplete: boolean;
error: ?string; error: ?string;
transport: any; transport: ?{
type: string;
version: string;
};
// browserState: {
// name: string;
// osname: string;
// supported: boolean;
// outdated: boolean;
// mobile: boolean;
// } | {};
browserState: any; browserState: any;
} }
@ -68,7 +78,6 @@ const mergeDevices = (current: TrezorDevice, upcoming: Object): TrezorDevice =>
// if (upcoming.features.passphrase_protection !== current.features.passphrase_protection) { // if (upcoming.features.passphrase_protection !== current.features.passphrase_protection) {
// // device settings has been changed, reset state // // device settings has been changed, reset state
// // dev.state = null; // // dev.state = null;
// // console.log("RESTETTTT STATE!");
// } // }
// } // }
@ -199,7 +208,6 @@ const setDeviceState = (state: State, action: any): State => {
//const affectedDevice: ?TrezorDevice = state.devices.find(d => d.path === action.device.path && d.instance === action.device.instance); //const affectedDevice: ?TrezorDevice = state.devices.find(d => d.path === action.device.path && d.instance === action.device.instance);
const index: number = state.devices.findIndex(d => d.path === action.device.path && d.instance === action.device.instance); const index: number = state.devices.findIndex(d => d.path === action.device.path && d.instance === action.device.instance);
if (index > -1) { if (index > -1) {
console.warn("APGREDJS", newState.devices[index].state)
// device could already have own state from firmware, do not override it // device could already have own state from firmware, do not override it
if (!newState.devices[index].state) { if (!newState.devices[index].state) {
const changedDevice: TrezorDevice = { const changedDevice: TrezorDevice = {
@ -239,15 +247,10 @@ const changeDevice = (state: State, device: Object): State => {
// else if (isAffectedUnacquired >= 0 && !device.unacquired && affectedDevices.length > 1) { // else if (isAffectedUnacquired >= 0 && !device.unacquired && affectedDevices.length > 1) {
// affectedDevices.splice(isAffectedUnacquired, 1); // affectedDevices.splice(isAffectedUnacquired, 1);
// console.warn("CLEARRRR", isAffectedUnacquired);
// } // }
console.warn("AFFEEE", isAffectedUnacquired, affectedDevices, otherDevices)
// acquiring selected device. remove unnecessary (not acquired) device from list // acquiring selected device. remove unnecessary (not acquired) device from list
// after this action selectedDevice needs to be updated (in TrezorConnectService) // after this action selectedDevice needs to be updated (in TrezorConnectService)
if (state.selectedDevice && device.path === state.selectedDevice.id && affectedDevices.length > 1) { if (state.selectedDevice && device.path === state.selectedDevice.id && affectedDevices.length > 1) {
console.warn("clear dupli", affectedDevices, otherDevices)
// affectedDevices = affectedDevices.filter(d => d.path !== state.selectedDevice.id && d.features); // affectedDevices = affectedDevices.filter(d => d.path !== state.selectedDevice.id && d.features);
} }
@ -358,7 +361,6 @@ const onSelectDevice = (state: State, action: any): State => {
const selected = findSelectedDevice(newState); const selected = findSelectedDevice(newState);
if (selected) { if (selected) {
selected.ts = new Date().getTime(); selected.ts = new Date().getTime();
console.warn("APDEJT SELECTED!", selected.instanceLabel, selected.ts)
} }
return newState; return newState;
@ -435,13 +437,7 @@ export default function connect(state: State = initialState, action: Action): St
case DEVICE.DISCONNECT_UNACQUIRED : case DEVICE.DISCONNECT_UNACQUIRED :
return disconnectDevice(state, action.device); return disconnectDevice(state, action.device);
default: default:
return state; return state;

@ -1,17 +1,22 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
import { LOCATION_CHANGE } from 'react-router-redux';
import { DEVICE } from 'trezor-connect';
import * as MODAL from '../actions/constants/modal'; import * as MODAL from '../actions/constants/modal';
import * as WEB3 from '../actions/constants/web3'; import * as WEB3 from '../actions/constants/web3';
import * as WALLET from '../actions/constants/wallet'; import * as WALLET from '../actions/constants/wallet';
import * as CONNECT from '../actions/constants/TrezorConnect';
import type { Action, RouterLocationState } from '../flowtype';
import type { Action, RouterLocationState, TrezorDevice } from '../flowtype';
type State = { type State = {
ready: boolean; ready: boolean;
dropdownOpened: boolean; dropdownOpened: boolean;
initialParams: ?RouterLocationState; initialParams: ?RouterLocationState;
initialPathname: ?string; initialPathname: ?string;
disconnectRequest: ?TrezorDevice;
} }
const initialState: State = { const initialState: State = {
@ -19,6 +24,7 @@ const initialState: State = {
dropdownOpened: false, dropdownOpened: false,
initialParams: null, initialParams: null,
initialPathname: null, initialPathname: null,
disconnectRequest: null
}; };
export default function wallet(state: State = initialState, action: Action): State { export default function wallet(state: State = initialState, action: Action): State {
@ -43,12 +49,28 @@ export default function wallet(state: State = initialState, action: Action): Sta
dropdownOpened: action.opened dropdownOpened: action.opened
} }
case LOCATION_CHANGE :
case MODAL.CLOSE : case MODAL.CLOSE :
return { return {
...state, ...state,
dropdownOpened: false dropdownOpened: false
} }
case CONNECT.DISCONNECT_REQUEST :
return {
...state,
disconnectRequest: action.device
}
case DEVICE.DISCONNECT :
if (state.disconnectRequest && action.device.path === state.disconnectRequest.path) {
return {
...state,
disconnectRequest: null
}
}
return state;
default: default:
return state; return state;
} }

@ -0,0 +1,40 @@
/* @flow */
'use strict';
import * as LogActions from '../actions/LogActions';
import * as STORAGE from '../actions/constants/localStorage';
import { OPEN, CLOSE, ADD } from '../actions/constants/log';
import type {
Middleware,
MiddlewareAPI,
MiddlewareDispatch,
State,
Dispatch,
Action,
AsyncAction,
GetState
} from '../flowtype';
const exclude: Array<string> = [
ADD, OPEN, CLOSE,
STORAGE.READY,
"web3__create"
];
/**
* Middleware
*/
const LogService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
next(action);
if (exclude.indexOf(action.type) < 0) {
// api.dispatch(LogActions.add(action.type, JSON.stringify( action )));
api.dispatch(LogActions.add(action.type, action));
}
return action;
};
export default LogService;

@ -65,15 +65,13 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa
//api.dispatch( TrezorConnectActions.forgetDevice(action.device) ); //api.dispatch( TrezorConnectActions.forgetDevice(action.device) );
api.dispatch( TrezorConnectActions.switchToFirstAvailableDevice() ); api.dispatch( TrezorConnectActions.switchToFirstAvailableDevice() );
} else if (action.type === CONNECT.FORGET_SINGLE) { } else if (action.type === CONNECT.FORGET_SINGLE) {
//api.dispatch( TrezorConnectActions.forgetDevice(action.device) );
if (api.getState().connect.devices.length < 1 && action.device.connected) { if (api.getState().connect.devices.length < 1 && action.device.connected) {
// prompt disconnect device modal // prompt disconnect device info in LandingPage
api.dispatch({ api.dispatch({
type: CONNECT.DISCONNECT_REQUEST, type: CONNECT.DISCONNECT_REQUEST,
device: action.device device: action.device
}); });
api.dispatch( push('/') );
} else { } else {
api.dispatch( TrezorConnectActions.switchToFirstAvailableDevice() ); api.dispatch( TrezorConnectActions.switchToFirstAvailableDevice() );
} }
@ -82,7 +80,6 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa
// we need to change route // we need to change route
if (prevState.selectedDevice) { if (prevState.selectedDevice) {
if (!action.device.unacquired && action.device.path === prevState.selectedDevice.id) { if (!action.device.unacquired && action.device.path === prevState.selectedDevice.id) {
console.warn("TODO: here! better")
api.dispatch( TrezorConnectActions.onSelectDevice(action.device) ); api.dispatch( TrezorConnectActions.onSelectDevice(action.device) );
} }
} }

@ -1,12 +1,14 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
import LogService from './LogService';
import RouterService from './RouterService'; import RouterService from './RouterService';
import LocalStorageService from './LocalStorageService'; import LocalStorageService from './LocalStorageService';
import CoinmarketcapService from './CoinmarketcapService'; import CoinmarketcapService from './CoinmarketcapService';
import TrezorConnectService from './TrezorConnectService'; import TrezorConnectService from './TrezorConnectService';
export default [ export default [
LogService,
RouterService, RouterService,
LocalStorageService, LocalStorageService,
TrezorConnectService, TrezorConnectService,

@ -12,9 +12,9 @@ import reducers from '../reducers';
import services from '../services'; import services from '../services';
import RavenMiddleware from 'redux-raven-middleware'; import RavenMiddleware from 'redux-raven-middleware';
import type { Store } from '../flowtype'; import type { Action, GetState, Store } from '../flowtype';
export const history = createHistory( { queryKey: false } ); export const history: History = createHistory( { queryKey: false } );
const initialState: any = {}; const initialState: any = {};
const enhancers = []; const enhancers = [];
@ -24,33 +24,40 @@ const middleware = [
routerMiddleware(history) routerMiddleware(history)
]; ];
const excludeLogger = (getState: any, action: any): boolean => {
//'@@router/LOCATION_CHANGE'
const excluded: Array<string> = ['LOG_TO_EXCLUDE'];
const pass: Array<string> = excluded.filter((act) => {
return action.type === act;
});
return pass.length === 0;
}
const logger = createLogger({
level: 'info',
// predicate: excludeLogger,
collapsed: true
});
let composedEnhancers: any;
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
const excludeLogger = (getState: GetState, action: Action): boolean => {
//'@@router/LOCATION_CHANGE'
const excluded: Array<string> = ['LOG_TO_EXCLUDE', 'log__add'];
const pass: Array<string> = excluded.filter((act) => {
return action.type === act;
});
return pass.length === 0;
}
const logger = createLogger({
level: 'info',
predicate: excludeLogger,
collapsed: true
});
const devToolsExtension: ?Function = window.devToolsExtension; const devToolsExtension: ?Function = window.devToolsExtension;
if (typeof devToolsExtension === 'function') { if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension()); enhancers.push(devToolsExtension());
} }
}
const composedEnhancers = compose( composedEnhancers = compose(
// applyMiddleware(...middleware, logger, ...services), applyMiddleware(...middleware, logger, ...services),
applyMiddleware(...middleware, logger, ...services), ...enhancers
...enhancers );
); } else {
composedEnhancers = compose(
applyMiddleware(...middleware, ...services),
...enhancers
);
}
export default createStore( export default createStore(
reducers, reducers,

@ -43,6 +43,7 @@
height: 200px; height: 200px;
min-height: 200px; min-height: 200px;
resize: vertical; resize: vertical;
font-size: 10px;
&:focus { &:focus {
box-shadow: none; box-shadow: none;
} }

@ -61,6 +61,7 @@
.content { .content {
display: flex; display: flex;
padding-bottom: 32px; padding-bottom: 32px;
padding-top: 24px;
.column { .column {
margin-right: 48px; margin-right: 48px;
@ -73,7 +74,7 @@
.fiat-value { .fiat-value {
font-weight: 500; font-weight: 500;
font-size: 18px; font-size: 18px;
margin: 7px 0 6px 0; margin: 7px 0px 7px 0px;
color: @color_text_primary; color: @color_text_primary;
} }
} }

Loading…
Cancel
Save