update actions and reducers

pull/25/head
Szymon Lesisz 6 years ago
parent e4552b0998
commit 1379a2e745

@ -34,12 +34,8 @@ import type { Token } from 'reducers/TokensReducer';
import type { NetworkToken } from 'reducers/LocalStorageReducer';
export type BlockchainAction = {
type: typeof BLOCKCHAIN.START | typeof BLOCKCHAIN.CONNECTING,
network: string,
} | {
type: typeof BLOCKCHAIN.STOP,
network: string,
};
type: typeof BLOCKCHAIN.READY,
}
export const discoverAccount = (device: TrezorDevice, xpub: string, network: string): PromiseAction<AccountDiscovery> => async (dispatch: Dispatch, getState: GetState): Promise<AccountDiscovery> => {
// get data from connect
@ -93,36 +89,22 @@ export const estimateGasLimit = (network: string, data: string, value: string, g
export const onBlockMined = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
// try to resolve pending transactions
// await dispatch( Web3Actions.resolvePendingTransactions(network) );
// get network accounts
// const accounts: Array<any> = getState().accounts.filter(a => a.network === network).map(a => {
// return {
// address: a.address,
// block: a.block,
// transactions: a.transactions
// }
// });
await dispatch( Web3Actions.resolvePendingTransactions(network) );
const accounts: Array<any> = getState().accounts.filter(a => a.network === network);
// find out which account changed
const response = await TrezorConnect.ethereumGetAccountInfo({
accounts,
coin: network,
});
if (!response.success) {
} else {
if (response.success) {
response.payload.forEach((a, i) => {
if (a.transactions > 0) {
// dispatch( Web3Actions.updateAccount(accounts[i], a, network) )
dispatch( Web3Actions.updateAccount(accounts[i], a, network) )
}
});
}
//return await dispatch( Web3Actions.estimateGasLimit(network, { to: '', data, value, gasPrice }) );
console.warn("onBlockMined", response)
}
export const onNotification = (payload: any): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
@ -177,4 +159,38 @@ export const subscribe = (network: string): PromiseAction<void> => async (dispat
accounts: [],
coin: network
});
}
// Conditionally subscribe to blockchain backend
// called after TrezorConnect.init successfully emits TRANSPORT.START event
// checks if there are discovery processes loaded from LocalStorage
// if so starts subscription to proper networks
export const init = (): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
if (getState().discovery.length > 0) {
// get unique networks
const networks: Array<string> = [];
getState().discovery.forEach(discovery => {
if (networks.indexOf(discovery.network) < 0) {
networks.push(discovery.network);
}
});
// subscribe
for (let i = 0; i < networks.length; i++) {
await dispatch( subscribe(networks[i]) );
}
} else {
await dispatch( subscribe('ropsten') );
}
// continue wallet initialization
dispatch({
type: BLOCKCHAIN.READY
});
}
// Handle BLOCKCHAIN.ERROR event from TrezorConnect
// disconnect and remove Web3 webscocket instance if exists
export const error = (payload: any): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
dispatch( Web3Actions.disconnect(payload.coin) );
}

@ -6,7 +6,7 @@ import * as DISCOVERY from 'actions/constants/discovery';
import * as ACCOUNT from 'actions/constants/account';
import * as NOTIFICATION from 'actions/constants/notification';
import type {
ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice,
ThunkAction, AsyncAction, PromiseAction, Action, GetState, Dispatch, TrezorDevice,
} from 'flowtype';
import type { Discovery, State } from 'reducers/DiscoveryReducer';
import * as AccountsActions from './AccountsActions';
@ -26,7 +26,7 @@ export type DiscoveryStartAction = {
}
export type DiscoveryWaitingAction = {
type: typeof DISCOVERY.WAITING_FOR_DEVICE | typeof DISCOVERY.WAITING_FOR_BACKEND,
type: typeof DISCOVERY.WAITING_FOR_DEVICE | typeof DISCOVERY.WAITING_FOR_BLOCKCHAIN,
device: TrezorDevice,
network: string
}
@ -80,8 +80,12 @@ export const start = (device: TrezorDevice, network: string, ignoreCompleted?: b
}
const blockchain = getState().blockchain.find(b => b.name === network);
if (blockchain && !blockchain.connected) {
console.error("NO BACKEND!") // TODO
if (blockchain && !blockchain.connected && (!discoveryProcess || !discoveryProcess.completed)) {
dispatch({
type: DISCOVERY.WAITING_FOR_BLOCKCHAIN,
device,
network,
});
return;
}
@ -93,7 +97,7 @@ export const start = (device: TrezorDevice, network: string, ignoreCompleted?: b
device,
network,
});
} else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice) {
} else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice || discoveryProcess.waitingForBlockchain) {
// discovery cycle was interrupted
// start from beginning
dispatch(begin(device, network));
@ -268,12 +272,19 @@ const finish = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction
}
export const reconnect = (network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
await dispatch(BlockchainActions.subscribe(network));
dispatch(restore());
}
export const restore = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
const selected = getState().wallet.selectedDevice;
if (selected && selected.connected && selected.features) {
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && d.waitingForDevice);
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === selected.state && (d.interrupted || d.waitingForDevice || d.waitingForBlockchain));
console.warn("AAAA2")
if (discoveryProcess) {
console.warn("AAAA3", discoveryProcess)
dispatch(start(selected, discoveryProcess.network));
}
}

