import type { ethers } from 'ethers'; export enum TxState { Default = 'Default', Requested = 'Requested', Pending = 'Pending', Complete = 'Complete', Error = 'Error', } export interface TransactionState { // claim form state txState: TxState; requiredConfirmations: number | null; txData: { hash: string | null; receipt: object | null; error: Error | null; userFacingError?: Error | null; confirmations: number | null; }; } export const initialState: TransactionState = { // claim tx txState: TxState.Default, requiredConfirmations: null, txData: { hash: null, receipt: null, error: null, userFacingError: null, confirmations: null, }, }; const substituteErrorMessage = ( errMessage: string, errorSubstitutions: { [errMessage: string]: string } ): Error => { let newErrorMessage = errorSubstitutions['unknown']; Object.keys(errorSubstitutions).forEach((errorSubstitutionKey) => { if (errMessage.includes(errorSubstitutionKey)) { newErrorMessage = errorSubstitutions[errorSubstitutionKey]; } }); return new Error(newErrorMessage); }; export enum TransactionActionType { TX_RESET, TX_REQUESTED, TX_SUBMITTED, TX_COMPLETE, TX_ERROR, TX_CONFIRMATION, } export type TransactionAction = | { type: TransactionActionType.TX_RESET; } | { type: TransactionActionType.TX_REQUESTED; } | { type: TransactionActionType.TX_SUBMITTED; txHash: string; } | { type: TransactionActionType.TX_COMPLETE; receipt: ethers.ContractReceipt; confirmations: number; } | { type: TransactionActionType.TX_ERROR; error: Error; errorSubstitutions: { [errMessage: string]: string }; } | { type: TransactionActionType.TX_CONFIRMATION; confirmations: number; }; export function transactionReducer( state: TransactionState, action: TransactionAction ): TransactionState { switch (action.type) { case TransactionActionType.TX_RESET: return { ...state, txState: TxState.Default, requiredConfirmations: state.requiredConfirmations || null, txData: { hash: null, receipt: null, error: null, confirmations: null, }, }; case TransactionActionType.TX_REQUESTED: return { ...state, txState: TxState.Requested, txData: { ...state.txData, }, }; case TransactionActionType.TX_SUBMITTED: { return { ...state, txState: TxState.Pending, txData: { ...state.txData, hash: action.txHash, }, }; } case TransactionActionType.TX_COMPLETE: return { ...state, txState: TxState.Complete, txData: { ...state.txData, receipt: action.receipt, confirmations: action.confirmations, }, }; case TransactionActionType.TX_CONFIRMATION: return { ...state, txData: { ...state.txData, confirmations: action.confirmations, }, }; case TransactionActionType.TX_ERROR: return { ...state, txState: TxState.Error, txData: { ...state.txData, userFacingError: substituteErrorMessage( action.error.message, action.errorSubstitutions ), error: action.error, }, }; } }