mirror of
https://github.com/trezor/trezor-wallet
synced 2024-12-29 02:18:06 +00:00
device clone, device connect priority + BIG refactoring for
components/containers
This commit is contained in:
parent
1e316ea9d2
commit
60ead5a452
@ -46,7 +46,7 @@
|
||||
{
|
||||
"name": "Ethereum Classic",
|
||||
"symbol": "ETC",
|
||||
"network": "ethereumclassic",
|
||||
"network": "ethereum-classic",
|
||||
"bip44": "m/44'/61'/0'/0",
|
||||
"defaultGasPrice": 64,
|
||||
"defaultGasLimit": 21000,
|
||||
|
0
src/js/actions/DiscoveryActions.js
Normal file
0
src/js/actions/DiscoveryActions.js
Normal file
@ -41,9 +41,6 @@ export function loadTokensFromJSON(): any {
|
||||
return collection;
|
||||
}, Promise.resolve({}));
|
||||
|
||||
console.log("JADE DAL")
|
||||
|
||||
|
||||
const devices: ?string = get('devices');
|
||||
if (devices) {
|
||||
dispatch({
|
||||
|
@ -2,7 +2,6 @@
|
||||
'use strict';
|
||||
|
||||
import TrezorConnect, { UI, UI_EVENT } from 'trezor-connect';
|
||||
import * as ACTIONS from './index';
|
||||
import * as MODAL from './constants/Modal';
|
||||
import * as CONNECT from './constants/TrezorConnect';
|
||||
|
||||
@ -10,7 +9,7 @@ import * as CONNECT from './constants/TrezorConnect';
|
||||
export function onPinSubmit(value: string): any {
|
||||
TrezorConnect.uiResponse({ type: UI.RECEIVE_PIN, payload: value });
|
||||
return {
|
||||
type: ACTIONS.CLOSE_MODAL
|
||||
type: MODAL.CLOSE
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +24,7 @@ export function onPassphraseSubmit(passphrase: string): any {
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.CLOSE_MODAL
|
||||
type: MODAL.CLOSE
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -60,7 +59,7 @@ export const onForgetSingleDevice = (device: any) => {
|
||||
|
||||
export const onCancel = () => {
|
||||
return {
|
||||
type: ACTIONS.CLOSE_MODAL
|
||||
type: MODAL.CLOSE
|
||||
}
|
||||
}
|
||||
|
||||
|
24
src/js/actions/NotificationActions.js
Normal file
24
src/js/actions/NotificationActions.js
Normal file
@ -0,0 +1,24 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import * as NOTIFICATION from './constants/notification';
|
||||
|
||||
|
||||
// called from RouterService
|
||||
export const clear = (currentParams, requestedParams): any => {
|
||||
return async (dispatch, getState) => {
|
||||
// if route has been changed from device view into something else (like other device, settings...)
|
||||
// try to remove all Notifications which are linked to previous device (they are not cancelable by user)
|
||||
if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) {
|
||||
const entries = getState().notifications.filter(entry => typeof entry.devicePath === 'string');
|
||||
entries.forEach(entry => {
|
||||
dispatch({
|
||||
type: NOTIFICATION.CLOSE,
|
||||
payload: {
|
||||
devicePath: entry.devicePath
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ export const init = (): any => {
|
||||
const state: State = {
|
||||
...initialState,
|
||||
deviceState: selected.state,
|
||||
deviceId: selected.features.device_id,
|
||||
deviceInstance: selected.instance,
|
||||
accountIndex: parseInt(urlParams.address),
|
||||
network: urlParams.network,
|
||||
location: location.pathname,
|
||||
@ -67,9 +69,10 @@ export const showAddress = (address_n: string): any => {
|
||||
const selected = findSelectedDevice(getState().connect);
|
||||
if (!selected) return;
|
||||
|
||||
if (selected && !selected.connected) {
|
||||
if (selected && (!selected.connected || !selected.available)) {
|
||||
dispatch({
|
||||
type: RECEIVE.REQUEST_UNVERIFIED,
|
||||
device: selected
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -117,6 +117,8 @@ export const init = (): any => {
|
||||
const state: State = {
|
||||
...initialState,
|
||||
deviceState: selected.state,
|
||||
deviceId: selected.features.device_id,
|
||||
deviceInstance: selected.instance,
|
||||
accountIndex: parseInt(urlParams.address),
|
||||
network: urlParams.network,
|
||||
coinSymbol: coin.symbol,
|
||||
|
@ -2,7 +2,6 @@
|
||||
'use strict';
|
||||
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import * as ACTIONS from './index';
|
||||
import * as SUMMARY from './constants/summary';
|
||||
import * as TOKEN from './constants/Token';
|
||||
import * as ADDRESS from './constants/Address';
|
||||
@ -20,11 +19,13 @@ export const init = (): any => {
|
||||
const urlParams = location.params;
|
||||
|
||||
const selected = findSelectedDevice( getState().connect );
|
||||
if (!selected) return;
|
||||
if (!selected || !selected.state) return;
|
||||
|
||||
const state: State = {
|
||||
...initialState,
|
||||
deviceState: selected.state,
|
||||
deviceId: selected.features.device_id,
|
||||
deviceInstance: selected.instance,
|
||||
accountIndex: parseInt(urlParams.address),
|
||||
network: urlParams.network,
|
||||
location: location.pathname,
|
||||
@ -46,7 +47,7 @@ export const update = (newProps: any): any => {
|
||||
} = getState();
|
||||
|
||||
const isLocationChanged: boolean = router.location.pathname !== summary.location;
|
||||
if (isLocationChanged) {
|
||||
if (isLocationChanged || !summary.deviceState) {
|
||||
dispatch( init() );
|
||||
return;
|
||||
}
|
||||
@ -137,98 +138,3 @@ export const removeToken = (token: any): any => {
|
||||
token
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const onTokenSearch = (search: string): any => {
|
||||
return {
|
||||
type: ACTIONS.TOKENS_SEARCH,
|
||||
search
|
||||
}
|
||||
}
|
||||
|
||||
export const onCustomTokenToggle = (): any => {
|
||||
return {
|
||||
type: ACTIONS.TOKENS_CUSTOM_TOGGLE
|
||||
}
|
||||
}
|
||||
|
||||
export const onCustomTokenAddressChange = (value: string): any => {
|
||||
// todo:
|
||||
// -validate address
|
||||
// - if adresss is ok, try to fetch token info
|
||||
// return {
|
||||
// type: ACTIONS.TOKENS_CUSTOM_ADDRESS_CHANGE,
|
||||
// value
|
||||
// }
|
||||
|
||||
return async (dispatch, getState) => {
|
||||
|
||||
const valid: boolean = EthereumjsUtil.isValidAddress(value);
|
||||
if (valid) {
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.TOKENS_CUSTOM_ADDRESS_CHANGE,
|
||||
value,
|
||||
valid,
|
||||
fetching: true
|
||||
});
|
||||
|
||||
const { web3, abi } = getState().web3;
|
||||
const contract = web3.eth.contract(abi).at(value);
|
||||
|
||||
contract.name.call((error, name) => {
|
||||
if (error) {
|
||||
// TODO: skip
|
||||
}
|
||||
contract.symbol.call((error, symbol) => {
|
||||
if (error) {
|
||||
// TODO: skip
|
||||
}
|
||||
|
||||
contract.decimals.call((error, decimals) => {
|
||||
console.log("fetched!", name, symbol, decimals)
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
dispatch({
|
||||
type: ACTIONS.TOKENS_CUSTOM_ADDRESS_CHANGE,
|
||||
value,
|
||||
valid
|
||||
});
|
||||
}
|
||||
|
||||
console.log("VALID!!!", valid);
|
||||
}
|
||||
}
|
||||
|
||||
export const onCustomTokenNameChange = (value: string): any => {
|
||||
return {
|
||||
type: ACTIONS.TOKENS_CUSTOM_NAME_CHANGE,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
export const onCustomTokenShortcutChange = (value: string): any => {
|
||||
return {
|
||||
type: ACTIONS.TOKENS_CUSTOM_SHORTCUT_CHANGE,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
export const onCustomTokenDecimalChange = (value: string): any => {
|
||||
return {
|
||||
type: ACTIONS.TOKENS_CUSTOM_DECIMAL_CHANGE,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
export const onCustomTokenAdd = (): any => {
|
||||
return {
|
||||
type: ACTIONS.TOKENS_CUSTOM_ADD
|
||||
}
|
||||
}
|
@ -2,20 +2,18 @@
|
||||
'use strict';
|
||||
|
||||
import TrezorConnect, { UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT } from 'trezor-connect';
|
||||
import * as ACTIONS from './index';
|
||||
import * as ADDRESS from './constants/Address';
|
||||
import * as TOKEN from './constants/Token';
|
||||
import * as CONNECT from './constants/TrezorConnect';
|
||||
import * as DISCOVERY from './constants/Discovery';
|
||||
import * as NOTIFICATION from './constants/notification';
|
||||
import * as WALLET from './constants/wallet';
|
||||
|
||||
import HDKey from 'hdkey';
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import EthereumjsTx from 'ethereumjs-tx';
|
||||
|
||||
//import { getBalance } from '../services/Web3Service';
|
||||
import { getBalance } from './Web3Actions';
|
||||
import { getTransactionHistory } from '../services/EtherscanService';
|
||||
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
@ -24,7 +22,7 @@ import { init as initWeb3, getNonceAsync, getBalanceAsync, getTokenBalanceAsync
|
||||
import type { Discovery } from '../reducers/DiscoveryReducer';
|
||||
import { resolveAfter } from '../utils/promiseUtils';
|
||||
import { getAccounts } from '../utils/reducerUtils';
|
||||
import { findSelectedDevice, isSavedDevice } from '../reducers/TrezorConnectReducer';
|
||||
import { findSelectedDevice, isSavedDevice, TrezorDevice } from '../reducers/TrezorConnectReducer';
|
||||
|
||||
export const init = (): any => {
|
||||
return async (dispatch, getState): Promise<void> => {
|
||||
@ -57,15 +55,18 @@ export const init = (): any => {
|
||||
await TrezorConnect.init({
|
||||
transportReconnect: true,
|
||||
connectSrc: 'https://localhost:8088/',
|
||||
// connectSrc: 'https://connect.trezor.io/tpm/',
|
||||
// connectSrc: 'https://sisyfos.trezor.io/',
|
||||
debug: true,
|
||||
popup: false,
|
||||
webusb: false
|
||||
webusb: true
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
dispatch( initWeb3() );
|
||||
}, 2000)
|
||||
// wait for init
|
||||
|
||||
// setTimeout(() => {
|
||||
// dispatch( initWeb3() );
|
||||
//}, 2000)
|
||||
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
@ -102,37 +103,53 @@ export const postInit = (): any => {
|
||||
// devices were connected before Web3 initialized. force DEVICE.CONNECT event on them
|
||||
const { devices } = getState().connect;
|
||||
|
||||
|
||||
const { initialPathname, initialParams } = getState().wallet
|
||||
if (initialPathname) {
|
||||
dispatch({
|
||||
type: WALLET.SET_INITIAL_URL,
|
||||
pathname: null,
|
||||
params: null
|
||||
});
|
||||
}
|
||||
|
||||
if (devices.length > 0) {
|
||||
const unacquired = devices.find(d => d.unacquired);
|
||||
if (unacquired) {
|
||||
handleDeviceConnect(unacquired);
|
||||
dispatch( onSelectDevice(unacquired) );
|
||||
} else {
|
||||
const latest = devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
} else {
|
||||
return a.ts > b.ts ? 1 : -1;
|
||||
}
|
||||
});
|
||||
const latest: Array<TrezorDevice> = sortDevices(devices);
|
||||
const firstConnected: ?TrezorDevice = latest.find(d => d.connected);
|
||||
dispatch( onSelectDevice(firstConnected || latest[0]) );
|
||||
|
||||
console.log("LATEST", latest)
|
||||
// TODO
|
||||
if (initialParams) {
|
||||
if (!initialParams.hasOwnProperty("network") && initialPathname !== getState().router.location.pathname) {
|
||||
// dispatch( push(initialPathname) );
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let d of devices) {
|
||||
handleDeviceConnect(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const initConnectedDevice = (device: any): any => {
|
||||
const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => {
|
||||
return devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
} else {
|
||||
return a.ts > b.ts ? -1 : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const initConnectedDevice = (device: any, force): any => {
|
||||
return (dispatch, getState): void => {
|
||||
|
||||
//dispatch( onSelectDevice(device) );
|
||||
|
||||
const selected = findSelectedDevice(getState().connect);
|
||||
if (selected && selected.state) {
|
||||
dispatch( onSelectDevice(device) );
|
||||
} else if (!selected) {
|
||||
if (!selected || (selected && selected.state)) {
|
||||
dispatch( onSelectDevice(device) );
|
||||
}
|
||||
// if (device.unacquired && selected && selected.path !== device.path && !selected.connected) {
|
||||
@ -143,11 +160,19 @@ export const initConnectedDevice = (device: any): any => {
|
||||
}
|
||||
}
|
||||
|
||||
// selection from Aside dropdown
|
||||
// selection from Aside dropdown button
|
||||
// after device_connect event
|
||||
// or after acquiring device
|
||||
export function onSelectDevice(device: any): any {
|
||||
// device type could be local TrezorDevice or Device (from trezor-connect device_connect event)
|
||||
export const onSelectDevice = (device: any): any => {
|
||||
return (dispatch, getState): void => {
|
||||
// || device.isUsedElsewhere
|
||||
|
||||
console.log("------> REDITTO", device, getState().wallet.initialUrl);
|
||||
|
||||
// switch to initial url and reset this value
|
||||
|
||||
|
||||
if (device.unacquired) {
|
||||
dispatch( push(`/device/${ device.path }/acquire`) );
|
||||
} else if (device.features.bootloader_mode) {
|
||||
@ -155,58 +180,50 @@ export function onSelectDevice(device: any): any {
|
||||
} else if (device.instance) {
|
||||
dispatch( push(`/device/${ device.features.device_id }:${ device.instance }`) );
|
||||
} else {
|
||||
|
||||
const urlParams: any = getState().router.location.params;
|
||||
// let url: string = `/device/${ device.features.device_id }/network/ethereum/address/0`;
|
||||
let url: string = `/device/${ device.features.device_id }`;
|
||||
let instance: ?string;
|
||||
// check if device is not TrezorDevice type
|
||||
if (!device.hasOwnProperty('ts')) {
|
||||
// its device from trezor-connect (called in initConnectedDevice triggered by device_connect event)
|
||||
// need to lookup if there are unavailable instances
|
||||
const available: Array<TrezorDevice> = getState().connect.devices.filter(d => d.path === device.path);
|
||||
const latest: Array<TrezorDevice> = sortDevices(available);
|
||||
|
||||
if (latest.length > 0 && latest[0].instance) {
|
||||
url += `:${ latest[0].instance }`;
|
||||
instance = latest[0].instance;
|
||||
}
|
||||
}
|
||||
// check if current location is not set to this device
|
||||
//dispatch( push(`/device/${ device.features.device_id }/network/etc/address/0`) );
|
||||
dispatch( push(`/device/${ device.features.device_id }`) );
|
||||
|
||||
if (urlParams.deviceInstance !== instance || urlParams.device !== device.features.device_id) {
|
||||
dispatch( push(url) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: as TrezorConnect method
|
||||
const __getDeviceState = async (path, instance, state): Promise<any> => {
|
||||
// return await TrezorConnect.getPublicKey({
|
||||
// device: {
|
||||
// path,
|
||||
// instance
|
||||
// },
|
||||
// path: "m/1'/0'/0'",
|
||||
// confirmation: false
|
||||
// });
|
||||
|
||||
return await TrezorConnect.getDeviceState({
|
||||
device: {
|
||||
path,
|
||||
instance,
|
||||
state
|
||||
},
|
||||
path: "m/1'/0'/0'",
|
||||
confirmation: false
|
||||
});
|
||||
}
|
||||
|
||||
export const switchToFirstAvailableDevice = (): any => {
|
||||
return async (dispatch, getState): Promise<void> => {
|
||||
|
||||
const { devices } = getState().connect;
|
||||
if (devices.length > 0) {
|
||||
// TODO: Priority:
|
||||
// 1. Unacquired
|
||||
// 1. First Unacquired
|
||||
// 2. First connected
|
||||
// 3. Saved with latest timestamp
|
||||
// 4. First from the list
|
||||
const unacquired = devices.find(d => d.unacquired);
|
||||
if (unacquired) {
|
||||
dispatch( initConnectedDevice(unacquired) );
|
||||
} else {
|
||||
const latest = devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
} else {
|
||||
return a.ts > b.ts ? 1 : -1;
|
||||
}
|
||||
});
|
||||
dispatch( initConnectedDevice(devices[0]) );
|
||||
const latest: Array<TrezorDevice> = sortDevices(devices);
|
||||
const firstConnected: ?TrezorDevice = latest.find(d => d.connected);
|
||||
dispatch( onSelectDevice(firstConnected || latest[0]) );
|
||||
}
|
||||
|
||||
} else {
|
||||
dispatch( push('/') );
|
||||
dispatch({
|
||||
@ -217,17 +234,24 @@ export const switchToFirstAvailableDevice = (): any => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const getSelectedDeviceState = (): any => {
|
||||
return async (dispatch, getState): Promise<void> => {
|
||||
const selected = findSelectedDevice(getState().connect);
|
||||
console.warn("init selected", selected)
|
||||
if (selected
|
||||
&& selected.connected
|
||||
&& !selected.unacquired
|
||||
&& selected.features
|
||||
&& !selected.acquiring
|
||||
&& !selected.state) {
|
||||
|
||||
const response = await __getDeviceState(selected.path, selected.instance, selected.state);
|
||||
const response = await TrezorConnect.getDeviceState({
|
||||
device: {
|
||||
path: selected.path,
|
||||
instance: selected.instance,
|
||||
state: selected.state
|
||||
}
|
||||
});
|
||||
|
||||
if (response && response.success) {
|
||||
dispatch({
|
||||
@ -239,20 +263,25 @@ export const getSelectedDeviceState = (): any => {
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
devicePath: selected.path,
|
||||
type: 'error',
|
||||
title: 'Authentification error',
|
||||
title: 'Authentication error',
|
||||
message: response.payload.error,
|
||||
cancelable: true,
|
||||
cancelable: false,
|
||||
actions: [
|
||||
{
|
||||
label: 'Try again',
|
||||
callback: () => {
|
||||
dispatch( {
|
||||
type: NOTIFICATION.CLOSE,
|
||||
payload: { devicePath: selected.path }
|
||||
});
|
||||
dispatch( getSelectedDeviceState() );
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,7 +302,7 @@ export const deviceDisconnect = (device: any): any => {
|
||||
dispatch({
|
||||
type: CONNECT.REMEMBER_REQUEST,
|
||||
device,
|
||||
allInstances: affected
|
||||
instances: affected
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -296,22 +325,26 @@ export const coinChanged = (network: ?string): any => {
|
||||
}
|
||||
}
|
||||
|
||||
export function reload(): any {
|
||||
return async (dispatch, getState) => {
|
||||
}
|
||||
}
|
||||
|
||||
export function acquire(): any {
|
||||
return async (dispatch, getState) => {
|
||||
|
||||
const selected = findSelectedDevice(getState().connect);
|
||||
|
||||
const saved = getState().connect.devices.map(d => {
|
||||
if (d.state) {
|
||||
return {
|
||||
instance: d.instance,
|
||||
state: d.state
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
// const saved = getState().connect.devices.map(d => {
|
||||
// if (d.state) {
|
||||
// return {
|
||||
// instance: d.instance,
|
||||
// state: d.state
|
||||
// }
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// });
|
||||
|
||||
//const response = await __acquire(selected.path, selected.instance);
|
||||
|
||||
@ -374,6 +407,12 @@ export const forgetDevice = (device: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const gotoDeviceSettings = (device: any) => {
|
||||
return (dispatch: any, getState: any): any => {
|
||||
dispatch( push(`/device/${ device.features.device_id }/settings`) );
|
||||
}
|
||||
}
|
||||
|
||||
// called from Aside - device menu (forget single instance)
|
||||
export const forget = (device: any) => {
|
||||
return {
|
||||
@ -404,6 +443,12 @@ export const beginDiscoveryProcess = (device: any, network: string): any => {
|
||||
const { config } = getState().localStorage;
|
||||
const coinToDiscover = config.coins.find(c => c.network === network);
|
||||
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING,
|
||||
device,
|
||||
network
|
||||
});
|
||||
|
||||
// TODO: validate device deviceState
|
||||
// const deviceState = await __acquire(device.path, device.instance);
|
||||
// if (deviceState && deviceState.success) {
|
||||
@ -425,9 +470,10 @@ export const beginDiscoveryProcess = (device: any, network: string): any => {
|
||||
keepSession: true // acquire and hold session
|
||||
});
|
||||
|
||||
// handle TREZOR response error
|
||||
if (!response.success) {
|
||||
// TODO: check message
|
||||
console.warn("DISCO ERROR", response)
|
||||
console.warn("DISCOVERY ERROR", response)
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
@ -448,9 +494,10 @@ export const beginDiscoveryProcess = (device: any, network: string): any => {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: check for interruption
|
||||
// check for interruption
|
||||
let discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === device.state && d.network === network);
|
||||
if (discoveryProcess && discoveryProcess.interrupted) return;
|
||||
|
||||
// TODO: handle response error
|
||||
const basePath: Array<number> = response.payload.path;
|
||||
const hdKey = new HDKey();
|
||||
hdKey.publicKey = new Buffer(response.payload.publicKey, 'hex');
|
||||
@ -502,6 +549,15 @@ export const discoverAddress = (device: any, discoveryProcess: Discovery): any =
|
||||
});
|
||||
if (discoveryProcess.interrupted) return;
|
||||
|
||||
// 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);
|
||||
@ -630,6 +686,9 @@ export function startDiscoveryProcess(device: any, network: string, ignoreComple
|
||||
} else if (!selected.state) {
|
||||
console.warn("Start discovery: Selected device wasn't authenticated yet...")
|
||||
return;
|
||||
} else if (selected.connected && !selected.available) {
|
||||
console.warn("Start discovery: Selected device is unavailable...")
|
||||
return;
|
||||
}
|
||||
|
||||
const discovery = getState().discovery;
|
||||
@ -679,8 +738,8 @@ export const restoreDiscovery = (): any => {
|
||||
}
|
||||
|
||||
// there is no discovery process but it should be
|
||||
// this is possible race condition when "network" was changed in url but device wasn't authenticated yet
|
||||
// try to discovery after CONNECT.AUTH_DEVICE action
|
||||
// this is possible race condition when "network" was changed in url but device was not authenticated yet
|
||||
// try to start discovery after CONNECT.AUTH_DEVICE action
|
||||
export const checkDiscoveryStatus = (): any => {
|
||||
return (dispatch, getState): void => {
|
||||
const selected = findSelectedDevice(getState().connect);
|
||||
|
@ -2,9 +2,8 @@
|
||||
'use strict';
|
||||
|
||||
export const ON_RESIZE: string = 'ON_RESIZE';
|
||||
export const ON_BEFORE_UNLOAD: string = 'app__on_before_unload';
|
||||
export const TOGGLE_DEVICE_DROPDOWN: string = 'TOGGLE_DEVICE_DROPDOWN';
|
||||
export const RESIZE_CONTAINER: string = 'RESIZE_CONTAINER';
|
||||
import * as WALLET from './constants/wallet';
|
||||
|
||||
export const onResize = (): any => {
|
||||
return {
|
||||
@ -14,20 +13,13 @@ export const onResize = (): any => {
|
||||
|
||||
export const onBeforeUnload = (): any => {
|
||||
return {
|
||||
type: ON_BEFORE_UNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
export const resizeAppContainer = (opened: boolean): any => {
|
||||
return {
|
||||
type: RESIZE_CONTAINER,
|
||||
opened
|
||||
type: WALLET.ON_BEFORE_UNLOAD
|
||||
}
|
||||
}
|
||||
|
||||
export const toggleDeviceDropdown = (opened: boolean): any => {
|
||||
return {
|
||||
type: TOGGLE_DEVICE_DROPDOWN,
|
||||
type: WALLET.TOGGLE_DEVICE_DROPDOWN,
|
||||
opened
|
||||
}
|
||||
}
|
@ -7,10 +7,8 @@ import EthereumjsUtil from 'ethereumjs-util';
|
||||
import EthereumjsTx from 'ethereumjs-tx';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import { strip } from '../utils/ethUtils';
|
||||
import * as ACTIONS from './index';
|
||||
import * as ADDRESS from './constants/Address';
|
||||
import * as WEB3 from './constants/Web3';
|
||||
import { loadHistory } from '../services/EtherscanService';
|
||||
import { httpRequest } from '../utils/networkUtils';
|
||||
|
||||
type ActionMethod = (dispatch: any, getState: any) => Promise<any>;
|
||||
@ -192,9 +190,6 @@ export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod {
|
||||
}
|
||||
}
|
||||
|
||||
function initBlockTicker() {
|
||||
|
||||
}
|
||||
|
||||
export function initContracts(): ActionMethod {
|
||||
return async (dispatch, getState) => {
|
||||
@ -241,14 +236,17 @@ export function getGasPrice(network: string): ActionMethod {
|
||||
|
||||
const index: number = getState().web3.findIndex(w3 => w3.network === network);
|
||||
|
||||
const web3 = getState().web3[ index ].web3;
|
||||
const web3instance = getState().web3[ index ];
|
||||
const web3 = web3instance.web3;
|
||||
web3.eth.getGasPrice((error, gasPrice) => {
|
||||
if (!error) {
|
||||
dispatch({
|
||||
type: WEB3.GAS_PRICE_UPDATED,
|
||||
network: network,
|
||||
gasPrice
|
||||
});
|
||||
if (web3instance.gasPrice && web3instance.gasPrice.toString() !== gasPrice.toString()) {
|
||||
dispatch({
|
||||
type: WEB3.GAS_PRICE_UPDATED,
|
||||
network: network,
|
||||
gasPrice
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -313,7 +311,6 @@ export function getTransactionReceipt(tx: any): any {
|
||||
web3.eth.getBlock(receipt.blockHash, (error, block) => {
|
||||
console.log("---MAMM BLOCK", error, block, receipt, receipt.blockHash)
|
||||
dispatch({
|
||||
//type: ACTIONS.TX_CONFIRMED,
|
||||
type: WEB3.PENDING_TX_RESOLVED,
|
||||
tx,
|
||||
receipt,
|
||||
|
@ -11,3 +11,4 @@ export const FORGET: string = 'modal__forget';
|
||||
export const REMEMBER: string = 'modal__remember';
|
||||
export const ON_FORGET: string = 'modal__on_forget';
|
||||
export const ON_REMEMBER: string = 'modal__on_remember';
|
||||
export const CLOSE: string = 'modal__close';
|
||||
|
6
src/js/actions/constants/wallet.js
Normal file
6
src/js/actions/constants/wallet.js
Normal file
@ -0,0 +1,6 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export const ON_BEFORE_UNLOAD: string = 'wallet__on_before_unload';
|
||||
export const TOGGLE_DEVICE_DROPDOWN: string = 'wallet_toggle_dropdown';
|
||||
export const SET_INITIAL_URL: string = 'wallet_set_initial_url';
|
@ -1,45 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export const CLOSE_MODAL: string = 'action__close_modal';
|
||||
|
||||
export const ON_PIN_SUBMIT: string = 'action__on_pin_submit';
|
||||
|
||||
export const ON_PASSPHRASE_SUBMIT: string = 'action__on_passphrase_submit';
|
||||
|
||||
|
||||
export const ON_ADDRESS_CHANGE: string = 'send__on_address_change';
|
||||
export const ON_AMOUNT_CHANGE: string = 'send__on_amount_change';
|
||||
export const ON_FEE_LEVEL_CHANGE: string = 'send__on_fee_level_change';
|
||||
export const ON_GAS_PRICE_CHANGE: string = 'send__on_gas_price_change';
|
||||
export const ON_GAS_LIMIT_CHANGE: string = 'send__on_gas_limit_change';
|
||||
export const ON_TX_DATA_CHANGE: string = 'send__on_data_change';
|
||||
export const ON_TX_SEND: string = 'send__on_send';
|
||||
export const ON_GAS_PRICE_UPDATE: string = 'send__on_gas_price_update';
|
||||
|
||||
|
||||
export const ADDRESS_CREATE: string = 'address__create';
|
||||
export const ADDRESS_DELETE: string = 'address__delete';
|
||||
export const ADDRESS_SET_BALANCE: string = 'address2__set_balance';
|
||||
export const ADDRESS_SET_HISTORY: string = 'address__set_history';
|
||||
export const ADDRESS_UPDATE_BALANCE: string = 'address__update_balance';
|
||||
export const ADDRESS_ADD_TO_HISTORY: string = 'address__add_to_history';
|
||||
|
||||
export const TX_STATUS_OK: string = 'tx__status_ok';
|
||||
export const TX_STATUS_ERROR: string = 'tx__status_error';
|
||||
export const TX_STATUS_UNKNOWN: string = 'tx__status_unknown';
|
||||
export const TX_CONFIRMED: string = 'tx__confirmed';
|
||||
|
||||
|
||||
|
||||
export const TOKENS_TOGGLE_SUMMARY: string = 'tokens_toggle_summary';
|
||||
|
||||
export const TOKENS_SEARCH: string = 'tokens_search';
|
||||
|
||||
|
||||
export const TOKENS_CUSTOM_TOGGLE: string = 'tokens_custom_toggle';
|
||||
export const TOKENS_CUSTOM_ADDRESS_CHANGE: string = 'tokens_custom_address_change';
|
||||
export const TOKENS_CUSTOM_NAME_CHANGE: string = 'tokens_custom_name_change';
|
||||
export const TOKENS_CUSTOM_SHORTCUT_CHANGE: string = 'tokens_custom_shortcut_change';
|
||||
export const TOKENS_CUSTOM_DECIMAL_CHANGE: string = 'tokens_custom_decimal_change';
|
||||
export const TOKENS_CUSTOM_ADD: string = 'tokens_custom_add';
|
@ -26,7 +26,7 @@ export const Notification = (props: any) => {
|
||||
) : null }
|
||||
<div className="notification-body">
|
||||
<h2>{ props.title }</h2>
|
||||
<p dangerouslySetInnerHTML={{__html: props.message }}></p>
|
||||
{ props.message ? (<p dangerouslySetInnerHTML={{__html: props.message }}></p>) : null }
|
||||
</div>
|
||||
{ props.actions && props.actions.length > 0 ? (
|
||||
<div className="notification-action">
|
||||
|
@ -6,19 +6,28 @@ import TrezorConnect from 'trezor-connect';
|
||||
|
||||
export default class InstallBridge extends Component {
|
||||
|
||||
|
||||
componentDidMount(): void {
|
||||
const transport: any = this.props.transport;
|
||||
if (transport && transport.version.indexOf('webusb') >= 0)
|
||||
TrezorConnect.renderWebUSBButton();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const transport = this.props.transport;
|
||||
if (transport && transport.type.indexOf('webusb') >= 0)
|
||||
if (transport && transport.version.indexOf('webusb') >= 0)
|
||||
TrezorConnect.renderWebUSBButton();
|
||||
}
|
||||
|
||||
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.type.indexOf('webusb') >= 0) {
|
||||
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>;
|
||||
@ -30,7 +39,7 @@ export default class InstallBridge extends Component {
|
||||
<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">
|
||||
<div className={ css }>
|
||||
<p className="connect">
|
||||
<span>
|
||||
<svg width="12px" height="35px" viewBox="0 0 20 57">
|
||||
@ -44,8 +53,8 @@ export default class InstallBridge extends Component {
|
||||
{ connectClaim }
|
||||
</span>
|
||||
</p>
|
||||
{ and }
|
||||
{ webusb }
|
||||
<p className="webusb-and">and</p>
|
||||
<button className="trezor-webusb-button">Check for devices</button>
|
||||
</div>
|
||||
<div className="image">
|
||||
<p>
|
||||
|
@ -2,6 +2,7 @@
|
||||
'use strict';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import Preloader from './Preloader';
|
||||
import Select from 'react-select';
|
||||
|
||||
type State = {
|
||||
@ -28,9 +29,9 @@ export default class InstallBridge extends Component {
|
||||
|
||||
const currentTarget = installers.find(i => i.id === props.browserState.osname);
|
||||
this.state = {
|
||||
version: '2.0.11',
|
||||
target: currentTarget,
|
||||
url: 'https://wallet.trezor.io/data/bridge/2.0.11/'
|
||||
version: '2.0.12',
|
||||
url: 'https://wallet.trezor.io/data/bridge/2.0.12/',
|
||||
target: null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -40,11 +41,25 @@ export default class InstallBridge extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
componentWillUpdate() {
|
||||
if (this.props.browserState.osname && !this.state.target) {
|
||||
const currentTarget = installers.find(i => i.id === this.props.browserState.osname);
|
||||
this.setState({
|
||||
target: currentTarget
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.target) {
|
||||
return <Preloader />;
|
||||
}
|
||||
|
||||
const url = `${ this.state.url }${ this.state.target.value }`;
|
||||
return (
|
||||
<main>
|
||||
<h3 className="claim">TREZOR Bridge. <span>Version 2.0.11</span></h3>
|
||||
<h3 className="claim">TREZOR Bridge. <span>Version 2.0.12</span></h3>
|
||||
<p>New communication tool to facilitate the connection between your TREZOR and your internet browser.</p>
|
||||
<div className="row">
|
||||
<Select
|
||||
|
@ -58,7 +58,7 @@ export default (props: any): any => {
|
||||
} else if (connectError || bridgeRoute) {
|
||||
css += ' install-bridge';
|
||||
body = <InstallBridge browserState={ props.connect.browserState } />;
|
||||
} else if (web3.length > 0 && devices.length < 1) {
|
||||
} else if (props.wallet.ready && devices.length < 1) {
|
||||
css += ' connect-device';
|
||||
body = <ConnectDevice transport={ transport } />;
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import LandingPage from '../components/landing/LandingPage';
|
||||
import * as LogActions from '../actions/LogActions';
|
||||
import LandingPage from './LandingPage';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
localStorage: state.localStorage,
|
||||
modal: state.modal,
|
||||
web3: state.web3,
|
||||
wallet: state.wallet,
|
||||
connect: state.connect,
|
||||
router: state.router
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
|
||||
};
|
@ -38,20 +38,42 @@ export const ConfirmUnverifiedAddress = (props: any): any => {
|
||||
showAddress
|
||||
} = props.receiveActions;
|
||||
|
||||
const {
|
||||
device
|
||||
} = props.modal;
|
||||
|
||||
return (
|
||||
<div className="confirm-address-unverified">
|
||||
<button className="close-modal transparent" onClick={ onCancel }></button>
|
||||
<h3>Your TREZOR is not connected</h3>
|
||||
<p>To prevent phishing attacks, you should verify the address on your TREZOR first. Please reconnect your device to continue with the verification process.</p>
|
||||
<button onClick={ event => {
|
||||
onCancel();
|
||||
showAddress(account.addressPath);
|
||||
} }>Try again</button>
|
||||
<button className="white" onClick={ event => {
|
||||
onCancel();
|
||||
showUnverifiedAddress();
|
||||
} }>Show unverified address</button>
|
||||
</div>
|
||||
);
|
||||
if (!device.connected) {
|
||||
return (
|
||||
<div className="confirm-address-unverified">
|
||||
<button className="close-modal transparent" onClick={ onCancel }></button>
|
||||
<h3>{ device.instanceLabel } is not connected</h3>
|
||||
<p>To prevent phishing attacks, you should verify the address on your TREZOR first. Please reconnect your device to continue with the verification process.</p>
|
||||
<button onClick={ event => {
|
||||
onCancel();
|
||||
showAddress(account.addressPath);
|
||||
} }>Try again</button>
|
||||
<button className="white" onClick={ event => {
|
||||
onCancel();
|
||||
showUnverifiedAddress();
|
||||
} }>Show unverified address</button>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
const enable: string = device.features.passphrase_protection ? 'Enable' : 'Disable';
|
||||
return (
|
||||
<div className="confirm-address-unverified">
|
||||
<button className="close-modal transparent" onClick={ onCancel }></button>
|
||||
<h3>{ device.instanceLabel } is unavailable</h3>
|
||||
<p>To prevent phishing attacks, you should verify the address on your TREZOR first. { enable } passphrase settings to continue with the verification process.</p>
|
||||
<button onClick={ event => {
|
||||
onCancel();
|
||||
showAddress(account.addressPath);
|
||||
} }>Try again</button>
|
||||
<button className="white" onClick={ event => {
|
||||
onCancel();
|
||||
showUnverifiedAddress();
|
||||
} }>Show unverified address</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,11 @@ const RememberDevice = (props: any): any => {
|
||||
const { device } = props.modal;
|
||||
const { onCancel, onDuplicateDevice } = props.modalActions;
|
||||
return (
|
||||
<div className="pin">
|
||||
<h3>Duplicate { device.label } ?</h3>
|
||||
|
||||
<label>Device label</label>
|
||||
<input type="text" />
|
||||
<button onClick={ onCancel }>Cancel</button>
|
||||
<button onClick={ event => onDuplicateDevice( { ...device, instanceLabel: "kokot" } ) }>Duplicate</button>
|
||||
<div className="duplicate">
|
||||
<h3>Clone { device.instanceLabel }?</h3>
|
||||
<p>This will create new instance of device which can be used with different passphrase</p>
|
||||
<button onClick={ event => onDuplicateDevice( { ...device, instanceLabel: "TODO: user label from input" } ) }>Create new instance</button>
|
||||
<button className="white" onClick={ onCancel }>Cancel</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -3,8 +3,10 @@
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import raf from 'raf';
|
||||
import { findSelectedDevice } from '../../reducers/TrezorConnectReducer';
|
||||
|
||||
type State = {
|
||||
deviceLabel: string;
|
||||
singleInput: boolean;
|
||||
passphrase: string;
|
||||
passphraseRevision: string;
|
||||
@ -25,10 +27,20 @@ export default class PinModal extends Component {
|
||||
super(props);
|
||||
|
||||
// check if this device is already known
|
||||
const isSavedDevice = props.devices.find(d => d.path === props.modal.device.path && d.remember);
|
||||
// const isSavedDevice = props.devices.find(d => d.path === props.modal.device.path && d.remember);
|
||||
const selected = findSelectedDevice(props.connect);
|
||||
let deviceLabel = props.modal.device.label;
|
||||
let singleInput = false;
|
||||
if (selected && selected.path === props.modal.device.path) {
|
||||
deviceLabel = selected.instanceLabel;
|
||||
singleInput = selected.remember;
|
||||
}
|
||||
|
||||
console.warn("-----PASSS", selected)
|
||||
|
||||
this.state = {
|
||||
singleInput: isSavedDevice ? true : false,
|
||||
deviceLabel,
|
||||
singleInput,
|
||||
passphrase: '',
|
||||
passphraseRevision: '',
|
||||
passphraseFocused: false,
|
||||
@ -220,6 +232,7 @@ export default class PinModal extends Component {
|
||||
} = this.props.modal;
|
||||
|
||||
const {
|
||||
deviceLabel,
|
||||
singleInput,
|
||||
passphrase,
|
||||
passphraseRevision,
|
||||
@ -242,7 +255,7 @@ export default class PinModal extends Component {
|
||||
return (
|
||||
<div className="passphrase">
|
||||
{/* <button className="close-modal transparent" onClick={ event => this.submit(true) }></button> */}
|
||||
<h3>Enter { device.label } passphrase</h3>
|
||||
<h3>Enter { deviceLabel } passphrase</h3>
|
||||
<p>Note that passphrase is case-sensitive.</p>
|
||||
<div className="row">
|
||||
<label>Passphrase</label>
|
||||
|
@ -63,11 +63,20 @@ export default class RememberDevice extends Component {
|
||||
}
|
||||
|
||||
render(): any {
|
||||
const { device } = this.props.modal;
|
||||
const { device, instances } = this.props.modal;
|
||||
const { onForgetDevice, onRememberDevice } = this.props.modalActions;
|
||||
|
||||
let label = device.label;
|
||||
let devicePlural = false;
|
||||
if (instances && instances.length > 0) {
|
||||
label = instances.map(i => {
|
||||
return (<span>{i.instanceLabel}</span>);
|
||||
})
|
||||
devicePlural = instances.length > 1;
|
||||
}
|
||||
return (
|
||||
<div className="remember">
|
||||
<h3>Forget { device.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>
|
||||
<button onClick={ event => onForgetDevice(device) }>Forget</button>
|
||||
<button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size={ 28 } label={ this.state.countdown } /></span></button>
|
||||
@ -81,7 +90,7 @@ export const ForgetDevice = (props: any): any => {
|
||||
const { onForgetSingleDevice, onCancel } = props.modalActions;
|
||||
return (
|
||||
<div className="remember">
|
||||
<h3>Forget { device.label } ?</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>
|
||||
<button onClick={ event => onForgetSingleDevice(device) }>Forget</button>
|
||||
<button className="white" onClick={ onCancel }>Don't forget</button>
|
||||
@ -94,7 +103,7 @@ export const DisconnectDevice = (props: any): any => {
|
||||
const { onForgetSingleDevice, onCancel } = props.modalActions;
|
||||
return (
|
||||
<div className="remember">
|
||||
<h3>Unplug { device.label }</h3>
|
||||
<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>
|
||||
|
@ -105,6 +105,7 @@ const mapStateToProps = (state: any, own: any): any => {
|
||||
modal: state.modal,
|
||||
accounts: state.accounts,
|
||||
devices: state.connect.devices,
|
||||
connect: state.connect,
|
||||
sendForm: state.sendForm,
|
||||
receive: state.receive,
|
||||
localStorage: state.localStorage
|
@ -2,7 +2,10 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Notification } from '../common/Notification';
|
||||
import * as TrezorConnectActions from '../../actions/TrezorConnectActions';
|
||||
|
||||
const Acquire = (props: any): any => {
|
||||
|
||||
@ -21,19 +24,24 @@ const Acquire = (props: any): any => {
|
||||
title="Device is used in other window"
|
||||
message="Do you want to use your device in this window?"
|
||||
className="info"
|
||||
cancelable={false}
|
||||
actions={actions}
|
||||
cancelable={ false }
|
||||
actions={ actions }
|
||||
close={ () => {} }
|
||||
/>
|
||||
{/* <div className="warning">
|
||||
<div>
|
||||
<h2></h2>
|
||||
<p></p>
|
||||
</div>
|
||||
<button onClick={ event => props.acquireDevice() }>Acquire device</button>
|
||||
</div> */}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Acquire;
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
connect: state.connect
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Acquire);
|
||||
|
@ -2,6 +2,8 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const Bootloader = (props: any): any => {
|
||||
return (
|
||||
@ -11,4 +13,15 @@ const Bootloader = (props: any): any => {
|
||||
);
|
||||
}
|
||||
|
||||
export default Bootloader;
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Bootloader);
|
||||
|
@ -2,6 +2,8 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const Dashboard = (props: any): any => {
|
||||
return (
|
||||
@ -16,4 +18,15 @@ const Dashboard = (props: any): any => {
|
||||
);
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
|
||||
|
27
src/js/components/wallet/DeviceSettings.js
Normal file
27
src/js/components/wallet/DeviceSettings.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
export const DeviceSettings = (props: any): any => {
|
||||
return (
|
||||
<section className="settings">
|
||||
Device settings
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DeviceSettings);
|
@ -2,18 +2,23 @@
|
||||
'use strict';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Tooltip from 'rc-tooltip';
|
||||
import { QRCode } from 'react-qr-svg';
|
||||
|
||||
import AbstractAccount from './account/AbstractAccount';
|
||||
import { Notification } from '../common/Notification';
|
||||
import Tooltip from 'rc-tooltip';
|
||||
import * as ReceiveActions from '../../actions/ReceiveActions';
|
||||
|
||||
export default class Receive extends AbstractAccount {
|
||||
class Receive extends AbstractAccount {
|
||||
render() {
|
||||
return super.render(this.props.receive) || _render(this.props);
|
||||
return super.render(this.props.receive) || _render(this.props, this.device, this.account, this.deviceStatusNotification);
|
||||
}
|
||||
}
|
||||
|
||||
const _render = (props: any): any => {
|
||||
const _render = (props: any, device, account, deviceStatusNotification): any => {
|
||||
|
||||
const {
|
||||
network,
|
||||
@ -23,8 +28,8 @@ const _render = (props: any): any => {
|
||||
addressUnverified,
|
||||
} = props.receive;
|
||||
|
||||
const device = props.devices.find(d => d.state === deviceState);
|
||||
const account = props.accounts.find(a => a.deviceState === deviceState && a.index === accountIndex && a.network === network);
|
||||
// const device = props.devices.find(d => d.state === deviceState);
|
||||
// const account = props.accounts.find(a => a.deviceState === deviceState && a.index === accountIndex && a.network === network);
|
||||
|
||||
let qrCode = null;
|
||||
let address = `${account.address.substring(0, 20)}...`;
|
||||
@ -50,7 +55,7 @@ const _render = (props: any): any => {
|
||||
className = addressUnverified ? 'address unverified' : 'address';
|
||||
|
||||
const tooltip = addressUnverified ?
|
||||
(<div>Unverified address.<br/>{ device.connected ? 'Show on TREZOR' : 'Connect your TREZOR to verify it.' }</div>)
|
||||
(<div>Unverified address.<br/>{ device.connected && device.available ? 'Show on TREZOR' : 'Connect your TREZOR to verify it.' }</div>)
|
||||
:
|
||||
(<div>{ device.connected ? 'Show on TREZOR' : 'Connect your TREZOR to verify address.' }</div>);
|
||||
|
||||
@ -68,9 +73,7 @@ const _render = (props: any): any => {
|
||||
|
||||
return (
|
||||
<section className="receive">
|
||||
{ !device.connected ? (
|
||||
<Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />
|
||||
) : null }
|
||||
{ deviceStatusNotification }
|
||||
<h2>Receive Ethereum or tokens</h2>
|
||||
|
||||
<div className={ className }>
|
||||
@ -86,3 +89,23 @@ const _render = (props: any): any => {
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
location: state.router.location,
|
||||
devices: state.connect.devices,
|
||||
accounts: state.accounts,
|
||||
discovery: state.discovery,
|
||||
receive: state.receive
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
initAccount: bindActionCreators(ReceiveActions.init, dispatch),
|
||||
updateAccount: bindActionCreators(ReceiveActions.update, dispatch),
|
||||
disposeAccount: bindActionCreators(ReceiveActions.dispose, dispatch),
|
||||
showAddress: bindActionCreators(ReceiveActions.showAddress, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Receive);
|
@ -1,12 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default (props: any): any => {
|
||||
return (
|
||||
<section className="settings">
|
||||
Settings
|
||||
</section>
|
||||
);
|
||||
}
|
@ -2,8 +2,10 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
export default (props: any): any => {
|
||||
const SignVerify = (props: any): any => {
|
||||
return (
|
||||
<section className="signverify">
|
||||
<div className="sign">
|
||||
@ -27,3 +29,16 @@ export default (props: any): any => {
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SignVerify);
|
27
src/js/components/wallet/WalletSettings.js
Normal file
27
src/js/components/wallet/WalletSettings.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
export const WalletSettings = (props: any): any => {
|
||||
return (
|
||||
<section className="settings">
|
||||
Wallet settings
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(WalletSettings);
|
@ -3,19 +3,54 @@
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Notification } from '../../common/Notification';
|
||||
import { findDevice } from '../../../utils/reducerUtils';
|
||||
import type { TrezorDevice } from '../../../reducers/TrezorConnectReducer';
|
||||
|
||||
export type AccountState = {
|
||||
device: TrezorDevice;
|
||||
discovery: any;
|
||||
account: any;
|
||||
}
|
||||
|
||||
export default class AbstractAccount extends Component {
|
||||
|
||||
device: TrezorDevice;
|
||||
discovery: any;
|
||||
account: any;
|
||||
deviceStatusNotification: any;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setLocalVars(vars: any) {
|
||||
this.device = vars.device;
|
||||
this.discovery = vars.discovery;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.initAccount();
|
||||
}
|
||||
|
||||
componentWillUpdate(newProps: any) {
|
||||
this.device = null;
|
||||
this.discovery = null;
|
||||
this.account = null;
|
||||
this.deviceStatusNotification = null;
|
||||
|
||||
this.props.updateAccount();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.disposeAccount();
|
||||
|
||||
this.device = null;
|
||||
this.discovery = null;
|
||||
this.account = null;
|
||||
this.deviceStatusNotification = null;
|
||||
}
|
||||
|
||||
render(state: any): any {
|
||||
@ -23,31 +58,49 @@ export default class AbstractAccount extends Component {
|
||||
const props = this.props;
|
||||
|
||||
if (!state.deviceState) {
|
||||
return (<section></section>);
|
||||
return (<section><Notification className="info" title="Loading device" /></section>);
|
||||
}
|
||||
|
||||
const device = this.props.devices.find(d => d.state === state.deviceState);
|
||||
|
||||
const device = findDevice(this.props.devices, state.deviceState, state.deviceId, state.deviceInstance);
|
||||
|
||||
if (!device) {
|
||||
return (<section>Device with state {state.deviceState} not found</section>);
|
||||
}
|
||||
const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === state.network);
|
||||
const account = props.accounts.find(a => a.deviceState === state.deviceState && a.index === state.accountIndex && a.network === state.network);
|
||||
let deviceStatusNotification = null;
|
||||
|
||||
if (!account) {
|
||||
if (!discovery || discovery.waitingForDevice) {
|
||||
return (
|
||||
<section>
|
||||
<Notification
|
||||
className="info"
|
||||
title="Loading account"
|
||||
message=""
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
if (device.connected) {
|
||||
if (device.available) {
|
||||
return (
|
||||
<section>
|
||||
<Notification className="info" title="Loading account" />
|
||||
</section>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<section>
|
||||
<Notification
|
||||
className="info"
|
||||
title={ `Device ${ device.instanceLabel } is unavailable` }
|
||||
message="Change passphrase settings to use this device"
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<section>
|
||||
<Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
} else if (discovery.completed) {
|
||||
return (
|
||||
<section>
|
||||
<Notification className="warning" title="Account is not exist" />
|
||||
<Notification className="warning" title="Account does not exist" />
|
||||
</section>
|
||||
);
|
||||
} else {
|
||||
@ -57,8 +110,20 @@ export default class AbstractAccount extends Component {
|
||||
</section>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!device.connected) {
|
||||
deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />;
|
||||
} else if (!device.available) {
|
||||
deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is unavailable` } message="Change passphrase settings to use this device" />;
|
||||
}
|
||||
}
|
||||
|
||||
// Set class variables for extender classes
|
||||
this.device = device;
|
||||
this.discovery = discovery;
|
||||
this.account = account;
|
||||
this.deviceStatusNotification = deviceStatusNotification;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -17,8 +17,9 @@ const AccountSelection = (props: any): any => {
|
||||
if (!selected) return null;
|
||||
|
||||
const { location } = props.router;
|
||||
const urlParams = location.params;
|
||||
const accounts = props.accounts;
|
||||
const baseUrl: string = `/device/${location.params.device}`;
|
||||
const baseUrl: string = urlParams.deviceInstance ? `/device/${urlParams.device}:${urlParams.deviceInstance}` : `/device/${urlParams.device}`;
|
||||
|
||||
const { config } = props.localStorage;
|
||||
const selectedCoin = config.coins.find(c => c.network === location.params.network);
|
||||
|
@ -48,7 +48,7 @@ const Aside = (props: any): any => {
|
||||
// );
|
||||
// }
|
||||
|
||||
let menu = null;
|
||||
let menu = <section></section>;
|
||||
|
||||
if (props.deviceDropdownOpened) {
|
||||
menu = <DeviceDropdown {...props} />;
|
||||
@ -77,4 +77,4 @@ const Aside = (props: any): any => {
|
||||
)
|
||||
}
|
||||
|
||||
export default Aside;
|
||||
export default Aside;
|
||||
|
@ -34,6 +34,10 @@ const Value = (props: any): any => {
|
||||
|
||||
const deviceMenuItems: Array<any> = [];
|
||||
|
||||
if (device.features && device.features.passphrase_protection) {
|
||||
deviceMenuItems.push("settings"); // TODO: clone
|
||||
}
|
||||
|
||||
if (device.unacquired) {
|
||||
css += " unacquired";
|
||||
deviceStatus = "Used in other window";
|
||||
@ -49,6 +53,9 @@ const Value = (props: any): any => {
|
||||
if (!device.connected) {
|
||||
css += " reload-features";
|
||||
deviceStatus = "Disconnected";
|
||||
} else if (!device.available) {
|
||||
css += " unavailable";
|
||||
deviceStatus = "Unavailable";
|
||||
}
|
||||
|
||||
if (device.remember) {
|
||||
@ -59,6 +66,8 @@ const Value = (props: any): any => {
|
||||
css += " trezor-t";
|
||||
}
|
||||
|
||||
|
||||
|
||||
const deviceMenuButtons = deviceMenuItems.map((item, index) => {
|
||||
return (
|
||||
<div key={ item } className={ item } onClick={ event => onClick(event, item, device) }></div>
|
||||
@ -81,9 +90,6 @@ const Value = (props: any): any => {
|
||||
<span className="label">{ device.instanceLabel }</span>
|
||||
<span className="status">{ deviceStatus }</span>
|
||||
</div>
|
||||
<div className="device-menu">
|
||||
{ deviceMenuButtons }
|
||||
</div>
|
||||
<div className="arrow">
|
||||
</div>
|
||||
</div>
|
||||
@ -143,8 +149,7 @@ export const DeviceSelect = (props: any): any => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("DEVSEL", props)
|
||||
const disabled: boolean = (devices && devices.length <= 1 && transport && transport.type.indexOf('webusb') < 0);
|
||||
const disabled: boolean = (devices.length < 1 && transport && transport.version.indexOf('webusb') < 0);
|
||||
|
||||
return (
|
||||
<Value
|
||||
@ -169,17 +174,16 @@ export class DeviceDropdown extends Component {
|
||||
|
||||
componentDidUpdate() {
|
||||
const transport: any = this.props.connect.transport;
|
||||
if (transport && transport.type.indexOf('webusb') >= 0)
|
||||
if (transport && transport.version.indexOf('webusb') >= 0)
|
||||
TrezorConnect.renderWebUSBButton();
|
||||
}
|
||||
|
||||
mouseDownHandler(event: MouseEvent): void {
|
||||
console.log("HANDLE DOWN!!!!", event)
|
||||
let elem = event.target;
|
||||
let block: boolean = false;
|
||||
while (elem.parentElement) {
|
||||
// if (elem.className.indexOf('aside-button') >= 0) {
|
||||
if (elem.tagName.toLowerCase() === 'aside') {
|
||||
if (elem.tagName.toLowerCase() === 'aside' || (elem.className && elem.className.indexOf('modal-container') >= 0)) {
|
||||
block = true;
|
||||
break;
|
||||
}
|
||||
@ -199,7 +203,7 @@ export class DeviceDropdown extends Component {
|
||||
window.addEventListener('mousedown', this.mouseDownHandler, false);
|
||||
// window.addEventListener('blur', this.blurHandler, false);
|
||||
const transport: any = this.props.connect.transport;
|
||||
if (transport && transport.type.indexOf('webusb') >= 0)
|
||||
if (transport && transport.version.indexOf('webusb') >= 0)
|
||||
TrezorConnect.renderWebUSBButton();
|
||||
}
|
||||
|
||||
@ -208,16 +212,69 @@ export class DeviceDropdown extends Component {
|
||||
// window.removeEventListener('blur', this.blurHandler, false);
|
||||
}
|
||||
|
||||
onDeviceMenuClick(item, device): void {
|
||||
if (item.type === 'reload') {
|
||||
this.props.acquireDevice(device);
|
||||
} else if (item.type === 'forget') {
|
||||
// this.props.toggleDeviceDropdown(false);
|
||||
this.props.forgetDevice(device);
|
||||
} else if (item.type === 'clone') {
|
||||
this.props.duplicateDevice(device);
|
||||
} else if (item.type === 'settings') {
|
||||
this.props.toggleDeviceDropdown(false);
|
||||
this.props.gotoDeviceSettings(device);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { devices, transport } = this.props.connect;
|
||||
const selected = findSelectedDevice(this.props.connect);
|
||||
|
||||
let webUsbButton = null;
|
||||
if (transport && transport.type.indexOf('webusb') >= 0) {
|
||||
if (transport && transport.version.indexOf('webusb') >= 0) {
|
||||
webUsbButton = <button className="trezor-webusb-button">Check for devices</button>;
|
||||
}
|
||||
|
||||
let currentDeviceMenu = null;
|
||||
if (selected.features) {
|
||||
const deviceMenuItems: Array<any> = [];
|
||||
|
||||
if (selected.isUsedElsewhere) {
|
||||
deviceMenuItems.push({ type: "reload", label: "Renew session" });
|
||||
} else if (selected.featuresNeedsReload) {
|
||||
deviceMenuItems.push({ type: "reload", label: "Reload device" });
|
||||
}
|
||||
|
||||
deviceMenuItems.push({ type: "settings", label: "Device settings" });
|
||||
if (selected.features.passphrase_protection && selected.connected && selected.available) {
|
||||
deviceMenuItems.push({ type: "clone", label: "Clone device" });
|
||||
}
|
||||
if (selected.remember) {
|
||||
deviceMenuItems.push({ type: "forget", label: "Forget device" });
|
||||
}
|
||||
|
||||
|
||||
const deviceMenuButtons = deviceMenuItems.map((item, index) => {
|
||||
return (
|
||||
<div key={ item.type } className={ item.type } onClick={ event => this.onDeviceMenuClick(item, selected) }>{ item.label}</div>
|
||||
)
|
||||
});
|
||||
currentDeviceMenu = deviceMenuButtons.length < 1 ? null : (
|
||||
<div className="device-menu">
|
||||
{ deviceMenuButtons }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 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) => {
|
||||
if (dev === selected) return null;
|
||||
|
||||
@ -227,6 +284,8 @@ export class DeviceDropdown extends Component {
|
||||
deviceStatus = "Used in other window";
|
||||
} else if (!dev.connected) {
|
||||
deviceStatus = "Disconnected";
|
||||
} else if (!dev.available) {
|
||||
deviceStatus = "Unavailable";
|
||||
}
|
||||
|
||||
if (dev.features && dev.features.major_version > 1) {
|
||||
@ -245,6 +304,7 @@ export class DeviceDropdown extends Component {
|
||||
|
||||
return (
|
||||
<section>
|
||||
{ currentDeviceMenu }
|
||||
{ webUsbButton }
|
||||
{ deviceList }
|
||||
</section>
|
||||
|
@ -5,23 +5,25 @@ import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import Aside from '../components/wallet/aside/Aside';
|
||||
import * as TrezorConnectActions from '../actions/TrezorConnectActions';
|
||||
import { toggleDeviceDropdown } from '../actions/AppActions';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
import * as TrezorConnectActions from '../../../actions/TrezorConnectActions';
|
||||
import { toggleDeviceDropdown } from '../../../actions/WalletActions';
|
||||
|
||||
import Aside from './Aside';
|
||||
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
connect: state.connect,
|
||||
accounts: state.accounts,
|
||||
router: state.router,
|
||||
deviceDropdownOpened: state.DOM.deviceDropdownOpened,
|
||||
deviceDropdownOpened: state.wallet.dropdownOpened,
|
||||
fiat: state.fiat,
|
||||
localStorage: state.localStorage,
|
||||
discovery: state.discovery
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
//onAccountSelect: bindActionCreators(AccountActions.onAccountSelect, dispatch),
|
||||
toggleDeviceDropdown: bindActionCreators(toggleDeviceDropdown, dispatch),
|
||||
@ -29,6 +31,7 @@ function mapDispatchToProps(dispatch) {
|
||||
acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
|
||||
forgetDevice: bindActionCreators(TrezorConnectActions.forget, dispatch),
|
||||
duplicateDevice: bindActionCreators(TrezorConnectActions.duplicateDevice, dispatch),
|
||||
gotoDeviceSettings: bindActionCreators(TrezorConnectActions.gotoDeviceSettings, dispatch),
|
||||
onSelectDevice: bindActionCreators(TrezorConnectActions.onSelectDevice, dispatch),
|
||||
};
|
||||
}
|
58
src/js/components/wallet/index.js
Normal file
58
src/js/components/wallet/index.js
Normal file
@ -0,0 +1,58 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Route, withRouter } from 'react-router-dom';
|
||||
|
||||
import Header from '../common/Header';
|
||||
import Footer from '../common/Footer';
|
||||
import AccountTabs from './account/AccountTabs';
|
||||
import AsideContainer from './aside';
|
||||
import ModalContainer from '../modal';
|
||||
import Notifications from '../common/Notification';
|
||||
import Log from '../common/Log';
|
||||
|
||||
const Content = (props) => {
|
||||
return (
|
||||
<article>
|
||||
<nav>
|
||||
<Route path="/device/:device/network/:network/address/:address" component={ AccountTabs } />
|
||||
</nav>
|
||||
<Notifications />
|
||||
<Log />
|
||||
{ props.children }
|
||||
<Footer />
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
const Wallet = (props: any): any => {
|
||||
return (
|
||||
<div className="app">
|
||||
<Header />
|
||||
<main>
|
||||
<AsideContainer />
|
||||
<Content>
|
||||
{ props.children }
|
||||
</Content>
|
||||
</main>
|
||||
<ModalContainer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return { };
|
||||
}
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps, mapDispatchToProps)(Wallet)
|
||||
);
|
@ -11,16 +11,16 @@ import AbstractAccount from '../account/AbstractAccount';
|
||||
|
||||
export default class Send extends AbstractAccount {
|
||||
render() {
|
||||
return super.render(this.props.sendForm) || _render(this.props);
|
||||
return super.render(this.props.sendForm) || _render(this.props, this.device, this.discovery, this.account, this.deviceStatusNotification);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const _render = (props: any): any => {
|
||||
const _render = (props: any, device, discovery, account, deviceStatusNotification): any => {
|
||||
|
||||
const device = props.devices.find(device => device.state === props.sendForm.deviceState);
|
||||
const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === props.sendForm.network);
|
||||
const account = props.accounts.find(a => a.deviceState === props.sendForm.deviceState && a.index === props.sendForm.accountIndex && a.network === props.sendForm.network);
|
||||
// const device = props.devices.find(device => device.state === props.sendForm.deviceState);
|
||||
// const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === props.sendForm.network);
|
||||
// const account = props.accounts.find(a => a.deviceState === props.sendForm.deviceState && a.index === props.sendForm.accountIndex && a.network === props.sendForm.network);
|
||||
const addressTokens = props.tokens.filter(t => t.ethAddress === account.address);
|
||||
|
||||
const {
|
||||
@ -87,9 +87,16 @@ const _render = (props: any): any => {
|
||||
buttonLabel += ` ${total} ${ selectedCoin.symbol }`;
|
||||
}
|
||||
|
||||
if (device && !device.connected) {
|
||||
buttonLabel = 'Device is not connected';
|
||||
buttonDisabled = true;
|
||||
if (device) {
|
||||
|
||||
if (!device.connected){
|
||||
buttonLabel = 'Device is not connected';
|
||||
buttonDisabled = true;
|
||||
} else if (!device.available) {
|
||||
buttonLabel = 'Device is unavailable';
|
||||
buttonDisabled = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let notification = null;
|
||||
@ -97,9 +104,7 @@ const _render = (props: any): any => {
|
||||
return (
|
||||
<section className="send-form">
|
||||
|
||||
{ !device.connected ? (
|
||||
<Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />
|
||||
) : null }
|
||||
{ deviceStatusNotification }
|
||||
|
||||
<h2>Send Ethereum or tokens</h2>
|
||||
<div className="row address-input">
|
||||
|
@ -5,10 +5,10 @@ import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import SendForm from '../components/wallet/send/SendForm';
|
||||
import * as SendFormActions from '../actions/SendFormActions';
|
||||
import * as SendFormActions from '../../../actions/SendFormActions';
|
||||
import SendForm from './SendForm';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
location: state.router.location,
|
||||
devices: state.connect.devices,
|
||||
@ -22,13 +22,13 @@ function mapStateToProps(state, own) {
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
sendFormActions: bindActionCreators(SendFormActions, dispatch),
|
||||
initAccount: bindActionCreators(SendFormActions.init, dispatch),
|
||||
updateAccount: bindActionCreators(SendFormActions.update, dispatch),
|
||||
disposeAccount: bindActionCreators(SendFormActions.dispose, dispatch),
|
||||
disposeAccount: bindActionCreators(SendFormActions.dispose, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SendForm);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SendForm)
|
@ -9,27 +9,28 @@ import AbstractAccount from '../account/AbstractAccount';
|
||||
import { Notification } from '../../common/Notification';
|
||||
import SummaryDetails from './SummaryDetails.js';
|
||||
import SummaryTokens from './SummaryTokens.js';
|
||||
import { findDevice } from '../../../utils/reducerUtils';
|
||||
|
||||
|
||||
export default class Summary extends AbstractAccount {
|
||||
render() {
|
||||
return super.render(this.props.summary) || _render(this.props);
|
||||
console.warn("RENDER SUMMARY!", this.device, this.discovery, this)
|
||||
return super.render(this.props.summary) || _render(this.props, this.device, this.discovery, this.account, this.deviceStatusNotification);
|
||||
}
|
||||
}
|
||||
|
||||
const _render = (props: any): any => {
|
||||
const _render = (props: any, device, discovery, account, deviceStatusNotification): any => {
|
||||
|
||||
const device = props.devices.find(d => d.state === props.summary.deviceState);
|
||||
const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === props.summary.network);
|
||||
const account = props.accounts.find(a => a.deviceState === props.summary.deviceState && a.index === props.summary.accountIndex && a.network === props.summary.network);
|
||||
//const device = props.devices.find(d => d.state === props.summary.deviceState && d.features.device_id === props.summary.deviceId);
|
||||
// const device = findDevice(props.devices, props.summary.deviceState, props.summary.deviceId);
|
||||
// const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === props.summary.network);
|
||||
//const account = props.accounts.find(a => a.deviceState === props.summary.deviceState && a.index === props.summary.accountIndex && a.network === props.summary.network);
|
||||
const tokens = props.tokens.filter(t => t.ethAddress === account.address);
|
||||
|
||||
return (
|
||||
|
||||
<section className="summary">
|
||||
{ !device.connected ? (
|
||||
<Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />
|
||||
) : null }
|
||||
{ deviceStatusNotification }
|
||||
|
||||
<h2 className={ `summary-header ${props.summary.network}` }>Address #{ parseInt(props.match.params.address) + 1 }</h2>
|
||||
|
||||
|
@ -8,7 +8,7 @@ import { connect } from 'react-redux';
|
||||
import Summary from './Summary';
|
||||
import * as SummaryActions from '../../../actions/SummaryActions';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
const mapStateToProps = (state, own) => {
|
||||
return {
|
||||
location: state.router.location,
|
||||
devices: state.connect.devices,
|
||||
@ -21,7 +21,7 @@ function mapStateToProps(state, own) {
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
summaryActions: bindActionCreators(SummaryActions, dispatch),
|
||||
initAccount: bindActionCreators(SummaryActions.init, dispatch),
|
@ -1,23 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Acquire from '../components/wallet/Acquire';
|
||||
import * as TrezorConnectActions from '../actions/TrezorConnectActions';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
connect: state.connect
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Acquire);
|
@ -1,21 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Bootloader from '../components/wallet/Bootloader';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Bootloader);
|
@ -1,46 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { Route } from 'react-router-dom';
|
||||
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import Log from '../components/common/Log';
|
||||
import Notifications from '../components/common/Notification';
|
||||
import Footer from '../components/common/Footer';
|
||||
import AccountTabs from '../components/wallet/account/AccountTabs';
|
||||
|
||||
import * as TrezorConnectActions from '../actions/TrezorConnectActions';
|
||||
import * as LogActions from '../actions/LogActions';
|
||||
|
||||
const Article = (props) => {
|
||||
return (
|
||||
<article>
|
||||
<nav>
|
||||
<Route path="/device/:device/network/:network/address/:address" component={ AccountTabs } />
|
||||
</nav>
|
||||
<Notifications />
|
||||
<Log />
|
||||
{ props.children }
|
||||
<Footer />
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps, mapDispatchToProps)(Article)
|
||||
);
|
@ -1,21 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Dashboard from '../components/wallet/Dashboard';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
|
@ -1,23 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import History from '../components/wallet/History';
|
||||
import * as SendFormActions from '../actions/SendFormActions';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
web3: state.web3.web3,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
//sendFormActions: bindActionCreators(SendFormActions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(History);
|
@ -1,31 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Receive from '../components/wallet/Receive';
|
||||
import * as ReceiveActions from '../actions/ReceiveActions';
|
||||
import { getAddress } from '../actions/TrezorConnectActions';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
location: state.router.location,
|
||||
devices: state.connect.devices,
|
||||
accounts: state.accounts,
|
||||
discovery: state.discovery,
|
||||
receive: state.receive
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
initAccount: bindActionCreators(ReceiveActions.init, dispatch),
|
||||
updateAccount: bindActionCreators(ReceiveActions.update, dispatch),
|
||||
disposeAccount: bindActionCreators(ReceiveActions.dispose, dispatch),
|
||||
showAddress: bindActionCreators(ReceiveActions.showAddress, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Receive);
|
@ -1,20 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Settings from '../components/wallet/Settings';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Settings);
|
@ -1,20 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import SignVerify from '../components/wallet/SignVerify';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SignVerify);
|
@ -1,31 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import TopNavigation from '../components/TopNavigation';
|
||||
import * as TrezorConnectActions from '../actions/TrezorConnectActions';
|
||||
import { resizeAppContainer, toggleDeviceDropdown } from '../actions/AppActions';
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
connect: state.connect
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
toggleDeviceDropdown: bindActionCreators(toggleDeviceDropdown, dispatch),
|
||||
resizeAppContainer: bindActionCreators(resizeAppContainer, dispatch),
|
||||
acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
|
||||
onSelectDevice: bindActionCreators(TrezorConnectActions.onSelectDevice, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
// export default connect(mapStateToProps, mapDispatchToProps)(TopNavigation);
|
||||
export default withRouter(
|
||||
connect(mapStateToProps, mapDispatchToProps)(TopNavigation)
|
||||
);
|
@ -1,40 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import Header from '../components/common/Header';
|
||||
import AsideContainer from './AsideContainer';
|
||||
import ContentContainer from './ContentContainer';
|
||||
import ModalContainer from '../components/modal/ModalContainer';
|
||||
|
||||
const Wallet = (props: any): any => {
|
||||
return (
|
||||
<div className="app">
|
||||
<Header />
|
||||
<main>
|
||||
<AsideContainer />
|
||||
<ContentContainer>
|
||||
{ props.children }
|
||||
</ContentContainer>
|
||||
</main>
|
||||
<ModalContainer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function mapStateToProps(state, own) {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return { };
|
||||
}
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps, mapDispatchToProps)(Wallet)
|
||||
);
|
@ -1,19 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
// wrapper layouts
|
||||
export { default as LandingPageContainer } from './LandingPageContainer';
|
||||
export { default as WalletContainer } from './WalletContainer';
|
||||
|
||||
// wallet sections
|
||||
export { default as AcquireContainer } from './AcquireContainer';
|
||||
export { default as BootloaderContainer } from './BootloaderContainer';
|
||||
|
||||
export { default as DashboardContainer } from './DashboardContainer';
|
||||
export { default as HistoryContainer } from './HistoryContainer';
|
||||
export { default as SendFormContainer } from './SendFormContainer';
|
||||
export { default as ReceiveContainer } from './ReceiveContainer';
|
||||
export { default as SignVerifyContainer } from './SignVerifyContainer';
|
||||
|
||||
|
||||
export { default as SettingsContainer } from './SettingsContainer';
|
@ -5,7 +5,7 @@ import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import store from './store';
|
||||
import router from './router';
|
||||
import { onResize, onBeforeUnload } from './actions/AppActions';
|
||||
import { onBeforeUnload } from './actions/WalletActions';
|
||||
|
||||
import Raven from 'raven-js';
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import { ON_RESIZE, TOGGLE_DEVICE_DROPDOWN, RESIZE_CONTAINER } from '../actions/AppActions';
|
||||
import * as WEB3 from '../actions/constants/Web3';
|
||||
|
||||
const WIDTH: number = 1080;
|
||||
const HEIGHT: number = 1920;
|
||||
|
||||
const initialState: Object = {
|
||||
orginalWidth: WIDTH,
|
||||
orginalHeight: HEIGHT,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
scale: Math.min(window.innerWidth / WIDTH, window.innerHeight / HEIGHT),
|
||||
coinDropdownOpened: false,
|
||||
deviceDropdownOpened: false,
|
||||
initialized: false,
|
||||
landingPage: true,
|
||||
};
|
||||
|
||||
export default function DOM(state: Object = initialState, action: Object): any {
|
||||
switch(action.type) {
|
||||
case ON_RESIZE :
|
||||
return {
|
||||
...state,
|
||||
scale: Math.min(window.innerWidth / WIDTH, window.innerHeight / HEIGHT),
|
||||
}
|
||||
case RESIZE_CONTAINER :
|
||||
return {
|
||||
...state,
|
||||
coinDropdownOpened: action.opened
|
||||
}
|
||||
case TOGGLE_DEVICE_DROPDOWN :
|
||||
return {
|
||||
...state,
|
||||
deviceDropdownOpened: action.opened
|
||||
}
|
||||
|
||||
case WEB3.READY :
|
||||
return {
|
||||
...state,
|
||||
initialized: true
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
'use strict';
|
||||
|
||||
import { UI, DEVICE } from 'trezor-connect';
|
||||
import * as ACTIONS from '../actions';
|
||||
import * as RECEIVE from '../actions/constants/receive';
|
||||
import * as MODAL from '../actions/constants/Modal';
|
||||
import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||
@ -10,12 +9,14 @@ import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||
type ModalState = {
|
||||
opened: boolean;
|
||||
device: any;
|
||||
instances: Array<any>;
|
||||
windowType: ?string;
|
||||
}
|
||||
|
||||
const initialState: ModalState = {
|
||||
opened: false,
|
||||
device: null,
|
||||
instances: null,
|
||||
windowType: null
|
||||
};
|
||||
|
||||
@ -26,6 +27,7 @@ export default function modal(state: ModalState = initialState, action: any): an
|
||||
case RECEIVE.REQUEST_UNVERIFIED :
|
||||
return {
|
||||
...state,
|
||||
device: action.device,
|
||||
opened: true,
|
||||
windowType: action.type
|
||||
}
|
||||
@ -36,6 +38,7 @@ export default function modal(state: ModalState = initialState, action: any): an
|
||||
return {
|
||||
...state,
|
||||
device: action.device,
|
||||
instances: action.instances,
|
||||
opened: true,
|
||||
windowType: action.type
|
||||
};
|
||||
@ -92,7 +95,7 @@ export default function modal(state: ModalState = initialState, action: any): an
|
||||
}
|
||||
|
||||
case UI.CLOSE_UI_WINDOW :
|
||||
case ACTIONS.CLOSE_MODAL :
|
||||
case MODAL.CLOSE :
|
||||
|
||||
case CONNECT.FORGET :
|
||||
case CONNECT.FORGET_SINGLE :
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import * as NOTIFICATION from '../actions/constants/notification';
|
||||
import { DEVICE } from 'trezor-connect';
|
||||
|
||||
type NotificationAction = {
|
||||
label: string;
|
||||
@ -11,6 +12,7 @@ type NotificationAction = {
|
||||
|
||||
type NotificationEntry = {
|
||||
+id: ?string;
|
||||
+devicePath: ?string;
|
||||
+type: string;
|
||||
+title: string;
|
||||
+message: string;
|
||||
@ -33,6 +35,7 @@ const addNotification = (state: Array<NotificationEntry>, payload: any): Array<N
|
||||
const newState: Array<NotificationEntry> = state.filter(e => !e.cancelable);
|
||||
newState.push({
|
||||
id: payload.id,
|
||||
devicePath: payload.devicePath,
|
||||
type: payload.type,
|
||||
title: payload.title.toString(),
|
||||
message: payload.message.toString(),
|
||||
@ -46,9 +49,11 @@ const addNotification = (state: Array<NotificationEntry>, payload: any): Array<N
|
||||
|
||||
const closeNotification = (state: Array<NotificationEntry>, payload: any): Array<NotificationEntry> => {
|
||||
if (payload && typeof payload.id === 'string') {
|
||||
return state.filter(e => e.id !== payload.id);
|
||||
return state.filter(entry => entry.id !== payload.id);
|
||||
} else if (payload && typeof payload.devicePath === 'string') {
|
||||
return state.filter(entry => entry.devicePath !== payload.devicePath);
|
||||
} else {
|
||||
return state.filter(e => !e.cancelable);
|
||||
return state.filter(entry => !entry.cancelable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +66,9 @@ export default function notification(state: Array<NotificationEntry> = initialSt
|
||||
case LOCATION_CHANGE :
|
||||
case NOTIFICATION.CLOSE :
|
||||
return closeNotification(state, action.payload);
|
||||
|
||||
case DEVICE.DISCONNECT :
|
||||
return state.filter(entry => entry.devicePath !== action.device.path);
|
||||
|
||||
default:
|
||||
return state;
|
||||
|
@ -5,6 +5,8 @@ import * as RECEIVE from '../actions/constants/receive';
|
||||
|
||||
export type State = {
|
||||
+deviceState: ?string;
|
||||
+deviceId: ?string;
|
||||
+deviceInstance: ?string;
|
||||
+accountIndex: ?number;
|
||||
+network: ?string;
|
||||
location: string;
|
||||
@ -14,6 +16,8 @@ export type State = {
|
||||
|
||||
export const initialState: State = {
|
||||
deviceState: null,
|
||||
deviceId: null,
|
||||
deviceInstance: null,
|
||||
accountIndex: null,
|
||||
network: null,
|
||||
location: '',
|
||||
|
@ -11,6 +11,8 @@ import { getFeeLevels } from '../actions/SendFormActions';
|
||||
|
||||
export type State = {
|
||||
+deviceState: ?string;
|
||||
+deviceId: ?string;
|
||||
+deviceInstance: ?string;
|
||||
+accountIndex: number;
|
||||
+network: string;
|
||||
+coinSymbol: string;
|
||||
@ -51,6 +53,8 @@ export type FeeLevel = {
|
||||
|
||||
export const initialState: State = {
|
||||
deviceState: null,
|
||||
deviceId: null,
|
||||
deviceInstance: null,
|
||||
accountIndex: 0,
|
||||
network: '',
|
||||
coinSymbol: '',
|
||||
@ -83,11 +87,11 @@ export const initialState: State = {
|
||||
|
||||
const onGasPriceUpdated = (state: State, action: any): State => {
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
const newPrice = getRandomInt(10, 50).toString();
|
||||
//const newPrice = EthereumjsUnits.convert(action.gasPrice, 'wei', 'gwei');
|
||||
// function getRandomInt(min, max) {
|
||||
// return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
// }
|
||||
// const newPrice = getRandomInt(10, 50).toString();
|
||||
const newPrice = EthereumjsUnits.convert(action.gasPrice, 'wei', 'gwei');
|
||||
if (action.network === state.network && newPrice !== state.recommendedGasPrice) {
|
||||
const newState: State = { ...state };
|
||||
if (!state.untouched) {
|
||||
|
@ -5,6 +5,8 @@ import * as SUMMARY from '../actions/constants/summary';
|
||||
|
||||
export type State = {
|
||||
+deviceState: ?string;
|
||||
+deviceId: ?string;
|
||||
+deviceInstance: ?string;
|
||||
+accountIndex: ?number;
|
||||
+network: ?string;
|
||||
location: string;
|
||||
@ -15,6 +17,8 @@ export type State = {
|
||||
|
||||
export const initialState: State = {
|
||||
deviceState: null,
|
||||
deviceId: null,
|
||||
deviceInstance: null,
|
||||
accountIndex: null,
|
||||
network: null,
|
||||
location: '',
|
||||
|
@ -7,6 +7,7 @@ import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||
export type TrezorDevice = {
|
||||
remember: boolean;
|
||||
connected: boolean;
|
||||
available: boolean; // device cannot be used because of features.passphrase_protection is different then expected (saved)
|
||||
path: string;
|
||||
+label: string;
|
||||
+state: string;
|
||||
@ -58,6 +59,8 @@ export const findSelectedDevice = (state: State): ?TrezorDevice => {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const isSavedDevice = (state: State, device: any): ?Array<TrezorDevice> => {
|
||||
const selected: ?SelectedDevice = state.selectedDevice;
|
||||
if (!selected) return null;
|
||||
@ -73,17 +76,36 @@ export const isSavedDevice = (state: State, device: any): ?Array<TrezorDevice> =
|
||||
}
|
||||
|
||||
const mergeDevices = (current: TrezorDevice, upcoming: Object): TrezorDevice => {
|
||||
|
||||
// do not merge if passphrase protection was changed
|
||||
// if (upcoming.features && current.features) {
|
||||
// if (upcoming.features.passphrase_protection !== current.features.passphrase_protection) {
|
||||
// // device settings has been changed, reset state
|
||||
// // dev.state = null;
|
||||
// // console.log("RESTETTTT STATE!");
|
||||
// }
|
||||
// }
|
||||
|
||||
let instanceLabel = current.instanceLabel;
|
||||
if (upcoming.label !== current.label) {
|
||||
instanceLabel = upcoming.label
|
||||
if (typeof current.instance === 'number') {
|
||||
instanceLabel += ` (${current.instance})`;
|
||||
}
|
||||
}
|
||||
|
||||
const dev: TrezorDevice = {
|
||||
// ...current,
|
||||
...upcoming,
|
||||
// make sure that instance specific variables will not be overridden
|
||||
connected: typeof upcoming.connected === 'boolean' ? upcoming.connected : current.connected,
|
||||
available: typeof upcoming.available === 'boolean' ? upcoming.available : current.available,
|
||||
remember: typeof upcoming.remember === 'boolean' ? upcoming.remember : current.remember,
|
||||
instance: current.instance,
|
||||
instanceLabel: current.instanceLabel,
|
||||
instanceLabel,
|
||||
state: current.state,
|
||||
acquiring: typeof upcoming.acquiring === 'boolean' ? upcoming.acquiring : current.acquiring,
|
||||
ts: new Date().getTime(),
|
||||
ts: typeof upcoming.ts === 'number' ? upcoming.ts : current.ts,
|
||||
}
|
||||
|
||||
if (upcoming.unacquired && current.state) {
|
||||
@ -94,18 +116,11 @@ const mergeDevices = (current: TrezorDevice, upcoming: Object): TrezorDevice =>
|
||||
} else if (!upcoming.unacquired && current.unacquired) {
|
||||
dev.instanceLabel = upcoming.label;
|
||||
if (typeof dev.instance === 'number') {
|
||||
dev.instanceLabel = `${upcoming.label} #${dev.instance}`;
|
||||
dev.instanceLabel = `${upcoming.label} TODO:(${dev.instance})`;
|
||||
}
|
||||
}
|
||||
|
||||
if (upcoming.features && current.features) {
|
||||
console.log("CZEKIN PASS PROT");
|
||||
if (upcoming.features.passphrase_protection !== current.features.passphrase_protection) {
|
||||
// device settings has been changed, reset state
|
||||
dev.state = null;
|
||||
console.log("RESTETTTT STATE!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return dev;
|
||||
}
|
||||
@ -132,7 +147,40 @@ const addDevice = (state: State, device: Object): State => {
|
||||
|
||||
if (affectedDevices.length > 0 ) {
|
||||
// replace existing values
|
||||
const changedDevices: Array<TrezorDevice> = affectedDevices.map(d => mergeDevices(d, { ...device, connected: true} ));
|
||||
// const changedDevices: Array<TrezorDevice> = affectedDevices.map(d => mergeDevices(d, { ...device, connected: true} ));
|
||||
let cloneInstance: number = 1;
|
||||
const changedDevices: Array<TrezorDevice> = affectedDevices.map(d => {
|
||||
if (d.features.passphrase_protection === device.features.passphrase_protection) {
|
||||
cloneInstance = 0;
|
||||
return mergeDevices(d, { ...device, connected: true, available: true } );
|
||||
} else {
|
||||
if (d.instance && cloneInstance > 0) {
|
||||
cloneInstance = d.instance + 1;
|
||||
}
|
||||
return mergeDevices(d, { ...d, connected: true, available: false } );
|
||||
// return d;
|
||||
}
|
||||
});
|
||||
|
||||
if (cloneInstance > 0) {
|
||||
// TODO: instance should be calculated form affectedDevice
|
||||
const instance = cloneInstance; //new Date().getTime();
|
||||
|
||||
const newDevice: TrezorDevice = {
|
||||
...device,
|
||||
acquiring: false,
|
||||
remember: false,
|
||||
connected: true,
|
||||
available: true,
|
||||
path: device.path,
|
||||
label: device.label,
|
||||
state: null,
|
||||
instance,
|
||||
instanceLabel: `${device.label} (${instance})`,
|
||||
ts: new Date().getTime(),
|
||||
}
|
||||
changedDevices.push(newDevice);
|
||||
}
|
||||
newState.devices = otherDevices.concat(changedDevices);
|
||||
|
||||
} else {
|
||||
@ -142,12 +190,13 @@ const addDevice = (state: State, device: Object): State => {
|
||||
acquiring: false,
|
||||
remember: false,
|
||||
connected: true,
|
||||
available: true,
|
||||
path: device.path,
|
||||
label: device.label,
|
||||
state: null,
|
||||
// instance: 0,
|
||||
instanceLabel: device.label,
|
||||
ts: 0,
|
||||
ts: new Date().getTime(),
|
||||
}
|
||||
newState.devices.push(newDevice);
|
||||
|
||||
@ -184,11 +233,15 @@ const changeDevice = (state: State, device: Object): State => {
|
||||
let affectedDevices: Array<TrezorDevice> = [];
|
||||
let otherDevices: Array<TrezorDevice> = [];
|
||||
if (device.features) {
|
||||
affectedDevices = state.devices.filter(d => (d.features && d.features.device_id === device.features.device_id) || (d.path.length > 0 && d.path === device.path) );
|
||||
affectedDevices = state.devices.filter(d =>
|
||||
(d.features && d.features.device_id === device.features.device_id && d.features.passphrase_protection === device.features.passphrase_protection) ||
|
||||
(d.path.length > 0 && d.path === device.path)
|
||||
);
|
||||
otherDevices = state.devices.filter(d => affectedDevices.indexOf(d) === -1);
|
||||
} else {
|
||||
affectedDevices = state.devices.filter(d => d.path === device.path);
|
||||
otherDevices = state.devices.filter(d => d.path !== device.path);
|
||||
affectedDevices = state.devices.filter(d => !d.features && d.path === device.path);
|
||||
otherDevices = state.devices.filter(d => affectedDevices.indexOf(d) === -1);
|
||||
// otherDevices = state.devices.filter(d => d.path !== device.path);
|
||||
}
|
||||
|
||||
if (affectedDevices.length > 0) {
|
||||
@ -226,13 +279,14 @@ const changeDevice = (state: State, device: Object): State => {
|
||||
const disconnectDevice = (state: State, device: Object): State => {
|
||||
|
||||
const newState: State = { ...state };
|
||||
const affectedDevices: Array<TrezorDevice> = state.devices.filter(d => d.path === device.path);
|
||||
const affectedDevices: Array<TrezorDevice> = state.devices.filter(d => d.path === device.path || (d.features && device.features && d.features.device_id === device.features.device_id));
|
||||
const otherDevices: Array<TrezorDevice> = state.devices.filter(d => affectedDevices.indexOf(d) === -1);
|
||||
|
||||
if (affectedDevices.length > 0) {
|
||||
const acquiredDevices = affectedDevices.filter(d => !d.unacquired && d.state);
|
||||
newState.devices = otherDevices.concat( acquiredDevices.map(d => {
|
||||
d.connected = false;
|
||||
d.available = false;
|
||||
d.isUsedElsewhere = false;
|
||||
d.featuresNeedsReload = false;
|
||||
d.acquiring = false;
|
||||
@ -261,7 +315,7 @@ const forgetDevice = (state: State, action: any): State => {
|
||||
} else {
|
||||
// remove all instances after disconnect (remember request declined)
|
||||
//newState.devices = state.devices.filter(d => d.path !== action.device.path);
|
||||
newState.devices = state.devices.filter(d => (d.features && d.features.device_id !== action.device.features.device_id) || (!d.features && d.path !== action.device.path));
|
||||
newState.devices = state.devices.filter(d => d.remember || (d.features && d.features.device_id !== action.device.features.device_id) || (!d.features && d.path !== action.device.path));
|
||||
}
|
||||
|
||||
return newState;
|
||||
@ -272,6 +326,7 @@ const devicesFromLocalStorage = (devices: Array<any>): Array<TrezorDevice> => {
|
||||
return {
|
||||
...d,
|
||||
connected: false,
|
||||
available: false,
|
||||
path: '',
|
||||
acquiring: false,
|
||||
featuresNeedsReload: false,
|
||||
@ -282,24 +337,33 @@ const devicesFromLocalStorage = (devices: Array<any>): Array<TrezorDevice> => {
|
||||
|
||||
const duplicate = (state: State, device: any): State => {
|
||||
const newState: State = { ...state };
|
||||
const affectedDevices: Array<TrezorDevice> = state.devices.filter(d => d.path === device.path);
|
||||
const affectedDevices: Array<TrezorDevice> = state.devices.filter(d => d.features.device_id === device.features.device_id);
|
||||
const instance = affectedDevices.reduce((inst, dev) => {
|
||||
console.warn("REDUC", inst, dev);
|
||||
return dev.instance ? dev.instance + 1 : inst;
|
||||
}, 1);
|
||||
|
||||
console.warn("NEEEW INST", instance);
|
||||
|
||||
// if (affectedDevices.length > 0) {
|
||||
|
||||
const newDevice: TrezorDevice = {
|
||||
...device,
|
||||
state: null,
|
||||
remember: device.remember,
|
||||
acquiring: false,
|
||||
remember: false,
|
||||
connected: device.connected,
|
||||
available: device.available,
|
||||
path: device.path,
|
||||
label: device.label,
|
||||
instance: new Date().getTime(),
|
||||
instanceLabel: device.instanceLabel,
|
||||
ts: 0,
|
||||
state: null,
|
||||
instance,
|
||||
instanceLabel: `${device.label} (${instance})`,
|
||||
ts: new Date().getTime(),
|
||||
}
|
||||
newState.devices.push(newDevice);
|
||||
newState.selectedDevice = {
|
||||
id: newDevice.features.device_id,
|
||||
instance: newDevice.instance
|
||||
instance
|
||||
}
|
||||
//}
|
||||
|
||||
@ -307,6 +371,19 @@ const duplicate = (state: State, device: any): State => {
|
||||
}
|
||||
|
||||
|
||||
const onSelectDevice = (state: State, action: any): State => {
|
||||
const newState: State = { ...state };
|
||||
newState.selectedDevice = action.payload;
|
||||
|
||||
const selected = findSelectedDevice(newState);
|
||||
if (selected) {
|
||||
selected.ts = new Date().getTime();
|
||||
console.warn("APDEJT SELECTED!", selected.instanceLabel, selected.ts)
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
|
||||
export default function connect(state: State = initialState, action: any): any {
|
||||
|
||||
@ -323,10 +400,11 @@ export default function connect(state: State = initialState, action: any): any {
|
||||
|
||||
|
||||
case CONNECT.SELECT_DEVICE :
|
||||
return {
|
||||
...state,
|
||||
selectedDevice: action.payload
|
||||
}
|
||||
return onSelectDevice(state, action);
|
||||
// return {
|
||||
// ...state,
|
||||
// selectedDevice: action.payload
|
||||
// }
|
||||
|
||||
case CONNECT.INITIALIZATION_ERROR :
|
||||
return {
|
||||
@ -378,7 +456,7 @@ export default function connect(state: State = initialState, action: any): any {
|
||||
return disconnectDevice(state, action.device);
|
||||
|
||||
case DEVICE.CHANGED :
|
||||
return changeDevice(state, { ...action.device, connected: true });
|
||||
return changeDevice(state, { ...action.device, connected: true, available: true });
|
||||
|
||||
default:
|
||||
return state;
|
||||
|
@ -1,26 +1,44 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import { ON_RESIZE, TOGGLE_DEVICE_DROPDOWN, RESIZE_CONTAINER } from '../actions/AppActions';
|
||||
import * as WEB3 from '../actions/constants/Web3';
|
||||
|
||||
const WIDTH: number = 1080;
|
||||
const HEIGHT: number = 1920;
|
||||
import * as WALLET from '../actions/constants/wallet';
|
||||
|
||||
type State = {
|
||||
network: string;
|
||||
device: string;
|
||||
|
||||
ready: boolean;
|
||||
dropdownOpened: boolean;
|
||||
initialUrl: boolean;
|
||||
}
|
||||
|
||||
const initialState: Object = {
|
||||
|
||||
ready: false,
|
||||
dropdownOpened: false,
|
||||
initialParams: null,
|
||||
initialPathname: null,
|
||||
};
|
||||
|
||||
export default function wallet(state: Object = initialState, action: Object): any {
|
||||
switch(action.type) {
|
||||
|
||||
|
||||
case WALLET.SET_INITIAL_URL :
|
||||
return {
|
||||
...state,
|
||||
initialParams: action.params,
|
||||
initialPathname: action.pathname
|
||||
}
|
||||
|
||||
case WEB3.READY :
|
||||
return {
|
||||
...state,
|
||||
ready: true
|
||||
}
|
||||
|
||||
case WALLET.TOGGLE_DEVICE_DROPDOWN :
|
||||
return {
|
||||
...state,
|
||||
dropdownOpened: action.opened
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import { routerReducer } from 'react-router-redux';
|
||||
|
||||
import DOM from './AppReducer.js';
|
||||
import log from './LogReducer.js';
|
||||
import localStorage from './LocalStorageReducer.js';
|
||||
import connect from './TrezorConnectReducer.js';
|
||||
@ -12,7 +11,7 @@ import notifications from './NotificationReducer.js';
|
||||
import modal from './ModalReducer.js';
|
||||
import web3 from './Web3Reducer.js';
|
||||
import accounts from './AccountsReducer.js';
|
||||
import accountDetail from './AccountDetailReducer.js';
|
||||
import abstractAccount from './AbstractAccountReducer.js';
|
||||
import sendForm from './SendFormReducer.js';
|
||||
import receive from './ReceiveReducer.js';
|
||||
import summary from './SummaryReducer.js';
|
||||
@ -20,10 +19,10 @@ import tokens from './TokensReducer.js';
|
||||
import discovery from './DiscoveryReducer.js';
|
||||
import pending from './PendingTxReducer.js';
|
||||
import fiat from './FiatRateReducer.js';
|
||||
import wallet from './WalletReducer.js';
|
||||
|
||||
export default combineReducers({
|
||||
router: routerReducer,
|
||||
DOM,
|
||||
log,
|
||||
localStorage,
|
||||
connect,
|
||||
@ -31,12 +30,13 @@ export default combineReducers({
|
||||
modal,
|
||||
web3,
|
||||
accounts,
|
||||
accountDetail,
|
||||
abstractAccount,
|
||||
sendForm,
|
||||
receive,
|
||||
summary,
|
||||
tokens,
|
||||
discovery,
|
||||
pending,
|
||||
fiat
|
||||
fiat,
|
||||
wallet
|
||||
});
|
@ -7,23 +7,18 @@ import { Provider } from 'react-redux';
|
||||
import { ConnectedRouter } from 'react-router-redux';
|
||||
import store, { history } from '../store';
|
||||
|
||||
import {
|
||||
LandingPageContainer,
|
||||
WalletContainer,
|
||||
import LandingPageContainer from '../components/landing';
|
||||
import WalletContainer from '../components/wallet';
|
||||
import BootloaderContainer from '../components/wallet/Bootloader';
|
||||
import AcquireContainer from '../components/wallet/Acquire';
|
||||
|
||||
AcquireContainer,
|
||||
BootloaderContainer,
|
||||
|
||||
DashboardContainer,
|
||||
|
||||
HistoryContainer,
|
||||
SendFormContainer,
|
||||
ReceiveContainer,
|
||||
SignVerifyContainer,
|
||||
SettingsContainer,
|
||||
} from '../containers';
|
||||
|
||||
import SummaryContainer from '../components/wallet/summary/SummaryContainer';
|
||||
import DashboardContainer from '../components/wallet/Dashboard';
|
||||
import SummaryContainer from '../components/wallet/summary';
|
||||
import SendFormContainer from '../components/wallet/send';
|
||||
import ReceiveContainer from '../components/wallet/Receive';
|
||||
import SignVerifyContainer from '../components/wallet/SignVerify';
|
||||
import DeviceSettingsContainer from '../components/wallet/DeviceSettings';
|
||||
import WalletSettingsContainer from '../components/wallet/WalletSettings';
|
||||
|
||||
export default (
|
||||
<Provider store={ store }>
|
||||
@ -34,20 +29,19 @@ export default (
|
||||
<Route exact path="/import" component={ LandingPageContainer } />
|
||||
<Route>
|
||||
<WalletContainer>
|
||||
<Route exact path="/settings" component={ WalletSettingsContainer } />
|
||||
<Route exact path="/device/:device/" component={ DashboardContainer } />
|
||||
<Route exact path="/device/:device/network/:network" component={ DashboardContainer } />
|
||||
<Route exact path="/device/:device/acquire" component={ AcquireContainer } />
|
||||
<Route exact path="/device/:device/bootloader" component={ BootloaderContainer } />
|
||||
<Route exact path="/device/:device/settings" component={ DeviceSettingsContainer } />
|
||||
<Route exact path="/device/:device/network/:network/address/:address" component={ SummaryContainer } />
|
||||
<Route path="/device/:device/network/:network/address/:address/send" component={ SendFormContainer } />
|
||||
<Route path="/device/:device/network/:network/address/:address/send/override" component={ SendFormContainer } />
|
||||
<Route path="/device/:device/network/:network/address/:address/receive" component={ ReceiveContainer } />
|
||||
<Route path="/device/:device/network/:network/address/:address/signverify" component={ SignVerifyContainer } />
|
||||
{/* <Route path="/device/:device/address/:address/history" component={ HistoryContainer } /> */}
|
||||
|
||||
</WalletContainer>
|
||||
</Route>
|
||||
<Route path="/settings" component={ SettingsContainer } />
|
||||
</Switch>
|
||||
</ConnectedRouter>
|
||||
</Provider>
|
||||
|
@ -1,174 +0,0 @@
|
||||
/* @flo */
|
||||
'use strict';
|
||||
|
||||
//http://ropsten.etherscan.io/api?module=account&action=txlist&address=0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad&startblock=0&endblock=99999999&sort=asc&apikey=89IZG471H8ITVXY377I2QWJIT2D62DGG9Z
|
||||
|
||||
import { LOCATION_CHANGE, push } from 'react-router-redux';
|
||||
import { httpRequest } from '../utils/networkUtils';
|
||||
import * as ACTIONS from '../actions/index';
|
||||
import { getBalance } from '../actions/Web3Actions';
|
||||
|
||||
const API_KEY: string = '89IZG471H8ITVXY377I2QWJIT2D62DGG9Z';
|
||||
//const API: string = `http://ropsten.etherscan.io/api?module=account&action=txlist&startblock=0&endblock=99999999&sort=asc&apikey=89IZG471H8ITVXY377I2QWJIT2D62DGG9Z`;
|
||||
const API: string = `http://ropsten.etherscan.io/api?module=account&action=txlist&startblock=0&endblock=99999999&sort=desc&apikey=${API_KEY}`;
|
||||
|
||||
export const getTransactionHistory = async (address: string): Promise<Array<any>> => {
|
||||
const json = await httpRequest(`${API}&address=${address}`);
|
||||
return json;
|
||||
}
|
||||
|
||||
const getTransactionStatus = async (txid: string): Promise<Array<any>> => {
|
||||
//https://ropsten.etherscan.io/api?module=proxy&action=eth_getTransactionByHash&txhash=0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1&apikey=YourApiKeyToken
|
||||
const url: string = `https://ropsten.etherscan.io/api?module=proxy&action=eth_getTransactionByHash&apikey=${API_KEY}`
|
||||
//const url: string = `https://ropsten.etherscan.io/api?module=transaction&action=getstatus&apikey=${API_KEY}`
|
||||
const json = await httpRequest(`${url}&txhash=${txid}`);
|
||||
return json;
|
||||
}
|
||||
|
||||
const getTokenHistory = async (tokenAddress, address) => {
|
||||
|
||||
// 0x58cda554935e4a1f2acbe15f8757400af275e084
|
||||
// 0x000000000000000000000000 + 98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad
|
||||
let url: string = 'https://ropsten.etherscan.io/api?module=logs&action=getLogs';
|
||||
url += '&fromBlock=0&toBlock=latest';
|
||||
url += `&address=${tokenAddress}`;
|
||||
url += '&topic0=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
|
||||
url += `&topic2=${ address }`;
|
||||
// https://api.etherscan.io/api?module=logs&action=getLogs
|
||||
// &fromBlock=0
|
||||
// &toBlock=latest
|
||||
// &address=[Token Contract Address]
|
||||
// &topic0=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
|
||||
// &topic1=[From Address, padded to 32 bytes - optional]
|
||||
// &topic2=[To Address, padded to 32 bytes - optional]
|
||||
|
||||
console.log("TOKENURL", url);
|
||||
const json = await httpRequest(url);
|
||||
return json;
|
||||
}
|
||||
|
||||
export const loadTokenHistory = (address): Promise<any> => {
|
||||
// https://ropsten.etherscan.io/apis#logs
|
||||
return async (dispatch, getState): Promise<any> => {
|
||||
const tkn = '0x58cda554935e4a1f2acbe15f8757400af275e084';
|
||||
const ad = '0x00000000000000000000000098ead4bd2fbbb0cf0b49459aa0510ef53faa6cad';
|
||||
const incoming = await getTokenHistory(tkn, ad);
|
||||
|
||||
console.log("TOKEN HIST!", JSON.parse(incoming) );
|
||||
}
|
||||
}
|
||||
|
||||
export const loadTransactionStatus = (txid): Promise<any> => {
|
||||
return async (dispatch, getState): Promise<any> => {
|
||||
const json = await getTransactionStatus(txid);
|
||||
const status = JSON.parse(json);
|
||||
|
||||
console.error("TXSTAT", status)
|
||||
|
||||
if (status.result.blockHash) {
|
||||
// find address with pending tx
|
||||
const { addresses } = getState().addresses;
|
||||
for (let addr of addresses) {
|
||||
if (addr.findPendingTx(txid)) {
|
||||
dispatch( getBalance(addr) );
|
||||
|
||||
const txType = status.result.from === addr.address ? 'out' : 'in';
|
||||
const txAddress = txType === 'out' ? status.result.to : status.result.from;
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.ADDRESS_ADD_TO_HISTORY,
|
||||
address: addr,
|
||||
entry: {
|
||||
txid: status.result.hash,
|
||||
type: txType,
|
||||
timestamp: '0',
|
||||
address: txAddress,
|
||||
value: status.result.value
|
||||
}
|
||||
});
|
||||
|
||||
//dispatch( loadHistory(addr, 3000) );
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.TX_STATUS_OK,
|
||||
txid
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
// if (status.status === "1" && status.message === "OK") {
|
||||
// if (status.result.isError === "0") {
|
||||
// dispatch({
|
||||
// type: ACTIONS.TX_STATUS_OK,
|
||||
// txid
|
||||
// });
|
||||
// } else {
|
||||
// dispatch({
|
||||
// type: ACTIONS.TX_STATUS_ERROR,
|
||||
// txid,
|
||||
// error: status.errDescription
|
||||
// });
|
||||
// }
|
||||
// } else {
|
||||
// dispatch({
|
||||
// type: ACTIONS.TX_STATUS_UNKNOWN,
|
||||
// txid,
|
||||
// status
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
export const loadHistory = (address, delay): void => {
|
||||
return async (dispatch, getState) => {
|
||||
|
||||
// const json = await getTransactionStatus('0x2113e578497f3486944566e2417b5ac3b31d7e76f71557ae0626e2a6fe191e58');
|
||||
// console.log("JSON!", json)
|
||||
|
||||
/*
|
||||
if (delay) {
|
||||
console.warn("-----PRELOAD with delay", address)
|
||||
await new Promise(resolve => {
|
||||
setTimeout(resolve, delay);
|
||||
})
|
||||
}
|
||||
|
||||
const history = await getTransactionHistory(address.address);
|
||||
dispatch({
|
||||
type: ACTIONS.ADDRESS_SET_HISTORY,
|
||||
address,
|
||||
history
|
||||
});
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
const EtherscanService = store => next => action => {
|
||||
|
||||
next(action);
|
||||
|
||||
if (action.type === LOCATION_CHANGE) {
|
||||
|
||||
const { location } = store.getState().router;
|
||||
const { addresses } = store.getState().addresses;
|
||||
|
||||
if (location) {
|
||||
const parts = location.pathname.split("/");
|
||||
if (parts.length === 3 && parts[1] === "address") {
|
||||
const addressId = parseInt(parts[2]);
|
||||
|
||||
if (!isNaN(addressId) && addresses[addressId]) {
|
||||
//store.dispatch( loadHistory( addresses[addressId] ) );
|
||||
//store.dispatch( loadTokenHistory( addresses[addressId] ) );
|
||||
}
|
||||
|
||||
//console.error("ETH", parts, "id", parts.length, parts.length === 3 && parts[1] === "address");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default EtherscanService;
|
@ -111,6 +111,7 @@ const LocalStorageService = (store: any) => (next: any) => (action: any) => {
|
||||
case DEVICE.CHANGED :
|
||||
case DEVICE.DISCONNECT :
|
||||
case CONNECT.AUTH_DEVICE :
|
||||
case CONNECT.SELECT_DEVICE :
|
||||
save(store.dispatch, store.getState);
|
||||
//store.dispatch( LocalStorageActions.save('devices', JSON.stringify( store.getState().connect.devices.filter(d => d.remember === true && !d.unacquired) ) ) );
|
||||
// store.dispatch( LocalStorageActions.save('selectedDevice', JSON.stringify( store.getState().connect.selectedDevice ) ) );
|
||||
|
@ -4,8 +4,9 @@
|
||||
import pathToRegexp from 'path-to-regexp';
|
||||
import { DEVICE } from 'trezor-connect';
|
||||
import { LOCATION_CHANGE, push, replace } from 'react-router-redux';
|
||||
import { ON_BEFORE_UNLOAD } from '../actions/AppActions';
|
||||
import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||
import * as WALLET from '../actions/constants/wallet';
|
||||
import * as NotificationActions from '../actions/NotificationActions';
|
||||
|
||||
/**
|
||||
* Middleware used for init application and managing router path.
|
||||
@ -66,25 +67,25 @@ let __unloading: boolean = false;
|
||||
|
||||
const RouterService = (store: any) => (next: any) => (action: any) => {
|
||||
|
||||
if (action.type === ON_BEFORE_UNLOAD) {
|
||||
if (action.type === WALLET.ON_BEFORE_UNLOAD) {
|
||||
__unloading = true;
|
||||
} else if (action.type === LOCATION_CHANGE && !__unloading) {
|
||||
|
||||
const { location } = store.getState().router;
|
||||
const web3 = store.getState().web3;
|
||||
const { devices, error } = store.getState().connect;
|
||||
const { opened } = store.getState().modal;
|
||||
const isModalOpened: boolean = store.getState().modal.opened;
|
||||
|
||||
let redirectPath: ?string;
|
||||
// first (initial) event after app loads
|
||||
// first event after application loads
|
||||
if (!location) {
|
||||
|
||||
action.payload.state = {
|
||||
initURL: action.payload.pathname,
|
||||
initSearch: action.payload.search
|
||||
}
|
||||
|
||||
// check if there are initial parameters in url (network/ device / account)
|
||||
store.dispatch({
|
||||
type: WALLET.SET_INITIAL_URL,
|
||||
pathname: action.payload.pathname,
|
||||
params: pathToParams(action.payload.pathname)
|
||||
});
|
||||
|
||||
if (action.payload.search.length > 0) {
|
||||
// save it in WalletReducer, after device detection will redirect to this request
|
||||
redirectPath = '/';
|
||||
@ -98,7 +99,7 @@ const RouterService = (store: any) => (next: any) => (action: any) => {
|
||||
// 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;
|
||||
|
||||
if (opened && action.payload.pathname !== location.pathname) {
|
||||
if (isModalOpened && action.payload.pathname !== location.pathname) {
|
||||
redirectPath = location.pathname;
|
||||
console.warn("Modal still opened");
|
||||
} else if (landingPage) {
|
||||
@ -113,7 +114,7 @@ const RouterService = (store: any) => (next: any) => (action: any) => {
|
||||
// TODO: switch to first device?
|
||||
// redirectPath = `/device/${ devices[0].path }`;
|
||||
redirectPath = location.pathname;
|
||||
} else {
|
||||
} else if (requestedParams.device) {
|
||||
|
||||
if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) {
|
||||
store.dispatch({
|
||||
@ -146,7 +147,8 @@ const RouterService = (store: any) => (next: any) => (action: any) => {
|
||||
} else {
|
||||
action.payload.params = requestedParams;
|
||||
}
|
||||
|
||||
|
||||
store.dispatch( NotificationActions.clear(currentParams, requestedParams) );
|
||||
}
|
||||
|
||||
// Pass all actions through by default
|
||||
|
@ -11,13 +11,14 @@ import * as WEB3 from '../actions/constants/Web3';
|
||||
import * as STORAGE from '../actions/constants/LocalStorage';
|
||||
import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||
import * as NOTIFICATION from '../actions/constants/notification';
|
||||
import * as ACTIONS from '../actions';
|
||||
import * as MODAL from '../actions/constants/Modal';
|
||||
|
||||
|
||||
const TrezorConnectService = (store: any) => (next: any) => (action: any) => {
|
||||
|
||||
const prevState = store.getState().connect;
|
||||
const prevModalState = store.getState().modal;
|
||||
const prevRouterState = store.getState().router;
|
||||
|
||||
next(action);
|
||||
|
||||
@ -25,8 +26,14 @@ const TrezorConnectService = (store: any) => (next: any) => (action: any) => {
|
||||
store.dispatch( TrezorConnectActions.init() );
|
||||
|
||||
} else if (action.type === TRANSPORT.ERROR) {
|
||||
store.dispatch( push('/') );
|
||||
} else if (action.type === TRANSPORT.START && store.getState().web3.length > 0 && prevState.devices.length > 0) {
|
||||
// TODO: check if modal is open
|
||||
// store.dispatch( push('/') );
|
||||
// } else if (action.type === TRANSPORT.START && store.getState().web3.length > 0 && prevState.devices.length > 0) {
|
||||
// store.dispatch( TrezorConnectActions.postInit() );
|
||||
} else if (action.type === TRANSPORT.START && store.getState().web3.length < 1) {
|
||||
//store.dispatch( TrezorConnectActions.postInit() );
|
||||
store.dispatch( initWeb3() );
|
||||
} else if (action.type === WEB3.READY) {
|
||||
store.dispatch( TrezorConnectActions.postInit() );
|
||||
} else if (action.type === TRANSPORT.UNREADABLE) {
|
||||
store.dispatch({
|
||||
@ -34,22 +41,16 @@ const TrezorConnectService = (store: any) => (next: any) => (action: any) => {
|
||||
payload: {
|
||||
type: 'error',
|
||||
title: 'Unreadable HID device',
|
||||
message: 'What to do?',
|
||||
message: '',
|
||||
cancelable: true,
|
||||
}
|
||||
})
|
||||
|
||||
} else if (action.type === WEB3.READY) {
|
||||
store.dispatch( TrezorConnectActions.postInit() );
|
||||
|
||||
});
|
||||
} else if (action.type === DEVICE.DISCONNECT) {
|
||||
store.dispatch( TrezorConnectActions.deviceDisconnect(action.device) );
|
||||
|
||||
} else if (action.type === CONNECT.REMEMBER_REQUEST) {
|
||||
// TODO:
|
||||
// TODO: 2 modals at once
|
||||
if (prevModalState.opened && prevModalState.windowType === CONNECT.REMEMBER_REQUEST) {
|
||||
|
||||
|
||||
store.dispatch({
|
||||
type: CONNECT.FORGET,
|
||||
device: store.getState().modal.device
|
||||
@ -82,6 +83,7 @@ const TrezorConnectService = (store: any) => (next: any) => (action: any) => {
|
||||
// we need to change route
|
||||
if (prevState.selectedDevice) {
|
||||
if (!action.device.unacquired && action.device.path === prevState.selectedDevice.id) {
|
||||
console.warn("TODO: here! better")
|
||||
store.dispatch( TrezorConnectActions.onSelectDevice(action.device) );
|
||||
}
|
||||
}
|
||||
@ -96,7 +98,7 @@ const TrezorConnectService = (store: any) => (next: any) => (action: any) => {
|
||||
if (modal.opened && modal.windowType === CONNECT.REMEMBER_REQUEST) {
|
||||
if (action.device.features && modal.device.features.device_id === action.device.features.device_id) {
|
||||
store.dispatch({
|
||||
type: ACTIONS.CLOSE_MODAL,
|
||||
type: MODAL.CLOSE,
|
||||
});
|
||||
} else {
|
||||
store.dispatch({
|
||||
@ -113,6 +115,7 @@ const TrezorConnectService = (store: any) => (next: any) => (action: any) => {
|
||||
store.dispatch( TrezorConnectActions.onDuplicateDevice() );
|
||||
|
||||
} else if (action.type === DEVICE.ACQUIRED || action.type === CONNECT.SELECT_DEVICE) {
|
||||
console.warn("here!!!!!", action.type)
|
||||
store.dispatch( TrezorConnectActions.getSelectedDeviceState() );
|
||||
|
||||
} else if (action.type === CONNECT.COIN_CHANGED) {
|
||||
|
@ -1,238 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import Web3 from 'web3';
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import * as ACTIONS from '../actions/index';
|
||||
import { getBalance, getGasPrice, getTransactionReceipt } from '../actions/Web3Actions';
|
||||
import { loadTransactionStatus } from './EtherscanService';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
let web3: Web3;
|
||||
|
||||
// export const getGasPrice = (): Promise<BigNumber> => {
|
||||
// return (dispatch, getState) => {
|
||||
// web3.eth.getGasPrice((error, gasPrice) => {
|
||||
// if (!error) {
|
||||
// dispatch({
|
||||
// type: 'update_gas',
|
||||
// gasPrice: web3.fromWei(gasPrice.toString(), 'gwei')
|
||||
// })
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
const Web3Service = store => next => action => {
|
||||
|
||||
next(action);
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
case 'WEB_2_START' :
|
||||
if (web3) break;
|
||||
|
||||
//web3 = new Web3(window.web3.currentProvider);
|
||||
//web3 = new Web3(new Web3.providers.HttpProvider("https://api.myetherapi.com/rop"));
|
||||
web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io2/QGyVKozSUEh2YhL4s2G4"));
|
||||
//web3 = new Web3( new Web3.providers.HttpProvider("ws://34.230.234.51:30303") );
|
||||
|
||||
|
||||
|
||||
|
||||
/*store.dispatch( getGasPrice() );
|
||||
|
||||
|
||||
const latestBlockFilter = web3.eth.filter('latest');
|
||||
latestBlockFilter.watch((error, blockHash) => {
|
||||
|
||||
const { addresses, pendingTxs } = store.getState().addresses;
|
||||
|
||||
for (const addr of addresses) {
|
||||
store.dispatch( getBalance(addr) );
|
||||
}
|
||||
|
||||
store.dispatch( getGasPrice() );
|
||||
|
||||
if (pendingTxs.length > 0) {
|
||||
for (const tx of pendingTxs) {
|
||||
store.dispatch( getTransactionReceipt(tx) );
|
||||
}
|
||||
}
|
||||
});*/
|
||||
|
||||
|
||||
|
||||
// store.dispatch({
|
||||
// type: 'web3__init',
|
||||
// web3
|
||||
// });
|
||||
|
||||
// store.dispatch({
|
||||
// type: 'update_gas',
|
||||
// gasPrice: web3.fromWei(web3.eth.gasPrice, 'gwei')
|
||||
// })
|
||||
|
||||
/*
|
||||
{
|
||||
"dd62ed3e": "allowance(address,address)",
|
||||
"095ea7b3": "approve(address,uint256)",
|
||||
"cae9ca51": "approveAndCall(address,uint256,bytes)",
|
||||
"70a08231": "balanceOf(address)",
|
||||
"313ce567": "decimals()",
|
||||
"06fdde03": "name()",
|
||||
"95d89b41": "symbol()",
|
||||
"18160ddd": "totalSupply()",
|
||||
"a9059cbb": "transfer(address,uint256)",
|
||||
"23b872dd": "transferFrom(address,address,uint256)",
|
||||
"54fd4d50": "version()"
|
||||
}*/
|
||||
|
||||
// var balanceHex = "06fdde03"; // I believe this is the hex for balance
|
||||
// var contractAddress = "0x58cda554935e4a1f2acbe15f8757400af275e084";
|
||||
// var userAddress = "0x5DBB9793537515398A1176d365b636A5321D9e39";
|
||||
// var balanceCall = getDataObj(contractAddress, balanceHex);
|
||||
// var balance = web3.eth.call(balanceCall);
|
||||
|
||||
|
||||
|
||||
|
||||
const abiArray = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}];
|
||||
//const contr = web3.eth.contract(abiArray, '0x58cda554935e4a1f2acbe15f8757400af275e084');
|
||||
const contr = web3.eth.contract(abiArray).at('0x58cda554935e4a1f2acbe15f8757400af275e084');
|
||||
console.log("contr", contr );
|
||||
|
||||
contr.name.call((e,r) => {
|
||||
console.log("nameeeee", e, r)
|
||||
})
|
||||
|
||||
contr.symbol.call((e,r) => {
|
||||
console.log("symboll", e, r)
|
||||
})
|
||||
|
||||
//console.log( const.name )
|
||||
|
||||
// contr.balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => {
|
||||
// console.warn('contrR', e, r.toString(10));
|
||||
// });
|
||||
|
||||
let cntrData = contr.transfer.getData("0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad", 1, {
|
||||
from: "0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad",
|
||||
gasLimit: 36158,
|
||||
gasPrice: "0x0ee6b28000"
|
||||
})
|
||||
|
||||
console.log("contr", cntrData);
|
||||
// const data = contr.transferFrom(
|
||||
// '0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad',
|
||||
// '0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad',
|
||||
// 1
|
||||
// );
|
||||
|
||||
// const data = contr.transferFrom(
|
||||
// '0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad',
|
||||
// {
|
||||
// from: '0x7314e0f1c0e28474bdb6be3e2c3e0453255188f8',
|
||||
// value: 1
|
||||
// }
|
||||
// );
|
||||
|
||||
// const data = contr.transferFrom(
|
||||
// '0x00000000000000000000000098ead4bd2fbbb0cf0b49459aa0510ef53faa6cad',
|
||||
// '0x000000000000000000000000a738ea40b69d87f4f9ac94c9a0763f96248df23b',
|
||||
// 2
|
||||
// );
|
||||
//console.log("contr", contr, data)
|
||||
|
||||
// var addr1 = '0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad';
|
||||
// var contractAddr = '0x58cda554935e4a1f2acbe15f8757400af275e084';
|
||||
// var tknAddress = (addr1).substring(2);
|
||||
// var contractData = ('0x70a08231000000000000000000000000' + tknAddress);
|
||||
|
||||
// console.warn("ADDDDDDDD", web3.toHex('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad'));
|
||||
// console.warn("ADDDDDDDD", web3.toHex('98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad'));
|
||||
|
||||
// web3.eth.call({
|
||||
// to: contractAddr,
|
||||
// data: contractData
|
||||
// }, function(err, result) {
|
||||
// if (result) {
|
||||
// console.log("---------result", result, web3);
|
||||
// //var tokens = web3.toBN(result).toString();
|
||||
// //console.log('Tokens Owned: ' + web3.utils.fromWei(tokens, 'ether'));
|
||||
// }
|
||||
// else {
|
||||
// console.log(err); // Dump errors here
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
|
||||
/*
|
||||
const pendingBlockFilter = web3.eth.filter('pending');
|
||||
pendingBlockFilter.watch((error, txid) => {
|
||||
//console.warn("Watch pending block", txid, error)
|
||||
if (!error) {
|
||||
|
||||
if (pendingTx.length > 0) {
|
||||
console.error("Watch pending block", pendingTx.indexOf(txid))
|
||||
}
|
||||
|
||||
web3.eth.getTransactionReceipt(txid, async (error, tx) => {
|
||||
if (!error && typeof tx === 'object') {
|
||||
const { addresses } = store.getState().addresses;
|
||||
const receiver = addresses.find(a => a.address === tx.to);
|
||||
if (receiver) {
|
||||
console.error("PendingTX RECV", txid, tx, receiver)
|
||||
const balance = await getBalance(receiver.address);
|
||||
store.dispatch({
|
||||
type: ACTIONS.ADDRESS_SET_BALANCE,
|
||||
txid,
|
||||
address: receiver,
|
||||
balance: web3.fromWei(balance.toString(), 'ether')
|
||||
})
|
||||
}
|
||||
const sender = addresses.find(a => a.address === tx.from);
|
||||
if (sender) {
|
||||
const balance = await getBalance(sender.address);
|
||||
store.dispatch({
|
||||
type: ACTIONS.ADDRESS_SET_BALANCE,
|
||||
txid,
|
||||
address: sender,
|
||||
balance: web3.fromWei(balance.toString(), 'ether')
|
||||
})
|
||||
}
|
||||
|
||||
//console.log("PendingTX", txid, tx, receiver, sender)
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
//"web3": "^0.19.0"
|
||||
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
export default Web3Service;
|
||||
|
||||
|
||||
export const estimateGas = (gasOptions): Promise<any> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
web3.eth.estimateGas(gasOptions, (error, result) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
@ -5,14 +5,10 @@ import RouterService from './RouterService';
|
||||
import LocalStorageService from './LocalStorageService';
|
||||
import CoinmarketcapService from './CoinmarketcapService';
|
||||
import TrezorConnectService from './TrezorConnectService';
|
||||
import Web3Service from './Web3Service';
|
||||
import EtherscanService from './EtherscanService';
|
||||
|
||||
export default [
|
||||
RouterService,
|
||||
LocalStorageService,
|
||||
TrezorConnectService,
|
||||
Web3Service,
|
||||
CoinmarketcapService,
|
||||
//EtherscanService,
|
||||
];
|
@ -9,4 +9,9 @@ export const getAccounts = (accounts: Array<any>, device: any, network: ?string)
|
||||
return accounts.filter((addr) => addr.deviceState === device.state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Public method used in components to find device by state and device_id
|
||||
export const findDevice = (devices: Array<TrezorDevice>, state: ?string, deviceId: ?string, instance: ?string): ?TrezorDevice => {
|
||||
return devices.find(d => d.state === state && d.features && d.features.device_id === deviceId && d.instance === instance);
|
||||
}
|
@ -95,6 +95,8 @@ aside {
|
||||
margin: 12px 0px 12px 80px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.device-select {
|
||||
background: @color_white;
|
||||
border-bottom: 1px solid @color_divider;
|
||||
@ -246,6 +248,56 @@ aside {
|
||||
|
||||
}
|
||||
|
||||
.device-menu {
|
||||
padding: 8px 0px;
|
||||
// padding-left: 80px;
|
||||
padding-left: 74px;
|
||||
border-bottom: 1px solid @color_divider;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
color: @color_text_secondary;
|
||||
.hover();
|
||||
|
||||
&:before {
|
||||
.icomoon-refresh;
|
||||
// color: @color_text_secondary;
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
margin-right: 12px;
|
||||
.hover();
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @color_text_primary;
|
||||
// &:before {
|
||||
// color: @color_text_primary;
|
||||
// }
|
||||
}
|
||||
|
||||
&.forget {
|
||||
&:before {
|
||||
.icomoon-eject;
|
||||
}
|
||||
}
|
||||
|
||||
&.clone {
|
||||
&:before {
|
||||
.icomoon-settings;
|
||||
}
|
||||
}
|
||||
|
||||
&.settings {
|
||||
&:before {
|
||||
.icomoon-settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
display: block;
|
||||
@ -391,12 +443,12 @@ aside {
|
||||
}
|
||||
|
||||
&.ropsten:before,
|
||||
&.eth:before {
|
||||
&.ethereum:before {
|
||||
background-image: url('../images/eth-logo.png');
|
||||
background-size: auto 20px;
|
||||
}
|
||||
&.rinkeby:before,
|
||||
&.etc:before {
|
||||
&.ethereum-classic:before {
|
||||
background-image: url('../images/etc-logo.png');
|
||||
background-size: auto 20px;
|
||||
}
|
||||
|
@ -169,5 +169,6 @@
|
||||
|
||||
.icomoon-download {
|
||||
.icomoon-base();
|
||||
content: "\e91f";
|
||||
content: "\e91b";
|
||||
transform: rotate(180deg)
|
||||
}
|
||||
|
@ -180,7 +180,7 @@
|
||||
justify-content: space-between;
|
||||
padding: 36px 0px;
|
||||
margin: 0 auto;
|
||||
width: 420px;
|
||||
// width: 420px;
|
||||
|
||||
p {
|
||||
// flex: 1;
|
||||
@ -197,6 +197,18 @@
|
||||
// color: @color_green_secondary;
|
||||
// }
|
||||
// }
|
||||
.webusb-and,
|
||||
.trezor-webusb-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.webusb {
|
||||
width: 400px;
|
||||
.webusb-and,
|
||||
.trezor-webusb-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
|
@ -108,6 +108,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.duplicate,
|
||||
.remember {
|
||||
width: 360px;
|
||||
padding: 24px 48px;
|
||||
@ -137,6 +138,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.close-modal {
|
||||
position: absolute;
|
||||
|
@ -190,20 +190,23 @@
|
||||
|
||||
.advanced-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0px 48px;
|
||||
|
||||
padding-bottom: 24px;
|
||||
button {
|
||||
width: 50%;
|
||||
min-width: 50%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&.opened {
|
||||
flex-direction: column;
|
||||
padding: 0px;
|
||||
button {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
width: 50%;
|
||||
// left: 50%;
|
||||
// width: 50%;
|
||||
float: right; // TODO: better
|
||||
}
|
||||
.advanced {
|
||||
display: inline-block;
|
||||
@ -231,6 +234,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @media screen and (max-width: 900px) {
|
||||
// :not(.opened) {
|
||||
// border: 1px solid red;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,12 @@
|
||||
}
|
||||
|
||||
&.ropsten:before,
|
||||
&.eth:before {
|
||||
&.ethereum:before {
|
||||
background-image: url('../images/eth-logo.png');
|
||||
background-size: auto 20px;
|
||||
}
|
||||
&.rinkeby:before,
|
||||
&.etc:before {
|
||||
&.ethereum-classic:before {
|
||||
background-image: url('../images/etc-logo.png');
|
||||
background-size: auto 20px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user