handle pending tx from blockchain notification

pull/260/head
Szymon Lesisz 6 years ago
parent a32f0faf38
commit ab4ab8b5a4

@ -3,6 +3,7 @@
import TrezorConnect from 'trezor-connect';
import BigNumber from 'bignumber.js';
import * as BLOCKCHAIN from 'actions/constants/blockchain';
import * as PENDING from 'actions/constants/pendingTx';
import type {
TrezorDevice,
@ -99,7 +100,6 @@ export const onBlockMined = (payload: $ElementType<BlockchainBlock, 'payload'>):
const fee = await TrezorConnect.blockchainGetFee({
coin: network,
});
if (!fee.success) return;
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;
if (notification.status === 'pending') {
dispatch({
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,
}));
// not used for now, waiting for fix in blockbook
export const onNotification = (payload: $ElementType<BlockchainNotification, 'payload'>): PromiseAction<void> => async (/*dispatch: Dispatch, getState: GetState*/): Promise<void> => {
console.warn('OnBL', payload);
// todo: get transaction history here
// console.warn("OnBlAccount", account);
// this event can be triggered multiple times
// // 1. check if pair [txid + address] is already in reducer
// const network: string = payload.coin.shortcut.toLowerCase();

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

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

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

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

Loading…
Cancel
Save