All files / src index.ts

68.18% Statements 30/44
58.33% Branches 14/24
66.66% Functions 10/15
69.76% Lines 30/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 13936x               1x     1x   1x               1x                   1x     1x 1x 1x       1x     1x                   1x     1x       1x           1x   1x               1x 1x 1x   1x   1x             1x           2x 2x             1x   2x       1x 1x     1x 1x                                                
import {
    AbstractTransactPlugin,
    API,
    Checksum256,
    TransactContext,
    TransactHookResponseType,
    TransactHookTypes,
    TransactResult,
} from '@wharfkit/session'
 
/** Import JSON localization strings */
import defaultTranslations from './translations'
 
const DEFAULT_FINALITY_CHECK_DELAY = 150000 // 2.5 minutes
 
interface TransactPluginFinalityCallbackOptions {
    onFinalityCallback: (response: API.v1.GetTransactionStatusResponse) => void
    finalityCheckDelay?: number
    logging?: boolean
}
 
export class TransactPluginFinalityCallback extends AbstractTransactPlugin {
    onFinalityCallback: (response: API.v1.GetTransactionStatusResponse) => void
    finalityCheckDelay: number
    logging: boolean
 
    constructor({
        onFinalityCallback,
        finalityCheckDelay,
        logging,
    }: TransactPluginFinalityCallbackOptions) {
        super()
 
        // Optional - Set the default translations for the plugin
        this.onFinalityCallback = onFinalityCallback
        this.finalityCheckDelay = finalityCheckDelay || DEFAULT_FINALITY_CHECK_DELAY
        this.logging = logging || false
    }
 
    /** A unique ID for this plugin */
    id = 'transact-plugin-finality-callback'
 
    /** Optional - The translation strings to use for the plugin */
    translations = defaultTranslations
 
    /**
     * Register the hooks required for this plugin to function
     *
     * @param context The TransactContext of the transaction being performed
     */
    register(context: TransactContext): void {
        // Optional - Retrieve the translation function from the UI if it exists
        let t
        Iif (context.ui) {
            t = context.ui.getTranslate()
        } else {
            t = (_key: string, args: {default: string}) => args.default
        }
 
        // Register any desired afterBroadcast hooks
        context.addHook(
            TransactHookTypes.afterBroadcast,
            (
                result: TransactResult,
                context: TransactContext
            ): Promise<TransactHookResponseType> => {
                const {resolved} = result
 
                Iif (!resolved) {
                    throw Error(
                        t('resolved_request_not_returned', {
                            default:
                                'Resolved Request not returned on afterBroadcast hook. This value is needed for the Finality Callback plugin to work.',
                        })
                    )
                }
                setTimeout(async () => {
                    this.log('Checking transaction finality')
                    waitForFinality(resolved.transaction.id, context)
                        .then((transactionResponse) => {
                            this.log('Transaction finality reached')
 
                            this.onFinalityCallback(transactionResponse)
                        })
                        .catch((error) => {
                            this.log('Error while checking transaction finality', error)
                        })
                }, this.finalityCheckDelay)
 
                return Promise.resolve()
            }
        )
    }
 
    log(...args: any[]) {
        if (!this.logging) {
            return
        }
        // eslint-disable-next-line no-console
        console.log('TransactPluginFinalityChecker, LOG:', ...args)
    }
}
 
let retries = 0
 
async function waitForFinality(
    transactionId: Checksum256,
    context: TransactContext
): Promise<API.v1.GetTransactionStatusResponse> {
    return new Promise((resolve, reject) => {
        context.client.v1.chain
            .get_transaction_status(transactionId)
            .then((response) => {
                if (response.state === 'IRREVERSIBLE') {
                    return resolve(response)
                }
 
                setTimeout(() => {
                    waitForFinality(transactionId, context).then(resolve).catch(reject)
                }, 5000)
            })
            .catch((error) => {
                if (error.response && error.response.status === 404 && retries < 3) {
                    retries++
 
                    setTimeout(() => {
                        waitForFinality(transactionId, context).then(resolve).catch(reject)
                    }, 5000)
                } else if (error.response.status === 500) {
                    reject(
                        `This API node cannot be used with the finality callback plugin. Full Error: ${error}`
                    )
                } else {
                    reject(error)
                }
            })
    })
}