Flowtype everywhere!

pull/2/merge
Szymon Lesisz 6 years ago
parent 8aeb10cf2c
commit c597f482dc

@ -1,3 +1,5 @@
[include]
[ignore]
.*/node_modules/bitcoinjs-lib-zcash/.*
.*/node_modules/bitcoinjs-lib/.*
@ -9,7 +11,13 @@
.*/src/solidity/.*
[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/trezor-connect.js
[options]

@ -10,6 +10,9 @@
"bugs": {
"url": "https://github.com/szymonlesisz/trezor-connect-react-boilerplate/issues"
},
"bin": {
"flow": "./node_modules/flow-bin"
},
"license": "LGPL-3.0+",
"scripts": {
"dev": "babel-node ./webpack/server.js --connect",
@ -48,6 +51,7 @@
"redux-logger": "^3.0.6",
"redux-raven-middleware": "^1.2.0",
"redux-thunk": "^2.2.0",
"trezor-connect": "^5.0.10",
"web3": "^0.19.0"
},
"devDependencies": {
@ -65,6 +69,7 @@
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.9",
"flow-bin": "^0.69.0",
"flow-typed": "^2.4.0",
"html-webpack-plugin": "^2.29.0",
"json-loader": "^0.5.7",
"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": {
"chrome": {
"version": 59,

@ -5,35 +5,51 @@ import * as ACCOUNT from './constants/account';
import { initialState } from '../reducers/AbstractAccountReducer';
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
import type { AsyncAction, Action, GetState, Dispatch, TrezorDevice } from '../flowtype';
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 = (): any => {
return (dispatch, getState): void => {
export const init = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
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;
const { config } = getState().localStorage;
const coin: ?Coin = config.coins.find(c => c.network === urlParams.network);
if (!coin) return;
const state: State = {
index: parseInt(urlParams.address),
deviceState: selected.state,
deviceId: selected.features.device_id,
deviceState: selected.state || '0',
deviceId: selected.features ? selected.features.device_id : '0',
deviceInstance: selected.instance,
network: urlParams.network,
location: location.pathname
coin,
location: location.pathname,
};
dispatch({
type: ACCOUNT.INIT,
state: state
});
}
}
export const update = (): any => {
return (dispatch, getState): void => {
export const update = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const {
abstractAccount,
router
@ -46,10 +62,14 @@ export const update = (): any => {
}
}
export const dispose = (): any => {
return (dispatch, getState): void => {
dispatch({
type: ACCOUNT.DISPOSE,
});
export const dispose = (): Action => {
return {
type: ACCOUNT.DISPOSE
}
}
export default {
init,
update,
dispose
}

@ -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 { 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 => {
return (dispatch, getState) => {
@ -310,7 +320,7 @@ export const check = (): any => {
const selected = findSelectedDevice(getState().connect);
if (!selected) return;
const urlParams = getState().router.location.params;
const urlParams = getState().router.location.state;
if (urlParams.network) {
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.network === urlParams.network);
if (!discoveryProcess) {

@ -1,10 +1,2 @@
/* @flow */
'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 DISCOVERY from './constants/discovery';
import * as STORAGE from './constants/localStorage';
import { httpRequest } from '../utils/networkUtils';
import { JSONRequest, httpRequest } from '../utils/networkUtils';
export function loadData(): any {
return async (dispatch, getState) => {
import type { AsyncAction, GetState, Dispatch } from '../flowtype';
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
// let available: boolean = true;
@ -27,16 +43,51 @@ export function loadData(): any {
}
}
export function loadTokensFromJSON(): any {
return async (dispatch, getState) => {
// const parseConfig = (json: JSON): Config => {
// 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 {
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');
// load tokens
const tokens = await config.coins.reduce(async (promise: Promise<any>, coin: any): Promise<any> => {
const collection = await promise;
const json: JSON = await httpRequest(coin.tokens, 'json');
const tokens = await config.coins.reduce(async (promise: Promise<TokensCollection>, coin: Coin): Promise<TokensCollection> => {
const collection: TokensCollection = await promise;
const json = await httpRequest(coin.tokens, 'json');
collection[ coin.network ] = json;
return collection;
}, Promise.resolve({}));
@ -99,8 +150,8 @@ export function loadTokensFromJSON(): any {
}
export const save = (key: string, value: string): any => {
return (dispatch, getState) => {
export const save = (key: string, value: string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState) => {
if (typeof window.localStorage !== 'undefined') {
try {
window.localStorage.setItem(key, value);

@ -1,15 +1,25 @@
/* @flow */
'use strict';
export const toggle = (): any => {
return (dispatch, getState) => {
import * as LOG from './constants/log';
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) {
window.scrollTo(0, 0);
}
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 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 });
return {
type: MODAL.CLOSE
}
}
export function onPassphraseSubmit(passphrase: string): any {
return async (dispatch, getState): Promise<void> => {
export const onPassphraseSubmit = (passphrase: string): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const resp = await TrezorConnect.uiResponse({
type: UI.RECEIVE_PASSPHRASE,
payload: {
@ -29,42 +37,42 @@ export function onPassphraseSubmit(passphrase: string): any {
}
}
export const askForRemember = (device: any) => {
export const askForRemember = (device: any): Action => {
return {
type: MODAL.REMEMBER,
device
}
}
export const onRememberDevice = (device: any) => {
export const onRememberDevice = (device: any): Action => {
return {
type: CONNECT.REMEMBER,
device
}
}
export const onForgetDevice = (device: any) => {
export const onForgetDevice = (device: any): Action => {
return {
type: CONNECT.FORGET,
device,
}
}
export const onForgetSingleDevice = (device: any) => {
export const onForgetSingleDevice = (device: any): Action => {
return {
type: CONNECT.FORGET_SINGLE,
device,
}
}
export const onCancel = () => {
export const onCancel = (): Action => {
return {
type: MODAL.CLOSE
}
}
export const onDuplicateDevice = (device: any): any => {
return (dispatch: any, getState: any): void => {
export const onDuplicateDevice = (device: any): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
dispatch( onCancel() );
@ -73,4 +81,15 @@ export const onDuplicateDevice = (device: any): any => {
device
});
}
}
export default {
onPinSubmit,
onPassphraseSubmit,
askForRemember,
onRememberDevice,
onForgetDevice,
onForgetSingleDevice,
onCancel,
onDuplicateDevice
}

@ -3,10 +3,33 @@
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
export const clear = (currentParams, requestedParams): any => {
return async (dispatch, getState) => {
export const clear = (currentParams: RouterLocationState, requestedParams: RouterLocationState): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
// if route has been changed from device view into something else (like other device, settings...)
// try to remove all Notifications which are linked to previous device (they are not cancelable by user)
if (currentParams.device !== requestedParams.device || currentParams.deviceInstance !== requestedParams.deviceInstance) {

@ -9,9 +9,24 @@ import { initialState } from '../reducers/ReceiveReducer';
import type { State } from '../reducers/ReceiveReducer';
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
import type { TrezorDevice, AsyncAction, Action, GetState, Dispatch } from '../flowtype';
export const init = (): any => {
return (dispatch, getState): void => {
export type ReceiveAction = {
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 = {
...initialState,
@ -25,8 +40,8 @@ export const init = (): any => {
}
export const update = (newProps: any): any => {
return (dispatch, getState): void => {
export const update = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const {
abstractAccount,
router
@ -39,20 +54,20 @@ export const update = (newProps: any): any => {
}
}
export const dispose = (address: string): any => {
export const dispose = (): Action => {
return {
type: RECEIVE.DISPOSE
}
}
export const showUnverifiedAddress = () => {
export const showUnverifiedAddress = (): Action => {
return {
type: RECEIVE.SHOW_UNVERIFIED_ADDRESS
}
}
export const showAddress = (address_n: string): any => {
return async (dispatch, getState) => {
export const showAddress = (address_n: string): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected = findSelectedDevice(getState().connect);
if (!selected) return;
@ -99,4 +114,12 @@ 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 { findAccount } from '../reducers/AccountsReducer';
import { findToken } from '../reducers/TokensReducer';
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';
import { findSelectedDevice } from '../reducers/TrezorConnectReducer';
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|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 => {
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 => {
const accountState = getState().abstractAccount;
const { token } = getState().sendForm;
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
// export const findBalance = (getState: GetState): string => {
// const accountState = getState().abstractAccount;
// const { token } = getState().sendForm;
// const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
if (token !== state.network) {
return getState().tokens.find(t => t.ethAddress === account.address && t.symbol === token).balance;
} else {
return account.balance;
}
}
// if (token !== state.network) {
// return getState().tokens.find(t => t.ethAddress === account.address && t.symbol === token).balance;
// } else {
// return account.balance;
// }
// }
// initialize component
export const init = (): any => {
return (dispatch, getState): void => {
export const init = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
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;
const web3instance = getState().web3.find(w3 => w3.network === urlParams.network);
const web3instance: ?Web3Instance = getState().web3.find(w3 => w3.network === urlParams.network);
if (!web3instance) {
// no backend for this network
//return;
return;
}
// TODO: check if there are some unfinished tx in 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 gasLimit: string = coin.defaultGasLimit.toString();
@ -123,9 +188,9 @@ export const init = (): any => {
const state: State = {
...initialState,
network: coin.network,
coinSymbol: coin.symbol,
token: coin.network,
feeLevels,
selectedFeeLevel: feeLevels.find(f => f.value === 'Normal'),
recommendedGasPrice: gasPrice.toString(),
@ -141,8 +206,8 @@ export const init = (): any => {
}
}
export const update = (): any => {
return (dispatch, getState): void => {
export const update = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const {
abstractAccount,
router
@ -156,29 +221,29 @@ export const update = (): any => {
}
}
export const dispose = (): any => {
export const dispose = (): Action => {
return {
type: SEND.DISPOSE
}
}
export const toggleAdvanced = (address: string): any => {
export const toggleAdvanced = (address: string): Action => {
return {
type: SEND.TOGGLE_ADVANCED
}
}
export const validation = (): any => {
return (dispatch, getState): void => {
export const validation = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState = getState().abstractAccount;
const accountState: AccountState = getState().abstractAccount;
const state: State = getState().sendForm;
const errors: {[k: string]: string} = {};
const warnings: {[k: string]: string} = {};
const infos: {[k: string]: string} = {};
if (!state.untouched) {
// valid address
if (state.touched.address) {
@ -208,8 +273,11 @@ export const validation = (): any => {
} else if (state.amount.length > 0 && !state.amount.match(numberRegExp)) {
errors.amount = 'Amount is not a number';
} else {
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) {
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 => {
return (dispatch, getState): void => {
export const onAddressChange = (address: string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const currentState: State = getState().sendForm;
const touched = { ...currentState.touched };
@ -318,10 +386,10 @@ export const onAddressChange = (address: string): any => {
}
}
export const onAmountChange = (amount: string): any => {
return (dispatch, getState): void => {
export const onAmountChange = (amount: string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState = getState().abstractAccount;
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const isToken: boolean = currentState.token !== accountState.network;
const touched = { ...currentState.touched };
@ -345,11 +413,10 @@ export const onAmountChange = (amount: string): any => {
}
}
export const onCurrencyChange = (currency: any): any => {
return (dispatch, getState): void => {
const accountState = getState().abstractAccount;
const currentState = getState().sendForm;
export const onCurrencyChange = (currency: any): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const isToken: boolean = currency.value !== 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 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 amount: string = currentState.amount;
@ -368,8 +437,9 @@ export const onCurrencyChange = (currency: any): any => {
if (isToken) {
gasLimit = coin.defaultGasLimitTokens.toString();
if (currentState.setMax) {
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currency.value).balance;
amount = tokenBalance;
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
if (!token) return;
amount = token.balance;
}
total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit);
} else {
@ -381,6 +451,8 @@ export const onCurrencyChange = (currency: any): any => {
}
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 = {
...currentState,
@ -388,7 +460,7 @@ export const onCurrencyChange = (currency: any): any => {
amount,
total,
feeLevels,
selectedFeeLevel: feeLevels.find(f => f.value === currentState.selectedFeeLevel.value),
selectedFeeLevel,
gasLimit,
};
@ -402,10 +474,10 @@ export const onCurrencyChange = (currency: any): any => {
export const onSetMax = (): any => {
return (dispatch, getState): void => {
const accountState = getState().abstractAccount;
const currentState = getState().sendForm;
export const onSetMax = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const isToken: boolean = currentState.token !== accountState.network;
const touched = { ...currentState.touched };
touched.amount = true;
@ -420,8 +492,9 @@ export const onSetMax = (): any => {
let total: string = currentState.total;
if (!currentState.setMax) {
if (isToken) {
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance;
amount = tokenBalance;
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
if (!token) return;
amount = token.balance;
total = calculateTotal('0', currentState.gasPrice, currentState.gasLimit);
} else {
amount = calculateMaxAmount(account.balance, currentState.gasPrice, currentState.gasLimit);
@ -446,12 +519,17 @@ export const onSetMax = (): any => {
}
}
export const onFeeLevelChange = (feeLevel: any): any => {
return (dispatch, getState): void => {
const accountState = getState().abstractAccount;
const currentState = getState().sendForm;
export const onFeeLevelChange = (feeLevel: FeeLevel): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
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 = {
...currentState,
untouched: false,
@ -464,16 +542,22 @@ export const onFeeLevelChange = (feeLevel: any): any => {
feeLevel.gasPrice = state.gasPrice;
feeLevel.label = `${ calculateFee(state.gasPrice, state.gasLimit) } ${ state.coinSymbol }`;
} else {
const customLevel = state.feeLevels.find(f => f.value === 'Custom');
customLevel.label = '';
const customLevel: ?FeeLevel = state.feeLevels.find(f => f.value === 'Custom');
if (customLevel)
customLevel.label = '';
state.gasPrice = feeLevel.gasPrice;
state.gasLimit = isToken ? coin.defaultGasLimitTokens.toString() : coin.defaultGasLimit.toString();
// reset custom gasLimit
}
if (currentState.setMax) {
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
if (!account) return;
if (isToken) {
const tokenBalance: string = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token).balance;
state.amount = tokenBalance;
const token: ?Token = findToken(getState().tokens, account.address, currentState.token, accountState.deviceState);
if (!token) return;
state.amount = token.balance;
} else {
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
}
@ -488,14 +572,16 @@ export const onFeeLevelChange = (feeLevel: any): any => {
}
}
export const updateFeeLevels = (): any => {
return (dispatch, getState): void => {
const accountState = getState().abstractAccount;
const currentState = getState().sendForm;
export const updateFeeLevels = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const isToken: boolean = currentState.token !== accountState.network;
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 = {
...currentState,
feeLevels,
@ -507,8 +593,11 @@ export const updateFeeLevels = (): any => {
if (currentState.setMax) {
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
if (!account) return;
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;
} else {
state.amount = calculateMaxAmount(account.balance, state.gasPrice, state.gasLimit);
@ -524,10 +613,10 @@ export const updateFeeLevels = (): any => {
}
}
export const onGasPriceChange = (gasPrice: string): any => {
return (dispatch, getState): void => {
const accountState = getState().abstractAccount;
const currentState = getState().sendForm;
export const onGasPriceChange = (gasPrice: string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const isToken: boolean = currentState.token !== accountState.network;
const touched = { ...currentState.touched };
@ -542,6 +631,7 @@ export const onGasPriceChange = (gasPrice: string): any => {
if (gasPrice.match(numberRegExp) && state.gasLimit.match(numberRegExp)) {
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
if (!customLevel) return;
customLevel.gasPrice = gasPrice;
customLevel.label = `${ calculateFee(gasPrice, state.gasLimit) } ${ state.coinSymbol }`;
@ -549,8 +639,11 @@ export const onGasPriceChange = (gasPrice: string): any => {
if (currentState.setMax) {
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
if (!account) return;
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;
} else {
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 => {
return (dispatch, getState): void => {
const accountState = getState().abstractAccount;
const currentState = getState().sendForm;
export const onGasLimitChange = (gasLimit: string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const isToken: boolean = currentState.token !== accountState.network;
const touched = { ...currentState.touched };
@ -585,15 +678,20 @@ export const onGasLimitChange = (gasLimit: string): any => {
};
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 }`;
state.selectedFeeLevel = customLevel;
if (state.setMax) {
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
if (!account) return;
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;
} else {
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 => {
return (dispatch, getState): void => {
const currentState = getState().sendForm;
export const onDataChange = (data: string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const currentState: State = getState().sendForm;
const touched = { ...currentState.touched };
touched.data = true;
@ -632,33 +730,37 @@ export const onDataChange = (data: string): any => {
}
}
export const onSend = (): any => {
export const onSend = (): AsyncAction => {
//return onSendERC20();
return async (dispatch: Dispatch, getState: GetState): Promise<any> => {
return async (dispatch, getState): Promise<any> => {
const accountState = getState().abstractAccount;
const accountState: AccountState = getState().abstractAccount;
const currentState: State = getState().sendForm;
const web3instance = getState().web3.filter(w3 => w3.network === accountState.network)[0];
const web3 = web3instance.web3;
const web3instance: ?Web3Instance = getState().web3.filter(w3 => w3.network === accountState.network)[0];
const account: ?Account = findAccount(getState().accounts, accountState.index, accountState.deviceState, accountState.network);
if (!account || !web3instance) return;
const isToken: boolean = currentState.token !== accountState.network;
const web3 = web3instance.web3;
const address_n = account.addressPath;
let data: string = '';
let txAmount = web3.toHex(web3.toWei(currentState.amount, 'ether'));
let txAddress = currentState.address;
let txAmount: string = web3.toHex(web3.toWei(currentState.amount, 'ether'));
let txAddress: string = currentState.address;
if (isToken) {
const t = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token);
const contract = web3instance.erc20.at(t.address);
// const t = getState().tokens.find(t => t.ethAddress === account.address && t.symbol === currentState.token);
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, {
from: account.address,
gasLimit: currentState.gasLimit,
gasPrice: currentState.gasPrice
});
txAmount = '0x00';
txAddress = t.address;
txAddress = token.address;
}
const txData = {
@ -693,7 +795,7 @@ export const onSend = (): any => {
// 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;
let signedTransaction = await TrezorConnect.ethereumSignTransaction({
@ -736,7 +838,9 @@ export const onSend = (): any => {
// console.log("---->GASSS", txData, gasLimit2.toString() );
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 {
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 { resolveAfter } from '../utils/promiseUtils';
import { getTokenInfoAsync, getTokenBalanceAsync } from './Web3Actions';
import { initialState } from '../reducers/SummaryReducer';
import type { State } from '../reducers/SummaryReducer';
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 type SummaryAction = {
type: typeof SUMMARY.INIT,
state: State
} | {
type: typeof SUMMARY.DISPOSE,
} | {
type: typeof SUMMARY.DETAILS_TOGGLE
}
export const init = (): any => {
return (dispatch, getState): void => {
export const init = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const state: State = {
...initialState,
@ -28,8 +38,8 @@ export const init = (): any => {
}
export const update = (newProps: any): any => {
return (dispatch, getState): void => {
export const update = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const {
abstractAccount,
router
@ -43,87 +53,15 @@ export const update = (newProps: any): any => {
}
}
export const dispose = (address: string): any => {
export const dispose = (): Action => {
return {
type: SUMMARY.DISPOSE
}
}
export const onDetailsToggle = (): any => {
export const onDetailsToggle = (): Action => {
return {
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
}
}

@ -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 { 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
TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => {
// post event to reducers
const type: DeviceMessageType = event.type; // assert flow type
dispatch({
type: event.type,
type,
device: event.payload
});
});
const version: Object = TrezorConnect.getVersion();
TrezorConnect.on(UI_EVENT, (event: UiMessage): void => {
// post event to reducers
const type: UiMessageType = event.type; // assert flow type
dispatch({
type: event.type,
type,
payload: event.payload
});
});
TrezorConnect.on(TRANSPORT_EVENT, (event: UiMessage): void => {
TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => {
// post event to reducers
const type: TransportMessageType = event.type; // assert flow type
dispatch({
type: event.type,
type,
payload: event.payload
});
});
@ -47,7 +125,7 @@ export const init = (): any => {
connectSrc: 'https://localhost:8088/',
// connectSrc: 'https://connect.trezor.io/tpm/',
// connectSrc: 'https://sisyfos.trezor.io/',
debug: true,
debug: false,
popup: false,
webusb: true
});
@ -62,10 +140,10 @@ export const init = (): any => {
// called after backend was initialized
// set listeners for connect/disconnect
export const postInit = (): any => {
return (dispatch, getState): void => {
export const postInit = (): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const handleDeviceConnect = (device) => {
const handleDeviceConnect = (device: Device) => {
dispatch( initConnectedDevice(device) );
}
@ -75,9 +153,11 @@ export const postInit = (): any => {
TrezorConnect.on(DEVICE.CONNECT, 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) {
dispatch({
type: WALLET.SET_INITIAL_URL,
@ -87,7 +167,7 @@ export const postInit = (): any => {
}
if (devices.length > 0) {
const unacquired = devices.find(d => d.unacquired);
const unacquired: ?TrezorDevice = devices.find(d => d.unacquired);
if (unacquired) {
dispatch( onSelectDevice(unacquired) );
} else {
@ -118,8 +198,8 @@ const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => {
});
}
export const initConnectedDevice = (device: any, force): any => {
return (dispatch, getState): void => {
export const initConnectedDevice = (device: any): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const selected = findSelectedDevice(getState().connect);
if (!selected || (selected && selected.state)) {
@ -137,27 +217,26 @@ export const initConnectedDevice = (device: any, force): any => {
// after device_connect event
// or after acquiring device
// device type could be local TrezorDevice or Device (from trezor-connect device_connect event)
export const onSelectDevice = (device: any): any => {
return (dispatch, getState): void => {
export const onSelectDevice = (device: TrezorDevice | Device): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
// || device.isUsedElsewhere
console.log("------> REDITTO", device, getState().wallet.initialUrl);
// switch to initial url and reset this value
if (device.unacquired) {
if (!device.features) {
dispatch( push(`/device/${ device.path }/acquire`) );
} else if (device.features.bootloader_mode) {
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 }`) );
} 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 }`;
let instance: ?string;
let url: string = `/device/${ deviceId }`;
let instance: ?number;
// check if device is not TrezorDevice type
if (!device.hasOwnProperty('ts')) {
// 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
//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) );
}
}
}
}
export const switchToFirstAvailableDevice = (): any => {
return async (dispatch, getState): Promise<void> => {
export const switchToFirstAvailableDevice = (): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const { devices } = getState().connect;
if (devices.length > 0) {
@ -208,8 +287,8 @@ export const switchToFirstAvailableDevice = (): any => {
}
export const getSelectedDeviceState = (): any => {
return async (dispatch, getState): Promise<void> => {
export const getSelectedDeviceState = (): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected = findSelectedDevice(getState().connect);
console.warn("init selected", selected)
if (selected
@ -260,13 +339,13 @@ export const getSelectedDeviceState = (): any => {
}
}
export const deviceDisconnect = (device: any): any => {
return async (dispatch, getState): Promise<void> => {
export const deviceDisconnect = (device: Device): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected = findSelectedDevice(getState().connect);
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
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) );
}
@ -287,9 +366,11 @@ export const deviceDisconnect = (device: any): any => {
}
}
export const coinChanged = (network: ?string): any => {
return (dispatch, getState): void => {
const selected = findSelectedDevice(getState().connect);
export const coinChanged = (network: ?string): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
if (!selected) return;
dispatch( DiscoveryActions.stop(selected) );
if (network) {
@ -298,15 +379,16 @@ export const coinChanged = (network: ?string): any => {
}
}
export function reload(): any {
return async (dispatch, getState) => {
export function reload(): AsyncAction {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
}
}
export function acquire(): any {
return async (dispatch, getState) => {
export function acquire(): AsyncAction {
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 => {
// if (d.state) {
@ -341,10 +423,11 @@ export function acquire(): any {
if (response && response.success) {
dispatch({
type: DEVICE.ACQUIRED,
device: null
})
} else {
// TODO: handle invalid pin?
console.log("-errror ack", response)
console.log("-error ack", response)
dispatch({
type: NOTIFICATION.ADD,
@ -367,35 +450,34 @@ export function acquire(): any {
}
}
export const forgetDevice = (device: any) => {
return (dispatch: any, getState: any): any => {
export const forgetDevice = (device: any): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
// 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
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) => {
return (dispatch: any, getState: any): any => {
export const gotoDeviceSettings = (device: any): AsyncAction => {
return (dispatch: Dispatch, getState: GetState): void => {
dispatch( push(`/device/${ device.features.device_id }/settings`) );
}
}
// called from Aside - device menu (forget single instance)
export const forget = (device: any) => {
export const forget = (device: any): Action => {
return {
type: CONNECT.FORGET_REQUEST,
device
};
}
export const duplicateDevice = (device: any) => {
return async (dispatch: any, getState: any): Promise<void> => {
export const duplicateDevice = (device: any): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
dispatch({
type: CONNECT.TRY_TO_DUPLICATE,
device
@ -403,17 +485,18 @@ export const duplicateDevice = (device: any) => {
}
}
export const onDuplicateDevice = () => {
return async (dispatch: any, getState: any): Promise<void> => {
const selected = findSelectedDevice(getState().connect);
dispatch(onSelectDevice(selected));
export const onDuplicateDevice = (): AsyncAction => {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected: ?TrezorDevice = findSelectedDevice(getState().connect);
if (selected)
dispatch(onSelectDevice(selected));
}
}
export function addAddress(): any {
return (dispatch, getState) => {
export function addAddress(): AsyncAction {
return (dispatch: Dispatch, getState: GetState): void => {
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 */
'use strict';
export const ON_RESIZE: string = 'ON_RESIZE';
export const TOGGLE_DEVICE_DROPDOWN: string = 'TOGGLE_DEVICE_DROPDOWN';
import * as WALLET from './constants/wallet';
export const onResize = (): any => {
return {
type: ON_RESIZE
}
import type { RouterLocationState } from '../flowtype';
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 {
type: WALLET.ON_BEFORE_UNLOAD
}
}
export const toggleDeviceDropdown = (opened: boolean): any => {
export const toggleDeviceDropdown = (opened: boolean): WalletAction => {
return {
type: WALLET.TOGGLE_DEVICE_DROPDOWN,
opened

@ -1,7 +1,7 @@
/* @flow */
'use strict';
import Web3 from 'web3';
import Web3, { ContractFactory, Contract } from 'web3';
import HDKey from 'hdkey';
import EthereumjsUtil from 'ethereumjs-util';
import EthereumjsTx from 'ethereumjs-tx';
@ -9,48 +9,47 @@ import TrezorConnect from 'trezor-connect';
import { strip } from '../utils/ethUtils';
import * as ADDRESS from './constants/address';
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';
import type { Account } from '../reducers/AccountsReducer';
export type Web3Action = {
type: typeof WEB3.READY,
} | {
type: typeof WEB3.PENDING_TX_RESOLVED
} | Web3CreateAction
| Web3UpdateBlockAction
| Web3UpdateGasPriceAction;
export type Web3CreateAction = {
type: typeof WEB3.CREATE,
network: string,
web3: any, //(web3instance)
erc20: any,
chainId: string;
};
type Web3Payload =
| {
name: string;
instance: Web3;
chainId: number;
erc20abi: any;
}
| {
network: string;
blockHash: string;
}
| {
network: string;
gasPrice: string;
}
| {
network: string;
address: string;
balance: string;
}
| {
network: string;
address: string;
nonce: string;
}
| {
network: string;
blockHash: string;
export type Web3UpdateBlockAction = {
type: typeof WEB3.BLOCK_UPDATED,
network: string,
blockHash: any
};
type Web3Action = {
type: string,
payload?: Web3Payload
export type Web3UpdateGasPriceAction = {
type: typeof WEB3.GAS_PRICE_UPDATED,
network: string,
gasPrice: any
};
export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod {
return async (dispatch, getState) => {
export function init(web3: ?Web3, coinIndex: number = 0): AsyncAction {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const { config, ERC20Abi } = getState().localStorage;
@ -191,48 +190,48 @@ export function init(web3: ?Web3, coinIndex: number = 0): ActionMethod {
}
export function initContracts(): ActionMethod {
return async (dispatch, getState) => {
const { web3, abi, tokens } = getState().web3;
const contracts = [];
for (let token of tokens) {
contracts.push({
contract: web3.eth.contract(abi).at(token.address),
name: token.name,
symbol: token.symbol,
decimal: token.decimal
});
// web3.eth.contract(abi).at(token.address).balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => {
// console.warn('contrR', e, r.toString(10));
// });
}
const contract = web3.eth.contract(abi).at('0x58cda554935e4a1f2acbe15f8757400af275e084');
contract.name.call((error, name) => {
if (error) {
// TODO: skip
}
contract.symbol.call((error, symbol) => {
if (error) {
// TODO: skip
}
contract.decimals.call((error, decimals) => {
console.log("nameeeee", name, symbol, decimals)
})
});
// export function initContracts(): AsyncAction {
// return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
// const { web3, abi, tokens } = getState().web3;
// const contracts = [];
// for (let token of tokens) {
// contracts.push({
// contract: web3.eth.contract(abi).at(token.address),
// name: token.name,
// symbol: token.symbol,
// decimal: token.decimal
// });
// // web3.eth.contract(abi).at(token.address).balanceOf('0x98ead4bd2fbbb0cf0b49459aa0510ef53faa6cad', (e, r) => {
// // console.warn('contrR', e, r.toString(10));
// // });
// }
// const contract = web3.eth.contract(abi).at('0x58cda554935e4a1f2acbe15f8757400af275e084');
// contract.name.call((error, name) => {
// if (error) {
// // TODO: skip
// }
// contract.symbol.call((error, symbol) => {
// if (error) {
// // TODO: skip
// }
// contract.decimals.call((error, decimals) => {
// console.log("nameeeee", name, symbol, decimals)
// })
// });
})
}
}
// })
// }
// }
export function getGasPrice(network: string): ActionMethod {
return async (dispatch, getState) => {
export function getGasPrice(network: string): AsyncAction {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
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 {
return async (dispatch, getState) => {
export function getBalance(account: Account): AsyncAction {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const web3instance = getState().web3.filter(w3 => w3.network === addr.network)[0];
const web3 = web3instance.web3;
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
const web3: Web3 = web3instance.web3;
web3.eth.getBalance(addr.address, (error, balance) => {
web3.eth.getBalance(account.address, (error, balance) => {
if (!error) {
const newBalance: string = web3.fromWei(balance.toString(), 'ether');
if (addr.balance !== newBalance) {
if (account.balance !== newBalance) {
dispatch({
type: ADDRESS.SET_BALANCE,
address: addr.address,
network: addr.network,
address: account.address,
network: account.network,
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;
web3.eth.getTransactionCount(addr.address, (error, result) => {
web3.eth.getTransactionCount(account.address, (error, result) => {
if (!error) {
if (addr.nonce !== result) {
if (account.nonce !== result) {
dispatch({
type: ADDRESS.SET_NONCE,
address: addr.address,
network: addr.network,
address: account.address,
network: account.network,
nonce: result
});
}
@ -298,8 +297,8 @@ export function getNonce(addr: Address) {
}
}
export function getTransactionReceipt(tx: any): any {
return async (dispatch, getState) => {
export function getTransactionReceipt(tx: any): AsyncAction {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0];
const web3 = web3instance.web3;
@ -323,14 +322,14 @@ export function getTransactionReceipt(tx: any): any {
}
export function updateLastBlock(hash: string) {
return {
type: 'web3__update_last_block',
hash
}
}
// export function updateLastBlock(hash: string): Action {
// return {
// type: 'web3__update_last_block',
// hash
// }
// }
export function getTransaction(web3, txid) {
export const getTransaction = (web3: Web3, txid: string): Promise<any> => {
return new Promise((resolve, reject) => {
web3.eth.getTransaction(txid, (error, result) => {
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) => {
web3.eth.getBalance(address, (error, result) => {
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) => {
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) => {
web3.eth.getTransactionCount(address, (error, result) => {
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) => {
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) => {
web3.eth.estimateGas(gasOptions, (error, result) => {
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) => {
web3.eth.getGasPrice((error, result) => {
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) => {
web3.eth.sendRawTransaction(tx, (error, result) => {
if (error) {
@ -452,7 +451,3 @@ export function pushTx(web3, tx) {
});
})
}

@ -1,26 +1,29 @@
/* @flow */
'use strict';
export const READY: string = 'trezorconnect__ready';
export const INITIALIZATION_ERROR: string = 'trezorconnect__init_error';
export const SELECT_DEVICE: string = 'trezorconnect__select_device';
//regExp1 : string = '(.*)'
//regExp2 : '$1' = '$1'
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 AUTH_DEVICE: string = 'trezorconnect__auth_device';
export const COIN_CHANGED: string = 'trezorconnect__coin_changed';
export const REMEMBER_REQUEST: string = 'trezorconnect__remember_request';
export const FORGET_REQUEST: string = 'trezorconnect__forget_request';
export const FORGET: string = 'trezorconnect__forget';
export const FORGET_SINGLE: string = 'trezorconnect__forget_single';
export const DISCONNECT_REQUEST: string = 'trezorconnect__disconnect_request';
export const REMEMBER: string = 'trezorconnect__remember';
export const DEVICE_FROM_STORAGE: 'trezorconnect__device_from_storage' = 'trezorconnect__device_from_storage';
export const AUTH_DEVICE: 'trezorconnect__auth_device' = 'trezorconnect__auth_device';
export const COIN_CHANGED: 'trezorconnect__coin_changed' = 'trezorconnect__coin_changed';
export const START_ACQUIRING: string = 'trezorconnect__start_acquiring';
export const STOP_ACQUIRING: string = 'trezorconnect__stop_acquiring';
export const REMEMBER_REQUEST: 'trezorconnect__remember_request' = 'trezorconnect__remember_request';
export const FORGET_REQUEST: 'trezorconnect__forget_request' = 'trezorconnect__forget_request';
export const FORGET: 'trezorconnect__forget' = 'trezorconnect__forget';
export const FORGET_SINGLE: 'trezorconnect__forget_single' = 'trezorconnect__forget_single';
export const DISCONNECT_REQUEST: 'trezorconnect__disconnect_request' = 'trezorconnect__disconnect_request';
export const REMEMBER: 'trezorconnect__remember' = 'trezorconnect__remember';
export const TRY_TO_DUPLICATE: string = 'trezorconnect__try_to_duplicate';
export const DUPLICATE: string = 'trezorconnect__duplicate';
export const START_ACQUIRING: 'trezorconnect__start_acquiring' = 'trezorconnect__start_acquiring';
export const STOP_ACQUIRING: 'trezorconnect__stop_acquiring' = 'trezorconnect__stop_acquiring';
export const DEVICE_STATE_EXCEPTION: string = 'trezorconnect__device_state_exception';
export const TRY_TO_DUPLICATE: 'trezorconnect__try_to_duplicate' = 'trezorconnect__try_to_duplicate';
export const DUPLICATE: 'trezorconnect__duplicate' = 'trezorconnect__duplicate';
export const DEVICE_STATE_EXCEPTION: 'trezorconnect__device_state_exception' = 'trezorconnect__device_state_exception';

@ -1,11 +1,11 @@
/* @flow */
'use strict';
export const INIT: string = 'account__init';
export const DISPOSE: string = 'account__dispose';
export const INIT: 'account__init' = 'account__init';
export const DISPOSE: 'account__dispose' = 'account__dispose';
export const CREATE: string = 'address__create';
export const REMOVE: string = 'address__remove';
export const SET_BALANCE: string = 'address__set_balance';
export const SET_NONCE: string = 'address__set_nonce';
export const FROM_STORAGE: string = 'address__from_storage';
// export const CREATE: 'address__create' = 'address__create';
// export const REMOVE: 'address__remove' = 'address__remove';
// export const SET_BALANCE: 'address__set_balance' = 'address__set_balance';
// export const SET_NONCE: 'address__set_nonce' = 'address__set_nonce';
// export const FROM_STORAGE: 'address__from_storage' = 'address__from_storage';

@ -1,9 +1,9 @@
/* @flow */
'use strict';
export const CREATE: string = 'address__create';
export const REMOVE: string = 'address__remove';
export const SET_BALANCE: string = 'address__set_balance';
export const SET_NONCE: string = 'address__set_nonce';
export const FROM_STORAGE: string = 'address__from_storage';
export const CREATE: 'address__create' = 'address__create';
export const REMOVE: 'address__remove' = 'address__remove';
export const SET_BALANCE: 'address__set_balance' = 'address__set_balance';
export const SET_NONCE: 'address__set_nonce' = 'address__set_nonce';
export const FROM_STORAGE: 'address__from_storage' = 'address__from_storage';

@ -1,8 +1,8 @@
/* @flow */
'use strict';
export const START: string = 'discovery__start';
export const STOP: string = 'discovery__stop';
export const COMPLETE: string = 'discovery__complete';
export const WAITING: string = 'discovery__waiting';
export const FROM_STORAGE: string = 'discovery__from_storage';
export const START: 'discovery__start' = 'discovery__start';
export const STOP: 'discovery__stop' = 'discovery__stop';
export const COMPLETE: 'discovery__complete' = 'discovery__complete';
export const WAITING: 'discovery__waiting' = 'discovery__waiting';
export const FROM_STORAGE: 'discovery__from_storage' = 'discovery__from_storage';

@ -1,6 +1,6 @@
/* @flow */
'use strict';
export const SAVE: string = 'storage__save';
export const READY: string = 'storage__ready';
export const ERROR: string = 'storage__error';
export const SAVE: 'storage__save' = 'storage__save';
export const READY: 'storage__ready' = 'storage__ready';
export const ERROR: 'storage__error' = 'storage__error';

@ -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';
export const ON_PASSPHRASE_SHOW: string = 'action__on_passphrase_show';
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';
/* @flow */
'use strict';
export const FORGET: string = 'modal__forget';
export const REMEMBER: string = 'modal__remember';
export const ON_FORGET: string = 'modal__on_forget';
export const ON_REMEMBER: string = 'modal__on_remember';
export const CLOSE: string = 'modal__close';
export const ON_PASSPHRASE_CHANGE: 'action__on_passphrase_change' = 'action__on_passphrase_change';
export const ON_PASSPHRASE_SHOW: 'action__on_passphrase_show' = 'action__on_passphrase_show';
export const ON_PASSPHRASE_HIDE: 'action__on_passphrase_hide' = 'action__on_passphrase_hide';
export const ON_PASSPHRASE_SAVE: 'action__on_passphrase_save' = 'action__on_passphrase_save';
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 */
'use strict';
export const ADD: string = 'notification__add';
export const CLOSE: string = 'notification__close';
export const REMOVE: string = 'account__remove';
export const ADD: 'notification__add' = 'notification__add';
export const CLOSE: 'notification__close' = 'notification__close';
export const REMOVE: 'account__remove' = 'account__remove';

@ -1,8 +1,8 @@
/* @flow */
'use strict';
export const INIT: string = 'receive__init';
export const DISPOSE: string = 'receive__dispose';
export const REQUEST_UNVERIFIED: string = 'receive__request_unverified';
export const SHOW_ADDRESS: string = 'receive__show_address';
export const SHOW_UNVERIFIED_ADDRESS: string = 'receive__show_unverified';
export const INIT: 'receive__init' = 'receive__init';
export const DISPOSE: 'receive__dispose' = 'receive__dispose';
export const REQUEST_UNVERIFIED: 'receive__request_unverified' = 'receive__request_unverified';
export const SHOW_ADDRESS: 'receive__show_address' = 'receive__show_address';
export const SHOW_UNVERIFIED_ADDRESS: 'receive__show_unverified' = 'receive__show_unverified';

@ -1,19 +1,19 @@
/* @flow */
'use strict';
export const INIT: string = 'send__init';
export const DISPOSE: string = 'send__dispose';
export const VALIDATION: string = 'send__validation';
export const ADDRESS_CHANGE: string = 'send__address_change';
export const AMOUNT_CHANGE: string = 'send__amount_change';
export const SET_MAX: string = 'send__set_max';
export const CURRENCY_CHANGE: string = 'send__currency_change';
export const FEE_LEVEL_CHANGE: string = 'send__fee_level_change';
export const GAS_PRICE_CHANGE: string = 'send__gas_price_change';
export const GAS_LIMIT_CHANGE: string = 'send__gas_limit_change';
export const UPDATE_FEE_LEVELS: string = 'send__update_fee_levels';
export const DATA_CHANGE: string = 'send__data_change';
export const SEND: string = 'send__submit';
export const TX_COMPLETE: string = 'send__tx_complete';
export const TX_ERROR: string = 'send__tx_error';
export const TOGGLE_ADVANCED: string = 'send__toggle_advanced';
export const INIT: 'send__init' = 'send__init';
export const DISPOSE: 'send__dispose' = 'send__dispose';
export const VALIDATION: 'send__validation' = 'send__validation';
export const ADDRESS_CHANGE: 'send__address_change' = 'send__address_change';
export const AMOUNT_CHANGE: 'send__amount_change' = 'send__amount_change';
export const SET_MAX: 'send__set_max' = 'send__set_max';
export const CURRENCY_CHANGE: 'send__currency_change' = 'send__currency_change';
export const FEE_LEVEL_CHANGE: 'send__fee_level_change' = 'send__fee_level_change';
export const GAS_PRICE_CHANGE: 'send__gas_price_change' = 'send__gas_price_change';
export const GAS_LIMIT_CHANGE: 'send__gas_limit_change' = 'send__gas_limit_change';
export const UPDATE_FEE_LEVELS: 'send__update_fee_levels' = 'send__update_fee_levels';
export const DATA_CHANGE: 'send__data_change' = 'send__data_change';
export const SEND: 'send__submit' = 'send__submit';
export const TX_COMPLETE: 'send__tx_complete' = 'send__tx_complete';
export const TX_ERROR: 'send__tx_error' = 'send__tx_error';
export const TOGGLE_ADVANCED: 'send__toggle_advanced' = 'send__toggle_advanced';

@ -1,7 +1,7 @@
/* @flow */
'use strict';
export const INIT: string = 'summary__init';
export const DISPOSE: string = 'summary__dispose';
export const ADD_TOKEN: string = 'summary__add_token';
export const DETAILS_TOGGLE: string = 'summary__details_toggle';
export const INIT: 'summary__init' = 'summary__init';
export const DISPOSE: 'summary__dispose' = 'summary__dispose';
export const ADD_TOKEN: 'summary__add_token' = 'summary__add_token';
export const DETAILS_TOGGLE: 'summary__details_toggle' = 'summary__details_toggle';

@ -1,7 +1,7 @@
/* @flow */
'use strict';
export const ADD: string = 'token__add';
export const REMOVE: string = 'token__remove';
export const SET_BALANCE: string = 'token__set_balance';
export const FROM_STORAGE: string = 'token__from_storage';
export const ADD: 'token__add' = 'token__add';
export const REMOVE: 'token__remove' = 'token__remove';
export const SET_BALANCE: 'token__set_balance' = 'token__set_balance';
export const FROM_STORAGE: 'token__from_storage' = 'token__from_storage';

@ -1,6 +1,6 @@
/* @flow */
'use strict';
export const ON_BEFORE_UNLOAD: string = 'wallet__on_before_unload';
export const TOGGLE_DEVICE_DROPDOWN: string = 'wallet_toggle_dropdown';
export const SET_INITIAL_URL: string = 'wallet_set_initial_url';
export const ON_BEFORE_UNLOAD: 'wallet__on_before_unload' = 'wallet__on_before_unload';
export const TOGGLE_DEVICE_DROPDOWN: 'wallet_toggle_dropdown' = 'wallet_toggle_dropdown';
export const SET_INITIAL_URL: 'wallet_set_initial_url' = 'wallet_set_initial_url';

@ -1,10 +1,10 @@
/* @flow */
'use strict';
export const START: string = 'web3__start';
export const STOP: string = 'web3__stop';
export const CREATE: string = 'web3__create';
export const READY: string = 'web3__ready';
export const BLOCK_UPDATED: string = 'web3__block_updated';
export const GAS_PRICE_UPDATED: string = 'web3__gas_price_updated';
export const PENDING_TX_RESOLVED: string = 'web3__pending_tx_resolved';
export const START: 'web3__start' = 'web3__start';
export const STOP: 'web3__stop' = 'web3__stop';
export const CREATE: 'web3__create' = 'web3__create';
export const READY: 'web3__ready' = 'web3__ready';
export const BLOCK_UPDATED: 'web3__block_updated' = 'web3__block_updated';
export const GAS_PRICE_UPDATED: 'web3__gas_price_updated' = 'web3__gas_price_updated';
export const PENDING_TX_RESOLVED: 'web3__pending_tx_resolved' = 'web3__pending_tx_resolved';

@ -6,8 +6,13 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
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 (
<footer>
<span>© 2018</span>
@ -19,12 +24,12 @@ const Footer = (props: any): any => {
}
export default connect(
(state) => {
(state: State) => {
return {
}
},
(dispatch) => {
(dispatch: Dispatch) => {
return {
toggle: bindActionCreators(LogActions.toggle, dispatch),
};

@ -1,33 +1,30 @@
/* @flow */
'use strict';
import React, { Component } from 'react';
import React from 'react';
export default class Header extends Component {
render() {
return (
<header>
<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">
<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="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 "/>
<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"/>
<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>
<div>
<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://blog.trezor.io/" target="_blank" rel="noreferrer noopener">Blog</a>
<a href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Support</a>
</div>
const Header = (): React$Element<string> => {
return (
<header>
<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">
<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="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 "/>
<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"/>
<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>
<div>
<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://blog.trezor.io/" target="_blank" rel="noreferrer noopener">Blog</a>
<a href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Support</a>
</div>
</header>
);
}
</div>
</header>
);
}
export default Header;

@ -3,7 +3,7 @@
import React from 'react';
export default (props: any): any => {
export default (props: { size: string, label?: string }): React$Element<string> => {
const style = {
width: `${props.size}px`,

@ -6,9 +6,14 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
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)
return null;
@ -23,12 +28,12 @@ const Log = (props: any) => {
}
export default connect(
(state) => {
(state: State) => {
return {
log: state.log
};
},
(dispatch) => {
(dispatch: Dispatch) => {
return {
toggle: bindActionCreators(LogActions.toggle, dispatch),
};

@ -6,23 +6,37 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
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) => {
const className = `notification ${ props.className }`;
type NProps = {
key?: number;
className: string;
cancelable?: boolean;
title: string;
message?: string;
actions?: Array<any>;
close?: (notif?: any) => Action
}
const actionButtons = !props.actions ? null : props.actions.map((a, i) => {
export const Notification = (props: NProps): React$Element<string> => {
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) => {
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 (
<div className={ className }>
{ props.cancelable ? (
<button className="notification-close transparent"
onClick={ event => props.close() }></button>
onClick={ event => close() }></button>
) : null }
<div className="notification-body">
<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;
return notifications.map((n, i) => {
return (
@ -56,14 +70,14 @@ export const NotificationGroup = (props: any) => {
}
export default connect(
(state) => {
(state: State) => {
return {
notifications: state.notifications
};
},
(dispatch) => {
(dispatch: Dispatch) => {
return {
close: bindActionCreators((notif) => {
close: bindActionCreators((notif?: any): Action => {
return {
type: NOTIFICATION.CLOSE,
payload: notif

@ -4,8 +4,11 @@
import React, { Component } from 'react';
import TrezorConnect from 'trezor-connect';
export default class InstallBridge extends Component {
type Props = {
transport: any;
}
export default class InstallBridge extends Component<Props> {
componentDidMount(): void {
const transport: any = this.props.transport;

@ -7,27 +7,39 @@ import Select from 'react-select';
type State = {
version: string;
target: string;
target: ?InstallTarget;
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: '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-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)' },
{ value: 'trezor-bridge_2.0.11_amd32.rpm', label: 'Linux 32-bit (rpm)' },
{ id: '01', value: 'trezor-bridge_2.0.11_amd32.deb', label: 'Linux 32-bit (deb)' },
{ 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);
const currentTarget = installers.find(i => i.id === props.browserState.osname);
const currentTarget: ?InstallTarget = installers.find(i => i.id === props.browserState.osname);
this.state = {
version: '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({
target: value
});
@ -44,7 +56,7 @@ export default class InstallBridge extends Component {
componentWillUpdate() {
if (this.props.browserState.osname && !this.state.target) {
const currentTarget = installers.find(i => i.id === this.props.browserState.osname);
const currentTarget: ?InstallTarget = installers.find(i => i.id === this.props.browserState.osname);
this.setState({
target: currentTarget
})
@ -55,8 +67,9 @@ export default class InstallBridge extends Component {
if (!this.state.target) {
return <Preloader />;
}
const label: string = this.state.target.label;
const url = `${ this.state.url }${ this.state.target.value }`;
return (
<main>
<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 }
onChange={ this.onChange.bind(this) }
options={ installers } />
<a href={ url } className="button">Download for { this.state.target.label }</a>
<a href={ url } className="button">Download for { label }</a>
</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>
</main>

@ -13,8 +13,9 @@ import Log from '../common/Log';
// import { 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 (
<main>
<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 { devices, browserState, transport } = props.connect;
@ -43,7 +46,7 @@ export default (props: any): any => {
let notification = null;
let body = null;
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) {
notification = (<Notification

@ -3,7 +3,7 @@
import React from 'react';
export default (props: any): any => {
export default (props: {}): React$Element<string> => {
return (
<section className="landing">
localstorage ERROR

@ -4,7 +4,7 @@
import React from 'react';
import Loader from '../common/LoaderCircle';
export default (props: any): any => {
export default (props: {}): React$Element<string> => {
return (
<section className="landing">
<Loader label="Loading" size="100" />

@ -3,7 +3,7 @@
import React from 'react';
export default (props: any): any => {
export default (props: {}): React$Element<string> => {
return (
<section className="landing">
connect ERROR

@ -7,7 +7,27 @@ import { connect } from 'react-redux';
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 {
localStorage: state.localStorage,
modal: state.modal,
@ -18,10 +38,10 @@ const mapStateToProps = (state, own) => {
};
}
const mapDispatchToProps = (dispatch) => {
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch) => {
return {
foo: ():string => { return "A"; }
};
}
export default connect(mapStateToProps, mapDispatchToProps)(LandingPage);
export default connect(mapStateToProps, null)(LandingPage);

@ -2,8 +2,9 @@
'use strict';
import React from 'react';
import type { Props } from './index';
const Confirmation = (props): any => {
const Confirmation = (props: Props) => {
const {
amount,
address,

@ -2,8 +2,9 @@
'use strict';
import React from 'react';
import type { Props } from './index';
const InvalidPin = (props): any => {
const InvalidPin = (props: Props) => {
const { device } = props.modal;
return (
<div className="pin">

@ -5,6 +5,7 @@ import React, { Component } from 'react';
import raf from 'raf';
import { findSelectedDevice } from '../../reducers/TrezorConnectReducer';
import type { Props } from './index';
type State = {
deviceLabel: string;
singleInput: boolean;
@ -17,13 +18,14 @@ type State = {
visible: boolean;
}
export default class PinModal extends Component {
export default class PinModal extends Component<Props, State> {
keyboardHandler: (event: KeyboardEvent) => void;
state: State;
passphraseInput: HTMLInputElement;
passphraseRevisionInput: HTMLInputElement;
passphraseInput: ?HTMLInputElement;
passphraseRevisionInput: ?HTMLInputElement;
constructor(props: any) {
constructor(props: Props) {
super(props);
// check if this device is already known
@ -36,8 +38,6 @@ export default class PinModal extends Component {
singleInput = selected.remember;
}
console.warn("-----PASSS", selected)
this.state = {
deviceLabel,
singleInput,
@ -72,7 +72,8 @@ export default class PinModal extends Component {
componentDidMount(): void {
// one time autofocus
this.passphraseInput.focus();
if (this.passphraseInput)
this.passphraseInput.focus();
this.keyboardHandler = this.keyboardHandler.bind(this);
window.addEventListener('keydown', this.keyboardHandler, false);
@ -117,9 +118,10 @@ export default class PinModal extends Component {
passphraseRevisionInputValue = passphraseRevision.replace(/./g, '•');
}
this.passphraseInput.value = passphraseInputValue;
this.passphraseInput.setAttribute("type", visible ? "text" : "password");
if (this.passphraseInput) {
this.passphraseInput.value = passphraseInputValue;
this.passphraseInput.setAttribute("type", visible ? "text" : "password");
}
if (this.passphraseRevisionInput) {
this.passphraseRevisionInput.value = passphraseRevisionInputValue;
this.passphraseRevisionInput.setAttribute("type", visible ? "text" : "password");
@ -207,28 +209,8 @@ export default class PinModal extends Component {
render(): any {
const {
//onPassphraseChange,
//onPassphraseSubmit,
//onPassphraseSubmitEmpty,
//onPassphraseForget,
//onPassphraseFocus,
//onPassphraseBlur,
//onPassphraseSave,
//onPassphraseShow,
//onPassphraseHide
} = this.props.modalActions;
const {
device,
//passphrase,
//passphraseRevision,
//passphraseFocused,
//passphraseRevisionFocused,
//passphraseVisible,
//passphraseMatch,
//passphraseRevisionTouched,
passphraseCached
} = this.props.modal;
const {

@ -3,9 +3,7 @@
import React from 'react';
const Confirmation = (props): any => {
const Confirmation = () => {
return (
<div className="confirm-tx">
<div className="header">

@ -1,17 +1,19 @@
/* @flow */
'use strict';
import React, { Component, KeyboardEvent } from 'react';
import React, { Component } from 'react';
import type { Props } from './index';
type State = {
pin: string;
}
export default class Pin extends Component {
export default class Pin extends Component<Props, State> {
keyboardHandler: (event: KeyboardEvent) => void;
state: State;
constructor(props: any) {
constructor(props: Props) {
super(props);
this.state = {
@ -36,7 +38,7 @@ export default class Pin extends Component {
}
keyboardHandler(event: KeyboardEvent): void {
const { onPinAdd, onPinBackspace, onPinSubmit } = this.props.modalActions;
const { onPinSubmit } = this.props.modalActions;
const { pin } = this.state;
event.preventDefault();

@ -4,20 +4,18 @@
import React, { Component } from 'react';
import Loader from '../common/LoaderCircle';
type Props = {
modal: any;
}
import type { Props } from './index';
type State = {
+countdown: number;
countdown: number;
ticker?: number;
}
export default class RememberDevice extends Component {
export default class RememberDevice extends Component<Props, State> {
state: State;
constructor(props: any) {
constructor(props: Props) {
super(props);
this.state = {
@ -79,7 +77,7 @@ export default class RememberDevice extends Component {
<h3>Forget {label}?</h3>
<p>Would you like TREZOR Wallet to forget your device or to remember it, so that it is still visible even while disconnected?</p>
<button onClick={ event => onForgetDevice(device) }>Forget</button>
<button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size={ 28 } label={ this.state.countdown } /></span></button>
<button className="white" onClick={ event => onRememberDevice(device) }><span>Remember <Loader size="28" label={ this.state.countdown.toString() } /></span></button>
</div>
);
}

@ -10,8 +10,8 @@ import { CSSTransition, Transition } from 'react-transition-group';
import { UI } from 'trezor-connect';
import * as ModalActions from '../../actions/ModalActions';
import * as ReceiveActions from '../../actions/ReceiveActions';
import { default as ModalActions } from '../../actions/ModalActions';
import { default as ReceiveActions } from '../../actions/ReceiveActions';
import Pin from './Pin';
import InvalidPin from './InvalidPin';
@ -26,6 +26,28 @@ import * as RECEIVE from '../../actions/constants/receive';
import * as MODAL from '../../actions/constants/modal';
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;
@ -38,7 +60,7 @@ const Fade = ({ children, ...props }) => (
</CSSTransition>
);
class Modal extends Component {
class Modal extends Component<Props> {
render() {
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 {
modal: state.modal,
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 {
modalActions: bindActionCreators(ModalActions, dispatch),
receiveActions: bindActionCreators(ReceiveActions, dispatch),

@ -7,7 +7,13 @@ import { connect } from 'react-redux';
import { Notification } from '../common/Notification';
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 = [
{
@ -26,22 +32,20 @@ const Acquire = (props: any): any => {
className="info"
cancelable={ false }
actions={ actions }
close={ () => {} }
/>
</section>
);
}
const mapStateToProps = (state, own) => {
return {
connect: state.connect
};
}
const mapDispatchToProps = (dispatch) => {
return {
acquireDevice: bindActionCreators(TrezorConnectActions.acquire, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Acquire);
export default connect(
(state: State) => {
return {
log: state.log
};
},
(dispatch: Dispatch) => {
return {
toggle: bindActionCreators(TrezorConnectActions.acquire, dispatch),
};
}
)(Acquire);

@ -5,7 +5,7 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
const Bootloader = (props: any): any => {
const Bootloader = () => {
return (
<section className="acquire">
<h3>Bootloader mode</h3>
@ -13,15 +13,4 @@ const Bootloader = (props: any): any => {
);
}
const mapStateToProps = (state, own) => {
return {
};
}
const mapDispatchToProps = (dispatch) => {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Bootloader);
export default connect(null, null)(Bootloader);

@ -5,7 +5,7 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
const Dashboard = (props: any): any => {
const Dashboard = () => {
return (
<section className="dashboard">
<h2>Dashboard</h2>
@ -18,15 +18,4 @@ const Dashboard = (props: any): any => {
);
}
const mapStateToProps = (state, own) => {
return {
};
}
const mapDispatchToProps = (dispatch) => {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
export default connect(null, null)(Dashboard);

@ -5,7 +5,7 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
export const DeviceSettings = (props: any): any => {
export const DeviceSettings = () => {
return (
<section className="settings">
Device settings
@ -13,15 +13,4 @@ export const DeviceSettings = (props: any): any => {
);
}
const mapStateToProps = (state, own) => {
return {
};
}
const mapDispatchToProps = (dispatch) => {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(DeviceSettings);
export default connect(null, null)(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 { Notification } from '../common/Notification';
import * as ReceiveActions from '../../actions/ReceiveActions';
import * as AbstractAccountActions from '../../actions/AbstractAccountActions';
import { default as ReceiveActions } from '../../actions/ReceiveActions';
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() {
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 {
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 {
abstractAccount: state.abstractAccount,
location: state.router.location,
devices: state.connect.devices,
accounts: state.accounts,
discovery: state.discovery,
@ -95,8 +121,8 @@ const mapStateToProps = (state, own) => {
};
}
const mapDispatchToProps = (dispatch) => {
return {
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
return {
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
initAccount: bindActionCreators(ReceiveActions.init, dispatch),
updateAccount: bindActionCreators(ReceiveActions.update, dispatch),

@ -5,7 +5,7 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
const SignVerify = (props: any): any => {
const SignVerify = () => {
return (
<section className="signverify">
<div className="sign">
@ -30,15 +30,4 @@ const SignVerify = (props: any): any => {
);
}
const mapStateToProps = (state, own) => {
return {
};
}
const mapDispatchToProps = (dispatch) => {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SignVerify);
export default connect(null, null)(SignVerify);

@ -5,7 +5,7 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
export const WalletSettings = (props: any): any => {
export const WalletSettings = () => {
return (
<section className="settings">
Wallet settings
@ -13,15 +13,4 @@ export const WalletSettings = (props: any): any => {
);
}
const mapStateToProps = (state, own) => {
return {
};
}
const mapDispatchToProps = (dispatch) => {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(WalletSettings);
export default connect(null, null)(WalletSettings);

@ -4,75 +4,103 @@
import React, { Component } from 'react';
import { Notification } from '../../common/Notification';
import { findDevice } from '../../../utils/reducerUtils';
import type { TrezorDevice } from '../../../reducers/TrezorConnectReducer';
export type AccountState = {
device: TrezorDevice;
discovery: any;
account: any;
// import * as AbstractAccountActions from '../../actions/AbstractAccountActions';
import { default as AbstractAccountActions } from '../../../actions/AbstractAccountActions';
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;
discovery: any;
account: any;
deviceStatusNotification: any;
export type Props = StateProps & DispatchProps;
constructor(props: any) {
super(props);
this.state = {
export type AccountState = {
device: ?TrezorDevice;
account: ?Account;
discovery: ?Discovery;
deviceStatusNotification: ?React$Element<typeof Notification>;
}
}
}
export default class AbstractAccount<P> extends Component<Props & P, AccountState> {
setLocalVars(vars: any) {
this.device = vars.device;
this.discovery = vars.discovery;
}
state: AccountState = {
device: null,
account: null,
discovery: null,
deviceStatusNotification: null
};
componentDidMount() {
this.props.abstractAccountActions.init();
this.props.initAccount();
}
componentWillUpdate(newProps: any) {
this.device = null;
this.discovery = null;
this.account = null;
this.deviceStatusNotification = null;
componentWillReceiveProps(props: Props & P) {
this.props.abstractAccountActions.update();
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() {
this.props.abstractAccountActions.dispose();
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 state = props.abstractAccount;
const currentState = props.abstractAccount;
if (!state.deviceState) {
if (!currentState.deviceState) {
return (<section><Notification className="info" title="Loading device" /></section>);
}
const {
device,
account,
discovery
} = this.state;
const device = findDevice(props.devices, state.deviceState, state.deviceId, state.deviceInstance);
// const device = findDevice(props.devices, accountState.deviceState, accountState.deviceId, accountState.deviceInstance);
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 (!discovery || discovery.waitingForDevice) {
@ -97,7 +125,11 @@ export default class AbstractAccount extends Component {
} else {
return (
<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>
);
}
@ -114,20 +146,8 @@ export default class AbstractAccount extends Component {
</section>
);
}
} else {
if (!device.connected) {
deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is disconnected` } />;
} else if (!device.available) {
deviceStatusNotification = <Notification className="info" title={ `Device ${ device.instanceLabel } is unavailable` } message="Change passphrase settings to use this device" />;
}
}
// Set class variables for extender classes
this.device = device;
this.discovery = discovery;
this.account = account;
this.deviceStatusNotification = deviceStatusNotification;
return null;
}
}

@ -4,13 +4,20 @@
import React, { Component } from 'react';
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;
constructor(props: any) {
@ -45,7 +52,9 @@ class Indicator extends Component {
reposition() {
const tabs = document.querySelector('.account-tabs');
if (!tabs) return;
const active = tabs.querySelector('.active');
if (!active) return;
const bounds = active.getBoundingClientRect();
const left = bounds.left - tabs.getBoundingClientRect().left;

@ -10,27 +10,30 @@ import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
import Loader from '../../common/LoaderCircle';
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);
if (!selected) return null;
const { location } = props.router;
const urlParams = location.params;
const urlParams = location.state;
const accounts = props.accounts;
const baseUrl: string = urlParams.deviceInstance ? `/device/${urlParams.device}:${urlParams.deviceInstance}` : `/device/${urlParams.device}`;
const { config } = props.localStorage;
const selectedCoin = config.coins.find(c => c.network === location.params.network);
const selectedCoin = config.coins.find(c => c.network === location.state.network);
if (!selectedCoin) return;
const fiatRate = props.fiat.find(f => f.network === selectedCoin.network);
// 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) => {
// 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}`);
let balance: string = 'Loading...';
@ -65,7 +68,7 @@ const AccountSelection = (props: any): any => {
}
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.completed) {

@ -1,7 +1,8 @@
/* @flow */
'use strict';
import React from 'react';
//import React, { Node } from 'react';
import * as React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
@ -11,7 +12,16 @@ import CoinSelection from './CoinSelection';
import StickyContainer from './StickyContainer';
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 (
<TransitionGroup component="div" className="transition-container">
<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;
if (location.pathname === '/' || !selected) return (<aside></aside>);
@ -52,15 +62,15 @@ const Aside = (props: any): any => {
if (props.deviceDropdownOpened) {
menu = <DeviceDropdown {...props} />;
} else if (location.params.network) {
} else if (location.state.network) {
menu = (
<TransitionMenu animationType={"slide-left"}>
<TransitionMenu animationType={ "slide-left" }>
<AccountSelection { ...props} />
</TransitionMenu>
);
} else if (!selected.unacquired) {
menu = (
<TransitionMenu animationType={"slide-right"}>
<TransitionMenu animationType={ "slide-right" }>
<CoinSelection { ...props} />
</TransitionMenu>
);

@ -4,7 +4,10 @@
import React from 'react';
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 { config } = props.localStorage;

@ -3,9 +3,12 @@
import React, { Component } from 'react';
import Select from 'react-select';
import TrezorConnect from 'trezor-connect';
import { findSelectedDevice } from '../../../reducers/TrezorConnectReducer';
import type { Props } from './index';
import type { TrezorDevice } from '../../../flowtype';
const Value = (props: any): any => {
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 selected = findSelectedDevice(props.connect);
const selected: ?TrezorDevice = findSelectedDevice(props.connect);
if (!selected) return null;
const handleMenuClick = (type, device) => {
console.log("handleMenuClick", type, device)
if (type === 'acquire') {
props.acquireDevice(device);
props.acquireDevice();
} else if (type === 'forget') {
props.forgetDevice(device);
}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;
}
export class DeviceDropdown extends Component<Props> {
mouseDownHandler: (event: MouseEvent) => void;
blurHandler: (event: FocusEvent) => void;
constructor(props) {
constructor(props: Props) {
super(props);
this.mouseDownHandler = this.mouseDownHandler.bind(this);
this.blurHandler = this.blurHandler.bind(this);
@ -179,7 +156,7 @@ export class DeviceDropdown extends Component {
}
mouseDownHandler(event: MouseEvent): void {
let elem = event.target;
let elem: any = (event.target : any);
let block: boolean = false;
while (elem.parentElement) {
// if (elem.className.indexOf('aside-button') >= 0) {
@ -212,9 +189,9 @@ export class DeviceDropdown extends Component {
// window.removeEventListener('blur', this.blurHandler, false);
}
onDeviceMenuClick(item, device): void {
onDeviceMenuClick(item: DeviceMenuItem, device: TrezorDevice): void {
if (item.type === 'reload') {
this.props.acquireDevice(device);
this.props.acquireDevice();
} else if (item.type === 'forget') {
// this.props.toggleDeviceDropdown(false);
this.props.forgetDevice(device);
@ -229,7 +206,8 @@ export class DeviceDropdown extends Component {
render() {
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;
if (transport && transport.version.indexOf('webusb') >= 0) {
@ -238,7 +216,7 @@ export class DeviceDropdown extends Component {
let currentDeviceMenu = null;
if (selected.features) {
const deviceMenuItems: Array<any> = [];
const deviceMenuItems: Array<DeviceMenuItem> = [];
if (selected.isUsedElsewhere) {
deviceMenuItems.push({ type: "reload", label: "Renew session" });
@ -247,7 +225,7 @@ export class DeviceDropdown extends Component {
}
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" });
}
if (selected.remember) {
@ -257,7 +235,7 @@ export class DeviceDropdown extends Component {
const deviceMenuButtons = deviceMenuItems.map((item, index) => {
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 : (

@ -8,7 +8,13 @@ import raf from 'raf';
import { DeviceSelect } from './DeviceSelection';
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.
currentScrollY: number = 0;
@ -18,15 +24,15 @@ export default class StickyContainer extends PureComponent {
framePending: boolean = false;
stickToBottom: boolean = false;
top: number = 0;
aside;
wrapper;
aside: ?HTMLElement;
wrapper: ?HTMLElement;
subscribers = [];
handleResize = event => {
handleResize = (event: Event) => {
}
handleScroll = event => {
handleScroll = (event: ?Event) => {
if (!this.framePending) {
this.framePending = true;
raf(this.update);
@ -34,24 +40,27 @@ export default class StickyContainer extends PureComponent {
}
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 asideBounds = this.aside.getBoundingClientRect();
const wrapperBounds = this.wrapper.getBoundingClientRect();
const asideBounds = aside.getBoundingClientRect();
const wrapperBounds = wrapper.getBoundingClientRect();
const scrollDirection = this.currentScrollY >= this.lastKnownScrollY ? 'down' : 'up';
const distanceScrolled = Math.abs(this.currentScrollY - this.lastKnownScrollY);
if (asideBounds.top < 0) {
this.wrapper.classList.add('fixed');
let maxTop = 1;
wrapper.classList.add('fixed');
let maxTop : number= 1;
if (wrapperBounds.height > viewportHeight) {
const bottomOutOfBounds = (helpButtonBounds.bottom <= viewportHeight && scrollDirection === 'down');
const topOutOfBounds = (wrapperBounds.top > 0 && scrollDirection === 'up');
const bottomOutOfBounds: boolean = (helpButtonBounds.bottom <= viewportHeight && scrollDirection === 'down');
const topOutOfBounds: boolean = (wrapperBounds.top > 0 && scrollDirection === 'up');
if (!bottomOutOfBounds && !topOutOfBounds) {
this.topOffset += scrollDirection === 'down' ? - distanceScrolled : distanceScrolled;
}
@ -60,27 +69,27 @@ export default class StickyContainer extends PureComponent {
if (this.topOffset > 0) this.topOffset = 0;
if (maxTop < 0 && this.topOffset < maxTop) this.topOffset = maxTop;
this.wrapper.style.top = `${this.topOffset}px`;
wrapper.style.top = `${this.topOffset}px`;
} else {
this.wrapper.classList.remove('fixed');
this.wrapper.style.top = `0px`;
wrapper.classList.remove('fixed');
wrapper.style.top = `0px`;
this.topOffset = 0;
}
if (wrapperBounds.height > viewportHeight) {
this.wrapper.classList.remove('fixed-bottom');
wrapper.classList.remove('fixed-bottom');
} else {
if (this.wrapper.classList.contains('fixed-bottom')) {
if (wrapper.classList.contains('fixed-bottom')) {
if (helpButtonBounds.top < wrapperBounds.bottom - helpButtonBounds.height) {
this.wrapper.classList.remove('fixed-bottom');
wrapper.classList.remove('fixed-bottom');
}
} else if(helpButtonBounds.bottom < viewportHeight) {
this.wrapper.classList.add('fixed-bottom');
} else if (helpButtonBounds.bottom < viewportHeight) {
wrapper.classList.add('fixed-bottom');
}
}
this.aside.style.minHeight = `${ wrapperBounds.height }px`;
aside.style.minHeight = `${ wrapperBounds.height }px`;
}
update = () => {
@ -101,8 +110,8 @@ export default class StickyContainer extends PureComponent {
window.removeEventListener('resize', this.handleScroll);
}
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
componentDidUpdate(prevProps: Props) {
if (this.props.location !== prevProps.location && this.aside) {
const asideBounds = this.aside.getBoundingClientRect();
if (asideBounds.top < 0) {
window.scrollTo(0, getScrollY() + asideBounds.top);

@ -11,7 +11,36 @@ import { toggleDeviceDropdown } from '../../../actions/WalletActions';
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 {
connect: state.connect,
accounts: state.accounts,
@ -23,7 +52,7 @@ const mapStateToProps = (state, own) => {
};
}
const mapDispatchToProps = (dispatch) => {
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
return {
//onAccountSelect: bindActionCreators(AccountActions.onAccountSelect, 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(
connect(mapStateToProps, mapDispatchToProps)(Aside)
);

@ -1,7 +1,7 @@
/* @flow */
'use strict';
import React from 'react';
import * as React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Route, withRouter } from 'react-router-dom';
@ -14,7 +14,13 @@ import ModalContainer from '../modal';
import Notifications from '../common/Notification';
import Log from '../common/Log';
const Content = (props) => {
import type { State, Dispatch } from '../../flowtype';
type Props = {
children: React.Node
}
const Content = (props: Props) => {
return (
<article>
<nav>
@ -28,7 +34,7 @@ const Content = (props) => {
);
}
const Wallet = (props: any): any => {
const Wallet = (props: Props) => {
return (
<div className="app">
<Header />
@ -43,16 +49,6 @@ const Wallet = (props: any): any => {
);
}
const mapStateToProps = (state, own) => {
return {
};
}
const mapDispatchToProps = (dispatch) => {
return { };
}
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Wallet)
connect(null, null)(Wallet)
);

@ -4,7 +4,9 @@
import React from 'react';
import Tooltip from 'rc-tooltip';
const AdvancedForm = (props: any): any => {
import type { Props } from './index';
const AdvancedForm = (props: Props) => {
const { network } = props.abstractAccount;
const {

@ -1,33 +1,35 @@
/* @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>
// )
// }
import * as React from 'react';
type Props = {
children: React.Node,
className: string,
isDisabled: boolean,
isFocused: boolean,
isSelected: boolean,
onFocus: Function,
onSelect: Function,
option: any,
}
class FeeSelectOption extends Component {
constructor(props) {
export default class CoinSelectOption extends React.Component<Props> {
constructor(props: Props) {
super(props);
}
handleMouseDown(event) {
handleMouseDown(event: MouseEvent) {
event.preventDefault();
event.stopPropagation();
this.props.onSelect(this.props.option, event);
}
handleMouseEnter(event) {
handleMouseEnter(event: MouseEvent) {
this.props.onFocus(this.props.option, event);
}
handleMouseMove(event) {
handleMouseMove(event: MouseEvent) {
if (this.props.isFocused) return;
this.props.onFocus(this.props.option, event);
}
@ -44,17 +46,4 @@ class FeeSelectOption extends Component {
</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;
}

@ -1,7 +1,7 @@
/* @flow */
'use strict';
import React, { Component } from 'react';
import * as React from 'react';
import PropTypes from 'prop-types';
@ -16,22 +16,33 @@ export const FeeSelectValue = (props: any): any => {
);
}
export class FeeSelectOption extends Component {
constructor(props) {
type 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);
}
handleMouseDown(event) {
handleMouseDown(event: MouseEvent) {
event.preventDefault();
event.stopPropagation();
this.props.onSelect(this.props.option, event);
}
handleMouseEnter(event) {
handleMouseEnter(event: MouseEvent) {
this.props.onFocus(this.props.option, event);
}
handleMouseMove(event) {
handleMouseMove(event: MouseEvent) {
if (this.props.isFocused) return;
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 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);
if (pending.length < 1) return null;

@ -9,14 +9,25 @@ import { FeeSelectValue, FeeSelectOption } from './FeeSelect';
import { Notification } from '../../common/Notification';
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() {
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 { network } = props.abstractAccount;
@ -170,7 +181,10 @@ const _render = (props: any, device, discovery, account, deviceStatusNotificatio
<button disabled={ buttonDisabled } onClick={ event => onSend() }>{ buttonLabel }</button>
</AdvancedForm>
<PendingTransactions {...props} selectedCoin={selectedCoin} />
<PendingTransactions
{ ...props }
account={ account }
selectedCoin={ selectedCoin } />
</section>
);

@ -5,14 +5,35 @@ import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as SendFormActions from '../../../actions/SendFormActions';
import * as AbstractAccountActions from '../../../actions/AbstractAccountActions';
import { default as SendFormActions } from '../../../actions/SendFormActions';
import { default as AbstractAccountActions } from '../../../actions/AbstractAccountActions';
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 {
abstractAccount: state.abstractAccount,
location: state.router.location,
devices: state.connect.devices,
accounts: state.accounts,
discovery: state.discovery,
@ -24,9 +45,9 @@ const mapStateToProps = (state, own) => {
};
}
const mapDispatchToProps = (dispatch) => {
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
return {
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
sendFormActions: bindActionCreators(SendFormActions, dispatch),
initAccount: bindActionCreators(SendFormActions.init, dispatch),
updateAccount: bindActionCreators(SendFormActions.update, dispatch),

@ -11,14 +11,29 @@ import SummaryDetails from './SummaryDetails.js';
import SummaryTokens from './SummaryTokens.js';
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() {
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 tokens = props.tokens.filter(t => t.ethAddress === account.address);
@ -36,7 +51,7 @@ const _render = (props: any, device, discovery, account, deviceStatusNotificatio
network={ abstractAccount.network }
fiat={ props.fiat }
localStorage={ props.localStorage }
onToggle={ props.summaryActions.onDetailsToggle } />
onToggle={ props.onDetailsToggle } />
<h2>Tokens</h2>
{/* 0x58cda554935e4a1f2acbe15f8757400af275e084 */}
@ -46,27 +61,28 @@ const _render = (props: any, device, discovery, account, deviceStatusNotificatio
multi={ false }
autoload={ false }
ignoreCase={ true }
backspaceRemoves={ true }
value={ null }
onChange={ token => props.addToken(token, account) }
loadOptions={ input => props.loadTokens(input, account.network) }
filterOptions= {
(options, search, values) => {
(options: Array<NetworkToken>, search: string, values) => {
return options.filter(o => {
return !tokens.find(t => t.symbol === o.symbol);
});
}
}
value={ props.summary.selectedToken }
onChange={ token => props.summaryActions.selectToken(token, account) }
valueKey="symbol"
labelKey="symbol"
placeholder="Search for token"
searchPromptText="Type token name or address"
noResultsText="Token not found"
loadOptions={ input => props.summaryActions.loadTokens(input, account) }
backspaceRemoves={true} />
/>
</div>
<SummaryTokens tokens={ tokens } removeToken={ props.summaryActions.removeToken } />
<SummaryTokens tokens={ tokens } removeToken={ props.removeToken } />
</section>

@ -4,7 +4,18 @@
import React from 'react';
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 (
<div className="summary-details">

@ -5,29 +5,36 @@ import React from 'react';
import ColorHash from 'color-hash';
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;
const bgColor = new ColorHash({lightness: 0.7});
const textColor = new ColorHash();
const tokens = props.tokens.map((t, i) => {
const tokens = props.tokens.map((token, index) => {
let iconColor = {
color: textColor.hex(t.name),
background: bgColor.hex(t.name),
borderColor: bgColor.hex(t.name)
color: textColor.hex(token.name),
background: bgColor.hex(token.name),
borderColor: bgColor.hex(token.name)
}
return (
<div key={i} className="token">
<div key={ index } className="token">
<div className="icon" style={ iconColor }>
<div className="icon-inner">
<ScaleText widthOnly><p>{ t.symbol }</p></ScaleText>
<ScaleText widthOnly><p>{ token.symbol }</p></ScaleText>
</div>
</div>
<div className="name">{ t.name }</div>
<div className="balance">{ t.balance } { t.symbol }</div>
<button className="transparent" onClick={ event => props.removeToken(t) }></button>
<div className="name">{ token.name }</div>
<div className="balance">{ token.balance } { token.symbol }</div>
<button className="transparent" onClick={ event => props.removeToken(token) }></button>
</div>
)
});
@ -37,7 +44,6 @@ const SummaryTokens = (props: any): any => {
{ tokens }
</div>
)
}
export default SummaryTokens;

@ -6,32 +6,62 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
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 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 {
abstractAccount: state.abstractAccount,
location: state.router.location,
devices: state.connect.devices,
accounts: state.accounts,
discovery: state.discovery,
tokens: state.tokens,
summary: state.summary,
fiat: state.fiat,
localStorage: state.localStorage
localStorage: state.localStorage,
};
}
const mapDispatchToProps = (dispatch) => {
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => {
return {
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
summaryActions: bindActionCreators(SummaryActions, dispatch),
abstractAccountActions: bindActionCreators(AbstractAccountActions, dispatch),
initAccount: bindActionCreators(SummaryActions.init, dispatch),
updateAccount: bindActionCreators(SummaryActions.update, 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 */
'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 ThunkAction = (dispatch: Dispatch, getState: GetState) => any;
export type PromiseAction = Promise<Action>;
export type AsyncAction = ReduxThunkAction<State, Action>;

@ -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>;
}

@ -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;
}

@ -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
}> {}
}

@ -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;
}

@ -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;
}

@ -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;
};
}

@ -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';
Raven.config('https://497392c3ff6e46dc9e54eef123979378@sentry.io/294339').install();
render(
router,
document.getElementById('root')
);
const root: ?HTMLElement = document.getElementById('root');
if (root) {
render(router, root);
}
window.onbeforeunload = () => {
store.dispatch( onBeforeUnload() );

@ -4,26 +4,43 @@
import * as ACCOUNT from '../actions/constants/account';
import * as CONNECT from '../actions/constants/TrezorConnect';
import type { Action } from '../flowtype';
import type { Coin } from './LocalStorageReducer';
export type State = {
+index: number;
+deviceState: ?string;
+deviceId: ?string;
+deviceInstance: ?string;
+deviceState: string;
+deviceId: string;
+deviceInstance: ?number;
+network: string;
+coin: Coin;
location: string;
}
export const initialState: State = {
index: 0,
deviceState: null,
deviceId: null,
deviceState: '0',
deviceId: '0',
deviceInstance: null,
network: '',
coin: {
name: '',
network: '',
symbol: '',
bip44: '',
defaultGasLimit: 0,
defaultGasLimitTokens: 0,
defaultGasPrice: 0,
explorer: '',
tokens: '',
backends: []
},
location: '',
};
export default (state: State = initialState, action: any): State => {
export default (state: State = initialState, action: Action): State => {
switch (action.type) {
@ -33,7 +50,6 @@ export default (state: State = initialState, action: any): State => {
case ACCOUNT.DISPOSE :
return initialState;
default:
return state;
}

@ -27,7 +27,6 @@ const createAccount = (state: Array<Account>, action: any): Array<Account> => {
// TODO check with device_id
// 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);
console.warn("MAM?", exist, action)
if (exist) {
return state;
}

@ -7,8 +7,10 @@ import * as CONNECT from '../actions/constants/TrezorConnect';
export type Discovery = {
network: string;
deviceState: string;
xpub: string;
hdKey: any;
basePath: any;
deviceState: string;
accountIndex: number;
interrupted: boolean;
completed: boolean;
@ -81,6 +83,8 @@ const waiting = (state: Array<Discovery>, action: any): Array<Discovery> => {
network: action.network,
deviceState: action.device.state,
xpub: '',
hdKey: null,
basePath: null,
accountIndex: 0,
interrupted: false,
completed: false,
@ -98,7 +102,7 @@ const waiting = (state: Array<Discovery>, action: any): Array<Discovery> => {
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) {
case DISCOVERY.START :

@ -1,6 +1,11 @@
/* @flow */
'use strict';
import { RATE_UPDATE } from '../services/CoinmarketcapService';
import type { Action } from '../flowtype';
import type { FiatRateAction } from '../services/CoinmarketcapService';
export type Fiat = {
+network: string;
value: string;
@ -8,7 +13,7 @@ export type 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 exists: ?Fiat = newState.find(f => f.network === action.network);
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) {
case 'rate__update' :
case RATE_UPDATE :
return update(state, action);
default:

@ -3,23 +3,77 @@
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;
error: any;
config: any;
ERC20Abi: any;
tokens: any;
error: ?string;
config: Config;
ERC20Abi: Array<Object>;
tokens: TokensCollection;
}
const initialState: State = {
initialized: false,
error: null,
config: null,
ERC20Abi: null,
tokens: null,
config: {
coins: [],
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) {
@ -44,4 +98,4 @@ export default function localStorage(state: State = initialState, action: any):
return state;
}
}
}

@ -1,6 +1,9 @@
/* @flow */
'use strict';
import * as LOG from '../actions/constants/log';
import type { Action } from '../flowtype';
type LogEntry = {
time: number;
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) {
case 'log__open':
case LOG.OPEN:
return {
...state,
opened: true
}
case 'log__close':
case LOG.CLOSE:
return {
...state,
opened: false
}
case 'log__add':
return {
...state,
}
// case 'log__add':
// return {
// ...state,
// }
default:
return state;

@ -6,21 +6,21 @@ import * as RECEIVE from '../actions/constants/receive';
import * as MODAL from '../actions/constants/modal';
import * as CONNECT from '../actions/constants/TrezorConnect';
type ModalState = {
export type State = {
opened: boolean;
device: any;
instances: Array<any>;
instances: ?Array<any>;
windowType: ?string;
}
const initialState: ModalState = {
const initialState: State = {
opened: false,
device: null,
instances: 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) {

@ -7,7 +7,7 @@ import { DEVICE } from 'trezor-connect';
type NotificationAction = {
label: string;
callback: any;
callback: Function;
}
type NotificationEntry = {

@ -34,7 +34,7 @@ const fromStorage = (state: Array<PendingTx>, action: any) => {
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) {

@ -5,7 +5,7 @@ import * as RECEIVE from '../actions/constants/receive';
export type State = {
addressVerified: boolean;
adressUnverified: boolean;
addressUnverified: boolean;
}
export const initialState: State = {

@ -1,7 +1,6 @@
/* @flow */
'use strict';
import { LOCATION_CHANGE } from 'react-router-redux';
import * as SEND from '../actions/constants/send';
import * as WEB3 from '../actions/constants/web3';
import * as ADDRESS from '../actions/constants/address';
@ -9,7 +8,14 @@ import EthereumjsUnits from 'ethereumjs-units';
import BigNumber from 'bignumber.js';
import { getFeeLevels } from '../actions/SendFormActions';
import type {
Web3CreateAction,
Web3UpdateBlockAction,
Web3UpdateGasPriceAction
} from '../actions/Web3Actions';
export type State = {
+network: string;
+coinSymbol: string;
token: string;
balanceNeedUpdate: boolean;
@ -22,7 +28,7 @@ export type State = {
amount: string;
setMax: boolean;
feeLevels: Array<FeeLevel>;
selectedFeeLevel: ?FeeLevel;
selectedFeeLevel: FeeLevel;
recommendedGasPrice: string;
gasPriceNeedsUpdate: boolean;
gasLimit: string;
@ -44,6 +50,7 @@ export type FeeLevel = {
export const initialState: State = {
network: '',
coinSymbol: '',
token: '',
@ -56,7 +63,11 @@ export const initialState: State = {
amount: '',
setMax: false,
feeLevels: [],
selectedFeeLevel: null,
selectedFeeLevel: {
label: 'Normal',
gasPrice: '0',
value: 'Normal'
},
recommendedGasPrice: '0',
gasPriceNeedsUpdate: false,
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) {
// return Math.floor(Math.random() * (max - min + 1)) + min;
// }
// 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) {
const newState: State = { ...state };
if (!state.untouched) {
@ -85,7 +96,8 @@ const onGasPriceUpdated = (state: State, action: any): State => {
newState.recommendedGasPrice = newPrice;
} else {
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.feeLevels = newFeeLevels;
newState.selectedFeeLevel = selectedFeeLevel;

@ -2,10 +2,12 @@
'use strict';
import * as SUMMARY from '../actions/constants/summary';
import type { Action } from '../flowtype';
import type { NetworkToken } from './LocalStorageReducer';
export type State = {
details: boolean;
selectedToken: any;
selectedToken: ?NetworkToken;
}
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) {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save