1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-28 03:08:30 +00:00

handle pending tx from blockchain notification

This commit is contained in:
Szymon Lesisz 2018-11-30 18:55:57 +01:00
parent a32f0faf38
commit ab4ab8b5a4
5 changed files with 100 additions and 64 deletions

View File

@ -3,6 +3,7 @@
import TrezorConnect from 'trezor-connect'; import TrezorConnect from 'trezor-connect';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import * as BLOCKCHAIN from 'actions/constants/blockchain'; import * as BLOCKCHAIN from 'actions/constants/blockchain';
import * as PENDING from 'actions/constants/pendingTx';
import type { import type {
TrezorDevice, TrezorDevice,
@ -99,7 +100,6 @@ export const onBlockMined = (payload: $ElementType<BlockchainBlock, 'payload'>):
const fee = await TrezorConnect.blockchainGetFee({ const fee = await TrezorConnect.blockchainGetFee({
coin: network, coin: network,
}); });
if (!fee.success) return; if (!fee.success) return;
dispatch({ dispatch({
@ -141,10 +141,52 @@ export const onBlockMined = (payload: $ElementType<BlockchainBlock, 'payload'>):
} }
}; };
export const onNotification = (payload: $ElementType<BlockchainNotification, 'payload'>): PromiseAction<void> => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const { notification } = payload;
const account = getState().accounts.find(a => a.address === notification.address);
if (!account) return;
// not used for now, waiting for fix in blockbook if (notification.status === 'pending') {
export const onNotification = (payload: $ElementType<BlockchainNotification, 'payload'>): PromiseAction<void> => async (/*dispatch: Dispatch, getState: GetState*/): Promise<void> => { dispatch({
console.warn('OnBL', payload); type: PENDING.ADD,
payload: {
type: notification.type,
hash: notification.hash,
network: account.network,
address: account.address,
currency: account.network,
amount: notification.amount,
total: notification.amount,
fee: notification.fee,
},
});
// todo: replace "send success" notification with link to explorer
} else if (notification.status === 'confirmed') {
dispatch({
type: PENDING.TX_RESOLVED,
hash: notification.hash,
});
}
const updatedAccount = await TrezorConnect.rippleGetAccountInfo({
account: {
address: account.address,
block: account.block,
history: false,
},
});
if (!updatedAccount.success) return;
dispatch(AccountsActions.update({
...account,
balance: updatedAccount.payload.balance,
block: updatedAccount.payload.block,
sequence: updatedAccount.payload.sequence,
}));
// todo: get transaction history here
// console.warn("OnBlAccount", account);
// this event can be triggered multiple times // this event can be triggered multiple times
// // 1. check if pair [txid + address] is already in reducer // // 1. check if pair [txid + address] is already in reducer
// const network: string = payload.coin.shortcut.toLowerCase(); // const network: string = payload.coin.shortcut.toLowerCase();

View File

@ -13,12 +13,11 @@ export type PendingTxAction = {
payload: PendingTx payload: PendingTx
} | { } | {
type: typeof PENDING.TX_RESOLVED, type: typeof PENDING.TX_RESOLVED,
tx: PendingTx, hash: string,
receipt?: Object,
} | { } | {
type: typeof PENDING.TX_REJECTED, type: typeof PENDING.TX_REJECTED,
tx: PendingTx, hash: string,
} | { } | {
type: typeof PENDING.TX_TOKEN_ERROR, type: typeof PENDING.TX_TOKEN_ERROR,
tx: PendingTx, hash: string,
} }

View File

@ -137,25 +137,24 @@ export const resolvePendingTransactions = (network: string): PromiseAction<void>
const instance: Web3Instance = await dispatch(initWeb3(network)); const instance: Web3Instance = await dispatch(initWeb3(network));
const pending = getState().pending.filter(p => p.network === network); const pending = getState().pending.filter(p => p.network === network);
pending.forEach(async (tx) => { pending.forEach(async (tx) => {
const status = await instance.web3.eth.getTransaction(tx.id); const status = await instance.web3.eth.getTransaction(tx.hash);
if (!status) { if (!status) {
dispatch({ dispatch({
type: PENDING.TX_REJECTED, type: PENDING.TX_REJECTED,
tx, hash: tx.hash,
}); });
} else { } else {
const receipt = await instance.web3.eth.getTransactionReceipt(tx.id); const receipt = await instance.web3.eth.getTransactionReceipt(tx.hash);
if (receipt) { if (receipt) {
if (status.gas !== receipt.gasUsed) { if (status.gas !== receipt.gasUsed) {
dispatch({ dispatch({
type: PENDING.TX_TOKEN_ERROR, type: PENDING.TX_TOKEN_ERROR,
tx, hash: tx.hash,
}); });
} }
dispatch({ dispatch({
type: PENDING.TX_RESOLVED, type: PENDING.TX_RESOLVED,
tx, hash: tx.hash,
receipt,
}); });
} }
} }

View File

@ -4,59 +4,55 @@ import * as PENDING from 'actions/constants/pendingTx';
import * as SEND from 'actions/constants/send'; import * as SEND from 'actions/constants/send';
import type { TrezorDevice, Action } from 'flowtype'; import type { TrezorDevice, Action } from 'flowtype';
import type { SendTxAction } from 'actions/SendFormActions';
export type PendingTx = { export type PendingTx = {
+type: 'send' | 'receive'; +type: 'send' | 'recv',
+id: string; +hash: string,
+network: string; +network: string,
+address: string; +address: string,
+deviceState: string; +currency: string,
+currency: string; +amount: string,
+amount: string; +total: string,
+total: string; +fee: string,
+tx: any; rejected?: boolean,
+nonce: number; };
rejected: boolean;
}
export type State = Array<PendingTx>; export type State = Array<PendingTx>;
const initialState: State = []; const initialState: State = [];
const add = (state: State, action: SendTxAction): State => { // const add = (state: State, action: SendTxAction): State => {
const newState = [...state]; // const newState = [...state];
newState.push({ // newState.push({
type: 'send', // type: 'send',
id: action.txid, // id: action.txid,
network: action.account.network, // network: action.account.network,
address: action.account.address, // address: action.account.address,
deviceState: action.account.deviceState, // deviceState: action.account.deviceState,
currency: action.selectedCurrency, // currency: action.selectedCurrency,
amount: action.amount, // amount: action.amount,
total: action.total, // total: action.total,
tx: action.tx, // tx: action.tx,
nonce: action.nonce, // nonce: action.nonce,
rejected: false, // rejected: false,
}); // });
return newState; // return newState;
}; // };
/*
const addFromBloockbokNotifiaction = (state: State, payload: any): State => { const addFromNotification = (state: State, payload: PendingTx): State => {
const newState = [...state]; const newState = [...state];
newState.push(payload); newState.push(payload);
return newState; return newState;
}; };
*/
const clear = (state: State, device: TrezorDevice): State => state.filter(tx => tx.deviceState !== device.state); //const clear = (state: State, device: TrezorDevice): State => state.filter(tx => tx.deviceState !== device.state);
const remove = (state: State, id: string): State => state.filter(tx => tx.id !== id); const remove = (state: State, hash: string): State => state.filter(tx => tx.hash !== hash);
const reject = (state: State, id: string): State => state.map((tx) => { const reject = (state: State, hash: string): State => state.map((tx) => {
if (tx.id === id && !tx.rejected) { if (tx.hash === hash && !tx.rejected) {
return { ...tx, rejected: true }; return { ...tx, rejected: true };
} }
return tx; return tx;
@ -64,21 +60,21 @@ const reject = (state: State, id: string): State => state.map((tx) => {
export default function pending(state: State = initialState, action: Action): State { export default function pending(state: State = initialState, action: Action): State {
switch (action.type) { switch (action.type) {
case SEND.TX_COMPLETE: // case SEND.TX_COMPLETE:
return add(state, action); // return add(state, action);
case CONNECT.FORGET: // case CONNECT.FORGET:
case CONNECT.FORGET_SINGLE: // case CONNECT.FORGET_SINGLE:
case CONNECT.FORGET_SILENT: // case CONNECT.FORGET_SILENT:
case CONNECT.RECEIVE_WALLET_TYPE: // case CONNECT.RECEIVE_WALLET_TYPE:
return clear(state, action.device); // return clear(state, action.device);
// case PENDING.ADD: case PENDING.ADD:
// return add(state, action.payload); return addFromNotification(state, action.payload);
case PENDING.TX_RESOLVED: case PENDING.TX_RESOLVED:
return remove(state, action.tx.id); return remove(state, action.hash);
case PENDING.TX_REJECTED: case PENDING.TX_REJECTED:
return reject(state, action.tx.id); return reject(state, action.hash);
case PENDING.FROM_STORAGE: case PENDING.FROM_STORAGE:
return action.payload; return action.payload;

View File

@ -140,7 +140,7 @@ class PendingTransactions extends PureComponent<Props> {
<H2>Pending transactions</H2> <H2>Pending transactions</H2>
{this.getPendingTransactions().map(tx => ( {this.getPendingTransactions().map(tx => (
<TransactionWrapper <TransactionWrapper
key={tx.id} key={tx.hash}
> >
<TransactionIcon <TransactionIcon
textColor={() => this.getTransactionIconColors(tx).textColor} textColor={() => this.getTransactionIconColors(tx).textColor}
@ -154,7 +154,7 @@ class PendingTransactions extends PureComponent<Props> {
<TransactionName> <TransactionName>
<StyledLink <StyledLink
href={`${this.props.network.explorer.tx}${tx.id}`} href={`${this.props.network.explorer.tx}${tx.hash}`}
isGray isGray
> >
{this.getTransactionName(tx)} {this.getTransactionName(tx)}