Usage docs Reference Examples

src/tracking/transactions/openTxChannel.js

import { END, eventChannel } from 'redux-saga';
import * as transactionsAT from './AT';

/**
 * Open a TX channel: this channel maps web3 events to our redux tracking system.
 *
 * @param promiEvent The event emitter to read transaction status updates from.
 * @param txID The ID of the transaction, used in the tracking system.
 * @returns {Channel<any>} The redux saga channel.
 */
const openTxChannel = (promiEvent, txID) => eventChannel((emit) => {
  // Web3 returns a "promise combined with an event emitter": we map this to redux events.
  promiEvent
    .on('transactionHash', (hash) => {
      emit({type: transactionsAT.TX_BROADCAST, txID, txHash: hash});
    })
    .on('receipt', (receipt) => {
      // TODO: first receipt is probably double, as it's also the initial confirmation.
      // This can be ignored for now, but maybe we can remove this listener altogether.
      emit({type: transactionsAT.TX_RECEIPT, txID, receipt});
    })
    .on('confirmation', (confirmationNumber, receipt) => {
      // re-fire the TX_RECEIPT
      emit({type: transactionsAT.TX_RECEIPT, txID, receipt});
      // We can safely close the channel once we received enough confirmations
      if (confirmationNumber >= 12) {
        emit(END);
      }
    })
    .on('error', (error, receipt) => {
      emit({type: transactionsAT.TX_FAILED, txID, receipt});
      // TODO This is tricky, an out-of-gas transaction technically did not fail until it's final,
      // as it could still be orphaned, and mined with a context
      // that does not make it run out of gas.
      emit(END);
    });
  // Return unsubscribe function (wrap for future compatibility)
  return () => promiEvent.off();
});

export default openTxChannel;