All files / src/TxSubmitProvider txSubmitHttpProvider.ts

87.87% Statements 29/33
83.33% Branches 25/30
100% Functions 4/4
87.5% Lines 28/32

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  11x                         11x 11x 11x     11x                       11x 5x 3x 1x     2x 1x         1x 1x     2x     11x 3x   2x       1x                       11x 10x       5x         5x   5x 5x 3x     2x         2x 2x                  
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
  CardanoNodeUtil,
  GeneralCardanoNodeError,
  GeneralCardanoNodeErrorCode,
  HandleOwnerChangeError,
  HttpProviderConfigPaths,
  ProviderError,
  ProviderFailure,
  TxSubmissionError,
  TxSubmissionErrorCode,
  TxSubmitProvider,
  reasonToProviderFailure
} from '@cardano-sdk/core';
import { CreateHttpProviderConfig, createHttpProvider } from '../HttpProvider';
import { apiVersion } from '../version';
import { mapHealthCheckError } from '../mapHealthCheckError';
 
/** The TxSubmitProvider endpoint paths. */
const paths: HttpProviderConfigPaths<TxSubmitProvider> = {
  healthCheck: '/health',
  submitTx: '/submit'
};
 
/**
 * Takes an unknown error param.
 * Returns an instance of TxSubmissionError or GeneralCardanoNodeError from the error if the error
 * is an object, with an undefined or valid TxSubmissionError or GeneralCardanoNodeError code, and
 * a string message.
 * Returns null otherwise.
 */
const toTxSubmissionError = (error: any): TxSubmissionError | GeneralCardanoNodeError | null => {
  if (typeof error === 'object' && error !== null && typeof error?.message === 'string') {
    if (CardanoNodeUtil.isTxSubmissionErrorCode(error.code)) {
      return new TxSubmissionError(error.code, error.data, error.message);
    }
 
    if (CardanoNodeUtil.isGeneralCardanoNodeErrorCode(error.code)) {
      return error instanceof GeneralCardanoNodeError
        ? error
        : new GeneralCardanoNodeError(error.code, error.data || null, error.message);
    }
 
    if (error.code === undefined || error.code === null) {
      return new GeneralCardanoNodeError(GeneralCardanoNodeErrorCode.Unknown, error?.data || null, error.message);
    }
  }
  return null;
};
 
const codeToProviderFailure = (code: GeneralCardanoNodeErrorCode | TxSubmissionErrorCode) => {
  switch (code) {
    case GeneralCardanoNodeErrorCode.Unknown:
      return ProviderFailure.Unknown;
    case GeneralCardanoNodeErrorCode.ServerNotReady:
      return ProviderFailure.ServerUnavailable;
    default:
      return ProviderFailure.BadRequest;
  }
};
 
/**
 * Connect to a Cardano Services HttpServer instance with the service available
 *
 * @param config The configuration object fot the TxSubmit Provider.
 * @returns {TxSubmitProvider} TxSubmitProvider
 * @throws {ProviderError} if reason === ProviderFailure.BadRequest then
 * innerError is set to either one of CardanoNodeErrors.TxSubmissionErrors or Cardano.UnknownTxSubmissionError
 */
export const txSubmitHttpProvider = (config: CreateHttpProviderConfig<TxSubmitProvider>): TxSubmitProvider =>
  createHttpProvider<TxSubmitProvider>({
    ...config,
    apiVersion: config.apiVersion || apiVersion.txSubmit,
    mapError: (error: any, method) => {
      switch (method) {
        case 'healthCheck': {
          return mapHealthCheckError(error);
        }
        case 'submitTx': {
          if (typeof error === 'object' && typeof error.innerError === 'object') {
            // Ogmios errors have inner error. Parse that to get the real error
            const txSubmissionError = toTxSubmissionError(error.innerError);
            if (txSubmissionError) {
              throw new ProviderError(codeToProviderFailure(txSubmissionError.code), txSubmissionError);
            }
 
            Iif (error.name === 'HandleOwnerChangeError') {
              Object.setPrototypeOf(error, HandleOwnerChangeError);
            }
          }
          // No inner error. Use the outer reason to determine the error type.
          if (error.reason && typeof error.reason === 'string') {
            throw new ProviderError(reasonToProviderFailure(error.reason), error);
          }
        }
      }
      throw new ProviderError(ProviderFailure.Unknown, error);
    },
    paths,
    serviceSlug: 'tx-submit'
  });