@ -9,7 +9,6 @@ import { getDuplicateInstanceNumber } from 'reducers/utils';
import { push } from 'react-router-redux';
import type {
DeviceMessage,
DeviceMessageType,
@ -129,8 +128,6 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
// $FlowIssue LOCAL not declared
window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/';
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/';
//window.__TREZOR_CONNECT_SRC = 'https://sisyfos.trezor.io/connect/';
// window.__TREZOR_CONNECT_SRC = 'https://localhost:8088/';
try {
await TrezorConnect.init({

@ -16,6 +16,7 @@ import * as PENDING from 'actions/constants/pendingTx';
import type {
Dispatch,
GetState,
ThunkAction,
AsyncAction,
PromiseAction,
AccountDiscovery,
@ -23,6 +24,7 @@ import type {
EthereumPreparedTx
} from 'flowtype';
import type { EthereumAccount } from 'trezor-connect';
import type { Account } from 'reducers/AccountsReducer';
import type { PendingTx } from 'reducers/PendingTxReducer';
import type { Web3Instance } from 'reducers/Web3Reducer';
@ -48,7 +50,7 @@ export type Web3Action = {
} | {
type: typeof WEB3.START,
} | {
type: typeof WEB3.CREATE,
type: typeof WEB3.CREATE | typeof WEB3.DISCONNECT,
instance: Web3Instance
} | Web3UpdateBlockAction
| Web3UpdateGasPriceAction;
@ -108,13 +110,8 @@ export const initWeb3 = (network: string, urlIndex: number = 0): PromiseAction<W
}
const onEnd = async () => {
web3.currentProvider.removeAllListeners('connect');
web3.currentProvider.removeAllListeners('end');
web3.currentProvider.removeAllListeners('error');
web3.currentProvider.reset();
// if (web3.eth)
// web3.eth.clearSubscriptions();
web3.currentProvider.reset();
const instance = getState().web3.find(w3 => w3.network === network);
if (instance && instance.web3.currentProvider.connected) {
@ -263,14 +260,25 @@ export const getTxInput = (): PromiseAction<void> => async (dispatch: Dispatch,
}
export const updateAccount = (account: Account, newAccount: AccountDiscovery, network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
export const updateAccount = (account: Account, newAccount: EthereumAccount, network: string): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const instance: Web3Instance = await dispatch( initWeb3(network) );
const balance = await instance.web3.eth.getBalance(account.address);
const nonce = await instance.web3.eth.getTransactionCount(account.address);
dispatch( AccountsActions.update( { ...account, ...newAccount, balance: EthereumjsUnits.convert(balance, 'wei', 'ether'), nonce }) );
// TODO update tokens for this account
// update tokens for this account
const tokens = getState().tokens.filter(t => t.network === account.network && t.ethAddress === account.address);
for (const token of tokens) {
const balance = await dispatch( getTokenBalance(token) );
// const newBalance: string = balance.dividedBy(Math.pow(10, token.decimals)).toString(10);
if (balance !== token.balance) {
dispatch(TokenActions.setBalance(
token.address,
token.ethAddress,
balance,
));
}
}
}
export const getTokenInfo = (address: string, network: string): PromiseAction<NetworkToken> => async (dispatch: Dispatch, getState: GetState): Promise<NetworkToken> => {
@ -337,48 +345,18 @@ export const estimateGasLimit = (network: string, options: EstimateGasOptions):
return limit;
};
// export const prepareTx = (tx: EthereumTxRequest): PromiseAction<EthereumPreparedTx> => async (dispatch: Dispatch, getState: GetState): Promise<EthereumPreparedTx> => {
// const instance = await dispatch( initWeb3(tx.network) );
// const token = tx.token;
// let data: string = `0x${tx.data}`; // TODO: check if already prefixed
// let value: string = instance.web3.utils.toHex( EthereumjsUnits.convert(tx.amount, 'ether', 'wei') );
// let to: string = tx.to;
// if (token) {
// // smart contract transaction
// const contract = instance.erc20.clone();
// contract.options.address = token.address;
// const tokenAmount: string = new BigNumber(tx.amount).times(Math.pow(10, token.decimals)).toString(10);
// data = instance.erc20.methods.transfer(to, tokenAmount).encodeABI();
// value = '0x00';
// to = token.address;
// }
// return {
// to,
// value,
// data,
// chainId: instance.chainId,
// nonce: instance.web3.utils.toHex(tx.nonce),
// gasLimit: instance.web3.utils.toHex(tx.gasLimit),
// gasPrice: instance.web3.utils.toHex( EthereumjsUnits.convert(tx.gasPrice, 'gwei', 'wei') ),
// r: '',
// s: '',
// v: '',
// }
// };
// export const pushTx = (network: string, tx: EthereumPreparedTx): PromiseAction<string> => async (dispatch: Dispatch, getState: GetState): Promise<string> => {
// const instance = await dispatch( initWeb3(network) );
// const ethTx = new EthereumjsTx(tx);
// const serializedTx = `0x${ethTx.serialize().toString('hex')}`;
// return new Promise((resolve, reject) => {
// instance.web3.eth.sendSignedTransaction(serializedTx)
// .on('error', error => reject(error))
// .once('transactionHash', (hash: string) => {
// resolve(hash);
// });
// });
// };
export const disconnect = (network: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
// check if Web3 was already initialized
const instance = getState().web3.find(w3 => w3.network === network);
if (instance) {
// reset current connection
instance.web3.currentProvider.reset();
instance.web3.currentProvider.connection.close();
// remove instance from reducer
dispatch({
type: WEB3.DISCONNECT,
instance
});
}
};

@ -29,7 +29,7 @@ export type Discovery = {
interrupted: boolean;
completed: boolean;
waitingForDevice: boolean;
waitingForBackend: boolean;
waitingForBlockchain: boolean;
}
export type State = Array<Discovery>;
@ -53,7 +53,7 @@ const start = (state: State, action: DiscoveryStartAction): State => {
interrupted: false,
completed: false,
waitingForDevice: false,
waitingForBackend: false,
waitingForBlockchain: false,
};
const newState: State = [...state];
@ -96,6 +96,7 @@ const stop = (state: State, action: DiscoveryStopAction): State => {
if (d.deviceState === action.device.state && !d.completed) {
d.interrupted = true;
d.waitingForDevice = false;
d.waitingForBlockchain = false;
}
return d;
});
@ -114,7 +115,7 @@ const waitingForDevice = (state: State, action: DiscoveryWaitingAction): State =
interrupted: false,
completed: false,
waitingForDevice: true,
waitingForBackend: false,
waitingForBlockchain: false,
};
const index: number = findIndex(state, action.network, deviceState);
@ -128,7 +129,7 @@ const waitingForDevice = (state: State, action: DiscoveryWaitingAction): State =
return newState;
};
const waitingForBackend = (state: State, action: DiscoveryWaitingAction): State => {
const waitingForBlockchain = (state: State, action: DiscoveryWaitingAction): State => {
const deviceState: string = action.device.state || '0';
const instance: Discovery = {
network: action.network,
@ -141,7 +142,7 @@ const waitingForBackend = (state: State, action: DiscoveryWaitingAction): State
interrupted: false,
completed: false,
waitingForDevice: false,
waitingForBackend: true,
waitingForBlockchain: true,
};
const index: number = findIndex(state, action.network, deviceState);
@ -167,8 +168,8 @@ export default function discovery(state: State = initialState, action: Action):
return complete(state, action);
case DISCOVERY.WAITING_FOR_DEVICE:
return waitingForDevice(state, action);
case DISCOVERY.WAITING_FOR_BACKEND:
return waitingForBackend(state, action);
case DISCOVERY.WAITING_FOR_BLOCKCHAIN:
return waitingForBlockchain(state, action);
case DISCOVERY.FROM_STORAGE:
return action.payload.map((d) => {
const hdKey: HDKey = new HDKey();
@ -179,7 +180,7 @@ export default function discovery(state: State = initialState, action: Action):
hdKey,
interrupted: false,
waitingForDevice: false,
waitingForBackend: false,
waitingForBlockchain: false,
};
});
case CONNECT.FORGET:

@ -22,23 +22,24 @@ export type State = Array<PendingTx>;
const initialState: State = [];
// const add01 = (state: State, action: SendTxAction): State => {
// const newState = [...state];
// newState.push({
// id: action.txid,
// network: action.account.network,
// currency: action.selectedCurrency,
// amount: action.amount,
// total: action.total,
// tx: action.tx,
// nonce: action.nonce,
// address: action.account.address,
// rejected: false,
// });
// return newState;
// };
const add = (state: State, action: SendTxAction): State => {
const newState = [...state];
newState.push({
type: 'send',
id: action.txid,
network: action.account.network,
currency: action.selectedCurrency,
amount: action.amount,
total: action.total,
tx: action.tx,
nonce: action.nonce,
address: action.account.address,
rejected: false,
});
return newState;
};
const add = (state: State, payload: any): State => {
const add_NEW = (state: State, payload: any): State => {
const newState = [...state];
newState.push(payload);
return newState;
@ -55,11 +56,11 @@ const reject = (state: State, id: string): State => state.map((tx) => {
export default function pending(state: State = initialState, action: Action): State {
switch (action.type) {
// case SEND.TX_COMPLETE:
// return add(state, action);
case SEND.TX_COMPLETE:
return add(state, action);
case PENDING.ADD:
return add(state, action.payload);
// case PENDING.ADD:
// return add(state, action.payload);
case PENDING.TX_RESOLVED:
return remove(state, action.tx.id);
case PENDING.TX_NOT_FOUND:

@ -51,6 +51,13 @@ const updateGasPrice = (state: State, action: Web3UpdateGasPriceAction): State =
return newState;
};
const disconnect = (state: State, instance: Web3Instance): State => {
const index: number = state.indexOf(instance);
const newState: Array<Web3Instance> = [...state];
newState.splice(index, 1);
return newState;
};
export default function web3(state: State = initialState, action: Action): State {
switch (action.type) {
case WEB3.CREATE:
@ -59,6 +66,8 @@ export default function web3(state: State = initialState, action: Action): State
return updateLatestBlock(state, action);
case WEB3.GAS_PRICE_UPDATED:
return updateGasPrice(state, action);
case WEB3.DISCONNECT:
return disconnect(state, action.instance);
default:
return state;
}

@ -10,6 +10,7 @@ import * as BlockchainActions from 'actions/BlockchainActions';
import * as ModalActions from 'actions/ModalActions';
import * as STORAGE from 'actions/constants/localStorage';
import * as CONNECT from 'actions/constants/TrezorConnect';
import { READY as BLOCKCHAIN_READY } from 'actions/constants/blockchain';
import type {
Middleware,
@ -32,10 +33,9 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa
// TODO: check if modal is open
// api.dispatch( push('/') );
} else if (action.type === TRANSPORT.START) {
api.dispatch(BlockchainActions.init());
} else if (action.type === BLOCKCHAIN_READY) {
api.dispatch(TrezorConnectActions.postInit());
api.dispatch( BlockchainActions.subscribe('ropsten') );
} else if (action.type === DEVICE.DISCONNECT) {
api.dispatch(TrezorConnectActions.deviceDisconnect(action.device));
} else if (action.type === CONNECT.REMEMBER_REQUEST) {
@ -64,9 +64,11 @@ const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: Middlewa
} else if (action.type === CONNECT.COIN_CHANGED) {
api.dispatch(TrezorConnectActions.coinChanged(action.payload.network));
} else if (action.type === BLOCKCHAIN.BLOCK) {
// api.dispatch(BlockchainActions.onBlockMined(action.payload.coin));
api.dispatch(BlockchainActions.onBlockMined(action.payload.coin));
} else if (action.type === BLOCKCHAIN.NOTIFICATION) {
// api.dispatch(BlockchainActions.onNotification(action.payload));
} else if (action.type === BLOCKCHAIN.ERROR) {
api.dispatch( BlockchainActions.error(action.payload) );
}
return action;

Loading…
Cancel
Save