mirror of
https://github.com/trezor/trezor-wallet
synced 2025-04-28 13:09:06 +00:00
Flowtype everywhere!
This commit is contained in:
parent
8aeb10cf2c
commit
c597f482dc
@ -1,3 +1,5 @@
|
|||||||
|
[include]
|
||||||
|
|
||||||
[ignore]
|
[ignore]
|
||||||
.*/node_modules/bitcoinjs-lib-zcash/.*
|
.*/node_modules/bitcoinjs-lib-zcash/.*
|
||||||
.*/node_modules/bitcoinjs-lib/.*
|
.*/node_modules/bitcoinjs-lib/.*
|
||||||
@ -9,7 +11,13 @@
|
|||||||
.*/src/solidity/.*
|
.*/src/solidity/.*
|
||||||
|
|
||||||
[libs]
|
[libs]
|
||||||
|
./src/js/flowtype/redux_v3.x.x.js
|
||||||
|
./src/js/flowtype/react-redux_v5.x.x.js
|
||||||
|
./src/js/flowtype/react-router_v4.x.x.js
|
||||||
|
./src/js/flowtype/react-router-dom_v4.x.x.js
|
||||||
|
./src/js/flowtype/react-router-redux.js
|
||||||
./src/js/flowtype/css.js
|
./src/js/flowtype/css.js
|
||||||
|
./src/js/flowtype/trezor-connect.js
|
||||||
|
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/szymonlesisz/trezor-connect-react-boilerplate/issues"
|
"url": "https://github.com/szymonlesisz/trezor-connect-react-boilerplate/issues"
|
||||||
},
|
},
|
||||||
|
"bin": {
|
||||||
|
"flow": "./node_modules/flow-bin"
|
||||||
|
},
|
||||||
"license": "LGPL-3.0+",
|
"license": "LGPL-3.0+",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "babel-node ./webpack/server.js --connect",
|
"dev": "babel-node ./webpack/server.js --connect",
|
||||||
@ -48,6 +51,7 @@
|
|||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-raven-middleware": "^1.2.0",
|
"redux-raven-middleware": "^1.2.0",
|
||||||
"redux-thunk": "^2.2.0",
|
"redux-thunk": "^2.2.0",
|
||||||
|
"trezor-connect": "^5.0.10",
|
||||||
"web3": "^0.19.0"
|
"web3": "^0.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -65,6 +69,7 @@
|
|||||||
"extract-text-webpack-plugin": "^3.0.0",
|
"extract-text-webpack-plugin": "^3.0.0",
|
||||||
"file-loader": "^1.1.9",
|
"file-loader": "^1.1.9",
|
||||||
"flow-bin": "^0.69.0",
|
"flow-bin": "^0.69.0",
|
||||||
|
"flow-typed": "^2.4.0",
|
||||||
"html-webpack-plugin": "^2.29.0",
|
"html-webpack-plugin": "^2.29.0",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"less": "^3.0.1",
|
"less": "^3.0.1",
|
||||||
|
@ -117,19 +117,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"bridge": {
|
|
||||||
"url": "https://localback.net:21324",
|
|
||||||
"configUrl": "data/config_signed.bin",
|
|
||||||
"latestUrl": "data/bridge/latest.txt"
|
|
||||||
},
|
|
||||||
"extensionId": "jcjjhjgimijdkoamemaghajlhegmoclj",
|
|
||||||
"storageVersion": "1.1.0",
|
|
||||||
"metadataVersion": "1.0.0",
|
|
||||||
|
|
||||||
|
|
||||||
"supportedBrowsers": {
|
"supportedBrowsers": {
|
||||||
"chrome": {
|
"chrome": {
|
||||||
"version": 59,
|
"version": 59,
|
||||||
|
@ -5,35 +5,51 @@ import * as ACCOUNT from './constants/account';
|
|||||||
|
|
||||||
import { initialState } from '../reducers/AbstractAccountReducer';
|
import { initialState } from '../reducers/AbstractAccountReducer';
|
||||||
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
||||||
import type { State } from '../reducers/AbstractAccountReducer';
|
|
||||||
|
|
||||||
export const init = (): any => {
|
import type { AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '../flowtype';
|
||||||
return (dispatch, getState): void => {
|
import type { State } from '../reducers/AbstractAccountReducer';
|
||||||
|
import type { Coin } from '../reducers/LocalStorageReducer';
|
||||||
|
|
||||||
|
export type AbstractAccountAction = {
|
||||||
|
type: typeof ACCOUNT.INIT,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof ACCOUNT.DISPOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const init = (): AsyncAction => {
|
||||||
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const { location } = getState().router;
|
const { location } = getState().router;
|
||||||
const urlParams = location.params;
|
const urlParams = location.state;
|
||||||
|
|
||||||
const selected = findSelectedDevice( getState().connect );
|
const selected: ?TrezorDevice = findSelectedDevice( getState().connect );
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
|
|
||||||
|
const { config } = getState().localStorage;
|
||||||
|
const coin: ?Coin = config.coins.find(c => c.network === urlParams.network);
|
||||||
|
if (!coin) return;
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
index: parseInt(urlParams.address),
|
index: parseInt(urlParams.address),
|
||||||
deviceState: selected.state,
|
deviceState: selected.state || '0',
|
||||||
deviceId: selected.features.device_id,
|
deviceId: selected.features ? selected.features.device_id : '0',
|
||||||
deviceInstance: selected.instance,
|
deviceInstance: selected.instance,
|
||||||
network: urlParams.network,
|
network: urlParams.network,
|
||||||
location: location.pathname
|
coin,
|
||||||
|
location: location.pathname,
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACCOUNT.INIT,
|
type: ACCOUNT.INIT,
|
||||||
state: state
|
state: state
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const update = (): any => {
|
export const update = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const {
|
const {
|
||||||
abstractAccount,
|
abstractAccount,
|
||||||
router
|
router
|
||||||
@ -46,10 +62,14 @@ export const update = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispose = (): any => {
|
export const dispose = (): Action => {
|
||||||
return (dispatch, getState): void => {
|
return {
|
||||||
dispatch({
|
type: ACCOUNT.DISPOSE
|
||||||
type: ACCOUNT.DISPOSE,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init,
|
||||||
|
update,
|
||||||
|
dispose
|
||||||
|
}
|
15
src/js/actions/AddressActions.js
Normal file
15
src/js/actions/AddressActions.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* @flow */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import * as ADDRESS from './constants/address';
|
||||||
|
|
||||||
|
export type AddressAction = {
|
||||||
|
type: typeof ADDRESS.CREATE,
|
||||||
|
payload: any
|
||||||
|
} | {
|
||||||
|
type: typeof ADDRESS.SET_BALANCE,
|
||||||
|
payload: any
|
||||||
|
} | {
|
||||||
|
type: typeof ADDRESS.SET_NONCE,
|
||||||
|
payload: any
|
||||||
|
}
|
@ -13,6 +13,16 @@ import HDKey from 'hdkey';
|
|||||||
import EthereumjsUtil from 'ethereumjs-util';
|
import EthereumjsUtil from 'ethereumjs-util';
|
||||||
import { getNonceAsync, getBalanceAsync, getTokenBalanceAsync } from './Web3Actions';
|
import { getNonceAsync, getBalanceAsync, getTokenBalanceAsync } from './Web3Actions';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export type DiscoveryAction = {
|
||||||
|
type: typeof DISCOVERY.START,
|
||||||
|
} | {
|
||||||
|
type: typeof DISCOVERY.STOP,
|
||||||
|
} | {
|
||||||
|
type: typeof DISCOVERY.COMPLETE,
|
||||||
|
};
|
||||||
|
|
||||||
export const start = (device: any, network: string, ignoreCompleted?: boolean): any => {
|
export const start = (device: any, network: string, ignoreCompleted?: boolean): any => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
|
|
||||||
@ -310,7 +320,7 @@ export const check = (): any => {
|
|||||||
const selected = findSelectedDevice(getState().connect);
|
const selected = findSelectedDevice(getState().connect);
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
|
|
||||||
const urlParams = getState().router.location.params;
|
const urlParams = getState().router.location.state;
|
||||||
if (urlParams.network) {
|
if (urlParams.network) {
|
||||||
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.network === urlParams.network);
|
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.network === urlParams.network);
|
||||||
if (!discoveryProcess) {
|
if (!discoveryProcess) {
|
||||||
|
@ -1,10 +1,2 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
export const onGasPriceChange2 = (gasPrice: string): void => {
|
|
||||||
return {
|
|
||||||
type: '',
|
|
||||||
gasPrice
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,10 +6,26 @@ import * as ADDRESS from './constants/address';
|
|||||||
import * as TOKEN from './constants/token';
|
import * as TOKEN from './constants/token';
|
||||||
import * as DISCOVERY from './constants/discovery';
|
import * as DISCOVERY from './constants/discovery';
|
||||||
import * as STORAGE from './constants/localStorage';
|
import * as STORAGE from './constants/localStorage';
|
||||||
import { httpRequest } from '../utils/networkUtils';
|
import { JSONRequest, httpRequest } from '../utils/networkUtils';
|
||||||
|
|
||||||
export function loadData(): any {
|
import type { AsyncAction, GetState, Dispatch } from '../flowtype';
|
||||||
return async (dispatch, getState) => {
|
import type { Config, Coin, TokensCollection } from '../reducers/LocalStorageReducer';
|
||||||
|
|
||||||
|
export type StorageAction = {
|
||||||
|
type: typeof STORAGE.READY,
|
||||||
|
config: any,
|
||||||
|
tokens: any,
|
||||||
|
ERC20Abi: any
|
||||||
|
} | {
|
||||||
|
type: typeof STORAGE.SAVE,
|
||||||
|
network: string,
|
||||||
|
} | {
|
||||||
|
type: typeof STORAGE.ERROR,
|
||||||
|
error: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadData = (): AsyncAction => {
|
||||||
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
// check if local storage is available
|
// check if local storage is available
|
||||||
// let available: boolean = true;
|
// let available: boolean = true;
|
||||||
@ -27,16 +43,51 @@ export function loadData(): any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadTokensFromJSON(): any {
|
// const parseConfig = (json: JSON): Config => {
|
||||||
return async (dispatch, getState) => {
|
|
||||||
|
// if (json['coins']) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (let key in json) {
|
||||||
|
// if (key === 'coins') {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const coins: Array<Object> = json.coins || [];
|
||||||
|
|
||||||
|
// if ("coins" in json){
|
||||||
|
// json.coins
|
||||||
|
// }
|
||||||
|
// if (!json.hasOwnProperty("fiatValueTickers")) throw new Error(`Property "fiatValueTickers" is missing in appConfig.json`);
|
||||||
|
// if (json.config && json.hasOwnProperty('coins') && Array.isArray(json.coins)) {
|
||||||
|
// json.coins.map(c => {
|
||||||
|
// return {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// } else {
|
||||||
|
// throw new Error(`Property "coins" is missing in appConfig.json`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// coins: [],
|
||||||
|
// fiatValueTickers: []
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
export function loadTokensFromJSON(): AsyncAction {
|
||||||
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const config = await httpRequest('data/appConfig.json', 'json');
|
const config: Config = await httpRequest('data/appConfig.json', 'json');
|
||||||
const ERC20Abi = await httpRequest('data/ERC20Abi.json', 'json');
|
const ERC20Abi = await httpRequest('data/ERC20Abi.json', 'json');
|
||||||
|
|
||||||
// load tokens
|
// load tokens
|
||||||
const tokens = await config.coins.reduce(async (promise: Promise<any>, coin: any): Promise<any> => {
|
const tokens = await config.coins.reduce(async (promise: Promise<TokensCollection>, coin: Coin): Promise<TokensCollection> => {
|
||||||
const collection = await promise;
|
const collection: TokensCollection = await promise;
|
||||||
const json: JSON = await httpRequest(coin.tokens, 'json');
|
const json = await httpRequest(coin.tokens, 'json');
|
||||||
collection[ coin.network ] = json;
|
collection[ coin.network ] = json;
|
||||||
return collection;
|
return collection;
|
||||||
}, Promise.resolve({}));
|
}, Promise.resolve({}));
|
||||||
@ -99,8 +150,8 @@ export function loadTokensFromJSON(): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const save = (key: string, value: string): any => {
|
export const save = (key: string, value: string): AsyncAction => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: Dispatch, getState: GetState) => {
|
||||||
if (typeof window.localStorage !== 'undefined') {
|
if (typeof window.localStorage !== 'undefined') {
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem(key, value);
|
window.localStorage.setItem(key, value);
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const toggle = (): any => {
|
import * as LOG from './constants/log';
|
||||||
return (dispatch, getState) => {
|
|
||||||
|
import type { AsyncAction, GetState, Dispatch } from '../flowtype';
|
||||||
|
|
||||||
|
export type LogAction = {
|
||||||
|
type: typeof LOG.OPEN,
|
||||||
|
} | {
|
||||||
|
type: typeof LOG.CLOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toggle = (): AsyncAction => {
|
||||||
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
if (!getState().log.opened) {
|
if (!getState().log.opened) {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: getState().log.opened ? 'log__close' : 'log__open'
|
type: getState().log.opened ? LOG.CLOSE : LOG.OPEN
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,24 @@ import TrezorConnect, { UI, UI_EVENT } from 'trezor-connect';
|
|||||||
import * as MODAL from './constants/modal';
|
import * as MODAL from './constants/modal';
|
||||||
import * as CONNECT from './constants/TrezorConnect';
|
import * as CONNECT from './constants/TrezorConnect';
|
||||||
|
|
||||||
|
import type { AsyncAction, Action, GetState, Dispatch } from '../flowtype';
|
||||||
|
|
||||||
export function onPinSubmit(value: string): any {
|
export type ModalAction = {
|
||||||
|
type: typeof MODAL.CLOSE
|
||||||
|
} | {
|
||||||
|
type: typeof MODAL.REMEMBER,
|
||||||
|
device: any
|
||||||
|
};
|
||||||
|
|
||||||
|
export const onPinSubmit = (value: string): Action => {
|
||||||
TrezorConnect.uiResponse({ type: UI.RECEIVE_PIN, payload: value });
|
TrezorConnect.uiResponse({ type: UI.RECEIVE_PIN, payload: value });
|
||||||
return {
|
return {
|
||||||
type: MODAL.CLOSE
|
type: MODAL.CLOSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onPassphraseSubmit(passphrase: string): any {
|
export const onPassphraseSubmit = (passphrase: string): AsyncAction => {
|
||||||
return async (dispatch, getState): Promise<void> => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const resp = await TrezorConnect.uiResponse({
|
const resp = await TrezorConnect.uiResponse({
|
||||||
type: UI.RECEIVE_PASSPHRASE,
|
type: UI.RECEIVE_PASSPHRASE,
|
||||||
payload: {
|
payload: {
|
||||||
@ -29,42 +37,42 @@ export function onPassphraseSubmit(passphrase: string): any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const askForRemember = (device: any) => {
|
export const askForRemember = (device: any): Action => {
|
||||||
return {
|
return {
|
||||||
type: MODAL.REMEMBER,
|
type: MODAL.REMEMBER,
|
||||||
device
|
device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onRememberDevice = (device: any) => {
|
export const onRememberDevice = (device: any): Action => {
|
||||||
return {
|
return {
|
||||||
type: CONNECT.REMEMBER,
|
type: CONNECT.REMEMBER,
|
||||||
device
|
device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onForgetDevice = (device: any) => {
|
export const onForgetDevice = (device: any): Action => {
|
||||||
return {
|
return {
|
||||||
type: CONNECT.FORGET,
|
type: CONNECT.FORGET,
|
||||||
device,
|
device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onForgetSingleDevice = (device: any) => {
|
export const onForgetSingleDevice = (device: any): Action => {
|
||||||
return {
|
return {
|
||||||
type: CONNECT.FORGET_SINGLE,
|
type: CONNECT.FORGET_SINGLE,
|
||||||
device,
|
device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onCancel = () => {
|
export const onCancel = (): Action => {
|
||||||
return {
|
return {
|
||||||
type: MODAL.CLOSE
|
type: MODAL.CLOSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onDuplicateDevice = (device: any): any => {
|
export const onDuplicateDevice = (device: any): AsyncAction => {
|
||||||
return (dispatch: any, getState: any): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
dispatch( onCancel() );
|
dispatch( onCancel() );
|
||||||
|
|
||||||
@ -74,3 +82,14 @@ export const onDuplicateDevice = (device: any): any => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
onPinSubmit,
|
||||||
|
onPassphraseSubmit,
|
||||||
|
askForRemember,
|
||||||
|
onRememberDevice,
|
||||||
|
onForgetDevice,
|
||||||
|
onForgetSingleDevice,
|
||||||
|
onCancel,
|
||||||
|
onDuplicateDevice
|
||||||
|
}
|
@ -3,10 +3,33 @@
|
|||||||
|
|
||||||
import * as NOTIFICATION from './constants/notification';
|
import * as NOTIFICATION from './constants/notification';
|
||||||
|
|
||||||
|
import type { AsyncAction, GetState, Dispatch, RouterLocationState } from '../flowtype';
|
||||||
|
|
||||||
|
export type NotificationAction = {
|
||||||
|
type: typeof NOTIFICATION.ADD,
|
||||||
|
payload: {
|
||||||
|
+type: string,
|
||||||
|
+title: string,
|
||||||
|
+message?: string,
|
||||||
|
+cancelable: boolean,
|
||||||
|
actions?: Array<any>
|
||||||
|
}
|
||||||
|
} | {
|
||||||
|
type: typeof NOTIFICATION.CLOSE,
|
||||||
|
payload?: {
|
||||||
|
id?: string;
|
||||||
|
devicePath?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const close = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// called from RouterService
|
// called from RouterService
|
||||||
export const clear = (currentParams, requestedParams): any => {
|
export const clear = (currentParams: RouterLocationState, requestedParams: RouterLocationState): AsyncAction => {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
// if route has been changed from device view into something else (like other device, settings...)
|
// 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)
|
// 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) {
|
if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) {
|
||||||
|
@ -9,9 +9,24 @@ import { initialState } from '../reducers/ReceiveReducer';
|
|||||||
import type { State } from '../reducers/ReceiveReducer';
|
import type { State } from '../reducers/ReceiveReducer';
|
||||||
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
|
import type { TrezorDevice, AsyncAction, Action, GetState, Dispatch } from '../flowtype';
|
||||||
|
|
||||||
export const init = (): any => {
|
export type ReceiveAction = {
|
||||||
return (dispatch, getState): void => {
|
type: typeof RECEIVE.INIT,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof RECEIVE.DISPOSE,
|
||||||
|
} | {
|
||||||
|
type: typeof RECEIVE.REQUEST_UNVERIFIED,
|
||||||
|
device: TrezorDevice
|
||||||
|
} | {
|
||||||
|
type: typeof RECEIVE.SHOW_ADDRESS
|
||||||
|
} | {
|
||||||
|
type: typeof RECEIVE.SHOW_UNVERIFIED_ADDRESS
|
||||||
|
}
|
||||||
|
|
||||||
|
export const init = (): AsyncAction => {
|
||||||
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
...initialState,
|
...initialState,
|
||||||
@ -25,8 +40,8 @@ export const init = (): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const update = (newProps: any): any => {
|
export const update = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const {
|
const {
|
||||||
abstractAccount,
|
abstractAccount,
|
||||||
router
|
router
|
||||||
@ -39,20 +54,20 @@ export const update = (newProps: any): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispose = (address: string): any => {
|
export const dispose = (): Action => {
|
||||||
return {
|
return {
|
||||||
type: RECEIVE.DISPOSE
|
type: RECEIVE.DISPOSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showUnverifiedAddress = () => {
|
export const showUnverifiedAddress = (): Action => {
|
||||||
return {
|
return {
|
||||||
type: RECEIVE.SHOW_UNVERIFIED_ADDRESS
|
type: RECEIVE.SHOW_UNVERIFIED_ADDRESS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showAddress = (address_n: string): any => {
|
export const showAddress = (address_n: string): AsyncAction => {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected = findSelectedDevice(getState().connect);
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
@ -100,3 +115,11 @@ export const showAddress = (address_n: string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init,
|
||||||
|
update,
|
||||||
|
dispose,
|
||||||
|
showAddress,
|
||||||
|
showUnverifiedAddress
|
||||||
|
}
|
@ -16,12 +16,72 @@ import BigNumber from 'bignumber.js';
|
|||||||
|
|
||||||
import { initialState } from '../reducers/SendFormReducer';
|
import { initialState } from '../reducers/SendFormReducer';
|
||||||
import { findAccount } from '../reducers/AccountsReducer';
|
import { findAccount } from '../reducers/AccountsReducer';
|
||||||
import type { State, FeeLevel } from '../reducers/SendFormReducer';
|
import { findToken } from '../reducers/TokensReducer';
|
||||||
import type { Account } from '../reducers/AccountsReducer';
|
|
||||||
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
Dispatch,
|
||||||
|
GetState,
|
||||||
|
Action,
|
||||||
|
AsyncAction,
|
||||||
|
RouterLocationState,
|
||||||
|
TrezorDevice
|
||||||
|
} from '../flowtype';
|
||||||
|
import type { State as AccountState } from '../reducers/AbstractAccountReducer';
|
||||||
|
import type { Web3Instance } from '../reducers/Web3Reducer';
|
||||||
|
import type { Config, Coin } from '../reducers/LocalStorageReducer';
|
||||||
|
import type { Token } from '../reducers/TokensReducer';
|
||||||
|
import type { State, FeeLevel } from '../reducers/SendFormReducer';
|
||||||
|
import type { Account } from '../reducers/AccountsReducer';
|
||||||
|
|
||||||
|
export type SendFormAction = {
|
||||||
|
type: typeof SEND.TX_COMPLETE,
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.INIT,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.DISPOSE
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.TOGGLE_ADVANCED
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.VALIDATION,
|
||||||
|
errors: {[k: string]: string},
|
||||||
|
warnings: {[k: string]: string},
|
||||||
|
infos: {[k: string]: string}
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.ADDRESS_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.AMOUNT_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.CURRENCY_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.SET_MAX,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.FEE_LEVEL_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.UPDATE_FEE_LEVELS,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.FEE_LEVEL_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.GAS_PRICE_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.GAS_LIMIT_CHANGE,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SEND.DATA_CHANGE,
|
||||||
|
state: State
|
||||||
|
};
|
||||||
|
|
||||||
//const numberRegExp = new RegExp('^([0-9]{0,10}\\.)?[0-9]{1,18}$');
|
//const numberRegExp = new RegExp('^([0-9]{0,10}\\.)?[0-9]{1,18}$');
|
||||||
const numberRegExp = new RegExp('^(0|0\\.([0-9]+)?|[1-9]+\\.?([0-9]+)?|\\.[0-9]+)$');
|
const numberRegExp: RegExp = new RegExp('^(0|0\\.([0-9]+)?|[1-9]+\\.?([0-9]+)?|\\.[0-9]+)$');
|
||||||
|
|
||||||
const calculateFee = (gasPrice: string, gasLimit: string): string => {
|
const calculateFee = (gasPrice: string, gasLimit: string): string => {
|
||||||
return EthereumjsUnits.convert( new BigNumber(gasPrice).times(gasLimit), 'gwei', 'ether');
|
return EthereumjsUnits.convert( new BigNumber(gasPrice).times(gasLimit), 'gwei', 'ether');
|
||||||
@ -82,38 +142,43 @@ export const getFeeLevels = (symbol: string, gasPrice: BigNumber | string, gasLi
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const findBalance = (getState: any): string => {
|
// export const findBalance = (getState: GetState): string => {
|
||||||
const accountState = getState().abstractAccount;
|
// const accountState = getState().abstractAccount;
|
||||||
const { token } = getState().sendForm;
|
// const { token } = getState().sendForm;
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
// const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
|
|
||||||
if (token !== state.network) {
|
// if (token !== state.network) {
|
||||||
return getState().tokens.find(t => t.ethAddress === account.address && t.symbol === token).balance;
|
// return getState().tokens.find(t => t.ethAddress === account.address && t.symbol === token).balance;
|
||||||
} else {
|
// } else {
|
||||||
return account.balance;
|
// return account.balance;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
// initialize component
|
// initialize component
|
||||||
export const init = (): any => {
|
export const init = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
|
|
||||||
const { location } = getState().router;
|
const { location } = getState().router;
|
||||||
const urlParams = location.params;
|
const urlParams: RouterLocationState = location.state;
|
||||||
|
|
||||||
const selected = findSelectedDevice( getState().connect );
|
const selected: ?TrezorDevice = findSelectedDevice( getState().connect );
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
|
|
||||||
const web3instance = getState().web3.find(w3 => w3.network === urlParams.network);
|
const web3instance: ?Web3Instance = getState().web3.find(w3 => w3.network === urlParams.network);
|
||||||
if (!web3instance) {
|
if (!web3instance) {
|
||||||
// no backend for this network
|
// no backend for this network
|
||||||
//return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check if there are some unfinished tx in localStorage
|
// TODO: check if there are some unfinished tx in localStorage
|
||||||
const { config } = getState().localStorage;
|
const { config } = getState().localStorage;
|
||||||
const coin = config.coins.find(c => c.network === urlParams.network);
|
if (!config) return;
|
||||||
|
|
||||||
|
const coin: ?Coin = config.coins.find(c => c.network === urlParams.network);
|
||||||
|
if (!coin) return;
|
||||||
|
|
||||||
const gasPrice: BigNumber = new BigNumber( EthereumjsUnits.convert(web3instance.gasPrice, 'wei', 'gwei') ) || new BigNumber(coin.defaultGasPrice);
|
const gasPrice: BigNumber = new BigNumber( EthereumjsUnits.convert(web3instance.gasPrice, 'wei', 'gwei') ) || new BigNumber(coin.defaultGasPrice);
|
||||||
const gasLimit: string = coin.defaultGasLimit.toString();
|
const gasLimit: string = coin.defaultGasLimit.toString();
|
||||||
@ -123,9 +188,9 @@ export const init = (): any => {
|
|||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
...initialState,
|
...initialState,
|
||||||
|
network: coin.network,
|
||||||
coinSymbol: coin.symbol,
|
coinSymbol: coin.symbol,
|
||||||
token: coin.network,
|
token: coin.network,
|
||||||
|
|
||||||
feeLevels,
|
feeLevels,
|
||||||
selectedFeeLevel: feeLevels.find(f => f.value === 'Normal'),
|
selectedFeeLevel: feeLevels.find(f => f.value === 'Normal'),
|
||||||
recommendedGasPrice: gasPrice.toString(),
|
recommendedGasPrice: gasPrice.toString(),
|
||||||
@ -141,8 +206,8 @@ export const init = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const update = (): any => {
|
export const update = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const {
|
const {
|
||||||
abstractAccount,
|
abstractAccount,
|
||||||
router
|
router
|
||||||
@ -156,29 +221,29 @@ export const update = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispose = (): any => {
|
export const dispose = (): Action => {
|
||||||
return {
|
return {
|
||||||
type: SEND.DISPOSE
|
type: SEND.DISPOSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const toggleAdvanced = (address: string): any => {
|
export const toggleAdvanced = (address: string): Action => {
|
||||||
return {
|
return {
|
||||||
type: SEND.TOGGLE_ADVANCED
|
type: SEND.TOGGLE_ADVANCED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const validation = (): any => {
|
export const validation = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const state: State = getState().sendForm;
|
const state: State = getState().sendForm;
|
||||||
|
|
||||||
const errors: {[k: string]: string} = {};
|
const errors: {[k: string]: string} = {};
|
||||||
const warnings: {[k: string]: string} = {};
|
const warnings: {[k: string]: string} = {};
|
||||||
const infos: {[k: string]: string} = {};
|
const infos: {[k: string]: string} = {};
|
||||||
|
|
||||||
if (!state.untouched) {
|
if (!state.untouched) {
|
||||||
|
|
||||||
// valid address
|
// valid address
|
||||||
if (state.touched.address) {
|
if (state.touched.address) {
|
||||||
|
|
||||||
@ -208,8 +273,11 @@ export const validation = (): any => {
|
|||||||
} else if (state.amount.length > 0 && !state.amount.match(numberRegExp)) {
|
} else if (state.amount.length > 0 && !state.amount.match(numberRegExp)) {
|
||||||
errors.amount = 'Amount is not a number';
|
errors.amount = 'Amount is not a number';
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
let decimalRegExp;
|
if (!account) return; // this should not happen
|
||||||
|
|
||||||
|
let decimalRegExp: RegExp;
|
||||||
|
|
||||||
if (state.token !== accountState.network) {
|
if (state.token !== accountState.network) {
|
||||||
const token: any = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === state.token);
|
const token: any = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === state.token);
|
||||||
@ -296,8 +364,8 @@ export const validation = (): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const onAddressChange = (address: string): any => {
|
export const onAddressChange = (address: string): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const currentState: State = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const touched = { ...currentState.touched };
|
const touched = { ...currentState.touched };
|
||||||
@ -318,10 +386,10 @@ export const onAddressChange = (address: string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onAmountChange = (amount: string): any => {
|
export const onAmountChange = (amount: string): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const currentState: State = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
const touched = { ...currentState.touched };
|
const touched = { ...currentState.touched };
|
||||||
@ -345,11 +413,10 @@ export const onAmountChange = (amount: string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onCurrencyChange = (currency: any): any => {
|
export const onCurrencyChange = (currency: any): AsyncAction => {
|
||||||
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
return (dispatch, getState): void => {
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const accountState = getState().abstractAccount;
|
const currentState: State = getState().sendForm;
|
||||||
const currentState = getState().sendForm;
|
|
||||||
const isToken: boolean = currency.value !== accountState.network;
|
const isToken: boolean = currency.value !== accountState.network;
|
||||||
|
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
@ -359,7 +426,9 @@ export const onCurrencyChange = (currency: any): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { config } = getState().localStorage;
|
const { config } = getState().localStorage;
|
||||||
const coin = config.coins.find(c => c.network === accountState.network);
|
if (!config) return;
|
||||||
|
const coin: ?Coin = config.coins.find(c => c.network === accountState.network);
|
||||||
|
if (!coin) return;
|
||||||
|
|
||||||
let gasLimit: string = '';
|
let gasLimit: string = '';
|
||||||
let amount: string = currentState.amount;
|
let amount: string = currentState.amount;
|
||||||
@ -368,8 +437,9 @@ export const onCurrencyChange = (currency: any): any => {
|
|||||||
if (isToken) {
|
if (isToken) {
|
||||||
gasLimit = coin.defaultGasLimitTokens.toString();
|
gasLimit = coin.defaultGasLimitTokens.toString();
|
||||||
if (currentState.setMax) {
|
if (currentState.setMax) {
|
||||||
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currency.value).balance;
|
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
|
||||||
amount = tokenBalance;
|
if (!token) return;
|
||||||
|
amount = token.balance;
|
||||||
}
|
}
|
||||||
total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit);
|
total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit);
|
||||||
} else {
|
} else {
|
||||||
@ -381,6 +451,8 @@ export const onCurrencyChange = (currency: any): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const feeLevels: Array<FeeLevel> = getFeeLevels(currentState.coinSymbol, currentState.gasPrice, gasLimit);
|
const feeLevels: Array<FeeLevel> = getFeeLevels(currentState.coinSymbol, currentState.gasPrice, gasLimit);
|
||||||
|
const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value);
|
||||||
|
if (!selectedFeeLevel) return;
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
...currentState,
|
...currentState,
|
||||||
@ -388,7 +460,7 @@ export const onCurrencyChange = (currency: any): any => {
|
|||||||
amount,
|
amount,
|
||||||
total,
|
total,
|
||||||
feeLevels,
|
feeLevels,
|
||||||
selectedFeeLevel: feeLevels.find(f => f.value === currentState.selectedFeeLevel.value),
|
selectedFeeLevel,
|
||||||
gasLimit,
|
gasLimit,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -402,10 +474,10 @@ export const onCurrencyChange = (currency: any): any => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const onSetMax = (): any => {
|
export const onSetMax = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const currentState = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
const touched = { ...currentState.touched };
|
const touched = { ...currentState.touched };
|
||||||
touched.amount = true;
|
touched.amount = true;
|
||||||
@ -420,8 +492,9 @@ export const onSetMax = (): any => {
|
|||||||
let total: string = currentState.total;
|
let total: string = currentState.total;
|
||||||
if (!currentState.setMax) {
|
if (!currentState.setMax) {
|
||||||
if (isToken) {
|
if (isToken) {
|
||||||
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance;
|
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
|
||||||
amount = tokenBalance;
|
if (!token) return;
|
||||||
|
amount = token.balance;
|
||||||
total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit);
|
total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit);
|
||||||
} else {
|
} else {
|
||||||
amount = calculateMaxAmount(account.balance, currentState.gasPrice, currentState.gasLimit);
|
amount = calculateMaxAmount(account.balance, currentState.gasPrice, currentState.gasLimit);
|
||||||
@ -446,12 +519,17 @@ export const onSetMax = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onFeeLevelChange = (feeLevel: any): any => {
|
export const onFeeLevelChange = (feeLevel: FeeLevel): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const currentState = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
|
|
||||||
|
const { config } = getState().localStorage;
|
||||||
|
if (!config) return;
|
||||||
|
const coin: ?Coin = config.coins.find(c => c.network === accountState.network);
|
||||||
|
if (!coin) return;
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
...currentState,
|
...currentState,
|
||||||
untouched: false,
|
untouched: false,
|
||||||
@ -464,16 +542,22 @@ export const onFeeLevelChange = (feeLevel: any): any => {
|
|||||||
feeLevel.gasPrice = state.gasPrice;
|
feeLevel.gasPrice = state.gasPrice;
|
||||||
feeLevel.label = `${ calculateFee(state.gasPrice, state.gasLimit) } ${ state.coinSymbol }`;
|
feeLevel.label = `${ calculateFee(state.gasPrice, state.gasLimit) } ${ state.coinSymbol }`;
|
||||||
} else {
|
} else {
|
||||||
const customLevel = state.feeLevels.find(f => f.value === 'Custom');
|
const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom');
|
||||||
customLevel.label = '';
|
if (customLevel)
|
||||||
|
customLevel.label = '';
|
||||||
state.gasPrice = feeLevel.gasPrice;
|
state.gasPrice = feeLevel.gasPrice;
|
||||||
|
state.gasLimit = isToken ? coin.defaultGasLimitTokens.toString() : coin.defaultGasLimit.toString();
|
||||||
|
// reset custom gasLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentState.setMax) {
|
if (currentState.setMax) {
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
|
if (!account) return;
|
||||||
|
|
||||||
if (isToken) {
|
if (isToken) {
|
||||||
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance;
|
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
|
||||||
state.amount = tokenBalance;
|
if (!token) return;
|
||||||
|
state.amount = token.balance;
|
||||||
} else {
|
} else {
|
||||||
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
||||||
}
|
}
|
||||||
@ -488,14 +572,16 @@ export const onFeeLevelChange = (feeLevel: any): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateFeeLevels = (): any => {
|
export const updateFeeLevels = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const currentState = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
|
|
||||||
const feeLevels: Array<FeeLevel> = getFeeLevels(currentState.coinSymbol, currentState.recommendedGasPrice, currentState.gasLimit);
|
const feeLevels: Array<FeeLevel> = getFeeLevels(currentState.coinSymbol, currentState.recommendedGasPrice, currentState.gasLimit);
|
||||||
const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value)
|
const selectedFeeLevel: ?FeeLevel = feeLevels.find(f => f.value === currentState.selectedFeeLevel.value);
|
||||||
|
if (!selectedFeeLevel) return;
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
...currentState,
|
...currentState,
|
||||||
feeLevels,
|
feeLevels,
|
||||||
@ -507,8 +593,11 @@ export const updateFeeLevels = (): any => {
|
|||||||
|
|
||||||
if (currentState.setMax) {
|
if (currentState.setMax) {
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
|
if (!account) return;
|
||||||
if (isToken) {
|
if (isToken) {
|
||||||
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance;
|
const token: ?Token = findToken(getState().tokens, account.address, state.token, accountState.deviceState);
|
||||||
|
if (!token) return;
|
||||||
|
const tokenBalance: string = token.balance;
|
||||||
state.amount = tokenBalance;
|
state.amount = tokenBalance;
|
||||||
} else {
|
} else {
|
||||||
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
||||||
@ -524,10 +613,10 @@ export const updateFeeLevels = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onGasPriceChange = (gasPrice: string): any => {
|
export const onGasPriceChange = (gasPrice: string): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const currentState = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
|
|
||||||
const touched = { ...currentState.touched };
|
const touched = { ...currentState.touched };
|
||||||
@ -542,6 +631,7 @@ export const onGasPriceChange = (gasPrice: string): any => {
|
|||||||
|
|
||||||
if (gasPrice.match(numberRegExp) && state.gasLimit.match(numberRegExp)) {
|
if (gasPrice.match(numberRegExp) && state.gasLimit.match(numberRegExp)) {
|
||||||
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
|
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
|
||||||
|
if (!customLevel) return;
|
||||||
customLevel.gasPrice = gasPrice;
|
customLevel.gasPrice = gasPrice;
|
||||||
customLevel.label = `${ calculateFee(gasPrice, state.gasLimit) } ${ state.coinSymbol }`;
|
customLevel.label = `${ calculateFee(gasPrice, state.gasLimit) } ${ state.coinSymbol }`;
|
||||||
|
|
||||||
@ -549,8 +639,11 @@ export const onGasPriceChange = (gasPrice: string): any => {
|
|||||||
|
|
||||||
if (currentState.setMax) {
|
if (currentState.setMax) {
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
|
if (!account) return;
|
||||||
if (isToken) {
|
if (isToken) {
|
||||||
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance;
|
const token: ?Token = findToken(getState().tokens, account.address, state.token, accountState.deviceState);
|
||||||
|
if (!token) return;
|
||||||
|
const tokenBalance: string = token.balance;
|
||||||
state.amount = tokenBalance;
|
state.amount = tokenBalance;
|
||||||
} else {
|
} else {
|
||||||
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
||||||
@ -568,10 +661,10 @@ export const onGasPriceChange = (gasPrice: string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onGasLimitChange = (gasLimit: string): any => {
|
export const onGasLimitChange = (gasLimit: string): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const accountState = getState().abstractAccount;
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
const currentState = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
|
|
||||||
const touched = { ...currentState.touched };
|
const touched = { ...currentState.touched };
|
||||||
@ -585,15 +678,20 @@ export const onGasLimitChange = (gasLimit: string): any => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (gasLimit.match(numberRegExp) && state.gasPrice.match(numberRegExp)) {
|
if (gasLimit.match(numberRegExp) && state.gasPrice.match(numberRegExp)) {
|
||||||
const customLevel = state.feeLevels.find(f => f.value === 'Custom');
|
const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom');
|
||||||
|
if (!customLevel) return;
|
||||||
customLevel.label = `${ calculateFee(currentState.gasPrice, gasLimit) } ${ state.coinSymbol }`;
|
customLevel.label = `${ calculateFee(currentState.gasPrice, gasLimit) } ${ state.coinSymbol }`;
|
||||||
|
|
||||||
state.selectedFeeLevel = customLevel;
|
state.selectedFeeLevel = customLevel;
|
||||||
|
|
||||||
if (state.setMax) {
|
if (state.setMax) {
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
|
if (!account) return;
|
||||||
|
|
||||||
if (isToken) {
|
if (isToken) {
|
||||||
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === state.token).balance;
|
const token: ?Token = findToken(getState().tokens, account.address, state.token, accountState.deviceState);
|
||||||
|
if (!token) return;
|
||||||
|
const tokenBalance: string = token.balance;
|
||||||
state.amount = tokenBalance;
|
state.amount = tokenBalance;
|
||||||
} else {
|
} else {
|
||||||
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
|
||||||
@ -611,9 +709,9 @@ export const onGasLimitChange = (gasLimit: string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onDataChange = (data: string): any => {
|
export const onDataChange = (data: string): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const currentState = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const touched = { ...currentState.touched };
|
const touched = { ...currentState.touched };
|
||||||
touched.data = true;
|
touched.data = true;
|
||||||
|
|
||||||
@ -632,33 +730,37 @@ export const onDataChange = (data: string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onSend = (): any => {
|
export const onSend = (): AsyncAction => {
|
||||||
//return onSendERC20();
|
//return onSendERC20();
|
||||||
|
return async (dispatch: Dispatch, getState: GetState): Promise<any> => {
|
||||||
|
|
||||||
return async (dispatch, getState): Promise<any> => {
|
const accountState: AccountState = getState().abstractAccount;
|
||||||
|
|
||||||
const accountState = getState().abstractAccount;
|
|
||||||
const currentState: State = getState().sendForm;
|
const currentState: State = getState().sendForm;
|
||||||
const web3instance = getState().web3.filter(w3 => w3.network === accountState.network)[0];
|
const web3instance: ?Web3Instance = getState().web3.filter(w3 => w3.network === accountState.network)[0];
|
||||||
const web3 = web3instance.web3;
|
|
||||||
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
|
||||||
|
if (!account || !web3instance) return;
|
||||||
|
|
||||||
const isToken: boolean = currentState.token !== accountState.network;
|
const isToken: boolean = currentState.token !== accountState.network;
|
||||||
|
const web3 = web3instance.web3;
|
||||||
|
|
||||||
const address_n = account.addressPath;
|
const address_n = account.addressPath;
|
||||||
|
|
||||||
let data: string = '';
|
let data: string = '';
|
||||||
let txAmount = web3.toHex(web3.toWei(currentState.amount, 'ether'));
|
let txAmount: string = web3.toHex(web3.toWei(currentState.amount, 'ether'));
|
||||||
let txAddress = currentState.address;
|
let txAddress: string = currentState.address;
|
||||||
if (isToken) {
|
if (isToken) {
|
||||||
const t = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token);
|
// const t = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token);
|
||||||
const contract = web3instance.erc20.at(t.address);
|
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
|
||||||
|
if (!token) return;
|
||||||
|
|
||||||
|
const contract = web3instance.erc20.at(token.address);
|
||||||
data = contract.transfer.getData(currentState.address, currentState.amount, {
|
data = contract.transfer.getData(currentState.address, currentState.amount, {
|
||||||
from: account.address,
|
from: account.address,
|
||||||
gasLimit: currentState.gasLimit,
|
gasLimit: currentState.gasLimit,
|
||||||
gasPrice: currentState.gasPrice
|
gasPrice: currentState.gasPrice
|
||||||
});
|
});
|
||||||
txAmount = '0x00';
|
txAmount = '0x00';
|
||||||
txAddress = t.address;
|
txAddress = token.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
const txData = {
|
const txData = {
|
||||||
@ -693,7 +795,7 @@ export const onSend = (): any => {
|
|||||||
|
|
||||||
// console.log("---->GASSS", txData, gasLimit, gasPrice, EthereumjsUnits.convert(gasPrice, 'gwei', 'wei'));
|
// console.log("---->GASSS", txData, gasLimit, gasPrice, EthereumjsUnits.convert(gasPrice, 'gwei', 'wei'));
|
||||||
|
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
|
|
||||||
let signedTransaction = await TrezorConnect.ethereumSignTransaction({
|
let signedTransaction = await TrezorConnect.ethereumSignTransaction({
|
||||||
@ -736,7 +838,9 @@ export const onSend = (): any => {
|
|||||||
// console.log("---->GASSS", txData, gasLimit2.toString() );
|
// console.log("---->GASSS", txData, gasLimit2.toString() );
|
||||||
|
|
||||||
const { config } = getState().localStorage;
|
const { config } = getState().localStorage;
|
||||||
const selectedCoin = config.coins.find(c => c.network === currentState.network);
|
if (!config) return;
|
||||||
|
const selectedCoin: ?Coin = config.coins.find(c => c.network === currentState.network);
|
||||||
|
if (!selectedCoin) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tx = new EthereumjsTx(txData);
|
const tx = new EthereumjsTx(txData);
|
||||||
@ -778,3 +882,21 @@ export const onSend = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init,
|
||||||
|
update,
|
||||||
|
dispose,
|
||||||
|
|
||||||
|
toggleAdvanced,
|
||||||
|
onAddressChange,
|
||||||
|
onAmountChange,
|
||||||
|
onCurrencyChange,
|
||||||
|
onSetMax,
|
||||||
|
onFeeLevelChange,
|
||||||
|
updateFeeLevels,
|
||||||
|
onGasPriceChange,
|
||||||
|
onGasLimitChange,
|
||||||
|
onDataChange,
|
||||||
|
onSend,
|
||||||
|
}
|
||||||
|
@ -7,14 +7,24 @@ import * as TOKEN from './constants/token';
|
|||||||
import * as ADDRESS from './constants/address';
|
import * as ADDRESS from './constants/address';
|
||||||
import { resolveAfter } from '../utils/promiseUtils';
|
import { resolveAfter } from '../utils/promiseUtils';
|
||||||
import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions';
|
import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions';
|
||||||
|
|
||||||
import { initialState } from '../reducers/SummaryReducer';
|
import { initialState } from '../reducers/SummaryReducer';
|
||||||
import type { State } from '../reducers/SummaryReducer';
|
|
||||||
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
|
import type { AsyncAction, Action, GetState, Dispatch } from '../flowtype';
|
||||||
|
import type { State } from '../reducers/SummaryReducer';
|
||||||
|
import type { Token } from '../reducers/TokensReducer';
|
||||||
|
|
||||||
export const init = (): any => {
|
export type SummaryAction = {
|
||||||
return (dispatch, getState): void => {
|
type: typeof SUMMARY.INIT,
|
||||||
|
state: State
|
||||||
|
} | {
|
||||||
|
type: typeof SUMMARY.DISPOSE,
|
||||||
|
} | {
|
||||||
|
type: typeof SUMMARY.DETAILS_TOGGLE
|
||||||
|
}
|
||||||
|
|
||||||
|
export const init = (): AsyncAction => {
|
||||||
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const state: State = {
|
const state: State = {
|
||||||
...initialState,
|
...initialState,
|
||||||
@ -28,8 +38,8 @@ export const init = (): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const update = (newProps: any): any => {
|
export const update = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const {
|
const {
|
||||||
abstractAccount,
|
abstractAccount,
|
||||||
router
|
router
|
||||||
@ -43,87 +53,15 @@ export const update = (newProps: any): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispose = (address: string): any => {
|
export const dispose = (): Action => {
|
||||||
return {
|
return {
|
||||||
type: SUMMARY.DISPOSE
|
type: SUMMARY.DISPOSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onDetailsToggle = (): any => {
|
export const onDetailsToggle = (): Action => {
|
||||||
return {
|
return {
|
||||||
type: SUMMARY.DETAILS_TOGGLE
|
type: SUMMARY.DETAILS_TOGGLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const loadTokens = (input: string, account: any): any => {
|
|
||||||
return async (dispatch, getState): Promise<any> => {
|
|
||||||
|
|
||||||
if (input.length < 1) return null;
|
|
||||||
|
|
||||||
const tokens = getState().localStorage.tokens[ account.network ];
|
|
||||||
const value = input.toLowerCase();
|
|
||||||
const result = tokens.filter(t =>
|
|
||||||
t.symbol.toLowerCase().indexOf(value) >= 0 ||
|
|
||||||
t.address.toLowerCase().indexOf(value) >= 0 ||
|
|
||||||
t.name.toLowerCase().indexOf(value) >= 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.length > 0) {
|
|
||||||
return { options: result };
|
|
||||||
} else {
|
|
||||||
const web3instance = getState().web3.find(w3 => w3.network === account.network);
|
|
||||||
|
|
||||||
const info = await getTokenInfoAsync(web3instance.erc20, input);
|
|
||||||
info.address = input;
|
|
||||||
|
|
||||||
if (info) {
|
|
||||||
return {
|
|
||||||
options: [ info ]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//await resolveAfter(300000);
|
|
||||||
//await resolveAfter(3000);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectToken = (token: any, account: any): any => {
|
|
||||||
return async (dispatch, getState): Promise<any> => {
|
|
||||||
|
|
||||||
const web3instance = getState().web3.find(w3 => w3.network === account.network);
|
|
||||||
dispatch({
|
|
||||||
type: TOKEN.ADD,
|
|
||||||
payload: {
|
|
||||||
...token,
|
|
||||||
ethAddress: account.address,
|
|
||||||
deviceState: account.deviceState
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, token.address, account.address);
|
|
||||||
dispatch({
|
|
||||||
type: TOKEN.SET_BALANCE,
|
|
||||||
payload: {
|
|
||||||
ethAddress: account.address,
|
|
||||||
address: token.address,
|
|
||||||
balance: tokenBalance.toString()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removeToken = (token: any): any => {
|
|
||||||
return {
|
|
||||||
type: TOKEN.REMOVE,
|
|
||||||
token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
113
src/js/actions/TokenActions.js
Normal file
113
src/js/actions/TokenActions.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/* @flow */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import * as TOKEN from './constants/token';
|
||||||
|
import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions';
|
||||||
|
|
||||||
|
import type { GetState, AsyncAction, Action } from '../flowtype';
|
||||||
|
import type { State, Token } from '../reducers/TokensReducer';
|
||||||
|
import type { Account } from '../reducers/AccountsReducer';
|
||||||
|
import type { NetworkToken } from '../reducers/LocalStorageReducer';
|
||||||
|
|
||||||
|
export type TokenAction = {
|
||||||
|
type: typeof TOKEN.FROM_STORAGE,
|
||||||
|
payload: State
|
||||||
|
} | {
|
||||||
|
type: typeof TOKEN.ADD,
|
||||||
|
payload: Token
|
||||||
|
} | {
|
||||||
|
type: typeof TOKEN.REMOVE,
|
||||||
|
token: Token
|
||||||
|
} | {
|
||||||
|
type: typeof TOKEN.SET_BALANCE,
|
||||||
|
payload: {
|
||||||
|
ethAddress: string,
|
||||||
|
address: string,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setBalance = (web3: any, coinIndex: number = 0): AsyncAction => {
|
||||||
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SelectOptions = {
|
||||||
|
options?: Array<NetworkToken>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// action from component <reactSelect>
|
||||||
|
export const load = (input: string, network: string): AsyncAction => {
|
||||||
|
return async (dispatch: Dispatch, getState: GetState): Promise<any> => {
|
||||||
|
|
||||||
|
if (input.length < 1) return;
|
||||||
|
|
||||||
|
const tokens = getState().localStorage.tokens[ network ];
|
||||||
|
const value = input.toLowerCase();
|
||||||
|
const result = tokens.filter(t =>
|
||||||
|
t.symbol.toLowerCase().indexOf(value) >= 0 ||
|
||||||
|
t.address.toLowerCase().indexOf(value) >= 0 ||
|
||||||
|
t.name.toLowerCase().indexOf(value) >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.length > 0) {
|
||||||
|
return { options: result };
|
||||||
|
} else {
|
||||||
|
const web3instance = getState().web3.find(w3 => w3.network === network);
|
||||||
|
if (!web3instance) return;
|
||||||
|
|
||||||
|
const info = await getTokenInfoAsync(web3instance.erc20, input);
|
||||||
|
info.address = input;
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
return {
|
||||||
|
options: [ info ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//await resolveAfter(300000);
|
||||||
|
//await resolveAfter(3000);
|
||||||
|
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const add = (token: NetworkToken, account: Account): AsyncAction => {
|
||||||
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
|
const web3instance = getState().web3.find(w3 => w3.network === account.network);
|
||||||
|
if (!web3instance) return;
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: TOKEN.ADD,
|
||||||
|
payload: {
|
||||||
|
loaded: false,
|
||||||
|
deviceState: account.deviceState,
|
||||||
|
name: token.name,
|
||||||
|
symbol: token.symbol,
|
||||||
|
address: token.address,
|
||||||
|
ethAddress: account.address,
|
||||||
|
decimals: token.decimals,
|
||||||
|
balance: '0'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const tokenBalance = await getTokenBalanceAsync(web3instance.erc20, token.address, account.address);
|
||||||
|
dispatch({
|
||||||
|
type: TOKEN.SET_BALANCE,
|
||||||
|
payload: {
|
||||||
|
ethAddress: account.address,
|
||||||
|
address: token.address,
|
||||||
|
balance: tokenBalance.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (token: Token): Action => {
|
||||||
|
return {
|
||||||
|
type: TOKEN.REMOVE,
|
||||||
|
token
|
||||||
|
}
|
||||||
|
}
|
@ -14,29 +14,107 @@ import { resolveAfter } from '../utils/promiseUtils';
|
|||||||
import { getAccounts } from '../utils/reducerUtils';
|
import { getAccounts } from '../utils/reducerUtils';
|
||||||
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
export const init = (): any => {
|
|
||||||
return async (dispatch, getState): Promise<void> => {
|
import type {
|
||||||
|
Device,
|
||||||
|
ResponseMessage,
|
||||||
|
DeviceMessage,
|
||||||
|
UiMessage,
|
||||||
|
TransportMessage,
|
||||||
|
DeviceMessageType,
|
||||||
|
TransportMessageType,
|
||||||
|
UiMessageType
|
||||||
|
} from 'trezor-connect';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
Dispatch,
|
||||||
|
GetState,
|
||||||
|
Action,
|
||||||
|
AsyncAction,
|
||||||
|
TrezorDevice,
|
||||||
|
RouterLocationState
|
||||||
|
} from '../flowtype';
|
||||||
|
|
||||||
|
|
||||||
|
export type TrezorConnectAction = {
|
||||||
|
type: typeof CONNECT.INITIALIZATION_ERROR,
|
||||||
|
error: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.SELECT_DEVICE,
|
||||||
|
payload: ?{
|
||||||
|
id: string,
|
||||||
|
instance: string
|
||||||
|
}
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.COIN_CHANGED,
|
||||||
|
payload: {
|
||||||
|
network: string
|
||||||
|
}
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.AUTH_DEVICE,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.DUPLICATE,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.REMEMBER_REQUEST,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.DISCONNECT_REQUEST,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.FORGET_REQUEST,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.FORGET,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.FORGET_SINGLE,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.REMEMBER,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.TRY_TO_DUPLICATE,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.DEVICE_FROM_STORAGE,
|
||||||
|
payload: Array<any>
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.START_ACQUIRING,
|
||||||
|
device: any
|
||||||
|
} | {
|
||||||
|
type: typeof CONNECT.STOP_ACQUIRING,
|
||||||
|
device: any
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const init = (): AsyncAction => {
|
||||||
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
// set listeners
|
// set listeners
|
||||||
TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => {
|
TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => {
|
||||||
|
// post event to reducers
|
||||||
|
const type: DeviceMessageType = event.type; // assert flow type
|
||||||
dispatch({
|
dispatch({
|
||||||
type: event.type,
|
type,
|
||||||
device: event.payload
|
device: event.payload
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const version: Object = TrezorConnect.getVersion();
|
|
||||||
TrezorConnect.on(UI_EVENT, (event: UiMessage): void => {
|
TrezorConnect.on(UI_EVENT, (event: UiMessage): void => {
|
||||||
// post event to reducers
|
// post event to reducers
|
||||||
|
const type: UiMessageType = event.type; // assert flow type
|
||||||
dispatch({
|
dispatch({
|
||||||
type: event.type,
|
type,
|
||||||
payload: event.payload
|
payload: event.payload
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
TrezorConnect.on(TRANSPORT_EVENT, (event: UiMessage): void => {
|
TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => {
|
||||||
// post event to reducers
|
// post event to reducers
|
||||||
|
const type: TransportMessageType = event.type; // assert flow type
|
||||||
dispatch({
|
dispatch({
|
||||||
type: event.type,
|
type,
|
||||||
payload: event.payload
|
payload: event.payload
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -47,7 +125,7 @@ export const init = (): any => {
|
|||||||
connectSrc: 'https://localhost:8088/',
|
connectSrc: 'https://localhost:8088/',
|
||||||
// connectSrc: 'https://connect.trezor.io/tpm/',
|
// connectSrc: 'https://connect.trezor.io/tpm/',
|
||||||
// connectSrc: 'https://sisyfos.trezor.io/',
|
// connectSrc: 'https://sisyfos.trezor.io/',
|
||||||
debug: true,
|
debug: false,
|
||||||
popup: false,
|
popup: false,
|
||||||
webusb: true
|
webusb: true
|
||||||
});
|
});
|
||||||
@ -62,10 +140,10 @@ export const init = (): any => {
|
|||||||
|
|
||||||
// called after backend was initialized
|
// called after backend was initialized
|
||||||
// set listeners for connect/disconnect
|
// set listeners for connect/disconnect
|
||||||
export const postInit = (): any => {
|
export const postInit = (): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const handleDeviceConnect = (device) => {
|
const handleDeviceConnect = (device: Device) => {
|
||||||
dispatch( initConnectedDevice(device) );
|
dispatch( initConnectedDevice(device) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +153,11 @@ export const postInit = (): any => {
|
|||||||
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
|
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
|
||||||
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||||
|
|
||||||
const { devices } = getState().connect;
|
// const devices: Array<TrezorDevice> = getState().connect.devices;
|
||||||
|
const devices: Array<TrezorDevice> = getState().connect.devices;
|
||||||
|
|
||||||
|
const { initialPathname, initialParams } = getState().wallet;
|
||||||
|
|
||||||
const { initialPathname, initialParams } = getState().wallet
|
|
||||||
if (initialPathname) {
|
if (initialPathname) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: WALLET.SET_INITIAL_URL,
|
type: WALLET.SET_INITIAL_URL,
|
||||||
@ -87,7 +167,7 @@ export const postInit = (): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (devices.length > 0) {
|
if (devices.length > 0) {
|
||||||
const unacquired = devices.find(d => d.unacquired);
|
const unacquired: ?TrezorDevice = devices.find(d => d.unacquired);
|
||||||
if (unacquired) {
|
if (unacquired) {
|
||||||
dispatch( onSelectDevice(unacquired) );
|
dispatch( onSelectDevice(unacquired) );
|
||||||
} else {
|
} else {
|
||||||
@ -118,8 +198,8 @@ const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initConnectedDevice = (device: any, force): any => {
|
export const initConnectedDevice = (device: any): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected = findSelectedDevice(getState().connect);
|
||||||
if (!selected || (selected && selected.state)) {
|
if (!selected || (selected && selected.state)) {
|
||||||
@ -137,27 +217,26 @@ export const initConnectedDevice = (device: any, force): any => {
|
|||||||
// after device_connect event
|
// after device_connect event
|
||||||
// or after acquiring device
|
// or after acquiring device
|
||||||
// device type could be local TrezorDevice or Device (from trezor-connect device_connect event)
|
// device type could be local TrezorDevice or Device (from trezor-connect device_connect event)
|
||||||
export const onSelectDevice = (device: any): any => {
|
export const onSelectDevice = (device: TrezorDevice | Device): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
// || device.isUsedElsewhere
|
// || device.isUsedElsewhere
|
||||||
|
|
||||||
console.log("------> REDITTO", device, getState().wallet.initialUrl);
|
|
||||||
|
|
||||||
// switch to initial url and reset this value
|
// switch to initial url and reset this value
|
||||||
|
|
||||||
|
|
||||||
if (device.unacquired) {
|
if (!device.features) {
|
||||||
dispatch( push(`/device/${ device.path }/acquire`) );
|
dispatch( push(`/device/${ device.path }/acquire`) );
|
||||||
} else if (device.features.bootloader_mode) {
|
} else if (device.features.bootloader_mode) {
|
||||||
dispatch( push(`/device/${ device.path }/bootloader`) );
|
dispatch( push(`/device/${ device.path }/bootloader`) );
|
||||||
} else if (device.instance) {
|
} else if (typeof device.instance === 'number') {
|
||||||
dispatch( push(`/device/${ device.features.device_id }:${ device.instance }`) );
|
dispatch( push(`/device/${ device.features.device_id }:${ device.instance }`) );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const urlParams: any = getState().router.location.params;
|
const deviceId: string = device.features.device_id;
|
||||||
|
const urlParams: RouterLocationState = getState().router.location.state;
|
||||||
// let url: string = `/device/${ device.features.device_id }/network/ethereum/address/0`;
|
// let url: string = `/device/${ device.features.device_id }/network/ethereum/address/0`;
|
||||||
let url: string = `/device/${ device.features.device_id }`;
|
let url: string = `/device/${ deviceId }`;
|
||||||
let instance: ?string;
|
let instance: ?number;
|
||||||
// check if device is not TrezorDevice type
|
// check if device is not TrezorDevice type
|
||||||
if (!device.hasOwnProperty('ts')) {
|
if (!device.hasOwnProperty('ts')) {
|
||||||
// its device from trezor-connect (called in initConnectedDevice triggered by device_connect event)
|
// its device from trezor-connect (called in initConnectedDevice triggered by device_connect event)
|
||||||
@ -173,15 +252,15 @@ export const onSelectDevice = (device: any): any => {
|
|||||||
// check if current location is not set to this device
|
// 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 }/network/etc/address/0`) );
|
||||||
|
|
||||||
if (urlParams.deviceInstance !== instance || urlParams.device !== device.features.device_id) {
|
if (urlParams.deviceInstance !== instance || urlParams.device !== deviceId) {
|
||||||
dispatch( push(url) );
|
dispatch( push(url) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const switchToFirstAvailableDevice = (): any => {
|
export const switchToFirstAvailableDevice = (): AsyncAction => {
|
||||||
return async (dispatch, getState): Promise<void> => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const { devices } = getState().connect;
|
const { devices } = getState().connect;
|
||||||
if (devices.length > 0) {
|
if (devices.length > 0) {
|
||||||
@ -208,8 +287,8 @@ export const switchToFirstAvailableDevice = (): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const getSelectedDeviceState = (): any => {
|
export const getSelectedDeviceState = (): AsyncAction => {
|
||||||
return async (dispatch, getState): Promise<void> => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected = findSelectedDevice(getState().connect);
|
||||||
console.warn("init selected", selected)
|
console.warn("init selected", selected)
|
||||||
if (selected
|
if (selected
|
||||||
@ -260,13 +339,13 @@ export const getSelectedDeviceState = (): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deviceDisconnect = (device: any): any => {
|
export const deviceDisconnect = (device: Device): AsyncAction => {
|
||||||
return async (dispatch, getState): Promise<void> => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
|
||||||
|
|
||||||
if (device && device.features) {
|
if (device && device.features) {
|
||||||
if (selected && selected.features.device_id === device.features.device_id) {
|
if (selected && selected.features && selected.features.device_id === device.features.device_id) {
|
||||||
dispatch( DiscoveryActions.stop(selected) );
|
dispatch( DiscoveryActions.stop(selected) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,9 +366,11 @@ export const deviceDisconnect = (device: any): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const coinChanged = (network: ?string): any => {
|
export const coinChanged = (network: ?string): AsyncAction => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
|
||||||
|
if (!selected) return;
|
||||||
|
|
||||||
dispatch( DiscoveryActions.stop(selected) );
|
dispatch( DiscoveryActions.stop(selected) );
|
||||||
|
|
||||||
if (network) {
|
if (network) {
|
||||||
@ -298,15 +379,16 @@ export const coinChanged = (network: ?string): any => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reload(): any {
|
export function reload(): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function acquire(): any {
|
export function acquire(): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
|
||||||
|
if (!selected) return;
|
||||||
|
|
||||||
// const saved = getState().connect.devices.map(d => {
|
// const saved = getState().connect.devices.map(d => {
|
||||||
// if (d.state) {
|
// if (d.state) {
|
||||||
@ -341,10 +423,11 @@ export function acquire(): any {
|
|||||||
if (response && response.success) {
|
if (response && response.success) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: DEVICE.ACQUIRED,
|
type: DEVICE.ACQUIRED,
|
||||||
|
device: null
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// TODO: handle invalid pin?
|
// TODO: handle invalid pin?
|
||||||
console.log("-errror ack", response)
|
console.log("-error ack", response)
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: NOTIFICATION.ADD,
|
type: NOTIFICATION.ADD,
|
||||||
@ -367,35 +450,34 @@ export function acquire(): any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const forgetDevice = (device: any) => {
|
export const forgetDevice = (device: any): AsyncAction => {
|
||||||
return (dispatch: any, getState: any): any => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
|
|
||||||
// find accounts associated with this device
|
// find accounts associated with this device
|
||||||
const accounts: Array<any> = getState().accounts.find(a => a.deviceState === device.state);
|
// const accounts: Array<any> = getState().accounts.find(a => a.deviceState === device.state);
|
||||||
|
|
||||||
|
|
||||||
// find discovery processes associated with this device
|
// find discovery processes associated with this device
|
||||||
const discovery: Array<any> = getState().discovery.find(d => d.deviceState === device.state);
|
// const discovery: Array<any> = getState().discovery.find(d => d.deviceState === device.state);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const gotoDeviceSettings = (device: any) => {
|
export const gotoDeviceSettings = (device: any): AsyncAction => {
|
||||||
return (dispatch: any, getState: any): any => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
dispatch( push(`/device/${ device.features.device_id }/settings`) );
|
dispatch( push(`/device/${ device.features.device_id }/settings`) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from Aside - device menu (forget single instance)
|
// called from Aside - device menu (forget single instance)
|
||||||
export const forget = (device: any) => {
|
export const forget = (device: any): Action => {
|
||||||
return {
|
return {
|
||||||
type: CONNECT.FORGET_REQUEST,
|
type: CONNECT.FORGET_REQUEST,
|
||||||
device
|
device
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const duplicateDevice = (device: any) => {
|
export const duplicateDevice = (device: any): AsyncAction => {
|
||||||
return async (dispatch: any, getState: any): Promise<void> => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: CONNECT.TRY_TO_DUPLICATE,
|
type: CONNECT.TRY_TO_DUPLICATE,
|
||||||
device
|
device
|
||||||
@ -403,17 +485,18 @@ export const duplicateDevice = (device: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onDuplicateDevice = () => {
|
export const onDuplicateDevice = (): AsyncAction => {
|
||||||
return async (dispatch: any, getState: any): Promise<void> => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
|
||||||
dispatch(onSelectDevice(selected));
|
if (selected)
|
||||||
|
dispatch(onSelectDevice(selected));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function addAddress(): any {
|
export function addAddress(): AsyncAction {
|
||||||
return (dispatch, getState) => {
|
return (dispatch: Dispatch, getState: GetState): void => {
|
||||||
const selected = findSelectedDevice(getState().connect);
|
const selected = findSelectedDevice(getState().connect);
|
||||||
dispatch( DiscoveryActions.start(selected, getState().router.location.params.network, true) ); // TODO: network nicer
|
dispatch( DiscoveryActions.start(selected, getState().router.location.state.network, true) ); // TODO: network nicer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const ON_RESIZE: string = 'ON_RESIZE';
|
|
||||||
export const TOGGLE_DEVICE_DROPDOWN: string = 'TOGGLE_DEVICE_DROPDOWN';
|
|
||||||
import * as WALLET from './constants/wallet';
|
import * as WALLET from './constants/wallet';
|
||||||
|
|
||||||
export const onResize = (): any => {
|
import type { RouterLocationState } from '../flowtype';
|
||||||
return {
|
|
||||||
type: ON_RESIZE
|
export type WalletAction = {
|
||||||
}
|
type: typeof WALLET.SET_INITIAL_URL,
|
||||||
|
state?: RouterLocationState,
|
||||||
|
pathname?: string
|
||||||
|
} | {
|
||||||
|
type: typeof WALLET.TOGGLE_DEVICE_DROPDOWN,
|
||||||
|
opened: boolean
|
||||||
|
} | {
|
||||||
|
type: typeof WALLET.ON_BEFORE_UNLOAD
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onBeforeUnload = (): any => {
|
export const onBeforeUnload = (): WalletAction => {
|
||||||
return {
|
return {
|
||||||
type: WALLET.ON_BEFORE_UNLOAD
|
type: WALLET.ON_BEFORE_UNLOAD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const toggleDeviceDropdown = (opened: boolean): any => {
|
export const toggleDeviceDropdown = (opened: boolean): WalletAction => {
|
||||||
return {
|
return {
|
||||||
type: WALLET.TOGGLE_DEVICE_DROPDOWN,
|
type: WALLET.TOGGLE_DEVICE_DROPDOWN,
|
||||||
opened
|
opened
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import Web3 from 'web3';
|
import Web3, { ContractFactory, Contract } from 'web3';
|
||||||
import HDKey from 'hdkey';
|
import HDKey from 'hdkey';
|
||||||
import EthereumjsUtil from 'ethereumjs-util';
|
import EthereumjsUtil from 'ethereumjs-util';
|
||||||
import EthereumjsTx from 'ethereumjs-tx';
|
import EthereumjsTx from 'ethereumjs-tx';
|
||||||
@ -9,48 +9,47 @@ import TrezorConnect from 'trezor-connect';
|
|||||||
import { strip } from '../utils/ethUtils';
|
import { strip } from '../utils/ethUtils';
|
||||||
import * as ADDRESS from './constants/address';
|
import * as ADDRESS from './constants/address';
|
||||||
import * as WEB3 from './constants/web3';
|
import * as WEB3 from './constants/web3';
|
||||||
import { httpRequest } from '../utils/networkUtils';
|
|
||||||
|
|
||||||
type ActionMethod = (dispatch: any, getState: any) => Promise<any>;
|
import type {
|
||||||
|
Dispatch,
|
||||||
|
GetState,
|
||||||
|
Action,
|
||||||
|
AsyncAction,
|
||||||
|
} from '../flowtype';
|
||||||
|
|
||||||
type Web3Payload =
|
import type { Account } from '../reducers/AccountsReducer';
|
||||||
| {
|
|
||||||
name: string;
|
export type Web3Action = {
|
||||||
instance: Web3;
|
type: typeof WEB3.READY,
|
||||||
chainId: number;
|
} | {
|
||||||
erc20abi: any;
|
type: typeof WEB3.PENDING_TX_RESOLVED
|
||||||
}
|
} | Web3CreateAction
|
||||||
| {
|
| Web3UpdateBlockAction
|
||||||
network: string;
|
| Web3UpdateGasPriceAction;
|
||||||
blockHash: string;
|
|
||||||
}
|
export type Web3CreateAction = {
|
||||||
| {
|
type: typeof WEB3.CREATE,
|
||||||
network: string;
|
network: string,
|
||||||
gasPrice: string;
|
web3: any, //(web3instance)
|
||||||
}
|
erc20: any,
|
||||||
| {
|
chainId: string;
|
||||||
network: string;
|
|
||||||
address: string;
|
|
||||||
balance: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
network: string;
|
|
||||||
address: string;
|
|
||||||
nonce: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
network: string;
|
|
||||||
blockHash: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Web3Action = {
|
export type Web3UpdateBlockAction = {
|
||||||
type: string,
|
type: typeof WEB3.BLOCK_UPDATED,
|
||||||
payload?: Web3Payload
|
network: string,
|
||||||
|
blockHash: any
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Web3UpdateGasPriceAction = {
|
||||||
|
type: typeof WEB3.GAS_PRICE_UPDATED,
|
||||||
|
network: string,
|
||||||
|
gasPrice: any
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod {
|
export function init(web3: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const { config, ERC20Abi } = getState().localStorage;
|
const { config, ERC20Abi } = getState().localStorage;
|
||||||
|
|
||||||
@ -191,48 +190,48 @@ export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function initContracts(): ActionMethod {
|
// export function initContracts(): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
// return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
const { web3, abi, tokens } = getState().web3;
|
// const { web3, abi, tokens } = getState().web3;
|
||||||
|
|
||||||
const contracts = [];
|
// const contracts = [];
|
||||||
for (let token of tokens) {
|
// for (let token of tokens) {
|
||||||
contracts.push({
|
// contracts.push({
|
||||||
contract: web3.eth.contract(abi).at(token.address),
|
// contract: web3.eth.contract(abi).at(token.address),
|
||||||
name: token.name,
|
// name: token.name,
|
||||||
symbol: token.symbol,
|
// symbol: token.symbol,
|
||||||
decimal: token.decimal
|
// decimal: token.decimal
|
||||||
});
|
// });
|
||||||
|
|
||||||
// web3.eth.contract(abi).at(token.address).balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => {
|
// // web3.eth.contract(abi).at(token.address).balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => {
|
||||||
// console.warn('contrR', e, r.toString(10));
|
// // console.warn('contrR', e, r.toString(10));
|
||||||
// });
|
// // });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const contract = web3.eth.contract(abi).at('0x58cda554935e4a1f2acbe15f8757400af275e084');
|
// const contract = web3.eth.contract(abi).at('0x58cda554935e4a1f2acbe15f8757400af275e084');
|
||||||
|
|
||||||
contract.name.call((error, name) => {
|
// contract.name.call((error, name) => {
|
||||||
if (error) {
|
// if (error) {
|
||||||
// TODO: skip
|
// // TODO: skip
|
||||||
}
|
// }
|
||||||
contract.symbol.call((error, symbol) => {
|
// contract.symbol.call((error, symbol) => {
|
||||||
if (error) {
|
// if (error) {
|
||||||
// TODO: skip
|
// // TODO: skip
|
||||||
}
|
// }
|
||||||
|
|
||||||
contract.decimals.call((error, decimals) => {
|
// contract.decimals.call((error, decimals) => {
|
||||||
console.log("nameeeee", name, symbol, decimals)
|
// console.log("nameeeee", name, symbol, decimals)
|
||||||
})
|
// })
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
export function getGasPrice(network: string): ActionMethod {
|
export function getGasPrice(network: string): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const index: number = getState().web3.findIndex(w3 => w3.network === network);
|
const index: number = getState().web3.findIndex(w3 => w3.network === network);
|
||||||
|
|
||||||
@ -252,20 +251,20 @@ export function getGasPrice(network: string): ActionMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBalance(addr: Address): ActionMethod {
|
export function getBalance(account: Account): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const web3instance = getState().web3.filter(w3 => w3.network === addr.network)[0];
|
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
|
||||||
const web3 = web3instance.web3;
|
const web3: Web3 = web3instance.web3;
|
||||||
|
|
||||||
web3.eth.getBalance(addr.address, (error, balance) => {
|
web3.eth.getBalance(account.address, (error, balance) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
const newBalance: string = web3.fromWei(balance.toString(), 'ether');
|
const newBalance: string = web3.fromWei(balance.toString(), 'ether');
|
||||||
if (addr.balance !== newBalance) {
|
if (account.balance !== newBalance) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ADDRESS.SET_BALANCE,
|
type: ADDRESS.SET_BALANCE,
|
||||||
address: addr.address,
|
address: account.address,
|
||||||
network: addr.network,
|
network: account.network,
|
||||||
balance: newBalance
|
balance: newBalance
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -276,20 +275,20 @@ export function getBalance(addr: Address): ActionMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNonce(addr: Address) {
|
export function getNonce(account: Account): AsyncAction {
|
||||||
|
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const web3instance = getState().web3.filter(w3 => w3.network === addr.network)[0];
|
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
|
||||||
const web3 = web3instance.web3;
|
const web3 = web3instance.web3;
|
||||||
|
|
||||||
web3.eth.getTransactionCount(addr.address, (error, result) => {
|
web3.eth.getTransactionCount(account.address, (error, result) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (addr.nonce !== result) {
|
if (account.nonce !== result) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ADDRESS.SET_NONCE,
|
type: ADDRESS.SET_NONCE,
|
||||||
address: addr.address,
|
address: account.address,
|
||||||
network: addr.network,
|
network: account.network,
|
||||||
nonce: result
|
nonce: result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -298,8 +297,8 @@ export function getNonce(addr: Address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTransactionReceipt(tx: any): any {
|
export function getTransactionReceipt(tx: any): AsyncAction {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||||
|
|
||||||
const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0];
|
const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0];
|
||||||
const web3 = web3instance.web3;
|
const web3 = web3instance.web3;
|
||||||
@ -323,14 +322,14 @@ export function getTransactionReceipt(tx: any): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function updateLastBlock(hash: string) {
|
// export function updateLastBlock(hash: string): Action {
|
||||||
return {
|
// return {
|
||||||
type: 'web3__update_last_block',
|
// type: 'web3__update_last_block',
|
||||||
hash
|
// hash
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function getTransaction(web3, txid) {
|
export const getTransaction = (web3: Web3, txid: string): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
web3.eth.getTransaction(txid, (error, result) => {
|
web3.eth.getTransaction(txid, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -344,7 +343,7 @@ export function getTransaction(web3, txid) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function getBalanceAsync(web3, address) {
|
export const getBalanceAsync = (web3: Web3, address: string): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
web3.eth.getBalance(address, (error, result) => {
|
web3.eth.getBalance(address, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -356,7 +355,7 @@ export function getBalanceAsync(web3, address) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTokenBalanceAsync = (erc20: any, token: any, address: any): Promise<any> => {
|
export const getTokenBalanceAsync = (erc20: any, token: string, address: string): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const contr = erc20.at(token);
|
const contr = erc20.at(token);
|
||||||
@ -370,7 +369,7 @@ export const getTokenBalanceAsync = (erc20: any, token: any, address: any): Prom
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNonceAsync(web3, address) {
|
export const getNonceAsync = (web3: Web3, address: string): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
web3.eth.getTransactionCount(address, (error, result) => {
|
web3.eth.getTransactionCount(address, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -383,7 +382,7 @@ export function getNonceAsync(web3, address) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getTokenInfoAsync(erc20: any, address: string): Promise<any> {
|
export const getTokenInfoAsync = (erc20: any, address: string): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const contract = erc20.at(address);
|
const contract = erc20.at(address);
|
||||||
@ -417,7 +416,7 @@ export function getTokenInfoAsync(erc20: any, address: string): Promise<any> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function estimateGas(web3, gasOptions) {
|
export const estimateGas = (web3: Web3, gasOptions: any): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
web3.eth.estimateGas(gasOptions, (error, result) => {
|
web3.eth.estimateGas(gasOptions, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -429,7 +428,7 @@ export function estimateGas(web3, gasOptions) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGasPrice2(web3) {
|
export const getGasPrice2 = (web3: Web3): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
web3.eth.getGasPrice((error, result) => {
|
web3.eth.getGasPrice((error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -441,7 +440,7 @@ export function getGasPrice2(web3) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pushTx(web3, tx) {
|
export const pushTx = (web3: Web3, tx: any): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
web3.eth.sendRawTransaction(tx, (error, result) => {
|
web3.eth.sendRawTransaction(tx, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -452,7 +451,3 @@ export function pushTx(web3, tx) {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,26 +1,29 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const READY: string = 'trezorconnect__ready';
|
//regExp1 : string = '(.*)'
|
||||||
export const INITIALIZATION_ERROR: string = 'trezorconnect__init_error';
|
//regExp2 : '$1' = '$1'
|
||||||
export const SELECT_DEVICE: string = 'trezorconnect__select_device';
|
|
||||||
|
export const READY: 'trezorconnect__ready' = 'trezorconnect__ready';
|
||||||
|
export const INITIALIZATION_ERROR: 'trezorconnect__init_error' = 'trezorconnect__init_error';
|
||||||
|
export const SELECT_DEVICE: 'trezorconnect__select_device' = 'trezorconnect__select_device';
|
||||||
|
|
||||||
|
|
||||||
export const DEVICE_FROM_STORAGE: string = 'trezorconnect__device_from_storage';
|
export const DEVICE_FROM_STORAGE: 'trezorconnect__device_from_storage' = 'trezorconnect__device_from_storage';
|
||||||
export const AUTH_DEVICE: string = 'trezorconnect__auth_device';
|
export const AUTH_DEVICE: 'trezorconnect__auth_device' = 'trezorconnect__auth_device';
|
||||||
export const COIN_CHANGED: string = 'trezorconnect__coin_changed';
|
export const COIN_CHANGED: 'trezorconnect__coin_changed' = 'trezorconnect__coin_changed';
|
||||||
|
|
||||||
export const REMEMBER_REQUEST: string = 'trezorconnect__remember_request';
|
export const REMEMBER_REQUEST: 'trezorconnect__remember_request' = 'trezorconnect__remember_request';
|
||||||
export const FORGET_REQUEST: string = 'trezorconnect__forget_request';
|
export const FORGET_REQUEST: 'trezorconnect__forget_request' = 'trezorconnect__forget_request';
|
||||||
export const FORGET: string = 'trezorconnect__forget';
|
export const FORGET: 'trezorconnect__forget' = 'trezorconnect__forget';
|
||||||
export const FORGET_SINGLE: string = 'trezorconnect__forget_single';
|
export const FORGET_SINGLE: 'trezorconnect__forget_single' = 'trezorconnect__forget_single';
|
||||||
export const DISCONNECT_REQUEST: string = 'trezorconnect__disconnect_request';
|
export const DISCONNECT_REQUEST: 'trezorconnect__disconnect_request' = 'trezorconnect__disconnect_request';
|
||||||
export const REMEMBER: string = 'trezorconnect__remember';
|
export const REMEMBER: 'trezorconnect__remember' = 'trezorconnect__remember';
|
||||||
|
|
||||||
export const START_ACQUIRING: string = 'trezorconnect__start_acquiring';
|
export const START_ACQUIRING: 'trezorconnect__start_acquiring' = 'trezorconnect__start_acquiring';
|
||||||
export const STOP_ACQUIRING: string = 'trezorconnect__stop_acquiring';
|
export const STOP_ACQUIRING: 'trezorconnect__stop_acquiring' = 'trezorconnect__stop_acquiring';
|
||||||
|
|
||||||
export const TRY_TO_DUPLICATE: string = 'trezorconnect__try_to_duplicate';
|
export const TRY_TO_DUPLICATE: 'trezorconnect__try_to_duplicate' = 'trezorconnect__try_to_duplicate';
|
||||||
export const DUPLICATE: string = 'trezorconnect__duplicate';
|
export const DUPLICATE: 'trezorconnect__duplicate' = 'trezorconnect__duplicate';
|
||||||
|
|
||||||
export const DEVICE_STATE_EXCEPTION: string = 'trezorconnect__device_state_exception';
|
export const DEVICE_STATE_EXCEPTION: 'trezorconnect__device_state_exception' = 'trezorconnect__device_state_exception';
|
@ -1,11 +1,11 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const INIT: string = 'account__init';
|
export const INIT: 'account__init' = 'account__init';
|
||||||
export const DISPOSE: string = 'account__dispose';
|
export const DISPOSE: 'account__dispose' = 'account__dispose';
|
||||||
|
|
||||||
export const CREATE: string = 'address__create';
|
// export const CREATE: 'address__create' = 'address__create';
|
||||||
export const REMOVE: string = 'address__remove';
|
// export const REMOVE: 'address__remove' = 'address__remove';
|
||||||
export const SET_BALANCE: string = 'address__set_balance';
|
// export const SET_BALANCE: 'address__set_balance' = 'address__set_balance';
|
||||||
export const SET_NONCE: string = 'address__set_nonce';
|
// export const SET_NONCE: 'address__set_nonce' = 'address__set_nonce';
|
||||||
export const FROM_STORAGE: string = 'address__from_storage';
|
// export const FROM_STORAGE: 'address__from_storage' = 'address__from_storage';
|
@ -1,9 +1,9 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const CREATE: string = 'address__create';
|
export const CREATE: 'address__create' = 'address__create';
|
||||||
export const REMOVE: string = 'address__remove';
|
export const REMOVE: 'address__remove' = 'address__remove';
|
||||||
export const SET_BALANCE: string = 'address__set_balance';
|
export const SET_BALANCE: 'address__set_balance' = 'address__set_balance';
|
||||||
export const SET_NONCE: string = 'address__set_nonce';
|
export const SET_NONCE: 'address__set_nonce' = 'address__set_nonce';
|
||||||
export const FROM_STORAGE: string = 'address__from_storage';
|
export const FROM_STORAGE: 'address__from_storage' = 'address__from_storage';
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const START: string = 'discovery__start';
|
export const START: 'discovery__start' = 'discovery__start';
|
||||||
export const STOP: string = 'discovery__stop';
|
export const STOP: 'discovery__stop' = 'discovery__stop';
|
||||||
export const COMPLETE: string = 'discovery__complete';
|
export const COMPLETE: 'discovery__complete' = 'discovery__complete';
|
||||||
export const WAITING: string = 'discovery__waiting';
|
export const WAITING: 'discovery__waiting' = 'discovery__waiting';
|
||||||
export const FROM_STORAGE: string = 'discovery__from_storage';
|
export const FROM_STORAGE: 'discovery__from_storage' = 'discovery__from_storage';
|
@ -1,6 +1,6 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const SAVE: string = 'storage__save';
|
export const SAVE: 'storage__save' = 'storage__save';
|
||||||
export const READY: string = 'storage__ready';
|
export const READY: 'storage__ready' = 'storage__ready';
|
||||||
export const ERROR: string = 'storage__error';
|
export const ERROR: 'storage__error' = 'storage__error';
|
5
src/js/actions/constants/log.js
Normal file
5
src/js/actions/constants/log.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/* @flow */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
export const OPEN: 'log__open' = 'log__open';
|
||||||
|
export const CLOSE: 'log__close' = 'log__close';
|
@ -1,14 +1,17 @@
|
|||||||
export const ON_PASSPHRASE_CHANGE: string = 'action__on_passphrase_change';
|
/* @flow */
|
||||||
export const ON_PASSPHRASE_SHOW: string = 'action__on_passphrase_show';
|
'use strict';
|
||||||
export const ON_PASSPHRASE_HIDE: string = 'action__on_passphrase_hide';
|
|
||||||
export const ON_PASSPHRASE_SAVE: string = 'action__on_passphrase_save';
|
|
||||||
export const ON_PASSPHRASE_FORGET: string = 'action__on_passphrase_forget';
|
|
||||||
export const ON_PASSPHRASE_FOCUS: string = 'action__on_passphrase_focus';
|
|
||||||
export const ON_PASSPHRASE_BLUR: string = 'action__on_passphrase_blur';
|
|
||||||
export const ON_PASSPHRASE_SUBMIT: string = 'action__on_passphrase_submit';
|
|
||||||
|
|
||||||
export const FORGET: string = 'modal__forget';
|
export const ON_PASSPHRASE_CHANGE: 'action__on_passphrase_change' = 'action__on_passphrase_change';
|
||||||
export const REMEMBER: string = 'modal__remember';
|
export const ON_PASSPHRASE_SHOW: 'action__on_passphrase_show' = 'action__on_passphrase_show';
|
||||||
export const ON_FORGET: string = 'modal__on_forget';
|
export const ON_PASSPHRASE_HIDE: 'action__on_passphrase_hide' = 'action__on_passphrase_hide';
|
||||||
export const ON_REMEMBER: string = 'modal__on_remember';
|
export const ON_PASSPHRASE_SAVE: 'action__on_passphrase_save' = 'action__on_passphrase_save';
|
||||||
export const CLOSE: string = 'modal__close';
|
export const ON_PASSPHRASE_FORGET: 'action__on_passphrase_forget' = 'action__on_passphrase_forget';
|
||||||
|
export const ON_PASSPHRASE_FOCUS: 'action__on_passphrase_focus' = 'action__on_passphrase_focus';
|
||||||
|
export const ON_PASSPHRASE_BLUR: 'action__on_passphrase_blur' = 'action__on_passphrase_blur';
|
||||||
|
export const ON_PASSPHRASE_SUBMIT: 'action__on_passphrase_submit' = 'action__on_passphrase_submit';
|
||||||
|
|
||||||
|
export const FORGET: 'modal__forget' = 'modal__forget';
|
||||||
|
export const REMEMBER: 'modal__remember' = 'modal__remember';
|
||||||
|
export const ON_FORGET: 'modal__on_forget' = 'modal__on_forget';
|
||||||
|
export const ON_REMEMBER: 'modal__on_remember' = 'modal__on_remember';
|
||||||
|
export const CLOSE: 'modal__close' = 'modal__close';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const ADD: string = 'notification__add';
|
export const ADD: 'notification__add' = 'notification__add';
|
||||||
export const CLOSE: string = 'notification__close';
|
export const CLOSE: 'notification__close' = 'notification__close';
|
||||||
export const REMOVE: string = 'account__remove';
|
export const REMOVE: 'account__remove' = 'account__remove';
|
@ -1,8 +1,8 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const INIT: string = 'receive__init';
|
export const INIT: 'receive__init' = 'receive__init';
|
||||||
export const DISPOSE: string = 'receive__dispose';
|
export const DISPOSE: 'receive__dispose' = 'receive__dispose';
|
||||||
export const REQUEST_UNVERIFIED: string = 'receive__request_unverified';
|
export const REQUEST_UNVERIFIED: 'receive__request_unverified' = 'receive__request_unverified';
|
||||||
export const SHOW_ADDRESS: string = 'receive__show_address';
|
export const SHOW_ADDRESS: 'receive__show_address' = 'receive__show_address';
|
||||||
export const SHOW_UNVERIFIED_ADDRESS: string = 'receive__show_unverified';
|
export const SHOW_UNVERIFIED_ADDRESS: 'receive__show_unverified' = 'receive__show_unverified';
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const INIT: string = 'send__init';
|
export const INIT: 'send__init' = 'send__init';
|
||||||
export const DISPOSE: string = 'send__dispose';
|
export const DISPOSE: 'send__dispose' = 'send__dispose';
|
||||||
export const VALIDATION: string = 'send__validation';
|
export const VALIDATION: 'send__validation' = 'send__validation';
|
||||||
export const ADDRESS_CHANGE: string = 'send__address_change';
|
export const ADDRESS_CHANGE: 'send__address_change' = 'send__address_change';
|
||||||
export const AMOUNT_CHANGE: string = 'send__amount_change';
|
export const AMOUNT_CHANGE: 'send__amount_change' = 'send__amount_change';
|
||||||
export const SET_MAX: string = 'send__set_max';
|
export const SET_MAX: 'send__set_max' = 'send__set_max';
|
||||||
export const CURRENCY_CHANGE: string = 'send__currency_change';
|
export const CURRENCY_CHANGE: 'send__currency_change' = 'send__currency_change';
|
||||||
export const FEE_LEVEL_CHANGE: string = 'send__fee_level_change';
|
export const FEE_LEVEL_CHANGE: 'send__fee_level_change' = 'send__fee_level_change';
|
||||||
export const GAS_PRICE_CHANGE: string = 'send__gas_price_change';
|
export const GAS_PRICE_CHANGE: 'send__gas_price_change' = 'send__gas_price_change';
|
||||||
export const GAS_LIMIT_CHANGE: string = 'send__gas_limit_change';
|
export const GAS_LIMIT_CHANGE: 'send__gas_limit_change' = 'send__gas_limit_change';
|
||||||
export const UPDATE_FEE_LEVELS: string = 'send__update_fee_levels';
|
export const UPDATE_FEE_LEVELS: 'send__update_fee_levels' = 'send__update_fee_levels';
|
||||||
export const DATA_CHANGE: string = 'send__data_change';
|
export const DATA_CHANGE: 'send__data_change' = 'send__data_change';
|
||||||
export const SEND: string = 'send__submit';
|
export const SEND: 'send__submit' = 'send__submit';
|
||||||
export const TX_COMPLETE: string = 'send__tx_complete';
|
export const TX_COMPLETE: 'send__tx_complete' = 'send__tx_complete';
|
||||||
export const TX_ERROR: string = 'send__tx_error';
|
export const TX_ERROR: 'send__tx_error' = 'send__tx_error';
|
||||||
export const TOGGLE_ADVANCED: string = 'send__toggle_advanced';
|
export const TOGGLE_ADVANCED: 'send__toggle_advanced' = 'send__toggle_advanced';
|
@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const INIT: string = 'summary__init';
|
export const INIT: 'summary__init' = 'summary__init';
|
||||||
export const DISPOSE: string = 'summary__dispose';
|
export const DISPOSE: 'summary__dispose' = 'summary__dispose';
|
||||||
export const ADD_TOKEN: string = 'summary__add_token';
|
export const ADD_TOKEN: 'summary__add_token' = 'summary__add_token';
|
||||||
export const DETAILS_TOGGLE: string = 'summary__details_toggle';
|
export const DETAILS_TOGGLE: 'summary__details_toggle' = 'summary__details_toggle';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const ADD: string = 'token__add';
|
export const ADD: 'token__add' = 'token__add';
|
||||||
export const REMOVE: string = 'token__remove';
|
export const REMOVE: 'token__remove' = 'token__remove';
|
||||||
export const SET_BALANCE: string = 'token__set_balance';
|
export const SET_BALANCE: 'token__set_balance' = 'token__set_balance';
|
||||||
export const FROM_STORAGE: string = 'token__from_storage';
|
export const FROM_STORAGE: 'token__from_storage' = 'token__from_storage';
|
@ -1,6 +1,6 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const ON_BEFORE_UNLOAD: string = 'wallet__on_before_unload';
|
export const ON_BEFORE_UNLOAD: 'wallet__on_before_unload' = 'wallet__on_before_unload';
|
||||||
export const TOGGLE_DEVICE_DROPDOWN: string = 'wallet_toggle_dropdown';
|
export const TOGGLE_DEVICE_DROPDOWN: 'wallet_toggle_dropdown' = 'wallet_toggle_dropdown';
|
||||||
export const SET_INITIAL_URL: string = 'wallet_set_initial_url';
|
export const SET_INITIAL_URL: 'wallet_set_initial_url' = 'wallet_set_initial_url';
|
@ -1,10 +1,10 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const START: string = 'web3__start';
|
export const START: 'web3__start' = 'web3__start';
|
||||||
export const STOP: string = 'web3__stop';
|
export const STOP: 'web3__stop' = 'web3__stop';
|
||||||
export const CREATE: string = 'web3__create';
|
export const CREATE: 'web3__create' = 'web3__create';
|
||||||
export const READY: string = 'web3__ready';
|
export const READY: 'web3__ready' = 'web3__ready';
|
||||||
export const BLOCK_UPDATED: string = 'web3__block_updated';
|
export const BLOCK_UPDATED: 'web3__block_updated' = 'web3__block_updated';
|
||||||
export const GAS_PRICE_UPDATED: string = 'web3__gas_price_updated';
|
export const GAS_PRICE_UPDATED: 'web3__gas_price_updated' = 'web3__gas_price_updated';
|
||||||
export const PENDING_TX_RESOLVED: string = 'web3__pending_tx_resolved';
|
export const PENDING_TX_RESOLVED: 'web3__pending_tx_resolved' = 'web3__pending_tx_resolved';
|
@ -6,8 +6,13 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import * as LogActions from '../../actions/LogActions';
|
import * as LogActions from '../../actions/LogActions';
|
||||||
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
|
||||||
const Footer = (props: any): any => {
|
type Props = {
|
||||||
|
toggle: typeof LogActions.toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
const Footer = (props: Props): React$Element<string> => {
|
||||||
return (
|
return (
|
||||||
<footer>
|
<footer>
|
||||||
<span>© 2018</span>
|
<span>© 2018</span>
|
||||||
@ -19,12 +24,12 @@ const Footer = (props: any): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
(state) => {
|
(state: State) => {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(dispatch) => {
|
(dispatch: Dispatch) => {
|
||||||
return {
|
return {
|
||||||
toggle: bindActionCreators(LogActions.toggle, dispatch),
|
toggle: bindActionCreators(LogActions.toggle, dispatch),
|
||||||
};
|
};
|
||||||
|
@ -1,33 +1,30 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default class Header extends Component {
|
const Header = (): React$Element<string> => {
|
||||||
render() {
|
return (
|
||||||
return (
|
<header>
|
||||||
<header>
|
<div className="layout-wrapper">
|
||||||
<div className="layout-wrapper">
|
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 163.7 41.9" width="100%" height="100%" preserveAspectRatio="xMinYMin meet">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 163.7 41.9" width="100%" height="100%" preserveAspectRatio="xMinYMin meet">
|
<polygon points="101.1,12.8 118.2,12.8 118.2,17.3 108.9,29.9 118.2,29.9 118.2,35.2 101.1,35.2 101.1,30.7 110.4,18.1 101.1,18.1"/>
|
||||||
<polygon points="101.1,12.8 118.2,12.8 118.2,17.3 108.9,29.9 118.2,29.9 118.2,35.2 101.1,35.2 101.1,30.7 110.4,18.1 101.1,18.1"/>
|
<path d="M158.8,26.9c2.1-0.8,4.3-2.9,4.3-6.6c0-4.5-3.1-7.4-7.7-7.4h-10.5v22.3h5.8v-7.5h2.2l4.1,7.5h6.7L158.8,26.9z M154.7,22.5 h-4V18h4c1.5,0,2.5,0.9,2.5,2.2C157.2,21.6,156.2,22.5,154.7,22.5z"/>
|
||||||
<path d="M158.8,26.9c2.1-0.8,4.3-2.9,4.3-6.6c0-4.5-3.1-7.4-7.7-7.4h-10.5v22.3h5.8v-7.5h2.2l4.1,7.5h6.7L158.8,26.9z M154.7,22.5 h-4V18h4c1.5,0,2.5,0.9,2.5,2.2C157.2,21.6,156.2,22.5,154.7,22.5z"/>
|
<path d="M130.8,12.5c-6.8,0-11.6,4.9-11.6,11.5s4.9,11.5,11.6,11.5s11.7-4.9,11.7-11.5S137.6,12.5,130.8,12.5z M130.8,30.3 c-3.4,0-5.7-2.6-5.7-6.3c0-3.8,2.3-6.3,5.7-6.3c3.4,0,5.8,2.6,5.8,6.3C136.6,27.7,134.2,30.3,130.8,30.3z"/>
|
||||||
<path d="M130.8,12.5c-6.8,0-11.6,4.9-11.6,11.5s4.9,11.5,11.6,11.5s11.7-4.9,11.7-11.5S137.6,12.5,130.8,12.5z M130.8,30.3 c-3.4,0-5.7-2.6-5.7-6.3c0-3.8,2.3-6.3,5.7-6.3c3.4,0,5.8,2.6,5.8,6.3C136.6,27.7,134.2,30.3,130.8,30.3z"/>
|
<polygon points="82.1,12.8 98.3,12.8 98.3,18 87.9,18 87.9,21.3 98,21.3 98,26.4 87.9,26.4 87.9,30 98.3,30 98.3,35.2 82.1,35.2 "/>
|
||||||
<polygon points="82.1,12.8 98.3,12.8 98.3,18 87.9,18 87.9,21.3 98,21.3 98,26.4 87.9,26.4 87.9,30 98.3,30 98.3,35.2 82.1,35.2 "/>
|
<path d="M24.6,9.7C24.6,4.4,20,0,14.4,0S4.2,4.4,4.2,9.7v3.1H0v22.3h0l14.4,6.7l14.4-6.7h0V12.9h-4.2V9.7z M9.4,9.7 c0-2.5,2.2-4.5,5-4.5s5,2,5,4.5v3.1H9.4V9.7z M23,31.5l-8.6,4l-8.6-4V18.1H23V31.5z"/>
|
||||||
<path d="M24.6,9.7C24.6,4.4,20,0,14.4,0S4.2,4.4,4.2,9.7v3.1H0v22.3h0l14.4,6.7l14.4-6.7h0V12.9h-4.2V9.7z M9.4,9.7 c0-2.5,2.2-4.5,5-4.5s5,2,5,4.5v3.1H9.4V9.7z M23,31.5l-8.6,4l-8.6-4V18.1H23V31.5z"/>
|
<path d="M79.4,20.3c0-4.5-3.1-7.4-7.7-7.4H61.2v22.3H67v-7.5h2.2l4.1,7.5H80l-4.9-8.3C77.2,26.1,79.4,24,79.4,20.3z M71,22.5h-4V18 h4c1.5,0,2.5,0.9,2.5,2.2C73.5,21.6,72.5,22.5,71,22.5z"/>
|
||||||
<path d="M79.4,20.3c0-4.5-3.1-7.4-7.7-7.4H61.2v22.3H67v-7.5h2.2l4.1,7.5H80l-4.9-8.3C77.2,26.1,79.4,24,79.4,20.3z M71,22.5h-4V18 h4c1.5,0,2.5,0.9,2.5,2.2C73.5,21.6,72.5,22.5,71,22.5z"/>
|
<polygon points="40.5,12.8 58.6,12.8 58.6,18.1 52.4,18.1 52.4,35.2 46.6,35.2 46.6,18.1 40.5,18.1 "/>
|
||||||
<polygon points="40.5,12.8 58.6,12.8 58.6,18.1 52.4,18.1 52.4,35.2 46.6,35.2 46.6,18.1 40.5,18.1 "/>
|
</svg>
|
||||||
</svg>
|
<div>
|
||||||
<div>
|
<a href="https://trezor.io/" target="_blank" rel="noreferrer noopener">TREZOR</a>
|
||||||
<a href="https://trezor.io/" target="_blank" rel="noreferrer noopener">TREZOR</a>
|
<a href="https://doc.satoshilabs.com/trezor-user/" target="_blank" rel="noreferrer noopener">Docs</a>
|
||||||
<a href="https://doc.satoshilabs.com/trezor-user/" target="_blank" rel="noreferrer noopener">Docs</a>
|
<a href="https://blog.trezor.io/" target="_blank" rel="noreferrer noopener">Blog</a>
|
||||||
<a href="https://blog.trezor.io/" target="_blank" rel="noreferrer noopener">Blog</a>
|
<a href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Support</a>
|
||||||
<a href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Support</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</div>
|
||||||
);
|
</header>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Header;
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default (props: any): any => {
|
export default (props: { size: string, label?: string }): React$Element<string> => {
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
width: `${props.size}px`,
|
width: `${props.size}px`,
|
||||||
|
@ -6,9 +6,14 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import * as LogActions from '../../actions/LogActions';
|
import * as LogActions from '../../actions/LogActions';
|
||||||
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
|
||||||
const Log = (props: any) => {
|
type Props = {
|
||||||
|
log: $ElementType<State, 'log'>,
|
||||||
|
toggle: typeof LogActions.toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
const Log = (props: Props): ?React$Element<string> => {
|
||||||
if (!props.log.opened)
|
if (!props.log.opened)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -23,12 +28,12 @@ const Log = (props: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
(state) => {
|
(state: State) => {
|
||||||
return {
|
return {
|
||||||
log: state.log
|
log: state.log
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(dispatch) => {
|
(dispatch: Dispatch) => {
|
||||||
return {
|
return {
|
||||||
toggle: bindActionCreators(LogActions.toggle, dispatch),
|
toggle: bindActionCreators(LogActions.toggle, dispatch),
|
||||||
};
|
};
|
||||||
|
@ -6,23 +6,37 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import * as NOTIFICATION from '../../actions/constants/notification';
|
import * as NOTIFICATION from '../../actions/constants/notification';
|
||||||
|
import type { Action, State, Dispatch } from '../../flowtype';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
notifications: $ElementType<State, 'notifications'>,
|
||||||
|
close: (notif?: any) => Action
|
||||||
|
}
|
||||||
|
|
||||||
export const Notification = (props: any) => {
|
type NProps = {
|
||||||
|
key?: number;
|
||||||
|
className: string;
|
||||||
|
cancelable?: boolean;
|
||||||
|
title: string;
|
||||||
|
message?: string;
|
||||||
|
actions?: Array<any>;
|
||||||
|
close?: (notif?: any) => Action
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Notification = (props: NProps): React$Element<string> => {
|
||||||
const className = `notification ${ props.className }`;
|
const className = `notification ${ props.className }`;
|
||||||
|
const close: Function = typeof props.close === 'function' ? props.close : () => {}; // TODO: add default close action
|
||||||
|
const actionButtons = props.actions ? props.actions.map((a, i) => {
|
||||||
const actionButtons = !props.actions ? null : props.actions.map((a, i) => {
|
|
||||||
return (
|
return (
|
||||||
<button key={ i } onClick={ event => { props.close(); a.callback(); } } className="transparent">{ a.label }</button>
|
<button key={ i } onClick={ event => { close(); a.callback(); } } className="transparent">{ a.label }</button>
|
||||||
)
|
)
|
||||||
});
|
}) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ className }>
|
<div className={ className }>
|
||||||
{ props.cancelable ? (
|
{ props.cancelable ? (
|
||||||
<button className="notification-close transparent"
|
<button className="notification-close transparent"
|
||||||
onClick={ event => props.close() }></button>
|
onClick={ event => close() }></button>
|
||||||
) : null }
|
) : null }
|
||||||
<div className="notification-body">
|
<div className="notification-body">
|
||||||
<h2>{ props.title }</h2>
|
<h2>{ props.title }</h2>
|
||||||
@ -38,7 +52,7 @@ export const Notification = (props: any) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NotificationGroup = (props: any) => {
|
export const NotificationGroup = (props: Props) => {
|
||||||
const { notifications, close } = props;
|
const { notifications, close } = props;
|
||||||
return notifications.map((n, i) => {
|
return notifications.map((n, i) => {
|
||||||
return (
|
return (
|
||||||
@ -56,14 +70,14 @@ export const NotificationGroup = (props: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
(state) => {
|
(state: State) => {
|
||||||
return {
|
return {
|
||||||
notifications: state.notifications
|
notifications: state.notifications
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(dispatch) => {
|
(dispatch: Dispatch) => {
|
||||||
return {
|
return {
|
||||||
close: bindActionCreators((notif) => {
|
close: bindActionCreators((notif?: any): Action => {
|
||||||
return {
|
return {
|
||||||
type: NOTIFICATION.CLOSE,
|
type: NOTIFICATION.CLOSE,
|
||||||
payload: notif
|
payload: notif
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import TrezorConnect from 'trezor-connect';
|
import TrezorConnect from 'trezor-connect';
|
||||||
|
|
||||||
export default class InstallBridge extends Component {
|
type Props = {
|
||||||
|
transport: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class InstallBridge extends Component<Props> {
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
const transport: any = this.props.transport;
|
const transport: any = this.props.transport;
|
||||||
|
@ -7,27 +7,39 @@ import Select from 'react-select';
|
|||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
version: string;
|
version: string;
|
||||||
target: string;
|
target: ?InstallTarget;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const installers = [
|
type InstallTarget = {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const installers: Array<InstallTarget> = [
|
||||||
{ id: 'Windows', value: 'trezor-bridge-2.0.11-win32-install.exe', label: 'Windows' },
|
{ id: 'Windows', value: 'trezor-bridge-2.0.11-win32-install.exe', label: 'Windows' },
|
||||||
{ id: 'macOS', value: 'trezor-bridge-2.0.11.pkg', label: 'Mac OS X' },
|
{ id: 'macOS', value: 'trezor-bridge-2.0.11.pkg', label: 'Mac OS X' },
|
||||||
{ id: 'Linux', value: 'trezor-bridge_2.0.11_amd64.deb', label: 'Linux 64-bit (deb)' },
|
{ id: 'Linux', value: 'trezor-bridge_2.0.11_amd64.deb', label: 'Linux 64-bit (deb)' },
|
||||||
{ id: 'Linux-rpm', value: 'trezor-bridge_2.0.11_amd64.rpm', label: 'Linux 64-bit (rpm)' },
|
{ id: 'Linux-rpm', value: 'trezor-bridge_2.0.11_amd64.rpm', label: 'Linux 64-bit (rpm)' },
|
||||||
{ value: 'trezor-bridge_2.0.11_amd32.deb', label: 'Linux 32-bit (deb)' },
|
{ id: '01', value: 'trezor-bridge_2.0.11_amd32.deb', label: 'Linux 32-bit (deb)' },
|
||||||
{ value: 'trezor-bridge_2.0.11_amd32.rpm', label: 'Linux 32-bit (rpm)' },
|
{ id: '02', value: 'trezor-bridge_2.0.11_amd32.rpm', label: 'Linux 32-bit (rpm)' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default class InstallBridge extends Component {
|
// import type { Props } from './index';
|
||||||
|
|
||||||
state: State;
|
type Props = {
|
||||||
|
browserState: {
|
||||||
|
osname: string,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
export default class InstallBridge extends Component<Props, State> {
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const currentTarget = installers.find(i => i.id === props.browserState.osname);
|
const currentTarget: ?InstallTarget = installers.find(i => i.id === props.browserState.osname);
|
||||||
this.state = {
|
this.state = {
|
||||||
version: '2.0.12',
|
version: '2.0.12',
|
||||||
url: 'https://wallet.trezor.io/data/bridge/2.0.12/',
|
url: 'https://wallet.trezor.io/data/bridge/2.0.12/',
|
||||||
@ -35,7 +47,7 @@ export default class InstallBridge extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(value) {
|
onChange(value: InstallTarget) {
|
||||||
this.setState({
|
this.setState({
|
||||||
target: value
|
target: value
|
||||||
});
|
});
|
||||||
@ -44,7 +56,7 @@ export default class InstallBridge extends Component {
|
|||||||
|
|
||||||
componentWillUpdate() {
|
componentWillUpdate() {
|
||||||
if (this.props.browserState.osname && !this.state.target) {
|
if (this.props.browserState.osname && !this.state.target) {
|
||||||
const currentTarget = installers.find(i => i.id === this.props.browserState.osname);
|
const currentTarget: ?InstallTarget = installers.find(i => i.id === this.props.browserState.osname);
|
||||||
this.setState({
|
this.setState({
|
||||||
target: currentTarget
|
target: currentTarget
|
||||||
})
|
})
|
||||||
@ -55,8 +67,9 @@ export default class InstallBridge extends Component {
|
|||||||
if (!this.state.target) {
|
if (!this.state.target) {
|
||||||
return <Preloader />;
|
return <Preloader />;
|
||||||
}
|
}
|
||||||
|
const label: string = this.state.target.label;
|
||||||
const url = `${ this.state.url }${ this.state.target.value }`;
|
const url = `${ this.state.url }${ this.state.target.value }`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<h3 className="claim">TREZOR Bridge. <span>Version 2.0.12</span></h3>
|
<h3 className="claim">TREZOR Bridge. <span>Version 2.0.12</span></h3>
|
||||||
@ -70,7 +83,7 @@ export default class InstallBridge extends Component {
|
|||||||
value={ this.state.target }
|
value={ this.state.target }
|
||||||
onChange={ this.onChange.bind(this) }
|
onChange={ this.onChange.bind(this) }
|
||||||
options={ installers } />
|
options={ installers } />
|
||||||
<a href={ url } className="button">Download for { this.state.target.label }</a>
|
<a href={ url } className="button">Download for { label }</a>
|
||||||
</div>
|
</div>
|
||||||
<p>Learn more about latest version in <a href="https://github.com/trezor/trezord-go/blob/master/CHANGELOG.md" className="green" target="_blank" rel="noreferrer noopener">Changelog</a></p>
|
<p>Learn more about latest version in <a href="https://github.com/trezor/trezord-go/blob/master/CHANGELOG.md" className="green" target="_blank" rel="noreferrer noopener">Changelog</a></p>
|
||||||
</main>
|
</main>
|
||||||
|
@ -13,8 +13,9 @@ import Log from '../common/Log';
|
|||||||
// import { Notification } from '../common/Notification';
|
// import { Notification } from '../common/Notification';
|
||||||
import Notifications, { Notification } from '../common/Notification';
|
import Notifications, { Notification } from '../common/Notification';
|
||||||
|
|
||||||
|
import type { Props } from './index';
|
||||||
|
|
||||||
const BrowserNotSupported = (props: any) => {
|
const BrowserNotSupported = (props: {}): React$Element<string> => {
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<h2>Your browser is not supported</h2>
|
<h2>Your browser is not supported</h2>
|
||||||
@ -33,7 +34,9 @@ const BrowserNotSupported = (props: any) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (props: any): any => {
|
|
||||||
|
|
||||||
|
export default (props: Props) => {
|
||||||
|
|
||||||
const web3 = props.web3;
|
const web3 = props.web3;
|
||||||
const { devices, browserState, transport } = props.connect;
|
const { devices, browserState, transport } = props.connect;
|
||||||
@ -43,7 +46,7 @@ export default (props: any): any => {
|
|||||||
let notification = null;
|
let notification = null;
|
||||||
let body = null;
|
let body = null;
|
||||||
let css: string = 'app landing';
|
let css: string = 'app landing';
|
||||||
const bridgeRoute: boolean = props.router.location.params.hasOwnProperty('bridge');
|
const bridgeRoute: boolean = props.router.location.state.hasOwnProperty('bridge');
|
||||||
|
|
||||||
if (localStorageError) {
|
if (localStorageError) {
|
||||||
notification = (<Notification
|
notification = (<Notification
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default (props: any): any => {
|
export default (props: {}): React$Element<string> => {
|
||||||
return (
|
return (
|
||||||
<section className="landing">
|
<section className="landing">
|
||||||
localstorage ERROR
|
localstorage ERROR
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Loader from '../common/LoaderCircle';
|
import Loader from '../common/LoaderCircle';
|
||||||
|
|
||||||
export default (props: any): any => {
|
export default (props: {}): React$Element<string> => {
|
||||||
return (
|
return (
|
||||||
<section className="landing">
|
<section className="landing">
|
||||||
<Loader label="Loading" size="100" />
|
<Loader label="Loading" size="100" />
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default (props: any): any => {
|
export default (props: {}): React$Element<string> => {
|
||||||
return (
|
return (
|
||||||
<section className="landing">
|
<section className="landing">
|
||||||
connect ERROR
|
connect ERROR
|
||||||
|
@ -7,7 +7,27 @@ import { connect } from 'react-redux';
|
|||||||
|
|
||||||
import LandingPage from './LandingPage';
|
import LandingPage from './LandingPage';
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
localStorage: any,
|
||||||
|
modal: any,
|
||||||
|
web3: any,
|
||||||
|
wallet: any,
|
||||||
|
connect: any,
|
||||||
|
router: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = {
|
||||||
|
foo: () => string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<State, OwnProps, Props> = (state: State): Props => {
|
||||||
return {
|
return {
|
||||||
localStorage: state.localStorage,
|
localStorage: state.localStorage,
|
||||||
modal: state.modal,
|
modal: state.modal,
|
||||||
@ -18,10 +38,10 @@ const mapStateToProps = (state, own) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch) => {
|
||||||
return {
|
return {
|
||||||
|
foo: ():string => { return "A"; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(LandingPage);
|
export default connect(mapStateToProps, null)(LandingPage);
|
@ -2,8 +2,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type { Props } from './index';
|
||||||
|
|
||||||
const Confirmation = (props): any => {
|
const Confirmation = (props: Props) => {
|
||||||
const {
|
const {
|
||||||
amount,
|
amount,
|
||||||
address,
|
address,
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type { Props } from './index';
|
||||||
|
|
||||||
const InvalidPin = (props): any => {
|
const InvalidPin = (props: Props) => {
|
||||||
const { device } = props.modal;
|
const { device } = props.modal;
|
||||||
return (
|
return (
|
||||||
<div className="pin">
|
<div className="pin">
|
||||||
|
@ -5,6 +5,7 @@ import React, { Component } from 'react';
|
|||||||
import raf from 'raf';
|
import raf from 'raf';
|
||||||
import { findSelectedDevice } from '../../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
|
import type { Props } from './index';
|
||||||
type State = {
|
type State = {
|
||||||
deviceLabel: string;
|
deviceLabel: string;
|
||||||
singleInput: boolean;
|
singleInput: boolean;
|
||||||
@ -17,13 +18,14 @@ type State = {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PinModal extends Component {
|
export default class PinModal extends Component<Props, State> {
|
||||||
|
|
||||||
|
keyboardHandler: (event: KeyboardEvent) => void;
|
||||||
state: State;
|
state: State;
|
||||||
passphraseInput: HTMLInputElement;
|
passphraseInput: ?HTMLInputElement;
|
||||||
passphraseRevisionInput: HTMLInputElement;
|
passphraseRevisionInput: ?HTMLInputElement;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// check if this device is already known
|
// check if this device is already known
|
||||||
@ -36,8 +38,6 @@ export default class PinModal extends Component {
|
|||||||
singleInput = selected.remember;
|
singleInput = selected.remember;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.warn("-----PASSS", selected)
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
deviceLabel,
|
deviceLabel,
|
||||||
singleInput,
|
singleInput,
|
||||||
@ -72,7 +72,8 @@ export default class PinModal extends Component {
|
|||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
// one time autofocus
|
// one time autofocus
|
||||||
this.passphraseInput.focus();
|
if (this.passphraseInput)
|
||||||
|
this.passphraseInput.focus();
|
||||||
this.keyboardHandler = this.keyboardHandler.bind(this);
|
this.keyboardHandler = this.keyboardHandler.bind(this);
|
||||||
window.addEventListener('keydown', this.keyboardHandler, false);
|
window.addEventListener('keydown', this.keyboardHandler, false);
|
||||||
|
|
||||||
@ -117,9 +118,10 @@ export default class PinModal extends Component {
|
|||||||
passphraseRevisionInputValue = passphraseRevision.replace(/./g, '•');
|
passphraseRevisionInputValue = passphraseRevision.replace(/./g, '•');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.passphraseInput.value = passphraseInputValue;
|
if (this.passphraseInput) {
|
||||||
this.passphraseInput.setAttribute("type", visible ? "text" : "password");
|
this.passphraseInput.value = passphraseInputValue;
|
||||||
|
this.passphraseInput.setAttribute("type", visible ? "text" : "password");
|
||||||
|
}
|
||||||
if (this.passphraseRevisionInput) {
|
if (this.passphraseRevisionInput) {
|
||||||
this.passphraseRevisionInput.value = passphraseRevisionInputValue;
|
this.passphraseRevisionInput.value = passphraseRevisionInputValue;
|
||||||
this.passphraseRevisionInput.setAttribute("type", visible ? "text" : "password");
|
this.passphraseRevisionInput.setAttribute("type", visible ? "text" : "password");
|
||||||
@ -207,28 +209,8 @@ export default class PinModal extends Component {
|
|||||||
|
|
||||||
render(): any {
|
render(): any {
|
||||||
|
|
||||||
const {
|
|
||||||
//onPassphraseChange,
|
|
||||||
//onPassphraseSubmit,
|
|
||||||
//onPassphraseSubmitEmpty,
|
|
||||||
//onPassphraseForget,
|
|
||||||
//onPassphraseFocus,
|
|
||||||
//onPassphraseBlur,
|
|
||||||
//onPassphraseSave,
|
|
||||||
//onPassphraseShow,
|
|
||||||
//onPassphraseHide
|
|
||||||
} = this.props.modalActions;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
device,
|
device,
|
||||||
//passphrase,
|
|
||||||
//passphraseRevision,
|
|
||||||
//passphraseFocused,
|
|
||||||
//passphraseRevisionFocused,
|
|
||||||
//passphraseVisible,
|
|
||||||
//passphraseMatch,
|
|
||||||
//passphraseRevisionTouched,
|
|
||||||
passphraseCached
|
|
||||||
} = this.props.modal;
|
} = this.props.modal;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const Confirmation = (props): any => {
|
const Confirmation = () => {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="confirm-tx">
|
<div className="confirm-tx">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React, { Component, KeyboardEvent } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import type { Props } from './index';
|
||||||
type State = {
|
type State = {
|
||||||
pin: string;
|
pin: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Pin extends Component {
|
export default class Pin extends Component<Props, State> {
|
||||||
|
|
||||||
|
keyboardHandler: (event: KeyboardEvent) => void;
|
||||||
state: State;
|
state: State;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -36,7 +38,7 @@ export default class Pin extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyboardHandler(event: KeyboardEvent): void {
|
keyboardHandler(event: KeyboardEvent): void {
|
||||||
const { onPinAdd, onPinBackspace, onPinSubmit } = this.props.modalActions;
|
const { onPinSubmit } = this.props.modalActions;
|
||||||
const { pin } = this.state;
|
const { pin } = this.state;
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -4,20 +4,18 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import Loader from '../common/LoaderCircle';
|
import Loader from '../common/LoaderCircle';
|
||||||
|
|
||||||
type Props = {
|
import type { Props } from './index';
|
||||||
modal: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
+countdown: number;
|
countdown: number;
|
||||||
ticker?: number;
|
ticker?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class RememberDevice extends Component {
|
export default class RememberDevice extends Component<Props, State> {
|
||||||
|
|
||||||
state: State;
|
state: State;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -79,7 +77,7 @@ export default class RememberDevice extends Component {
|
|||||||
<h3>Forget {label}?</h3>
|
<h3>Forget {label}?</h3>
|
||||||
<p>Would you like TREZOR Wallet to forget your device or to remember it, so that it is still visible even while disconnected?</p>
|
<p>Would you like TREZOR Wallet to forget your device or to remember it, so that it is still visible even while disconnected?</p>
|
||||||
<button onClick={ event => onForgetDevice(device) }>Forget</button>
|
<button onClick={ event => onForgetDevice(device) }>Forget</button>
|
||||||
<button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size={ 28 } label={ this.state.countdown } /></span></button>
|
<button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size="28" label={ this.state.countdown.toString() } /></span></button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ import { CSSTransition, Transition } from 'react-transition-group';
|
|||||||
|
|
||||||
import { UI } from 'trezor-connect';
|
import { UI } from 'trezor-connect';
|
||||||
|
|
||||||
import * as ModalActions from '../../actions/ModalActions';
|
import { default as ModalActions } from '../../actions/ModalActions';
|
||||||
import * as ReceiveActions from '../../actions/ReceiveActions';
|
import { default as ReceiveActions } from '../../actions/ReceiveActions';
|
||||||
|
|
||||||
import Pin from './Pin';
|
import Pin from './Pin';
|
||||||
import InvalidPin from './InvalidPin';
|
import InvalidPin from './InvalidPin';
|
||||||
@ -26,6 +26,28 @@ import * as RECEIVE from '../../actions/constants/receive';
|
|||||||
import * as MODAL from '../../actions/constants/modal';
|
import * as MODAL from '../../actions/constants/modal';
|
||||||
import * as CONNECT from '../../actions/constants/TrezorConnect';
|
import * as CONNECT from '../../actions/constants/TrezorConnect';
|
||||||
|
|
||||||
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
|
||||||
|
type OwnProps = { }
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
modal: $ElementType<State, 'modal'>,
|
||||||
|
accounts: $ElementType<State, 'accounts'>,
|
||||||
|
devices: $PropertyType<$ElementType<State, 'connect'>, 'devices'>,
|
||||||
|
connect: $ElementType<State, 'connect'>,
|
||||||
|
sendForm: $ElementType<State, 'sendForm'>,
|
||||||
|
receive: $ElementType<State, 'receive'>,
|
||||||
|
localStorage: $ElementType<State, 'localStorage'>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = {
|
||||||
|
modalActions: typeof ModalActions,
|
||||||
|
receiveActions: typeof ReceiveActions,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = StateProps & DispatchProps;
|
||||||
|
|
||||||
const duration = 300;
|
const duration = 300;
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +60,7 @@ const Fade = ({ children, ...props }) => (
|
|||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
);
|
);
|
||||||
|
|
||||||
class Modal extends Component {
|
class Modal extends Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { opened, windowType } = this.props.modal;
|
const { opened, windowType } = this.props.modal;
|
||||||
|
|
||||||
@ -100,7 +122,7 @@ class Modal extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any, own: any): any => {
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => {
|
||||||
return {
|
return {
|
||||||
modal: state.modal,
|
modal: state.modal,
|
||||||
accounts: state.accounts,
|
accounts: state.accounts,
|
||||||
@ -112,7 +134,7 @@ const mapStateToProps = (state: any, own: any): any => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any): any => {
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
|
||||||
return {
|
return {
|
||||||
modalActions: bindActionCreators(ModalActions, dispatch),
|
modalActions: bindActionCreators(ModalActions, dispatch),
|
||||||
receiveActions: bindActionCreators(ReceiveActions, dispatch),
|
receiveActions: bindActionCreators(ReceiveActions, dispatch),
|
||||||
|
@ -7,7 +7,13 @@ import { connect } from 'react-redux';
|
|||||||
import { Notification } from '../common/Notification';
|
import { Notification } from '../common/Notification';
|
||||||
import * as TrezorConnectActions from '../../actions/TrezorConnectActions';
|
import * as TrezorConnectActions from '../../actions/TrezorConnectActions';
|
||||||
|
|
||||||
const Acquire = (props: any): any => {
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
type Props = {
|
||||||
|
connect: $ElementType<State, 'connect'>,
|
||||||
|
acquireDevice: typeof TrezorConnectActions.acquire
|
||||||
|
}
|
||||||
|
|
||||||
|
const Acquire = (props: Props) => {
|
||||||
|
|
||||||
const actions = [
|
const actions = [
|
||||||
{
|
{
|
||||||
@ -26,22 +32,20 @@ const Acquire = (props: any): any => {
|
|||||||
className="info"
|
className="info"
|
||||||
cancelable={ false }
|
cancelable={ false }
|
||||||
actions={ actions }
|
actions={ actions }
|
||||||
close={ () => {} }
|
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
export default connect(
|
||||||
return {
|
(state: State) => {
|
||||||
connect: state.connect
|
return {
|
||||||
};
|
log: state.log
|
||||||
}
|
};
|
||||||
|
},
|
||||||
const mapDispatchToProps = (dispatch) => {
|
(dispatch: Dispatch) => {
|
||||||
return {
|
return {
|
||||||
acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
|
toggle: bindActionCreators(TrezorConnectActions.acquire, dispatch),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
)(Acquire);
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Acquire);
|
|
||||||
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
const Bootloader = (props: any): any => {
|
const Bootloader = () => {
|
||||||
return (
|
return (
|
||||||
<section className="acquire">
|
<section className="acquire">
|
||||||
<h3>Bootloader mode</h3>
|
<h3>Bootloader mode</h3>
|
||||||
@ -13,15 +13,4 @@ const Bootloader = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
export default connect(null, null)(Bootloader);
|
||||||
return {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Bootloader);
|
|
||||||
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
const Dashboard = (props: any): any => {
|
const Dashboard = () => {
|
||||||
return (
|
return (
|
||||||
<section className="dashboard">
|
<section className="dashboard">
|
||||||
<h2>Dashboard</h2>
|
<h2>Dashboard</h2>
|
||||||
@ -18,15 +18,4 @@ const Dashboard = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
export default connect(null, null)(Dashboard);
|
||||||
return {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
|
|
||||||
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
export const DeviceSettings = (props: any): any => {
|
export const DeviceSettings = () => {
|
||||||
return (
|
return (
|
||||||
<section className="settings">
|
<section className="settings">
|
||||||
Device settings
|
Device settings
|
||||||
@ -13,15 +13,4 @@ export const DeviceSettings = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
export default connect(null, null)(DeviceSettings);
|
||||||
return {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(DeviceSettings);
|
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
/* @flow */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
|
|
||||||
const formatTime = (ts) => {
|
|
||||||
var date = new Date(ts * 1000);
|
|
||||||
// Hours part from the timestamp
|
|
||||||
var hours = date.getHours();
|
|
||||||
// Minutes part from the timestamp
|
|
||||||
var minutes = "0" + date.getMinutes();
|
|
||||||
// Seconds part from the timestamp
|
|
||||||
var seconds = "0" + date.getSeconds();
|
|
||||||
|
|
||||||
// Will display time in 10:30:23 format
|
|
||||||
return hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
const History = (props): any => {
|
|
||||||
|
|
||||||
const web3 = props.web3;
|
|
||||||
const { addresses } = props.addresses;
|
|
||||||
const currentAddress = addresses[ parseInt(props.match.params.address) ];
|
|
||||||
|
|
||||||
if (!currentAddress) return null;
|
|
||||||
|
|
||||||
let txs = null;
|
|
||||||
let pendingTransactions = null;
|
|
||||||
|
|
||||||
if (currentAddress.history) {
|
|
||||||
|
|
||||||
const pending = currentAddress.pendingTx;
|
|
||||||
|
|
||||||
if (pending.length > 0) {
|
|
||||||
pendingTransactions = pending.map((tx, i) => {
|
|
||||||
|
|
||||||
const etherscanLink = `https://ropsten.etherscan.io/tx/${ tx.hash }`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={i} className="history-pending-transaction">
|
|
||||||
<a href={ etherscanLink } target="_blank" rel="noreferrer noopener">Details</a>
|
|
||||||
<span className="address">{ tx.to }</span>
|
|
||||||
Pending...
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
txs = currentAddress.history.map((tx, i) => {
|
|
||||||
const etherscanLink = `https://ropsten.etherscan.io/tx/${ tx.hash }`;
|
|
||||||
return (
|
|
||||||
<div key={i} className={ `history-transaction ${ tx.type }` }>
|
|
||||||
<a href={ etherscanLink } target="_blank">Details</a>
|
|
||||||
<span className="time">{ formatTime( parseInt(tx.timeStamp) ) }</span>
|
|
||||||
<span className="address">{ tx.address }</span>
|
|
||||||
<span className="amount">{ web3.fromWei(tx.value, 'ether') }</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className="history">
|
|
||||||
{ pendingTransactions ?
|
|
||||||
<div>
|
|
||||||
<h2>Pending:</h2>
|
|
||||||
{ pendingTransactions }
|
|
||||||
</div>
|
|
||||||
: null}
|
|
||||||
|
|
||||||
<h3>HISTORY OF { currentAddress.address }</h3>
|
|
||||||
{ txs }
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default History;
|
|
@ -10,16 +10,43 @@ import { QRCode } from 'react-qr-svg';
|
|||||||
|
|
||||||
import AbstractAccount from './account/AbstractAccount';
|
import AbstractAccount from './account/AbstractAccount';
|
||||||
import { Notification } from '../common/Notification';
|
import { Notification } from '../common/Notification';
|
||||||
import * as ReceiveActions from '../../actions/ReceiveActions';
|
import { default as ReceiveActions } from '../../actions/ReceiveActions';
|
||||||
import * as AbstractAccountActions from '../../actions/AbstractAccountActions';
|
import { default as AbstractAccountActions } from '../../actions/AbstractAccountActions';
|
||||||
|
|
||||||
class Receive extends AbstractAccount {
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps, Props as BaseProps} from './account/AbstractAccount';
|
||||||
|
|
||||||
|
import type { AccountState } from './account/AbstractAccount';
|
||||||
|
|
||||||
|
type OwnProps = { }
|
||||||
|
|
||||||
|
type StateProps = StateProps & {
|
||||||
|
receive: $ElementType<State, 'receive'>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = BaseDispatchProps & {
|
||||||
|
showAddress: typeof ReceiveActions.showAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = BaseProps & StateProps & DispatchProps;
|
||||||
|
|
||||||
|
|
||||||
|
class Receive extends AbstractAccount<Props> {
|
||||||
render() {
|
render() {
|
||||||
return super.render() || _render(this.props, this.device, this.account, this.deviceStatusNotification);
|
return super.render() || _render(this.props, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _render = (props: any, device, account, deviceStatusNotification): any => {
|
const _render = (props: Props, state: AccountState): React$Element<string> => {
|
||||||
|
|
||||||
|
const {
|
||||||
|
device,
|
||||||
|
account,
|
||||||
|
deviceStatusNotification
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
if (!device || !account) return <section></section>;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
addressVerified,
|
addressVerified,
|
||||||
@ -84,10 +111,9 @@ const _render = (props: any, device, account, deviceStatusNotification): any =>
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => {
|
||||||
return {
|
return {
|
||||||
abstractAccount: state.abstractAccount,
|
abstractAccount: state.abstractAccount,
|
||||||
location: state.router.location,
|
|
||||||
devices: state.connect.devices,
|
devices: state.connect.devices,
|
||||||
accounts: state.accounts,
|
accounts: state.accounts,
|
||||||
discovery: state.discovery,
|
discovery: state.discovery,
|
||||||
@ -95,7 +121,7 @@ const mapStateToProps = (state, own) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
|
||||||
return {
|
return {
|
||||||
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
|
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
|
||||||
initAccount: bindActionCreators(ReceiveActions.init, dispatch),
|
initAccount: bindActionCreators(ReceiveActions.init, dispatch),
|
||||||
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
const SignVerify = (props: any): any => {
|
const SignVerify = () => {
|
||||||
return (
|
return (
|
||||||
<section className="signverify">
|
<section className="signverify">
|
||||||
<div className="sign">
|
<div className="sign">
|
||||||
@ -30,15 +30,4 @@ const SignVerify = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
export default connect(null, null)(SignVerify);
|
||||||
return {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(SignVerify);
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
export const WalletSettings = (props: any): any => {
|
export const WalletSettings = () => {
|
||||||
return (
|
return (
|
||||||
<section className="settings">
|
<section className="settings">
|
||||||
Wallet settings
|
Wallet settings
|
||||||
@ -13,15 +13,4 @@ export const WalletSettings = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
export default connect(null, null)(WalletSettings);
|
||||||
return {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(WalletSettings);
|
|
||||||
|
@ -4,75 +4,103 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Notification } from '../../common/Notification';
|
import { Notification } from '../../common/Notification';
|
||||||
import { findDevice } from '../../../utils/reducerUtils';
|
import { findDevice } from '../../../utils/reducerUtils';
|
||||||
import type { TrezorDevice } from '../../../reducers/TrezorConnectReducer';
|
|
||||||
|
|
||||||
export type AccountState = {
|
// import * as AbstractAccountActions from '../../actions/AbstractAccountActions';
|
||||||
device: TrezorDevice;
|
import { default as AbstractAccountActions } from '../../../actions/AbstractAccountActions';
|
||||||
discovery: any;
|
|
||||||
account: any;
|
import type { State, TrezorDevice } from '../../../flowtype';
|
||||||
|
import type { Account } from '../../../reducers/AccountsReducer';
|
||||||
|
import type { Discovery } from '../../../reducers/DiscoveryReducer';
|
||||||
|
|
||||||
|
export type StateProps = {
|
||||||
|
abstractAccount: $ElementType<State, 'abstractAccount'>,
|
||||||
|
devices: $PropertyType<$ElementType<State, 'connect'>, 'devices'>,
|
||||||
|
discovery: $ElementType<State, 'discovery'>,
|
||||||
|
accounts: $ElementType<State, 'accounts'>,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AbstractAccount extends Component {
|
export type DispatchProps = {
|
||||||
|
abstractAccountActions: typeof AbstractAccountActions,
|
||||||
|
initAccount: typeof AbstractAccountActions.init,
|
||||||
|
updateAccount: typeof AbstractAccountActions.update,
|
||||||
|
disposeAccount: typeof AbstractAccountActions.dispose,
|
||||||
|
}
|
||||||
|
|
||||||
device: TrezorDevice;
|
export type Props = StateProps & DispatchProps;
|
||||||
discovery: any;
|
|
||||||
account: any;
|
|
||||||
deviceStatusNotification: any;
|
|
||||||
|
|
||||||
constructor(props: any) {
|
export type AccountState = {
|
||||||
super(props);
|
device: ?TrezorDevice;
|
||||||
this.state = {
|
account: ?Account;
|
||||||
|
discovery: ?Discovery;
|
||||||
|
deviceStatusNotification: ?React$Element<typeof Notification>;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
export default class AbstractAccount<P> extends Component<Props & P, AccountState> {
|
||||||
}
|
|
||||||
|
|
||||||
setLocalVars(vars: any) {
|
state: AccountState = {
|
||||||
this.device = vars.device;
|
device: null,
|
||||||
this.discovery = vars.discovery;
|
account: null,
|
||||||
}
|
discovery: null,
|
||||||
|
deviceStatusNotification: null
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.abstractAccountActions.init();
|
this.props.abstractAccountActions.init();
|
||||||
this.props.initAccount();
|
this.props.initAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUpdate(newProps: any) {
|
componentWillReceiveProps(props: Props & P) {
|
||||||
this.device = null;
|
|
||||||
this.discovery = null;
|
|
||||||
this.account = null;
|
|
||||||
this.deviceStatusNotification = null;
|
|
||||||
|
|
||||||
this.props.abstractAccountActions.update();
|
this.props.abstractAccountActions.update();
|
||||||
this.props.updateAccount();
|
this.props.updateAccount();
|
||||||
|
|
||||||
|
const currentState = props.abstractAccount;
|
||||||
|
|
||||||
|
const device = findDevice(props.devices, currentState.deviceState, currentState.deviceId, currentState.deviceInstance);
|
||||||
|
if (!device) return;
|
||||||
|
const discovery = props.discovery.find(d => d.deviceState === device.state && d.network === currentState.network);
|
||||||
|
const account = props.accounts.find(a => a.deviceState === currentState.deviceState && a.index === currentState.index && a.network === currentState.network);
|
||||||
|
|
||||||
|
let deviceStatusNotification: ?React$Element<typeof Notification> = null;
|
||||||
|
if (account) {
|
||||||
|
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" />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
device,
|
||||||
|
discovery,
|
||||||
|
account,
|
||||||
|
deviceStatusNotification
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.abstractAccountActions.dispose();
|
this.props.abstractAccountActions.dispose();
|
||||||
this.props.disposeAccount();
|
this.props.disposeAccount();
|
||||||
|
|
||||||
this.device = null;
|
|
||||||
this.discovery = null;
|
|
||||||
this.account = null;
|
|
||||||
this.deviceStatusNotification = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): any {
|
render(): ?React$Element<string> {
|
||||||
|
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
const state = props.abstractAccount;
|
const currentState = props.abstractAccount;
|
||||||
|
|
||||||
if (!state.deviceState) {
|
if (!currentState.deviceState) {
|
||||||
return (<section><Notification className="info" title="Loading device" /></section>);
|
return (<section><Notification className="info" title="Loading device" /></section>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const device = findDevice(props.devices, state.deviceState, state.deviceId, state.deviceInstance);
|
const {
|
||||||
|
device,
|
||||||
|
account,
|
||||||
|
discovery
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
// const device = findDevice(props.devices, accountState.deviceState, accountState.deviceId, accountState.deviceInstance);
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return (<section>Device with state {state.deviceState} not found</section>);
|
return (<section>Device with state {currentState.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.index && a.network === state.network);
|
|
||||||
let deviceStatusNotification = null;
|
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
if (!discovery || discovery.waitingForDevice) {
|
if (!discovery || discovery.waitingForDevice) {
|
||||||
@ -97,7 +125,11 @@ export default class AbstractAccount extends Component {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />
|
<Notification
|
||||||
|
className="info"
|
||||||
|
title={ `Device ${ device.instanceLabel } is disconnected` }
|
||||||
|
message="Connect to load accounts"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -114,20 +146,8 @@ export default class AbstractAccount extends Component {
|
|||||||
</section>
|
</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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,13 +4,20 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
|
|
||||||
type State = {
|
|
||||||
style: any;
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
pathname: string;
|
||||||
|
}
|
||||||
|
type State = {
|
||||||
|
style: {
|
||||||
|
width: number,
|
||||||
|
left: number
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Indicator extends Component {
|
class Indicator extends Component<Props, State> {
|
||||||
|
|
||||||
|
reposition: () => void;
|
||||||
state: State;
|
state: State;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
@ -45,7 +52,9 @@ class Indicator extends Component {
|
|||||||
|
|
||||||
reposition() {
|
reposition() {
|
||||||
const tabs = document.querySelector('.account-tabs');
|
const tabs = document.querySelector('.account-tabs');
|
||||||
|
if (!tabs) return;
|
||||||
const active = tabs.querySelector('.active');
|
const active = tabs.querySelector('.active');
|
||||||
|
if (!active) return;
|
||||||
const bounds = active.getBoundingClientRect();
|
const bounds = active.getBoundingClientRect();
|
||||||
|
|
||||||
const left = bounds.left - tabs.getBoundingClientRect().left;
|
const left = bounds.left - tabs.getBoundingClientRect().left;
|
||||||
|
@ -10,27 +10,30 @@ import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
|
|||||||
import Loader from '../../common/LoaderCircle';
|
import Loader from '../../common/LoaderCircle';
|
||||||
import Tooltip from 'rc-tooltip';
|
import Tooltip from 'rc-tooltip';
|
||||||
|
|
||||||
|
import type { Props } from './index';
|
||||||
|
import type { TrezorDevice } from '../../../flowtype';
|
||||||
|
|
||||||
const AccountSelection = (props: any): any => {
|
const AccountSelection = (props: Props): ?React$Element<string> => {
|
||||||
|
|
||||||
const selected = findSelectedDevice(props.connect);
|
const selected = findSelectedDevice(props.connect);
|
||||||
if (!selected) return null;
|
if (!selected) return null;
|
||||||
|
|
||||||
const { location } = props.router;
|
const { location } = props.router;
|
||||||
const urlParams = location.params;
|
const urlParams = location.state;
|
||||||
const accounts = props.accounts;
|
const accounts = props.accounts;
|
||||||
const baseUrl: string = urlParams.deviceInstance ? `/device/${urlParams.device}:${urlParams.deviceInstance}` : `/device/${urlParams.device}`;
|
const baseUrl: string = urlParams.deviceInstance ? `/device/${urlParams.device}:${urlParams.deviceInstance}` : `/device/${urlParams.device}`;
|
||||||
|
|
||||||
const { config } = props.localStorage;
|
const { config } = props.localStorage;
|
||||||
const selectedCoin = config.coins.find(c => c.network === location.params.network);
|
const selectedCoin = config.coins.find(c => c.network === location.state.network);
|
||||||
|
if (!selectedCoin) return;
|
||||||
|
|
||||||
const fiatRate = props.fiat.find(f => f.network === selectedCoin.network);
|
const fiatRate = props.fiat.find(f => f.network === selectedCoin.network);
|
||||||
|
|
||||||
// console.warn("AccountSelectionRender", selected, props);
|
// console.warn("AccountSelectionRender", selected, props);
|
||||||
|
|
||||||
const deviceAddresses: Array<any> = getAccounts(accounts, selected, location.params.network);
|
const deviceAddresses: Array<any> = getAccounts(accounts, selected, location.state.network);
|
||||||
let selectedAccounts = deviceAddresses.map((address, i) => {
|
let selectedAccounts = deviceAddresses.map((address, i) => {
|
||||||
// const url: string = `${baseUrl}/network/${location.params.network}/address/${i}`;
|
// const url: string = `${baseUrl}/network/${location.state.network}/address/${i}`;
|
||||||
const url: string = location.pathname.replace(/address+\/([0-9]*)/, `address/${i}`);
|
const url: string = location.pathname.replace(/address+\/([0-9]*)/, `address/${i}`);
|
||||||
|
|
||||||
let balance: string = 'Loading...';
|
let balance: string = 'Loading...';
|
||||||
@ -65,7 +68,7 @@ const AccountSelection = (props: any): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let discoveryStatus = null;
|
let discoveryStatus = null;
|
||||||
const discovery = props.discovery.find(d => d.deviceState === selected.state && d.network === location.params.network);
|
const discovery = props.discovery.find(d => d.deviceState === selected.state && d.network === location.state.network);
|
||||||
|
|
||||||
if (discovery) {
|
if (discovery) {
|
||||||
if (discovery.completed) {
|
if (discovery.completed) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
//import React, { Node } from 'react';
|
||||||
|
import * as React from 'react';
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
||||||
|
|
||||||
@ -11,7 +12,16 @@ import CoinSelection from './CoinSelection';
|
|||||||
import StickyContainer from './StickyContainer';
|
import StickyContainer from './StickyContainer';
|
||||||
import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
const TransitionMenu = (props: any) => {
|
import type { Props } from './index';
|
||||||
|
import type { TrezorDevice } from '../../../flowtype';
|
||||||
|
|
||||||
|
|
||||||
|
type TransitionMenuProps = {
|
||||||
|
animationType: string;
|
||||||
|
children?: React.Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TransitionMenu = (props: TransitionMenuProps): React$Element<TransitionGroup> => {
|
||||||
return (
|
return (
|
||||||
<TransitionGroup component="div" className="transition-container">
|
<TransitionGroup component="div" className="transition-container">
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
@ -29,9 +39,9 @@ const TransitionMenu = (props: any) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Aside = (props: any): any => {
|
const Aside = (props: Props): React$Element<typeof StickyContainer | string> => {
|
||||||
|
|
||||||
const selected = findSelectedDevice(props.connect);
|
const selected: ?TrezorDevice = findSelectedDevice(props.connect);
|
||||||
const { location } = props.router;
|
const { location } = props.router;
|
||||||
|
|
||||||
if (location.pathname === '/' || !selected) return (<aside></aside>);
|
if (location.pathname === '/' || !selected) return (<aside></aside>);
|
||||||
@ -52,15 +62,15 @@ const Aside = (props: any): any => {
|
|||||||
|
|
||||||
if (props.deviceDropdownOpened) {
|
if (props.deviceDropdownOpened) {
|
||||||
menu = <DeviceDropdown {...props} />;
|
menu = <DeviceDropdown {...props} />;
|
||||||
} else if (location.params.network) {
|
} else if (location.state.network) {
|
||||||
menu = (
|
menu = (
|
||||||
<TransitionMenu animationType={"slide-left"}>
|
<TransitionMenu animationType={ "slide-left" }>
|
||||||
<AccountSelection { ...props} />
|
<AccountSelection { ...props} />
|
||||||
</TransitionMenu>
|
</TransitionMenu>
|
||||||
);
|
);
|
||||||
} else if (!selected.unacquired) {
|
} else if (!selected.unacquired) {
|
||||||
menu = (
|
menu = (
|
||||||
<TransitionMenu animationType={"slide-right"}>
|
<TransitionMenu animationType={ "slide-right" }>
|
||||||
<CoinSelection { ...props} />
|
<CoinSelection { ...props} />
|
||||||
</TransitionMenu>
|
</TransitionMenu>
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link, NavLink } from 'react-router-dom';
|
import { Link, NavLink } from 'react-router-dom';
|
||||||
|
|
||||||
const CoinSelection = (props: any): any => {
|
import type { Props } from './index';
|
||||||
|
import type { TrezorDevice } from '../../../flowtype';
|
||||||
|
|
||||||
|
const CoinSelection = (props: Props): React$Element<string> => {
|
||||||
const { location } = props.router;
|
const { location } = props.router;
|
||||||
const { config } = props.localStorage;
|
const { config } = props.localStorage;
|
||||||
|
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import Select from 'react-select';
|
import Select from 'react-select';
|
||||||
|
import TrezorConnect from 'trezor-connect';
|
||||||
|
|
||||||
import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
|
import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
|
||||||
|
|
||||||
|
import type { Props } from './index';
|
||||||
|
import type { TrezorDevice } from '../../../flowtype';
|
||||||
|
|
||||||
const Value = (props: any): any => {
|
const Value = (props: any): any => {
|
||||||
const device = props.value; // device is passed as value of selected item
|
const device = props.value; // device is passed as value of selected item
|
||||||
@ -96,52 +99,18 @@ const Value = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeviceSelect1 = (props: any): any => {
|
|
||||||
|
|
||||||
const { devices } = props.connect;
|
|
||||||
const selected = findSelectedDevice(props.connect);
|
|
||||||
if (!selected) return null;
|
|
||||||
|
|
||||||
const handleMenuClick = (type, device) => {
|
|
||||||
console.log("handleMenuClick", type, device)
|
|
||||||
if (type === 'acquire') {
|
|
||||||
props.acquireDevice(device);
|
|
||||||
} else if (type === 'forget') {
|
|
||||||
props.forgetDevice(device);
|
|
||||||
}else if (type === 'settings') {
|
|
||||||
props.duplicateDevice(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
className="device-select"
|
|
||||||
// disabled={ (devices && devices.length <= 1) }
|
|
||||||
disabled={ false }
|
|
||||||
searchable={ false }
|
|
||||||
clearable= { false }
|
|
||||||
tabSelectsValue={ false }
|
|
||||||
valueComponent={ Value }
|
|
||||||
onValueClick={ handleMenuClick }
|
|
||||||
value={ selected }
|
|
||||||
options={ [ ] }
|
|
||||||
onOpen={ () => props.toggleDeviceDropdown(true) }
|
|
||||||
onClose={ () => props.toggleDeviceDropdown(false) }
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const DeviceSelect = (props: any): any => {
|
export const DeviceSelect = (props: Props) => {
|
||||||
|
|
||||||
const { devices, transport } = props.connect;
|
const { devices, transport } = props.connect;
|
||||||
const selected = findSelectedDevice(props.connect);
|
const selected: ?TrezorDevice = findSelectedDevice(props.connect);
|
||||||
if (!selected) return null;
|
if (!selected) return null;
|
||||||
|
|
||||||
const handleMenuClick = (type, device) => {
|
const handleMenuClick = (type, device) => {
|
||||||
console.log("handleMenuClick", type, device)
|
console.log("handleMenuClick", type, device)
|
||||||
if (type === 'acquire') {
|
if (type === 'acquire') {
|
||||||
props.acquireDevice(device);
|
props.acquireDevice();
|
||||||
} else if (type === 'forget') {
|
} else if (type === 'forget') {
|
||||||
props.forgetDevice(device);
|
props.forgetDevice(device);
|
||||||
}else if (type === 'settings') {
|
}else if (type === 'settings') {
|
||||||
@ -164,9 +133,17 @@ export const DeviceSelect = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DeviceDropdown extends Component {
|
type DeviceMenuItem = {
|
||||||
|
type: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
export class DeviceDropdown extends Component<Props> {
|
||||||
|
|
||||||
|
mouseDownHandler: (event: MouseEvent) => void;
|
||||||
|
blurHandler: (event: FocusEvent) => void;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.mouseDownHandler = this.mouseDownHandler.bind(this);
|
this.mouseDownHandler = this.mouseDownHandler.bind(this);
|
||||||
this.blurHandler = this.blurHandler.bind(this);
|
this.blurHandler = this.blurHandler.bind(this);
|
||||||
@ -179,7 +156,7 @@ export class DeviceDropdown extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mouseDownHandler(event: MouseEvent): void {
|
mouseDownHandler(event: MouseEvent): void {
|
||||||
let elem = event.target;
|
let elem: any = (event.target : any);
|
||||||
let block: boolean = false;
|
let block: boolean = false;
|
||||||
while (elem.parentElement) {
|
while (elem.parentElement) {
|
||||||
// if (elem.className.indexOf('aside-button') >= 0) {
|
// if (elem.className.indexOf('aside-button') >= 0) {
|
||||||
@ -212,9 +189,9 @@ export class DeviceDropdown extends Component {
|
|||||||
// window.removeEventListener('blur', this.blurHandler, false);
|
// window.removeEventListener('blur', this.blurHandler, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeviceMenuClick(item, device): void {
|
onDeviceMenuClick(item: DeviceMenuItem, device: TrezorDevice): void {
|
||||||
if (item.type === 'reload') {
|
if (item.type === 'reload') {
|
||||||
this.props.acquireDevice(device);
|
this.props.acquireDevice();
|
||||||
} else if (item.type === 'forget') {
|
} else if (item.type === 'forget') {
|
||||||
// this.props.toggleDeviceDropdown(false);
|
// this.props.toggleDeviceDropdown(false);
|
||||||
this.props.forgetDevice(device);
|
this.props.forgetDevice(device);
|
||||||
@ -229,7 +206,8 @@ export class DeviceDropdown extends Component {
|
|||||||
render() {
|
render() {
|
||||||
|
|
||||||
const { devices, transport } = this.props.connect;
|
const { devices, transport } = this.props.connect;
|
||||||
const selected = findSelectedDevice(this.props.connect);
|
const selected: ?TrezorDevice = findSelectedDevice(this.props.connect);
|
||||||
|
if (!selected) return;
|
||||||
|
|
||||||
let webUsbButton = null;
|
let webUsbButton = null;
|
||||||
if (transport && transport.version.indexOf('webusb') >= 0) {
|
if (transport && transport.version.indexOf('webusb') >= 0) {
|
||||||
@ -238,7 +216,7 @@ export class DeviceDropdown extends Component {
|
|||||||
|
|
||||||
let currentDeviceMenu = null;
|
let currentDeviceMenu = null;
|
||||||
if (selected.features) {
|
if (selected.features) {
|
||||||
const deviceMenuItems: Array<any> = [];
|
const deviceMenuItems: Array<DeviceMenuItem> = [];
|
||||||
|
|
||||||
if (selected.isUsedElsewhere) {
|
if (selected.isUsedElsewhere) {
|
||||||
deviceMenuItems.push({ type: "reload", label: "Renew session" });
|
deviceMenuItems.push({ type: "reload", label: "Renew session" });
|
||||||
@ -247,7 +225,7 @@ export class DeviceDropdown extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deviceMenuItems.push({ type: "settings", label: "Device settings" });
|
deviceMenuItems.push({ type: "settings", label: "Device settings" });
|
||||||
if (selected.features.passphrase_protection && selected.connected && selected.available) {
|
if (selected.features && selected.features.passphrase_protection && selected.connected && selected.available) {
|
||||||
deviceMenuItems.push({ type: "clone", label: "Clone device" });
|
deviceMenuItems.push({ type: "clone", label: "Clone device" });
|
||||||
}
|
}
|
||||||
if (selected.remember) {
|
if (selected.remember) {
|
||||||
@ -257,7 +235,7 @@ export class DeviceDropdown extends Component {
|
|||||||
|
|
||||||
const deviceMenuButtons = deviceMenuItems.map((item, index) => {
|
const deviceMenuButtons = deviceMenuItems.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={ item.type } className={ item.type } onClick={ event => this.onDeviceMenuClick(item, selected) }>{ item.label}</div>
|
<div key={ item.type } className={ item.type } onClick={ (event) => this.onDeviceMenuClick(item, selected) }>{ item.label}</div>
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
currentDeviceMenu = deviceMenuButtons.length < 1 ? null : (
|
currentDeviceMenu = deviceMenuButtons.length < 1 ? null : (
|
||||||
|
@ -8,7 +8,13 @@ import raf from 'raf';
|
|||||||
import { DeviceSelect } from './DeviceSelection';
|
import { DeviceSelect } from './DeviceSelection';
|
||||||
import { getViewportHeight, getScrollY } from '../../../utils/windowUtils';
|
import { getViewportHeight, getScrollY } from '../../../utils/windowUtils';
|
||||||
|
|
||||||
export default class StickyContainer extends PureComponent {
|
type Props = {
|
||||||
|
location: any,
|
||||||
|
devices: any,
|
||||||
|
children: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class StickyContainer extends PureComponent<Props> {
|
||||||
|
|
||||||
// Class variables.
|
// Class variables.
|
||||||
currentScrollY: number = 0;
|
currentScrollY: number = 0;
|
||||||
@ -18,15 +24,15 @@ export default class StickyContainer extends PureComponent {
|
|||||||
framePending: boolean = false;
|
framePending: boolean = false;
|
||||||
stickToBottom: boolean = false;
|
stickToBottom: boolean = false;
|
||||||
top: number = 0;
|
top: number = 0;
|
||||||
aside;
|
aside: ?HTMLElement;
|
||||||
wrapper;
|
wrapper: ?HTMLElement;
|
||||||
subscribers = [];
|
subscribers = [];
|
||||||
|
|
||||||
handleResize = event => {
|
handleResize = (event: Event) => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScroll = event => {
|
handleScroll = (event: ?Event) => {
|
||||||
if (!this.framePending) {
|
if (!this.framePending) {
|
||||||
this.framePending = true;
|
this.framePending = true;
|
||||||
raf(this.update);
|
raf(this.update);
|
||||||
@ -34,24 +40,27 @@ export default class StickyContainer extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shouldUpdate = () => {
|
shouldUpdate = () => {
|
||||||
if (!this.wrapper) return;
|
const wrapper: ?HTMLElement = this.wrapper;
|
||||||
|
const aside: ?HTMLElement = this.aside;
|
||||||
|
if (!wrapper || !aside) return;
|
||||||
|
const helpButton: ?HTMLElement = wrapper.querySelector('.help');
|
||||||
|
if (!helpButton) return;
|
||||||
|
|
||||||
const viewportHeight = getViewportHeight();
|
|
||||||
const helpButton = this.wrapper.querySelector('.help');
|
const viewportHeight: number = getViewportHeight();
|
||||||
const helpButtonBounds = helpButton.getBoundingClientRect();
|
const helpButtonBounds = helpButton.getBoundingClientRect();
|
||||||
const asideBounds = this.aside.getBoundingClientRect();
|
const asideBounds = aside.getBoundingClientRect();
|
||||||
const wrapperBounds = this.wrapper.getBoundingClientRect();
|
const wrapperBounds = wrapper.getBoundingClientRect();
|
||||||
|
|
||||||
const scrollDirection = this.currentScrollY >= this.lastKnownScrollY ? 'down' : 'up';
|
const scrollDirection = this.currentScrollY >= this.lastKnownScrollY ? 'down' : 'up';
|
||||||
const distanceScrolled = Math.abs(this.currentScrollY - this.lastKnownScrollY);
|
const distanceScrolled = Math.abs(this.currentScrollY - this.lastKnownScrollY);
|
||||||
|
|
||||||
|
|
||||||
if (asideBounds.top < 0) {
|
if (asideBounds.top < 0) {
|
||||||
this.wrapper.classList.add('fixed');
|
wrapper.classList.add('fixed');
|
||||||
let maxTop = 1;
|
let maxTop : number= 1;
|
||||||
if (wrapperBounds.height > viewportHeight) {
|
if (wrapperBounds.height > viewportHeight) {
|
||||||
const bottomOutOfBounds = (helpButtonBounds.bottom <= viewportHeight && scrollDirection === 'down');
|
const bottomOutOfBounds: boolean = (helpButtonBounds.bottom <= viewportHeight && scrollDirection === 'down');
|
||||||
const topOutOfBounds = (wrapperBounds.top > 0 && scrollDirection === 'up');
|
const topOutOfBounds: boolean = (wrapperBounds.top > 0 && scrollDirection === 'up');
|
||||||
if (!bottomOutOfBounds && !topOutOfBounds) {
|
if (!bottomOutOfBounds && !topOutOfBounds) {
|
||||||
this.topOffset += scrollDirection === 'down' ? - distanceScrolled : distanceScrolled;
|
this.topOffset += scrollDirection === 'down' ? - distanceScrolled : distanceScrolled;
|
||||||
}
|
}
|
||||||
@ -60,27 +69,27 @@ export default class StickyContainer extends PureComponent {
|
|||||||
|
|
||||||
if (this.topOffset > 0) this.topOffset = 0;
|
if (this.topOffset > 0) this.topOffset = 0;
|
||||||
if (maxTop < 0 && this.topOffset < maxTop) this.topOffset = maxTop;
|
if (maxTop < 0 && this.topOffset < maxTop) this.topOffset = maxTop;
|
||||||
this.wrapper.style.top = `${this.topOffset}px`;
|
wrapper.style.top = `${this.topOffset}px`;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.wrapper.classList.remove('fixed');
|
wrapper.classList.remove('fixed');
|
||||||
this.wrapper.style.top = `0px`;
|
wrapper.style.top = `0px`;
|
||||||
this.topOffset = 0;
|
this.topOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wrapperBounds.height > viewportHeight) {
|
if (wrapperBounds.height > viewportHeight) {
|
||||||
this.wrapper.classList.remove('fixed-bottom');
|
wrapper.classList.remove('fixed-bottom');
|
||||||
} else {
|
} else {
|
||||||
if (this.wrapper.classList.contains('fixed-bottom')) {
|
if (wrapper.classList.contains('fixed-bottom')) {
|
||||||
if (helpButtonBounds.top < wrapperBounds.bottom - helpButtonBounds.height) {
|
if (helpButtonBounds.top < wrapperBounds.bottom - helpButtonBounds.height) {
|
||||||
this.wrapper.classList.remove('fixed-bottom');
|
wrapper.classList.remove('fixed-bottom');
|
||||||
}
|
}
|
||||||
} else if(helpButtonBounds.bottom < viewportHeight) {
|
} else if (helpButtonBounds.bottom < viewportHeight) {
|
||||||
this.wrapper.classList.add('fixed-bottom');
|
wrapper.classList.add('fixed-bottom');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.aside.style.minHeight = `${ wrapperBounds.height }px`;
|
aside.style.minHeight = `${ wrapperBounds.height }px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
update = () => {
|
update = () => {
|
||||||
@ -101,8 +110,8 @@ export default class StickyContainer extends PureComponent {
|
|||||||
window.removeEventListener('resize', this.handleScroll);
|
window.removeEventListener('resize', this.handleScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
if (this.props.location !== prevProps.location) {
|
if (this.props.location !== prevProps.location && this.aside) {
|
||||||
const asideBounds = this.aside.getBoundingClientRect();
|
const asideBounds = this.aside.getBoundingClientRect();
|
||||||
if (asideBounds.top < 0) {
|
if (asideBounds.top < 0) {
|
||||||
window.scrollTo(0, getScrollY() + asideBounds.top);
|
window.scrollTo(0, getScrollY() + asideBounds.top);
|
||||||
|
@ -11,7 +11,36 @@ import { toggleDeviceDropdown } from '../../../actions/WalletActions';
|
|||||||
|
|
||||||
import Aside from './Aside';
|
import Aside from './Aside';
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from '../../../flowtype';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
connect: $ElementType<State, 'connect'>,
|
||||||
|
accounts: $ElementType<State, 'accounts'>,
|
||||||
|
router: $ElementType<State, 'router'>,
|
||||||
|
deviceDropdownOpened: boolean,
|
||||||
|
fiat: $ElementType<State, 'fiat'>,
|
||||||
|
localStorage: $ElementType<State, 'localStorage'>,
|
||||||
|
discovery: $ElementType<State, 'discovery'>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = {
|
||||||
|
toggleDeviceDropdown: typeof toggleDeviceDropdown,
|
||||||
|
addAddress: typeof TrezorConnectActions.addAddress,
|
||||||
|
acquireDevice: typeof TrezorConnectActions.acquire,
|
||||||
|
forgetDevice: typeof TrezorConnectActions.forget,
|
||||||
|
duplicateDevice: typeof TrezorConnectActions.duplicateDevice,
|
||||||
|
gotoDeviceSettings: typeof TrezorConnectActions.gotoDeviceSettings,
|
||||||
|
onSelectDevice: typeof TrezorConnectActions.onSelectDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = StateProps & DispatchProps;
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => {
|
||||||
return {
|
return {
|
||||||
connect: state.connect,
|
connect: state.connect,
|
||||||
accounts: state.accounts,
|
accounts: state.accounts,
|
||||||
@ -23,7 +52,7 @@ const mapStateToProps = (state, own) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
|
||||||
return {
|
return {
|
||||||
//onAccountSelect: bindActionCreators(AccountActions.onAccountSelect, dispatch),
|
//onAccountSelect: bindActionCreators(AccountActions.onAccountSelect, dispatch),
|
||||||
toggleDeviceDropdown: bindActionCreators(toggleDeviceDropdown, dispatch),
|
toggleDeviceDropdown: bindActionCreators(toggleDeviceDropdown, dispatch),
|
||||||
@ -36,7 +65,7 @@ const mapDispatchToProps = (dispatch) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//export default connect(mapStateToProps, mapDispatchToProps)(AddressMenu);
|
// export default connect(mapStateToProps, mapDispatchToProps)(Aside);
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
connect(mapStateToProps, mapDispatchToProps)(Aside)
|
connect(mapStateToProps, mapDispatchToProps)(Aside)
|
||||||
);
|
);
|
@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import * as React from 'react';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Route, withRouter } from 'react-router-dom';
|
import { Route, withRouter } from 'react-router-dom';
|
||||||
@ -14,7 +14,13 @@ import ModalContainer from '../modal';
|
|||||||
import Notifications from '../common/Notification';
|
import Notifications from '../common/Notification';
|
||||||
import Log from '../common/Log';
|
import Log from '../common/Log';
|
||||||
|
|
||||||
const Content = (props) => {
|
import type { State, Dispatch } from '../../flowtype';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
const Content = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<article>
|
<article>
|
||||||
<nav>
|
<nav>
|
||||||
@ -28,7 +34,7 @@ const Content = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wallet = (props: any): any => {
|
const Wallet = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<div className="app">
|
||||||
<Header />
|
<Header />
|
||||||
@ -43,16 +49,6 @@ const Wallet = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
|
||||||
return {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return { };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
connect(mapStateToProps, mapDispatchToProps)(Wallet)
|
connect(null, null)(Wallet)
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Tooltip from 'rc-tooltip';
|
import Tooltip from 'rc-tooltip';
|
||||||
|
|
||||||
const AdvancedForm = (props: any): any => {
|
import type { Props } from './index';
|
||||||
|
|
||||||
|
const AdvancedForm = (props: Props) => {
|
||||||
|
|
||||||
const { network } = props.abstractAccount;
|
const { network } = props.abstractAccount;
|
||||||
const {
|
const {
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import * as React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.Node,
|
||||||
|
className: string,
|
||||||
|
isDisabled: boolean,
|
||||||
|
isFocused: boolean,
|
||||||
|
isSelected: boolean,
|
||||||
|
onFocus: Function,
|
||||||
|
onSelect: Function,
|
||||||
|
option: any,
|
||||||
|
}
|
||||||
|
|
||||||
// export default (props: any): any => {
|
export default class CoinSelectOption extends React.Component<Props> {
|
||||||
// console.log("RENDER CUSTOM OPTION", props)
|
constructor(props: Props) {
|
||||||
// return (
|
|
||||||
// <div>1</div>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
class FeeSelectOption extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseDown(event) {
|
handleMouseDown(event: MouseEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.props.onSelect(this.props.option, event);
|
this.props.onSelect(this.props.option, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseEnter(event) {
|
handleMouseEnter(event: MouseEvent) {
|
||||||
this.props.onFocus(this.props.option, event);
|
this.props.onFocus(this.props.option, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseMove(event) {
|
handleMouseMove(event: MouseEvent) {
|
||||||
if (this.props.isFocused) return;
|
if (this.props.isFocused) return;
|
||||||
this.props.onFocus(this.props.option, event);
|
this.props.onFocus(this.props.option, event);
|
||||||
}
|
}
|
||||||
@ -45,16 +47,3 @@ class FeeSelectOption extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FeeSelectOption.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
className: PropTypes.string,
|
|
||||||
isDisabled: PropTypes.bool,
|
|
||||||
isFocused: PropTypes.bool,
|
|
||||||
isSelected: PropTypes.bool,
|
|
||||||
onFocus: PropTypes.func,
|
|
||||||
onSelect: PropTypes.func,
|
|
||||||
option: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FeeSelectOption;
|
|
@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import * as React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
|
||||||
@ -16,22 +16,33 @@ export const FeeSelectValue = (props: any): any => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FeeSelectOption extends Component {
|
type Props = {
|
||||||
constructor(props) {
|
children: React.Node,
|
||||||
|
className: string,
|
||||||
|
isDisabled: boolean,
|
||||||
|
isFocused: boolean,
|
||||||
|
isSelected: boolean,
|
||||||
|
onFocus: Function,
|
||||||
|
onSelect: Function,
|
||||||
|
option: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FeeSelectOption extends React.Component<Props> {
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseDown(event) {
|
handleMouseDown(event: MouseEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.props.onSelect(this.props.option, event);
|
this.props.onSelect(this.props.option, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseEnter(event) {
|
handleMouseEnter(event: MouseEvent) {
|
||||||
this.props.onFocus(this.props.option, event);
|
this.props.onFocus(this.props.option, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseMove(event) {
|
handleMouseMove(event: MouseEvent) {
|
||||||
if (this.props.isFocused) return;
|
if (this.props.isFocused) return;
|
||||||
this.props.onFocus(this.props.option, event);
|
this.props.onFocus(this.props.option, event);
|
||||||
}
|
}
|
||||||
@ -48,16 +59,3 @@ export class FeeSelectOption extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FeeSelectOption.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
className: PropTypes.string,
|
|
||||||
isDisabled: PropTypes.bool,
|
|
||||||
isFocused: PropTypes.bool,
|
|
||||||
isSelected: PropTypes.bool,
|
|
||||||
onFocus: PropTypes.func,
|
|
||||||
onSelect: PropTypes.func,
|
|
||||||
option: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
/* @flow */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
|
|
||||||
// export default (props: any): any => {
|
|
||||||
// console.log("RENDER CUSTOM OPTION", props)
|
|
||||||
// return (
|
|
||||||
// <div>1</div>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
class FeeSelectOption extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseDown(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.props.onSelect(this.props.option, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseEnter(event) {
|
|
||||||
this.props.onFocus(this.props.option, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseMove(event) {
|
|
||||||
if (this.props.isFocused) return;
|
|
||||||
this.props.onFocus(this.props.option, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className={ this.props.className }
|
|
||||||
onMouseDown={ this.handleMouseDown.bind(this) }
|
|
||||||
onMouseEnter={ this.handleMouseEnter.bind(this) }
|
|
||||||
onMouseMove={ this.handleMouseMove.bind(this) }>
|
|
||||||
<span className="fee-label">{ this.props.children }</span>
|
|
||||||
|
|
||||||
<span className="fee-value">$10.20 / 8.828392159996002 ETH</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FeeSelectOption.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
className: PropTypes.string,
|
|
||||||
isDisabled: PropTypes.bool,
|
|
||||||
isFocused: PropTypes.bool,
|
|
||||||
isSelected: PropTypes.bool,
|
|
||||||
onFocus: PropTypes.func,
|
|
||||||
onSelect: PropTypes.func,
|
|
||||||
option: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FeeSelectOption;
|
|
@ -5,9 +5,19 @@ import React from 'react';
|
|||||||
import ColorHash from 'color-hash';
|
import ColorHash from 'color-hash';
|
||||||
import ScaleText from 'react-scale-text';
|
import ScaleText from 'react-scale-text';
|
||||||
|
|
||||||
const PendingTransactions = (props: any): any => {
|
import type { Props as ParentProps } from './index';
|
||||||
|
import type { Coin } from '../../../reducers/LocalStorageReducer';
|
||||||
|
import type { Account } from '../../../reducers/AccountsReducer';
|
||||||
|
|
||||||
const account = props.accounts.find(a => a.deviceState === props.sendForm.deviceState && a.index === props.sendForm.accountIndex && a.network === props.sendForm.network);
|
type Props = ParentProps & {
|
||||||
|
account: Account,
|
||||||
|
selectedCoin: Coin
|
||||||
|
// account: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const PendingTransactions = (props: Props) => {
|
||||||
|
|
||||||
|
const account = props.account; //props.accounts.find(a => a.deviceState === props.sendForm.deviceState && a.index === props.sendForm.accountIndex && a.network === props.sendForm.network);
|
||||||
const pending = props.pending.filter(p => p.network === account.network && p.address === account.address);
|
const pending = props.pending.filter(p => p.network === account.network && p.address === account.address);
|
||||||
|
|
||||||
if (pending.length < 1) return null;
|
if (pending.length < 1) return null;
|
||||||
|
@ -9,14 +9,25 @@ import { FeeSelectValue, FeeSelectOption } from './FeeSelect';
|
|||||||
import { Notification } from '../../common/Notification';
|
import { Notification } from '../../common/Notification';
|
||||||
import AbstractAccount from '../account/AbstractAccount';
|
import AbstractAccount from '../account/AbstractAccount';
|
||||||
|
|
||||||
export default class Send extends AbstractAccount {
|
import type { Props } from './index';
|
||||||
|
import type { AccountState } from '../account/AbstractAccount';
|
||||||
|
|
||||||
|
export default class Send extends AbstractAccount<Props> {
|
||||||
render() {
|
render() {
|
||||||
return super.render() || _render(this.props, this.device, this.discovery, this.account, this.deviceStatusNotification);
|
return super.render() || _render(this.props, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const _render = (props: any, device, discovery, account, deviceStatusNotification): any => {
|
const _render = (props: Props, state: AccountState): React$Element<string> => {
|
||||||
|
|
||||||
|
const {
|
||||||
|
device,
|
||||||
|
account,
|
||||||
|
deviceStatusNotification
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
if (!device || !account) return <section></section>;
|
||||||
|
|
||||||
const addressTokens = props.tokens.filter(t => t.ethAddress === account.address);
|
const addressTokens = props.tokens.filter(t => t.ethAddress === account.address);
|
||||||
const { network } = props.abstractAccount;
|
const { network } = props.abstractAccount;
|
||||||
@ -170,7 +181,10 @@ const _render = (props: any, device, discovery, account, deviceStatusNotificatio
|
|||||||
<button disabled={ buttonDisabled } onClick={ event => onSend() }>{ buttonLabel }</button>
|
<button disabled={ buttonDisabled } onClick={ event => onSend() }>{ buttonLabel }</button>
|
||||||
</AdvancedForm>
|
</AdvancedForm>
|
||||||
|
|
||||||
<PendingTransactions {...props} selectedCoin={selectedCoin} />
|
<PendingTransactions
|
||||||
|
{ ...props }
|
||||||
|
account={ account }
|
||||||
|
selectedCoin={ selectedCoin } />
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
@ -5,14 +5,35 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import * as SendFormActions from '../../../actions/SendFormActions';
|
import { default as SendFormActions } from '../../../actions/SendFormActions';
|
||||||
import * as AbstractAccountActions from '../../../actions/AbstractAccountActions';
|
import { default as AbstractAccountActions } from '../../../actions/AbstractAccountActions';
|
||||||
import SendForm from './SendForm';
|
import SendForm from './SendForm';
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from '../../../flowtype';
|
||||||
|
import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps, Props as BaseProps} from '../account/AbstractAccount';
|
||||||
|
|
||||||
|
type OwnProps = { }
|
||||||
|
|
||||||
|
type StateProps = StateProps & {
|
||||||
|
tokens: $ElementType<State, 'tokens'>,
|
||||||
|
pending: $ElementType<State, 'pending'>,
|
||||||
|
fiat: $ElementType<State, 'fiat'>,
|
||||||
|
localStorage: $ElementType<State, 'localStorage'>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = BaseDispatchProps & {
|
||||||
|
initAccount: typeof SendFormActions.init,
|
||||||
|
updateAccount: typeof SendFormActions.update,
|
||||||
|
disposeAccount: typeof SendFormActions.dispose,
|
||||||
|
sendFormActions: typeof SendFormActions
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = BaseProps & StateProps & DispatchProps;
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => {
|
||||||
return {
|
return {
|
||||||
abstractAccount: state.abstractAccount,
|
abstractAccount: state.abstractAccount,
|
||||||
location: state.router.location,
|
|
||||||
devices: state.connect.devices,
|
devices: state.connect.devices,
|
||||||
accounts: state.accounts,
|
accounts: state.accounts,
|
||||||
discovery: state.discovery,
|
discovery: state.discovery,
|
||||||
@ -24,7 +45,7 @@ const mapStateToProps = (state, own) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
|
||||||
return {
|
return {
|
||||||
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
|
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
|
||||||
sendFormActions: bindActionCreators(SendFormActions, dispatch),
|
sendFormActions: bindActionCreators(SendFormActions, dispatch),
|
||||||
|
@ -11,14 +11,29 @@ import SummaryDetails from './SummaryDetails.js';
|
|||||||
import SummaryTokens from './SummaryTokens.js';
|
import SummaryTokens from './SummaryTokens.js';
|
||||||
import { findDevice } from '../../../utils/reducerUtils';
|
import { findDevice } from '../../../utils/reducerUtils';
|
||||||
|
|
||||||
|
import type { Props } from './index';
|
||||||
|
import type { AccountState } from '../account/AbstractAccount';
|
||||||
|
|
||||||
export default class Summary extends AbstractAccount {
|
import type { TrezorDevice } from '../../../flowtype';
|
||||||
|
import type { NetworkToken } from '../../../reducers/LocalStorageReducer';
|
||||||
|
import type { Account } from '../../../reducers/AccountsReducer';
|
||||||
|
import type { Discovery } from '../../../reducers/DiscoveryReducer';
|
||||||
|
|
||||||
|
export default class Summary extends AbstractAccount<Props> {
|
||||||
render() {
|
render() {
|
||||||
return super.render() || _render(this.props, this.device, this.discovery, this.account, this.deviceStatusNotification);
|
return super.render() || _render(this.props, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _render = (props: any, device, discovery, account, deviceStatusNotification): any => {
|
const _render = (props: Props, state: AccountState): React$Element<string> => {
|
||||||
|
|
||||||
|
const {
|
||||||
|
device,
|
||||||
|
account,
|
||||||
|
deviceStatusNotification
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
if (!device || !account) return <section></section>;
|
||||||
|
|
||||||
const abstractAccount = props.abstractAccount;
|
const abstractAccount = props.abstractAccount;
|
||||||
const tokens = props.tokens.filter(t => t.ethAddress === account.address);
|
const tokens = props.tokens.filter(t => t.ethAddress === account.address);
|
||||||
@ -36,7 +51,7 @@ const _render = (props: any, device, discovery, account, deviceStatusNotificatio
|
|||||||
network={ abstractAccount.network }
|
network={ abstractAccount.network }
|
||||||
fiat={ props.fiat }
|
fiat={ props.fiat }
|
||||||
localStorage={ props.localStorage }
|
localStorage={ props.localStorage }
|
||||||
onToggle={ props.summaryActions.onDetailsToggle } />
|
onToggle={ props.onDetailsToggle } />
|
||||||
|
|
||||||
<h2>Tokens</h2>
|
<h2>Tokens</h2>
|
||||||
{/* 0x58cda554935e4a1f2acbe15f8757400af275e084 */}
|
{/* 0x58cda554935e4a1f2acbe15f8757400af275e084 */}
|
||||||
@ -46,27 +61,28 @@ const _render = (props: any, device, discovery, account, deviceStatusNotificatio
|
|||||||
multi={ false }
|
multi={ false }
|
||||||
autoload={ false }
|
autoload={ false }
|
||||||
ignoreCase={ true }
|
ignoreCase={ true }
|
||||||
|
backspaceRemoves={ true }
|
||||||
|
value={ null }
|
||||||
|
onChange={ token => props.addToken(token, account) }
|
||||||
|
loadOptions={ input => props.loadTokens(input, account.network) }
|
||||||
filterOptions= {
|
filterOptions= {
|
||||||
(options, search, values) => {
|
(options: Array<NetworkToken>, search: string, values) => {
|
||||||
return options.filter(o => {
|
return options.filter(o => {
|
||||||
return !tokens.find(t => t.symbol === o.symbol);
|
return !tokens.find(t => t.symbol === o.symbol);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value={ props.summary.selectedToken }
|
|
||||||
onChange={ token => props.summaryActions.selectToken(token, account) }
|
|
||||||
valueKey="symbol"
|
valueKey="symbol"
|
||||||
labelKey="symbol"
|
labelKey="symbol"
|
||||||
placeholder="Search for token"
|
placeholder="Search for token"
|
||||||
searchPromptText="Type token name or address"
|
searchPromptText="Type token name or address"
|
||||||
noResultsText="Token not found"
|
noResultsText="Token not found"
|
||||||
loadOptions={ input => props.summaryActions.loadTokens(input, account) }
|
|
||||||
backspaceRemoves={true} />
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SummaryTokens tokens={ tokens } removeToken={ props.summaryActions.removeToken } />
|
<SummaryTokens tokens={ tokens } removeToken={ props.removeToken } />
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -4,7 +4,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
const SummaryDetails = (props: any): any => {
|
import type { Props as BaseProps } from './index';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
summary: $ElementType<BaseProps, 'summary'>,
|
||||||
|
balance: string,
|
||||||
|
network: string,
|
||||||
|
fiat: $ElementType<BaseProps, 'fiat'>,
|
||||||
|
localStorage: $ElementType<BaseProps, 'localStorage'>,
|
||||||
|
onToggle: $ElementType<BaseProps, 'onDetailsToggle'>
|
||||||
|
}
|
||||||
|
|
||||||
|
const SummaryDetails = (props: Props): ?React$Element<string> => {
|
||||||
|
|
||||||
if (!props.summary.details) return (
|
if (!props.summary.details) return (
|
||||||
<div className="summary-details">
|
<div className="summary-details">
|
||||||
|
@ -5,29 +5,36 @@ import React from 'react';
|
|||||||
import ColorHash from 'color-hash';
|
import ColorHash from 'color-hash';
|
||||||
import ScaleText from 'react-scale-text';
|
import ScaleText from 'react-scale-text';
|
||||||
|
|
||||||
const SummaryTokens = (props: any): any => {
|
import type { Token } from '../../../reducers/TokensReducer';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tokens: Array<Token>,
|
||||||
|
removeToken: (token: Token) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const SummaryTokens = (props: Props) => {
|
||||||
|
|
||||||
if (!props.tokens || props.tokens.length < 1) return null;
|
if (!props.tokens || props.tokens.length < 1) return null;
|
||||||
|
|
||||||
const bgColor = new ColorHash({lightness: 0.7});
|
const bgColor = new ColorHash({lightness: 0.7});
|
||||||
const textColor = new ColorHash();
|
const textColor = new ColorHash();
|
||||||
|
|
||||||
const tokens = props.tokens.map((t, i) => {
|
const tokens = props.tokens.map((token, index) => {
|
||||||
let iconColor = {
|
let iconColor = {
|
||||||
color: textColor.hex(t.name),
|
color: textColor.hex(token.name),
|
||||||
background: bgColor.hex(t.name),
|
background: bgColor.hex(token.name),
|
||||||
borderColor: bgColor.hex(t.name)
|
borderColor: bgColor.hex(token.name)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div key={i} className="token">
|
<div key={ index } className="token">
|
||||||
<div className="icon" style={ iconColor }>
|
<div className="icon" style={ iconColor }>
|
||||||
<div className="icon-inner">
|
<div className="icon-inner">
|
||||||
<ScaleText widthOnly><p>{ t.symbol }</p></ScaleText>
|
<ScaleText widthOnly><p>{ token.symbol }</p></ScaleText>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="name">{ t.name }</div>
|
<div className="name">{ token.name }</div>
|
||||||
<div className="balance">{ t.balance } { t.symbol }</div>
|
<div className="balance">{ token.balance } { token.symbol }</div>
|
||||||
<button className="transparent" onClick={ event => props.removeToken(t) }></button>
|
<button className="transparent" onClick={ event => props.removeToken(token) }></button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@ -37,7 +44,6 @@ const SummaryTokens = (props: any): any => {
|
|||||||
{ tokens }
|
{ tokens }
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SummaryTokens;
|
export default SummaryTokens;
|
@ -6,32 +6,62 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import Summary from './Summary';
|
import Summary from './Summary';
|
||||||
import * as AbstractAccountActions from '../../../actions/AbstractAccountActions';
|
import { default as AbstractAccountActions } from '../../../actions/AbstractAccountActions';
|
||||||
import * as SummaryActions from '../../../actions/SummaryActions';
|
import * as SummaryActions from '../../../actions/SummaryActions';
|
||||||
|
import * as TokenActions from '../../../actions/TokenActions';
|
||||||
|
|
||||||
const mapStateToProps = (state, own) => {
|
import type { ActionCreators } from 'redux';
|
||||||
|
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
|
import type { State, Dispatch } from '../../../flowtype';
|
||||||
|
import type { StateProps as BaseStateProps, DispatchProps as BaseDispatchProps, Props as BaseProps} from '../account/AbstractAccount';
|
||||||
|
|
||||||
|
type OwnProps = { }
|
||||||
|
|
||||||
|
type StateProps = StateProps & {
|
||||||
|
tokens: $ElementType<State, 'tokens'>,
|
||||||
|
summary: $ElementType<State, 'summary'>,
|
||||||
|
fiat: $ElementType<State, 'fiat'>,
|
||||||
|
localStorage: $ElementType<State, 'localStorage'>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DispatchProps = BaseDispatchProps & {
|
||||||
|
initAccount: typeof SummaryActions.init,
|
||||||
|
updateAccount: typeof SummaryActions.update,
|
||||||
|
disposeAccount: typeof SummaryActions.dispose,
|
||||||
|
onDetailsToggle: typeof SummaryActions.onDetailsToggle,
|
||||||
|
addToken: typeof TokenActions.add,
|
||||||
|
loadTokens: typeof TokenActions.load,
|
||||||
|
removeToken: typeof TokenActions.remove,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = BaseProps & StateProps & DispatchProps;
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => {
|
||||||
return {
|
return {
|
||||||
abstractAccount: state.abstractAccount,
|
abstractAccount: state.abstractAccount,
|
||||||
|
|
||||||
location: state.router.location,
|
|
||||||
devices: state.connect.devices,
|
devices: state.connect.devices,
|
||||||
accounts: state.accounts,
|
accounts: state.accounts,
|
||||||
discovery: state.discovery,
|
discovery: state.discovery,
|
||||||
tokens: state.tokens,
|
|
||||||
|
|
||||||
|
tokens: state.tokens,
|
||||||
summary: state.summary,
|
summary: state.summary,
|
||||||
fiat: state.fiat,
|
fiat: state.fiat,
|
||||||
localStorage: state.localStorage
|
localStorage: state.localStorage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
|
||||||
return {
|
return {
|
||||||
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
|
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
|
||||||
summaryActions: bindActionCreators(SummaryActions, dispatch),
|
|
||||||
initAccount: bindActionCreators(SummaryActions.init, dispatch),
|
initAccount: bindActionCreators(SummaryActions.init, dispatch),
|
||||||
updateAccount: bindActionCreators(SummaryActions.update, dispatch),
|
updateAccount: bindActionCreators(SummaryActions.update, dispatch),
|
||||||
disposeAccount: bindActionCreators(SummaryActions.dispose, dispatch),
|
disposeAccount: bindActionCreators(SummaryActions.dispose, dispatch),
|
||||||
|
|
||||||
|
onDetailsToggle: bindActionCreators(SummaryActions.onDetailsToggle, dispatch),
|
||||||
|
addToken: bindActionCreators(TokenActions.add, dispatch),
|
||||||
|
loadTokens: bindActionCreators(TokenActions.load, dispatch),
|
||||||
|
removeToken: bindActionCreators(TokenActions.remove, dispatch),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,126 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
Store as ReduxStore,
|
||||||
|
StoreEnhancer as ReduxStoreEnhancer,
|
||||||
|
Dispatch as ReduxDispatch,
|
||||||
|
Middleware as ReduxMiddleware,
|
||||||
|
MiddlewareAPI as ReduxMiddlewareAPI,
|
||||||
|
ThunkAction as ReduxThunkAction,
|
||||||
|
ThunkDispatch as ReduxThunkDispatch,
|
||||||
|
PlainDispatch as ReduxPlainDispatch
|
||||||
|
} from 'redux';
|
||||||
|
|
||||||
|
import type { Reducers, ReducersState } from '../reducers';
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
import type { AbstractAccountAction } from '../actions/AbstractAccountActions';
|
||||||
|
import type { AddressAction } from '../actions/AddressActions';
|
||||||
|
import type { DiscoveryAction } from '../actions/DiscoveryActions';
|
||||||
|
import type { StorageAction } from '../actions/LocalStorageActions';
|
||||||
|
import type { LogAction } from '../actions/LogActions';
|
||||||
|
import type { ModalAction } from '../actions/ModalActions';
|
||||||
|
import type { NotificationAction } from '../actions/NotificationActions';
|
||||||
|
import type { ReceiveAction } from '../actions/ReceiveActions';
|
||||||
|
import type { SendFormAction } from '../actions/SendFormActions';
|
||||||
|
import type { SummaryAction } from '../actions/SummaryActions';
|
||||||
|
import type { TokenAction } from '../actions/TokenActions';
|
||||||
|
import type { TrezorConnectAction } from '../actions/TrezorConnectActions';
|
||||||
|
import type { WalletAction } from '../actions/WalletActions';
|
||||||
|
import type { Web3Action } from '../actions/Web3Actions';
|
||||||
|
import type { FiatRateAction } from '../services/CoinmarketcapService'; // this service has no action file, all is written inside one file
|
||||||
|
|
||||||
|
import type {
|
||||||
|
Device,
|
||||||
|
Features,
|
||||||
|
DeviceMessageType,
|
||||||
|
TransportMessageType,
|
||||||
|
UiMessageType,
|
||||||
|
} from 'trezor-connect';
|
||||||
|
|
||||||
|
import type { RouterAction, LocationState } from 'react-router-redux';
|
||||||
|
|
||||||
|
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;
|
||||||
|
instance?: number;
|
||||||
|
instanceLabel: string;
|
||||||
|
features?: Features;
|
||||||
|
unacquired?: boolean;
|
||||||
|
acquiring: boolean;
|
||||||
|
isUsedElsewhere?: boolean;
|
||||||
|
featuresNeedsReload?: boolean;
|
||||||
|
ts: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RouterLocationState = LocationState;
|
||||||
|
|
||||||
|
// Cast event from TrezorConnect event listener to react Action
|
||||||
|
type DeviceEventAction = {
|
||||||
|
type: DeviceMessageType,
|
||||||
|
device: Device,
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransportEventAction = {
|
||||||
|
type: TransportMessageType,
|
||||||
|
payload: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
type UiEventAction = {
|
||||||
|
type: UiMessageType,
|
||||||
|
payload: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: join this message with uiMessage
|
||||||
|
type IFrameHandshake = {
|
||||||
|
type: 'iframe_handshake',
|
||||||
|
payload: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Action =
|
||||||
|
RouterAction
|
||||||
|
| IFrameHandshake
|
||||||
|
| TransportEventAction
|
||||||
|
| DeviceEventAction
|
||||||
|
| UiEventAction
|
||||||
|
|
||||||
|
| AbstractAccountAction
|
||||||
|
| AddressAction
|
||||||
|
| DiscoveryAction
|
||||||
|
| StorageAction
|
||||||
|
| LogAction
|
||||||
|
| ModalAction
|
||||||
|
| NotificationAction
|
||||||
|
| ReceiveAction
|
||||||
|
| SendFormAction
|
||||||
|
| SummaryAction
|
||||||
|
| TokenAction
|
||||||
|
| TrezorConnectAction
|
||||||
|
| WalletAction
|
||||||
|
| Web3Action
|
||||||
|
| FiatRateAction;
|
||||||
|
|
||||||
|
export type State = ReducersState;
|
||||||
|
|
||||||
|
export type Accounts = $ElementType<State, 'accounts'>;
|
||||||
|
export type LocalStorage = $ElementType<State, 'localStorage'>;
|
||||||
|
export type Config = $PropertyType<$ElementType<State, 'localStorage'>, 'config'>;
|
||||||
|
|
||||||
|
|
||||||
|
export type Dispatch = ReduxDispatch<State, Action>;
|
||||||
|
export type MiddlewareDispatch = ReduxPlainDispatch<Action>;
|
||||||
|
|
||||||
|
export type MiddlewareAPI = ReduxMiddlewareAPI<State, Action>;
|
||||||
|
export type Middleware = ReduxMiddleware<State, Action>;
|
||||||
|
|
||||||
|
export type Store = ReduxStore<State, Action>;
|
||||||
|
export type StoreEnhancer = ReduxStoreEnhancer<State, Action>;
|
||||||
|
|
||||||
export type Dispatch = (action: Action | ThunkAction | PromiseAction) => any;
|
|
||||||
export type GetState = () => State;
|
export type GetState = () => State;
|
||||||
export type ThunkAction = (dispatch: Dispatch, getState: GetState) => any;
|
|
||||||
export type PromiseAction = Promise<Action>;
|
export type AsyncAction = ReduxThunkAction<State, Action>;
|
||||||
|
132
src/js/flowtype/react-redux_v5.x.x.js
Normal file
132
src/js/flowtype/react-redux_v5.x.x.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// flow-typed signature: 59b0c4be0e1408f21e2446be96c79804
|
||||||
|
// flow-typed version: 9092387fd2/react-redux_v5.x.x/flow_>=v0.54.x
|
||||||
|
|
||||||
|
import type { Dispatch, Store } from "redux";
|
||||||
|
|
||||||
|
declare module "react-redux" {
|
||||||
|
/*
|
||||||
|
|
||||||
|
S = State
|
||||||
|
A = Action
|
||||||
|
OP = OwnProps
|
||||||
|
SP = StateProps
|
||||||
|
DP = DispatchProps
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare type MapStateToProps<S, OP: Object, SP: Object> = (
|
||||||
|
state: S,
|
||||||
|
ownProps: OP
|
||||||
|
) => ((state: S, ownProps: OP) => SP) | SP;
|
||||||
|
|
||||||
|
declare type MapDispatchToProps<A, OP: Object, DP: Object> =
|
||||||
|
| ((dispatch: Dispatch<A>, ownProps: OP) => DP)
|
||||||
|
| DP;
|
||||||
|
|
||||||
|
declare type MergeProps<SP, DP: Object, OP: Object, P: Object> = (
|
||||||
|
stateProps: SP,
|
||||||
|
dispatchProps: DP,
|
||||||
|
ownProps: OP
|
||||||
|
) => P;
|
||||||
|
|
||||||
|
declare type Context = { store: Store<*, *> };
|
||||||
|
|
||||||
|
declare type ComponentWithDefaultProps<DP: {}, P: {}, CP: P> = Class<
|
||||||
|
React$Component<CP>
|
||||||
|
> & { defaultProps: DP };
|
||||||
|
|
||||||
|
declare class ConnectedComponentWithDefaultProps<
|
||||||
|
OP,
|
||||||
|
DP,
|
||||||
|
CP
|
||||||
|
> extends React$Component<OP> {
|
||||||
|
static defaultProps: DP, // <= workaround for https://github.com/facebook/flow/issues/4644
|
||||||
|
static WrappedComponent: Class<React$Component<CP>>,
|
||||||
|
getWrappedInstance(): React$Component<CP>,
|
||||||
|
props: OP,
|
||||||
|
state: void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare class ConnectedComponent<OP, P> extends React$Component<OP> {
|
||||||
|
static WrappedComponent: Class<React$Component<P>>,
|
||||||
|
getWrappedInstance(): React$Component<P>,
|
||||||
|
props: OP,
|
||||||
|
state: void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type ConnectedComponentWithDefaultPropsClass<OP, DP, CP> = Class<
|
||||||
|
ConnectedComponentWithDefaultProps<OP, DP, CP>
|
||||||
|
>;
|
||||||
|
|
||||||
|
declare type ConnectedComponentClass<OP, P> = Class<
|
||||||
|
ConnectedComponent<OP, P>
|
||||||
|
>;
|
||||||
|
|
||||||
|
declare type Connector<OP, P> = (<DP: {}, CP: {}>(
|
||||||
|
component: ComponentWithDefaultProps<DP, P, CP>
|
||||||
|
) => ConnectedComponentWithDefaultPropsClass<OP, DP, CP>) &
|
||||||
|
((component: React$ComponentType<P>) => ConnectedComponentClass<OP, P>);
|
||||||
|
|
||||||
|
declare class Provider<S, A> extends React$Component<{
|
||||||
|
store: Store<S, A>,
|
||||||
|
children?: any
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare function createProvider(
|
||||||
|
storeKey?: string,
|
||||||
|
subKey?: string
|
||||||
|
): Provider<*, *>;
|
||||||
|
|
||||||
|
declare type ConnectOptions = {
|
||||||
|
pure?: boolean,
|
||||||
|
withRef?: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type Null = null | void;
|
||||||
|
|
||||||
|
declare function connect<A, OP>(
|
||||||
|
...rest: Array<void> // <= workaround for https://github.com/facebook/flow/issues/2360
|
||||||
|
): Connector<OP, $Supertype<{ dispatch: Dispatch<A> } & OP>>;
|
||||||
|
|
||||||
|
declare function connect<A, OP>(
|
||||||
|
mapStateToProps: Null,
|
||||||
|
mapDispatchToProps: Null,
|
||||||
|
mergeProps: Null,
|
||||||
|
options: ConnectOptions
|
||||||
|
): Connector<OP, $Supertype<{ dispatch: Dispatch<A> } & OP>>;
|
||||||
|
|
||||||
|
declare function connect<S, A, OP, SP>(
|
||||||
|
mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||||
|
mapDispatchToProps: Null,
|
||||||
|
mergeProps: Null,
|
||||||
|
options?: ConnectOptions
|
||||||
|
): Connector<OP, $Supertype<SP & { dispatch: Dispatch<A> } & OP>>;
|
||||||
|
|
||||||
|
declare function connect<A, OP, DP>(
|
||||||
|
mapStateToProps: Null,
|
||||||
|
mapDispatchToProps: MapDispatchToProps<A, OP, DP>,
|
||||||
|
mergeProps: Null,
|
||||||
|
options?: ConnectOptions
|
||||||
|
): Connector<OP, $Supertype<DP & OP>>;
|
||||||
|
|
||||||
|
declare function connect<S, A, OP, SP, DP>(
|
||||||
|
mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||||
|
mapDispatchToProps: MapDispatchToProps<A, OP, DP>,
|
||||||
|
mergeProps: Null,
|
||||||
|
options?: ConnectOptions
|
||||||
|
): Connector<OP, $Supertype<SP & DP & OP>>;
|
||||||
|
|
||||||
|
declare function connect<S, A, OP, SP, DP, P>(
|
||||||
|
mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||||
|
mapDispatchToProps: Null,
|
||||||
|
mergeProps: MergeProps<SP, DP, OP, P>,
|
||||||
|
options?: ConnectOptions
|
||||||
|
): Connector<OP, P>;
|
||||||
|
|
||||||
|
declare function connect<S, A, OP, SP, DP, P>(
|
||||||
|
mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||||
|
mapDispatchToProps: MapDispatchToProps<A, OP, DP>,
|
||||||
|
mergeProps: MergeProps<SP, DP, OP, P>,
|
||||||
|
options?: ConnectOptions
|
||||||
|
): Connector<OP, P>;
|
||||||
|
}
|
157
src/js/flowtype/react-router-dom_v4.x.x.js
Normal file
157
src/js/flowtype/react-router-dom_v4.x.x.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
declare module "react-router-dom" {
|
||||||
|
declare export class BrowserRouter extends React$Component<{
|
||||||
|
basename?: string,
|
||||||
|
forceRefresh?: boolean,
|
||||||
|
getUserConfirmation?: GetUserConfirmation,
|
||||||
|
keyLength?: number,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class HashRouter extends React$Component<{
|
||||||
|
basename?: string,
|
||||||
|
getUserConfirmation?: GetUserConfirmation,
|
||||||
|
hashType?: "slash" | "noslash" | "hashbang",
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Link extends React$Component<{
|
||||||
|
className?: string,
|
||||||
|
to: string | LocationShape,
|
||||||
|
replace?: boolean,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class NavLink extends React$Component<{
|
||||||
|
to: string | LocationShape,
|
||||||
|
activeClassName?: string,
|
||||||
|
className?: string,
|
||||||
|
activeStyle?: Object,
|
||||||
|
style?: Object,
|
||||||
|
isActive?: (match: Match, location: Location) => boolean,
|
||||||
|
children?: React$Node,
|
||||||
|
exact?: boolean,
|
||||||
|
strict?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
// NOTE: Below are duplicated from react-router. If updating these, please
|
||||||
|
// update the react-router and react-router-native types as well.
|
||||||
|
declare export type Location = {
|
||||||
|
pathname: string,
|
||||||
|
search: string,
|
||||||
|
hash: string,
|
||||||
|
state?: any,
|
||||||
|
key?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type LocationShape = {
|
||||||
|
pathname?: string,
|
||||||
|
search?: string,
|
||||||
|
hash?: string,
|
||||||
|
state?: any
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type HistoryAction = "PUSH" | "REPLACE" | "POP";
|
||||||
|
|
||||||
|
declare export type RouterHistory = {
|
||||||
|
length: number,
|
||||||
|
location: Location,
|
||||||
|
action: HistoryAction,
|
||||||
|
listen(
|
||||||
|
callback: (location: Location, action: HistoryAction) => void
|
||||||
|
): () => void,
|
||||||
|
push(path: string | LocationShape, state?: any): void,
|
||||||
|
replace(path: string | LocationShape, state?: any): void,
|
||||||
|
go(n: number): void,
|
||||||
|
goBack(): void,
|
||||||
|
goForward(): void,
|
||||||
|
canGo?: (n: number) => boolean,
|
||||||
|
block(
|
||||||
|
callback: (location: Location, action: HistoryAction) => boolean
|
||||||
|
): void,
|
||||||
|
// createMemoryHistory
|
||||||
|
index?: number,
|
||||||
|
entries?: Array<Location>
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type Match = {
|
||||||
|
params: { [key: string]: ?string },
|
||||||
|
isExact: boolean,
|
||||||
|
path: string,
|
||||||
|
url: string
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type ContextRouter = {|
|
||||||
|
history: RouterHistory,
|
||||||
|
location: Location,
|
||||||
|
match: Match,
|
||||||
|
staticContext?: StaticRouterContext,
|
||||||
|
|};
|
||||||
|
|
||||||
|
declare export type GetUserConfirmation = (
|
||||||
|
message: string,
|
||||||
|
callback: (confirmed: boolean) => void
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
declare type StaticRouterContext = {
|
||||||
|
url?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export class StaticRouter extends React$Component<{
|
||||||
|
basename?: string,
|
||||||
|
location?: string | Location,
|
||||||
|
context: StaticRouterContext,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class MemoryRouter extends React$Component<{
|
||||||
|
initialEntries?: Array<LocationShape | string>,
|
||||||
|
initialIndex?: number,
|
||||||
|
getUserConfirmation?: GetUserConfirmation,
|
||||||
|
keyLength?: number,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Router extends React$Component<{
|
||||||
|
history: RouterHistory,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Prompt extends React$Component<{
|
||||||
|
message: string | ((location: Location) => string | boolean),
|
||||||
|
when?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Redirect extends React$Component<{
|
||||||
|
to: string | LocationShape,
|
||||||
|
push?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Route extends React$Component<{
|
||||||
|
component?: React$ComponentType<*>,
|
||||||
|
render?: (router: ContextRouter) => React$Node,
|
||||||
|
children?: React$ComponentType<ContextRouter> | React$Node,
|
||||||
|
path?: string,
|
||||||
|
exact?: boolean,
|
||||||
|
strict?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Switch extends React$Component<{
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export function withRouter<P>(
|
||||||
|
Component: React$ComponentType<{| ...ContextRouter, ...P |}>
|
||||||
|
): React$ComponentType<P>;
|
||||||
|
|
||||||
|
declare type MatchPathOptions = {
|
||||||
|
path?: string,
|
||||||
|
exact?: boolean,
|
||||||
|
sensitive?: boolean,
|
||||||
|
strict?: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export function matchPath(
|
||||||
|
pathname: string,
|
||||||
|
options?: MatchPathOptions | string
|
||||||
|
): null | Match;
|
||||||
|
}
|
44
src/js/flowtype/react-router-redux.js
vendored
Normal file
44
src/js/flowtype/react-router-redux.js
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import type {
|
||||||
|
RouterHistory,
|
||||||
|
Location as RouterLocation
|
||||||
|
} from 'react-router';
|
||||||
|
|
||||||
|
declare module "react-router-redux" {
|
||||||
|
|
||||||
|
// custom state for location
|
||||||
|
declare export type LocationState = {[key: string] : string};
|
||||||
|
|
||||||
|
declare export type Location = {
|
||||||
|
pathname: string,
|
||||||
|
search: string,
|
||||||
|
hash: string,
|
||||||
|
key?: string,
|
||||||
|
state: LocationState
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export var LOCATION_CHANGE: "@@router/LOCATION_CHANGE";
|
||||||
|
|
||||||
|
declare export type RouterAction = {
|
||||||
|
type: typeof LOCATION_CHANGE,
|
||||||
|
// type: "@@router/LOCATION_CHANGE",
|
||||||
|
payload: Location;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export type State = {
|
||||||
|
location: Location; // should be ?Location
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export function push(a: string): void;
|
||||||
|
declare export function replace(a: string): void;
|
||||||
|
declare export function go(a: string): void;
|
||||||
|
declare export function goBack(): void;
|
||||||
|
declare export function goForward(): void;
|
||||||
|
|
||||||
|
//declare export function routerReducer<S, A>(state?: S, action: A): S;
|
||||||
|
declare export function routerReducer(state?: State, action: any): State;
|
||||||
|
declare export function routerMiddleware(history: any): any;
|
||||||
|
|
||||||
|
declare export class ConnectedRouter extends React$Component<{
|
||||||
|
history: any
|
||||||
|
}> {}
|
||||||
|
}
|
123
src/js/flowtype/react-router_v4.x.x.js
Normal file
123
src/js/flowtype/react-router_v4.x.x.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
declare module "react-router" {
|
||||||
|
// NOTE: many of these are re-exported by react-router-dom and
|
||||||
|
// react-router-native, so when making changes, please be sure to update those
|
||||||
|
// as well.
|
||||||
|
declare export type Location = {
|
||||||
|
pathname: string,
|
||||||
|
search: string,
|
||||||
|
hash: string,
|
||||||
|
state?: any,
|
||||||
|
key?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type LocationShape = {
|
||||||
|
pathname?: string,
|
||||||
|
search?: string,
|
||||||
|
hash?: string,
|
||||||
|
state?: any
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type HistoryAction = "PUSH" | "REPLACE" | "POP";
|
||||||
|
|
||||||
|
declare export type RouterHistory = {
|
||||||
|
length: number,
|
||||||
|
location: Location,
|
||||||
|
action: HistoryAction,
|
||||||
|
listen(
|
||||||
|
callback: (location: Location, action: HistoryAction) => void
|
||||||
|
): () => void,
|
||||||
|
push(path: string | LocationShape, state?: any): void,
|
||||||
|
replace(path: string | LocationShape, state?: any): void,
|
||||||
|
go(n: number): void,
|
||||||
|
goBack(): void,
|
||||||
|
goForward(): void,
|
||||||
|
canGo?: (n: number) => boolean,
|
||||||
|
block(
|
||||||
|
callback: (location: Location, action: HistoryAction) => boolean
|
||||||
|
): void,
|
||||||
|
// createMemoryHistory
|
||||||
|
index?: number,
|
||||||
|
entries?: Array<Location>
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type Match = {
|
||||||
|
params: { [key: string]: ?string },
|
||||||
|
isExact: boolean,
|
||||||
|
path: string,
|
||||||
|
url: string
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type ContextRouter = {|
|
||||||
|
history: RouterHistory,
|
||||||
|
location: Location,
|
||||||
|
match: Match,
|
||||||
|
staticContext?: StaticRouterContext
|
||||||
|
|};
|
||||||
|
|
||||||
|
declare export type GetUserConfirmation = (
|
||||||
|
message: string,
|
||||||
|
callback: (confirmed: boolean) => void
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
declare type StaticRouterContext = {
|
||||||
|
url?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export class StaticRouter extends React$Component<{
|
||||||
|
basename?: string,
|
||||||
|
location?: string | Location,
|
||||||
|
context: StaticRouterContext,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class MemoryRouter extends React$Component<{
|
||||||
|
initialEntries?: Array<LocationShape | string>,
|
||||||
|
initialIndex?: number,
|
||||||
|
getUserConfirmation?: GetUserConfirmation,
|
||||||
|
keyLength?: number,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Router extends React$Component<{
|
||||||
|
history: RouterHistory,
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Prompt extends React$Component<{
|
||||||
|
message: string | ((location: Location) => string | true),
|
||||||
|
when?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Redirect extends React$Component<{
|
||||||
|
to: string | LocationShape,
|
||||||
|
push?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Route extends React$Component<{
|
||||||
|
component?: React$ComponentType<*>,
|
||||||
|
render?: (router: ContextRouter) => React$Node,
|
||||||
|
children?: React$ComponentType<ContextRouter> | React$Node,
|
||||||
|
path?: string,
|
||||||
|
exact?: boolean,
|
||||||
|
strict?: boolean
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export class Switch extends React$Component<{
|
||||||
|
children?: React$Node
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
declare export function withRouter<P>(
|
||||||
|
Component: React$ComponentType<{| ...ContextRouter, ...P |}>
|
||||||
|
): React$ComponentType<P>;
|
||||||
|
|
||||||
|
declare type MatchPathOptions = {
|
||||||
|
path?: string,
|
||||||
|
exact?: boolean,
|
||||||
|
strict?: boolean,
|
||||||
|
sensitive?: boolean
|
||||||
|
};
|
||||||
|
declare export function matchPath(
|
||||||
|
pathname: string,
|
||||||
|
options?: MatchPathOptions | string
|
||||||
|
): null | Match;
|
||||||
|
}
|
72
src/js/flowtype/redux_v3.x.x.js
Normal file
72
src/js/flowtype/redux_v3.x.x.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// flow-typed signature: cca4916b0213065533df8335c3285a4a
|
||||||
|
// flow-typed version: cab04034e7/redux_v3.x.x/flow_>=v0.55.x
|
||||||
|
|
||||||
|
declare module 'redux' {
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
S = State
|
||||||
|
A = Action
|
||||||
|
D = Dispatch
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare export type DispatchAPI<A> = (action: A) => A;
|
||||||
|
// declare export type Dispatch<A: { type: $Subtype<string> }> = DispatchAPI<A>;
|
||||||
|
|
||||||
|
declare export type ThunkAction<S, A> = (dispatch: Dispatch<S, A>, getState: () => S) => Promise<void> | void;
|
||||||
|
declare export type ThunkDispatch<S, A> = (action: ThunkAction<S, A>) => void;
|
||||||
|
|
||||||
|
declare export type PlainDispatch<A: {type: $Subtype<string>}> = DispatchAPI<A>;
|
||||||
|
/* NEW: Dispatch is now a combination of these different dispatch types */
|
||||||
|
declare export type Dispatch<S, A> = PlainDispatch<A> & ThunkDispatch<S, A>;
|
||||||
|
|
||||||
|
// declare export type ThunkAction<S, D> = (dispatch: D, getState: () => S) => Promise<void> | void;
|
||||||
|
// declare type ThunkDispatch<S, D> = (action: ThunkAction<S, D & ThunkDispatch<S, D>>) => void;
|
||||||
|
|
||||||
|
declare export type MiddlewareAPI<S, A> = {
|
||||||
|
dispatch: Dispatch<S, A>;
|
||||||
|
getState(): S;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type Store<S, A, D = Dispatch<S, A>> = {
|
||||||
|
// rewrite MiddlewareAPI members in order to get nicer error messages (intersections produce long messages)
|
||||||
|
dispatch: D;
|
||||||
|
getState(): S;
|
||||||
|
subscribe(listener: () => void): () => void;
|
||||||
|
replaceReducer(nextReducer: Reducer<S, A>): void
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type Reducer<S, A> = (state: S | void, action: A) => S;
|
||||||
|
|
||||||
|
declare export type CombinedReducer<S, A> = (state: $Shape<S> & {} | void, action: A) => S;
|
||||||
|
|
||||||
|
declare export type Middleware<S, A> =
|
||||||
|
(api: MiddlewareAPI<S, A>) =>
|
||||||
|
(next: PlainDispatch<A>) => PlainDispatch<A>;
|
||||||
|
|
||||||
|
declare export type StoreCreator<S, A, D = Dispatch<S, A>> = {
|
||||||
|
(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
|
||||||
|
(reducer: Reducer<S, A>, preloadedState: S, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare export type StoreEnhancer<S, A, D = Dispatch<S, A>> = (next: StoreCreator<S, A, D>) => StoreCreator<S, A, D>;
|
||||||
|
|
||||||
|
declare export function createStore<S, A, D>(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
|
||||||
|
declare export function createStore<S, A, D>(reducer: Reducer<S, A>, preloadedState?: S, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
|
||||||
|
|
||||||
|
declare export function applyMiddleware<S, A, D>(...middlewares: Array<Middleware<S, A>>): StoreEnhancer<S, A, D>;
|
||||||
|
|
||||||
|
declare export type ActionCreator<A, B> = (...args: Array<B>) => A;
|
||||||
|
declare export type ActionCreators<K, A> = { [key: K]: ActionCreator<A, any> };
|
||||||
|
|
||||||
|
declare export function bindActionCreators<A, C: ActionCreator<A, any>, D: DispatchAPI<A>>(actionCreator: C, dispatch: D): C;
|
||||||
|
declare export function bindActionCreators<A, K, C: ActionCreators<K, A>, D: DispatchAPI<A>>(actionCreators: C, dispatch: D): C;
|
||||||
|
// declare export function bindActionCreators<A, C: ActionCreator<A, any>, D: Dispatch>(actionCreator: C, dispatch: D): C;
|
||||||
|
// declare export function bindActionCreators<A, K, C: ActionCreators<K, A>, D: Dispatch>(actionCreators: C, dispatch: D): C;
|
||||||
|
|
||||||
|
declare export function combineReducers<O: Object, A>(reducers: O): CombinedReducer<$ObjMap<O, <S>(r: Reducer<S, any>) => S>, A>;
|
||||||
|
|
||||||
|
declare export var compose: $Compose;
|
||||||
|
}
|
||||||
|
|
195
src/js/flowtype/trezor-connect.js
Normal file
195
src/js/flowtype/trezor-connect.js
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
declare module 'trezor-connect' {
|
||||||
|
|
||||||
|
// CONSTANTS (from trezor-connect/src/js/constants)
|
||||||
|
|
||||||
|
declare type T_DEVICE_EVENT = 'DEVICE_EVENT';
|
||||||
|
declare type T_DEVICE = {
|
||||||
|
CONNECT: 'device__connect',
|
||||||
|
CONNECT_UNACQUIRED: 'device__connect_unacquired',
|
||||||
|
DISCONNECT: 'device__disconnect',
|
||||||
|
DISCONNECT_UNACQUIRED: 'device__disconnect_unacquired',
|
||||||
|
|
||||||
|
ACQUIRE: 'device__acquire', // remove? internal
|
||||||
|
RELEASE: 'device__release', // internal
|
||||||
|
ACQUIRED: 'device__acquired',
|
||||||
|
RELEASED: 'device__released', // internal
|
||||||
|
USED_ELSEWHERE: 'device__used_elsewhere', // internal
|
||||||
|
CHANGED: 'device__changed',
|
||||||
|
|
||||||
|
LOADING: 'device__loading', // internal
|
||||||
|
|
||||||
|
// trezor-link events
|
||||||
|
BUTTON: 'button',
|
||||||
|
PIN: 'pin',
|
||||||
|
PASSPHRASE: 'passphrase',
|
||||||
|
PASSPHRASE_ON_DEVICE: 'passphrase_on_device',
|
||||||
|
WORD: 'word',
|
||||||
|
|
||||||
|
// custom (not emitted)
|
||||||
|
// AUTHENTICATED: 'device__authenticated',
|
||||||
|
// WAIT_FOR_SELECTION: 'device__wait_for_selection',
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type T_UI_EVENT = 'UI_EVENT';
|
||||||
|
declare type T_UI = {
|
||||||
|
TRANSPORT: 'ui-no_transport',
|
||||||
|
BOOTLOADER: 'ui-device_bootloader_mode',
|
||||||
|
INITIALIZE: 'ui-device_not_initialized',
|
||||||
|
FIRMWARE: 'ui-device_firmware_old',
|
||||||
|
BROWSER_NOT_SUPPORTED: 'ui-browser_not_supported',
|
||||||
|
BROWSER_OUTDATED: 'ui-browser_outdated',
|
||||||
|
RECEIVE_BROWSER: 'ui-receive_browser',
|
||||||
|
REQUEST_UI_WINDOW: 'ui-request_window',
|
||||||
|
CLOSE_UI_WINDOW: 'ui-close_window',
|
||||||
|
REQUEST_PERMISSION: 'ui-request_permission',
|
||||||
|
REQUEST_CONFIRMATION: 'ui-request_confirmation',
|
||||||
|
REQUEST_PIN: 'ui-request_pin',
|
||||||
|
INVALID_PIN: 'ui-invalid_pin',
|
||||||
|
REQUEST_PASSPHRASE: 'ui-request_passphrase',
|
||||||
|
REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request_passphrase_on_device',
|
||||||
|
CONNECT: 'ui-connect',
|
||||||
|
LOADING: 'ui-loading',
|
||||||
|
SET_OPERATION: 'ui-set_operation',
|
||||||
|
SELECT_DEVICE: 'ui-select_device',
|
||||||
|
SELECT_ACCOUNT: 'ui-select_account',
|
||||||
|
SELECT_FEE: 'ui-select_fee',
|
||||||
|
UPDATE_CUSTOM_FEE: 'ui-update_custom_fee',
|
||||||
|
INSUFFICIENT_FUNDS: 'ui-insufficient_funds',
|
||||||
|
REQUEST_BUTTON: 'ui-button',
|
||||||
|
RECEIVE_PERMISSION: 'ui-receive_permission',
|
||||||
|
RECEIVE_CONFIRMATION: 'ui-receive_confirmation',
|
||||||
|
RECEIVE_PIN: 'ui-receive_pin',
|
||||||
|
RECEIVE_PASSPHRASE: 'ui-receive_passphrase',
|
||||||
|
RECEIVE_DEVICE: 'ui-receive_device',
|
||||||
|
CHANGE_ACCOUNT: 'ui-change_account',
|
||||||
|
RECEIVE_ACCOUNT: 'ui-receive_account',
|
||||||
|
RECEIVE_FEE: 'ui-receive_fee',
|
||||||
|
CHANGE_SETTINGS: 'ui-change_settings',
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type T_TRANSPORT_EVENT = 'TRANSPORT_EVENT';
|
||||||
|
declare type T_TRANSPORT = {
|
||||||
|
START: 'transport__start',
|
||||||
|
ERROR: 'transport__error',
|
||||||
|
UPDATE: 'transport__update',
|
||||||
|
STREAM: 'transport__stream',
|
||||||
|
REQUEST: 'transport__request_device',
|
||||||
|
UNREADABLE: 'transport__unreadable_hid_device',
|
||||||
|
RECONNECT: 'transport__reconnect'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
declare export type ResponseMessage = {
|
||||||
|
event: string;
|
||||||
|
type: string;
|
||||||
|
id: number;
|
||||||
|
success: boolean;
|
||||||
|
payload: Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export type UiMessageType = $Values<T_UI>;
|
||||||
|
declare export type UiMessage = {
|
||||||
|
event: string;
|
||||||
|
type: UiMessageType;
|
||||||
|
payload: Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export type DeviceMessageType = $Values<T_DEVICE>;
|
||||||
|
declare export type DeviceMessage = {
|
||||||
|
event: string;
|
||||||
|
type: DeviceMessageType;
|
||||||
|
payload: Device;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export type TransportMessageType = $Values<T_TRANSPORT>;
|
||||||
|
declare export type TransportMessage = {
|
||||||
|
event: string;
|
||||||
|
type: TransportMessageType;
|
||||||
|
payload: Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export type Device = {
|
||||||
|
path: string,
|
||||||
|
label: string,
|
||||||
|
isUsedElsewhere: boolean,
|
||||||
|
featuresNeedsReload: boolean,
|
||||||
|
unacquired?: boolean,
|
||||||
|
features: Features,
|
||||||
|
}
|
||||||
|
|
||||||
|
declare export type Features = {
|
||||||
|
vendor: string,
|
||||||
|
major_version: number,
|
||||||
|
minor_version: number,
|
||||||
|
patch_version: number,
|
||||||
|
bootloader_mode: boolean,
|
||||||
|
device_id: string,
|
||||||
|
pin_protection: boolean,
|
||||||
|
passphrase_protection: boolean,
|
||||||
|
language: string,
|
||||||
|
label: string,
|
||||||
|
// coins: CoinType[],
|
||||||
|
coins: Array<any>,
|
||||||
|
initialized: boolean,
|
||||||
|
revision: string,
|
||||||
|
bootloader_hash: string,
|
||||||
|
imported: boolean,
|
||||||
|
pin_cached: boolean,
|
||||||
|
passphrase_cached: boolean,
|
||||||
|
state?: string;
|
||||||
|
needs_backup?: boolean,
|
||||||
|
firmware_present?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
// declare export interface TrezorConnect = {
|
||||||
|
// on: (type: string, handler: (event: any) => void) => void;
|
||||||
|
// }
|
||||||
|
|
||||||
|
declare type OnEvents = "device__event";
|
||||||
|
|
||||||
|
// declare type TRANSPORT = {
|
||||||
|
// ERROR: 'transport__error';
|
||||||
|
// READY: 'transport__ready';
|
||||||
|
// }
|
||||||
|
|
||||||
|
declare type DeviceEventListener = (type: T_DEVICE_EVENT, handler: (event: DeviceMessage) => void) => void;
|
||||||
|
declare type DeviceEventListenerByType = (type: DeviceMessageType, handler: (device: Device) => void) => void;
|
||||||
|
declare type UiEventListener = (type: T_UI_EVENT, handler: (event: UiMessage) => void) => void;
|
||||||
|
declare type TransportEventListener = (type: T_TRANSPORT_EVENT, handler: (event: TransportMessage) => void) => void;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
declare module.exports: {
|
||||||
|
init: (options: Object) => Promise<Object>;
|
||||||
|
// on: (type: string, handler: (event: any) => void) => void;
|
||||||
|
on: DeviceEventListener & DeviceEventListenerByType & UiEventListener & TransportEventListener;
|
||||||
|
off: (type: string, handler: (event: any) => void) => void;
|
||||||
|
getVersion: () => any;
|
||||||
|
renderWebUSBButton: (className?: string) => void;
|
||||||
|
|
||||||
|
getDeviceState: (options: Object) => Promise<Object>;
|
||||||
|
getFeatures: (options: Object) => Promise<Object>;
|
||||||
|
getPublicKey: (options: Object) => Promise<Object>;
|
||||||
|
ethereumGetAddress: (options: Object) => Promise<Object>;
|
||||||
|
uiResponse: (options: Object) => Promise<Object>;
|
||||||
|
|
||||||
|
ethereumSignTransaction: (options: Object) => Promise<Object>;
|
||||||
|
|
||||||
|
|
||||||
|
// export const RESPONSE_EVENT: string = 'RESPONSE_EVENT';
|
||||||
|
// export const ERROR_EVENT: string = 'ERROR_EVENT';
|
||||||
|
|
||||||
|
DEVICE_EVENT: T_DEVICE_EVENT;
|
||||||
|
DEVICE: T_DEVICE;
|
||||||
|
|
||||||
|
|
||||||
|
UI_EVENT: T_UI_EVENT;
|
||||||
|
UI: T_UI;
|
||||||
|
|
||||||
|
TRANSPORT_EVENT: T_TRANSPORT_EVENT;
|
||||||
|
TRANSPORT: T_TRANSPORT;
|
||||||
|
};
|
||||||
|
}
|
75
src/js/flowtype/web3.js
Normal file
75
src/js/flowtype/web3.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
declare module 'web3' {
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
eth: {
|
||||||
|
_requestManager: any;
|
||||||
|
iban: {
|
||||||
|
(iban: string): void;
|
||||||
|
fromAddress: (address: string) => any;
|
||||||
|
fromBban: (bban: string) => any;
|
||||||
|
createIndirect: (options: any) => any;
|
||||||
|
isValid: (iban: string) => boolean;
|
||||||
|
};
|
||||||
|
sendIBANTransaction: any;
|
||||||
|
contract: (abi: any) => {
|
||||||
|
eth: any;
|
||||||
|
abi: any[];
|
||||||
|
new: (...args: any[]) => {
|
||||||
|
_eth: any;
|
||||||
|
transactionHash: any;
|
||||||
|
address: any;
|
||||||
|
abi: any[];
|
||||||
|
};
|
||||||
|
at: (address: any, callback: Function) => any;
|
||||||
|
getData: (...args: any[]) => any;
|
||||||
|
};
|
||||||
|
filter: (fil: any, callback: any, filterCreationErrorCallback: any) => {
|
||||||
|
requestManager: any;
|
||||||
|
options: any;
|
||||||
|
implementation: {
|
||||||
|
[x: string]: any;
|
||||||
|
};
|
||||||
|
filterId: any;
|
||||||
|
callbacks: any[];
|
||||||
|
getLogsCallbacks: any[];
|
||||||
|
pollFilters: any[];
|
||||||
|
formatter: any;
|
||||||
|
watch: (callback: any) => any;
|
||||||
|
stopWatching: (callback: any) => any;
|
||||||
|
get: (callback: any) => any;
|
||||||
|
};
|
||||||
|
namereg: () => {
|
||||||
|
eth: any;
|
||||||
|
abi: any[];
|
||||||
|
new: (...args: any[]) => {
|
||||||
|
_eth: any;
|
||||||
|
transactionHash: any;
|
||||||
|
address: any;
|
||||||
|
abi: any[];
|
||||||
|
};
|
||||||
|
at: (address: any, callback: Function) => any;
|
||||||
|
getData: (...args: any[]) => any;
|
||||||
|
};
|
||||||
|
icapNamereg: () => {
|
||||||
|
eth: any;
|
||||||
|
abi: any[];
|
||||||
|
new: (...args: any[]) => {
|
||||||
|
_eth: any;
|
||||||
|
transactionHash: any;
|
||||||
|
address: any;
|
||||||
|
abi: any[];
|
||||||
|
};
|
||||||
|
at: (address: any, callback: Function) => any;
|
||||||
|
getData: (...args: any[]) => any;
|
||||||
|
};
|
||||||
|
isSyncing: (callback: any) => {
|
||||||
|
requestManager: any;
|
||||||
|
pollId: string;
|
||||||
|
callbacks: any[];
|
||||||
|
lastSyncState: boolean;
|
||||||
|
addCallback: (callback: any) => any;
|
||||||
|
stopWatching: () => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,13 +11,12 @@ import Raven from 'raven-js';
|
|||||||
|
|
||||||
import styles from '../styles/index.less';
|
import styles from '../styles/index.less';
|
||||||
|
|
||||||
|
|
||||||
Raven.config('https://497392c3ff6e46dc9e54eef123979378@sentry.io/294339').install();
|
Raven.config('https://497392c3ff6e46dc9e54eef123979378@sentry.io/294339').install();
|
||||||
|
|
||||||
render(
|
const root: ?HTMLElement = document.getElementById('root');
|
||||||
router,
|
if (root) {
|
||||||
document.getElementById('root')
|
render(router, root);
|
||||||
);
|
}
|
||||||
|
|
||||||
window.onbeforeunload = () => {
|
window.onbeforeunload = () => {
|
||||||
store.dispatch( onBeforeUnload() );
|
store.dispatch( onBeforeUnload() );
|
||||||
|
@ -4,26 +4,43 @@
|
|||||||
import * as ACCOUNT from '../actions/constants/account';
|
import * as ACCOUNT from '../actions/constants/account';
|
||||||
import * as CONNECT from '../actions/constants/TrezorConnect';
|
import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||||
|
|
||||||
|
import type { Action } from '../flowtype';
|
||||||
|
import type { Coin } from './LocalStorageReducer';
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
+index: number;
|
+index: number;
|
||||||
+deviceState: ?string;
|
+deviceState: string;
|
||||||
+deviceId: ?string;
|
+deviceId: string;
|
||||||
+deviceInstance: ?string;
|
+deviceInstance: ?number;
|
||||||
+network: string;
|
+network: string;
|
||||||
|
+coin: Coin;
|
||||||
location: string;
|
location: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
index: 0,
|
index: 0,
|
||||||
deviceState: null,
|
deviceState: '0',
|
||||||
deviceId: null,
|
deviceId: '0',
|
||||||
deviceInstance: null,
|
deviceInstance: null,
|
||||||
network: '',
|
network: '',
|
||||||
|
coin: {
|
||||||
|
name: '',
|
||||||
|
network: '',
|
||||||
|
symbol: '',
|
||||||
|
bip44: '',
|
||||||
|
defaultGasLimit: 0,
|
||||||
|
defaultGasLimitTokens: 0,
|
||||||
|
defaultGasPrice: 0,
|
||||||
|
explorer: '',
|
||||||
|
tokens: '',
|
||||||
|
backends: []
|
||||||
|
},
|
||||||
location: '',
|
location: '',
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default (state: State = initialState, action: any): State => {
|
export default (state: State = initialState, action: Action): State => {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
@ -33,7 +50,6 @@ export default (state: State = initialState, action: any): State => {
|
|||||||
case ACCOUNT.DISPOSE :
|
case ACCOUNT.DISPOSE :
|
||||||
return initialState;
|
return initialState;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ const createAccount = (state: Array<Account>, action: any): Array<Account> => {
|
|||||||
// TODO check with device_id
|
// TODO check with device_id
|
||||||
// check if account was created before
|
// check if account was created before
|
||||||
const exist: ?Account = state.find((account: Account) => account.address === action.address && account.network === action.network && account.deviceID === action.device.features.device_id);
|
const exist: ?Account = state.find((account: Account) => account.address === action.address && account.network === action.network && account.deviceID === action.device.features.device_id);
|
||||||
console.warn("MAM?", exist, action)
|
|
||||||
if (exist) {
|
if (exist) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@ import * as CONNECT from '../actions/constants/TrezorConnect';
|
|||||||
|
|
||||||
export type Discovery = {
|
export type Discovery = {
|
||||||
network: string;
|
network: string;
|
||||||
deviceState: string;
|
|
||||||
xpub: string;
|
xpub: string;
|
||||||
|
hdKey: any;
|
||||||
|
basePath: any;
|
||||||
|
deviceState: string;
|
||||||
accountIndex: number;
|
accountIndex: number;
|
||||||
interrupted: boolean;
|
interrupted: boolean;
|
||||||
completed: boolean;
|
completed: boolean;
|
||||||
@ -81,6 +83,8 @@ const waiting = (state: Array<Discovery>, action: any): Array<Discovery> => {
|
|||||||
network: action.network,
|
network: action.network,
|
||||||
deviceState: action.device.state,
|
deviceState: action.device.state,
|
||||||
xpub: '',
|
xpub: '',
|
||||||
|
hdKey: null,
|
||||||
|
basePath: null,
|
||||||
accountIndex: 0,
|
accountIndex: 0,
|
||||||
interrupted: false,
|
interrupted: false,
|
||||||
completed: false,
|
completed: false,
|
||||||
@ -98,7 +102,7 @@ const waiting = (state: Array<Discovery>, action: any): Array<Discovery> => {
|
|||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function discovery(state: Array<Discovery> = initialState, action: any): any {
|
export default function discovery(state: Array<Discovery> = initialState, action: any): Array<Discovery> {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case DISCOVERY.START :
|
case DISCOVERY.START :
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import { RATE_UPDATE } from '../services/CoinmarketcapService';
|
||||||
|
|
||||||
|
import type { Action } from '../flowtype';
|
||||||
|
import type { FiatRateAction } from '../services/CoinmarketcapService';
|
||||||
|
|
||||||
export type Fiat = {
|
export type Fiat = {
|
||||||
+network: string;
|
+network: string;
|
||||||
value: string;
|
value: string;
|
||||||
@ -8,7 +13,7 @@ export type Fiat = {
|
|||||||
|
|
||||||
export const initialState: Array<Fiat> = [];
|
export const initialState: Array<Fiat> = [];
|
||||||
|
|
||||||
const update = (state: Array<Fiat>, action: any): Array<Fiat> => {
|
const update = (state: Array<Fiat>, action: FiatRateAction): Array<Fiat> => {
|
||||||
const newState: Array<Fiat> = [ ...state ];
|
const newState: Array<Fiat> = [ ...state ];
|
||||||
const exists: ?Fiat = newState.find(f => f.network === action.network);
|
const exists: ?Fiat = newState.find(f => f.network === action.network);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
@ -23,11 +28,11 @@ const update = (state: Array<Fiat>, action: any): Array<Fiat> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default (state: Array<Fiat> = initialState, action: any): Array<Fiat> => {
|
export default (state: Array<Fiat> = initialState, action: Action): Array<Fiat> => {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
case 'rate__update' :
|
case RATE_UPDATE :
|
||||||
return update(state, action);
|
return update(state, action);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -3,23 +3,77 @@
|
|||||||
|
|
||||||
import * as STORAGE from '../actions/constants/localStorage';
|
import * as STORAGE from '../actions/constants/localStorage';
|
||||||
|
|
||||||
type State = {
|
import type { Action } from '../flowtype';
|
||||||
|
|
||||||
|
export type Coin = {
|
||||||
|
name: string;
|
||||||
|
network: string;
|
||||||
|
symbol: string;
|
||||||
|
bip44: string;
|
||||||
|
defaultGasLimit: number;
|
||||||
|
defaultGasLimitTokens: number;
|
||||||
|
defaultGasPrice: number;
|
||||||
|
explorer: string;
|
||||||
|
tokens: string;
|
||||||
|
backends: Array<any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NetworkToken = {
|
||||||
|
address: string,
|
||||||
|
name: string,
|
||||||
|
symbol: string,
|
||||||
|
decimals: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TokensCollection = { [network: string]: Array<NetworkToken> };
|
||||||
|
|
||||||
|
// type AbiField = {
|
||||||
|
// constant: boolean,
|
||||||
|
// inputs: Array<{
|
||||||
|
// name: string,
|
||||||
|
// type: string,
|
||||||
|
// }>,
|
||||||
|
// name: string,
|
||||||
|
// outputs: Array<{
|
||||||
|
// name: string,
|
||||||
|
// type: string,
|
||||||
|
// }>,
|
||||||
|
// payable: boolean,
|
||||||
|
// stateMutability: string,
|
||||||
|
// type: string
|
||||||
|
// }
|
||||||
|
|
||||||
|
export type FiatValueTicker = {
|
||||||
|
network: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Config = {
|
||||||
|
coins: Array<Coin>;
|
||||||
|
fiatValueTickers: Array<FiatValueTicker>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type State = {
|
||||||
initialized: boolean;
|
initialized: boolean;
|
||||||
error: any;
|
error: ?string;
|
||||||
config: any;
|
config: Config;
|
||||||
ERC20Abi: any;
|
ERC20Abi: Array<Object>;
|
||||||
tokens: any;
|
tokens: TokensCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: State = {
|
const initialState: State = {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
error: null,
|
error: null,
|
||||||
config: null,
|
config: {
|
||||||
ERC20Abi: null,
|
coins: [],
|
||||||
tokens: null,
|
fiatValueTickers: []
|
||||||
|
},
|
||||||
|
ERC20Abi: [],
|
||||||
|
tokens: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function localStorage(state: State = initialState, action: any): any {
|
export default function localStorage(state: State = initialState, action: Action): State {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import * as LOG from '../actions/constants/log';
|
||||||
|
import type { Action } from '../flowtype';
|
||||||
|
|
||||||
type LogEntry = {
|
type LogEntry = {
|
||||||
time: number;
|
time: number;
|
||||||
type: string;
|
type: string;
|
||||||
@ -18,26 +21,26 @@ export const initialState: State = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default (state: State = initialState, action: any): State => {
|
export default (state: State = initialState, action: Action): State => {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
case 'log__open':
|
case LOG.OPEN:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
opened: true
|
opened: true
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'log__close':
|
case LOG.CLOSE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
opened: false
|
opened: false
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'log__add':
|
// case 'log__add':
|
||||||
return {
|
// return {
|
||||||
...state,
|
// ...state,
|
||||||
}
|
// }
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
@ -6,21 +6,21 @@ import * as RECEIVE from '../actions/constants/receive';
|
|||||||
import * as MODAL from '../actions/constants/modal';
|
import * as MODAL from '../actions/constants/modal';
|
||||||
import * as CONNECT from '../actions/constants/TrezorConnect';
|
import * as CONNECT from '../actions/constants/TrezorConnect';
|
||||||
|
|
||||||
type ModalState = {
|
export type State = {
|
||||||
opened: boolean;
|
opened: boolean;
|
||||||
device: any;
|
device: any;
|
||||||
instances: Array<any>;
|
instances: ?Array<any>;
|
||||||
windowType: ?string;
|
windowType: ?string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: ModalState = {
|
const initialState: State = {
|
||||||
opened: false,
|
opened: false,
|
||||||
device: null,
|
device: null,
|
||||||
instances: null,
|
instances: null,
|
||||||
windowType: null
|
windowType: null
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function modal(state: ModalState = initialState, action: any): any {
|
export default function modal(state: State = initialState, action: any): State {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { DEVICE } from 'trezor-connect';
|
|||||||
|
|
||||||
type NotificationAction = {
|
type NotificationAction = {
|
||||||
label: string;
|
label: string;
|
||||||
callback: any;
|
callback: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationEntry = {
|
type NotificationEntry = {
|
||||||
|
@ -34,7 +34,7 @@ const fromStorage = (state: Array<PendingTx>, action: any) => {
|
|||||||
return state.filter(tx => tx.id !== action.tx.id);
|
return state.filter(tx => tx.id !== action.tx.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function pending(state: Array<PendingTx> = initialState, action: any): any {
|
export default function pending(state: Array<PendingTx> = initialState, action: any): Array<PendingTx> {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import * as RECEIVE from '../actions/constants/receive';
|
|||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
addressVerified: boolean;
|
addressVerified: boolean;
|
||||||
adressUnverified: boolean;
|
addressUnverified: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
|
||||||
import * as SEND from '../actions/constants/send';
|
import * as SEND from '../actions/constants/send';
|
||||||
import * as WEB3 from '../actions/constants/web3';
|
import * as WEB3 from '../actions/constants/web3';
|
||||||
import * as ADDRESS from '../actions/constants/address';
|
import * as ADDRESS from '../actions/constants/address';
|
||||||
@ -9,7 +8,14 @@ import EthereumjsUnits from 'ethereumjs-units';
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { getFeeLevels } from '../actions/SendFormActions';
|
import { getFeeLevels } from '../actions/SendFormActions';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
Web3CreateAction,
|
||||||
|
Web3UpdateBlockAction,
|
||||||
|
Web3UpdateGasPriceAction
|
||||||
|
} from '../actions/Web3Actions';
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
|
+network: string;
|
||||||
+coinSymbol: string;
|
+coinSymbol: string;
|
||||||
token: string;
|
token: string;
|
||||||
balanceNeedUpdate: boolean;
|
balanceNeedUpdate: boolean;
|
||||||
@ -22,7 +28,7 @@ export type State = {
|
|||||||
amount: string;
|
amount: string;
|
||||||
setMax: boolean;
|
setMax: boolean;
|
||||||
feeLevels: Array<FeeLevel>;
|
feeLevels: Array<FeeLevel>;
|
||||||
selectedFeeLevel: ?FeeLevel;
|
selectedFeeLevel: FeeLevel;
|
||||||
recommendedGasPrice: string;
|
recommendedGasPrice: string;
|
||||||
gasPriceNeedsUpdate: boolean;
|
gasPriceNeedsUpdate: boolean;
|
||||||
gasLimit: string;
|
gasLimit: string;
|
||||||
@ -44,6 +50,7 @@ export type FeeLevel = {
|
|||||||
|
|
||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
|
network: '',
|
||||||
coinSymbol: '',
|
coinSymbol: '',
|
||||||
token: '',
|
token: '',
|
||||||
|
|
||||||
@ -56,7 +63,11 @@ export const initialState: State = {
|
|||||||
amount: '',
|
amount: '',
|
||||||
setMax: false,
|
setMax: false,
|
||||||
feeLevels: [],
|
feeLevels: [],
|
||||||
selectedFeeLevel: null,
|
selectedFeeLevel: {
|
||||||
|
label: 'Normal',
|
||||||
|
gasPrice: '0',
|
||||||
|
value: 'Normal'
|
||||||
|
},
|
||||||
recommendedGasPrice: '0',
|
recommendedGasPrice: '0',
|
||||||
gasPriceNeedsUpdate: false,
|
gasPriceNeedsUpdate: false,
|
||||||
gasLimit: '0',
|
gasLimit: '0',
|
||||||
@ -71,13 +82,13 @@ export const initialState: State = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const onGasPriceUpdated = (state: State, action: any): State => {
|
const onGasPriceUpdated = (state: State, action: Web3UpdateGasPriceAction): State => {
|
||||||
|
|
||||||
// function getRandomInt(min, max) {
|
// function getRandomInt(min, max) {
|
||||||
// return Math.floor(Math.random() * (max - min + 1)) + min;
|
// return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
// }
|
// }
|
||||||
// const newPrice = getRandomInt(10, 50).toString();
|
// const newPrice = getRandomInt(10, 50).toString();
|
||||||
const newPrice = EthereumjsUnits.convert(action.gasPrice, 'wei', 'gwei');
|
const newPrice: string = EthereumjsUnits.convert(action.gasPrice, 'wei', 'gwei');
|
||||||
if (action.network === state.network && newPrice !== state.recommendedGasPrice) {
|
if (action.network === state.network && newPrice !== state.recommendedGasPrice) {
|
||||||
const newState: State = { ...state };
|
const newState: State = { ...state };
|
||||||
if (!state.untouched) {
|
if (!state.untouched) {
|
||||||
@ -85,7 +96,8 @@ const onGasPriceUpdated = (state: State, action: any): State => {
|
|||||||
newState.recommendedGasPrice = newPrice;
|
newState.recommendedGasPrice = newPrice;
|
||||||
} else {
|
} else {
|
||||||
const newFeeLevels = getFeeLevels(state.network, newPrice, state.gasLimit);
|
const newFeeLevels = getFeeLevels(state.network, newPrice, state.gasLimit);
|
||||||
const selectedFeeLevel = newFeeLevels.find(f => f.value === 'Normal');
|
const selectedFeeLevel: ?FeeLevel = newFeeLevels.find(f => f.value === 'Normal');
|
||||||
|
if (!selectedFeeLevel) return state;
|
||||||
newState.recommendedGasPrice = newPrice;
|
newState.recommendedGasPrice = newPrice;
|
||||||
newState.feeLevels = newFeeLevels;
|
newState.feeLevels = newFeeLevels;
|
||||||
newState.selectedFeeLevel = selectedFeeLevel;
|
newState.selectedFeeLevel = selectedFeeLevel;
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as SUMMARY from '../actions/constants/summary';
|
import * as SUMMARY from '../actions/constants/summary';
|
||||||
|
import type { Action } from '../flowtype';
|
||||||
|
import type { NetworkToken } from './LocalStorageReducer';
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
details: boolean;
|
details: boolean;
|
||||||
selectedToken: any;
|
selectedToken: ?NetworkToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
@ -14,7 +16,7 @@ export const initialState: State = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default (state: State = initialState, action: any): State => {
|
export default (state: State = initialState, action: Action): State => {
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user