diff --git a/packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts b/packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts index 9bda1718075..9892b329b8f 100644 --- a/packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts +++ b/packages/chain-adapters/src/cosmossdk/CosmosSdkBaseAdapter.ts @@ -12,7 +12,7 @@ import { bech32 } from 'bech32' import PQueue from 'p-queue' import type { ChainAdapter as IChainAdapter } from '../api' -import { ErrorHandler } from '../error/ErrorHandler' +import { ErrorHandler, handleBroadcastTransactionError } from '../error/ErrorHandler' import type { Account, BroadcastTransactionInput, @@ -382,19 +382,9 @@ export abstract class CosmosSdkBaseAdapter implement return txHash } catch (err) { - if ((err as Error).name === 'ResponseError') { - const response = await ((err as any).response as Response).json() - + return handleBroadcastTransactionError(err, response => { const match = response.message.match(/description:\s*([^,]+)$/) - - return ErrorHandler(JSON.stringify(response), { - translation: 'chainAdapters.errors.broadcastTransactionWithMessage', - options: { message: match && match[1] ? match[1].trim() : response.message }, - }) - } - - return ErrorHandler(err, { - translation: 'chainAdapters.errors.broadcastTransaction', + return match && match[1] ? match[1].trim() : response.message }) } } diff --git a/packages/chain-adapters/src/error/ErrorHandler.ts b/packages/chain-adapters/src/error/ErrorHandler.ts index 8ab4000b2b7..ebed120575d 100644 --- a/packages/chain-adapters/src/error/ErrorHandler.ts +++ b/packages/chain-adapters/src/error/ErrorHandler.ts @@ -1,3 +1,4 @@ +import type * as unchained from '@shapeshiftoss/unchained-client' import type { AxiosError } from 'axios' import type { InterpolationOptions } from 'node-polyglot' @@ -6,6 +7,15 @@ type ErrorMetadata = { options?: InterpolationOptions } +const isResponseError = (err: unknown): err is unchained.ResponseError => { + return ( + err instanceof Error && + err.name === 'ResponseError' && + 'response' in err && + err.response instanceof Response + ) +} + export class ChainAdapterError extends Error { metadata: ErrorMetadata @@ -25,6 +35,36 @@ export class ChainAdapterError extends Error { } } +export const handleBroadcastTransactionError = async ( + err: unknown, + customMessage?: (response: any) => string, +) => { + try { + if (!isResponseError(err)) throw err + + const response = await err.response.clone().json() + + const message = (() => { + if (customMessage) return customMessage(response) + + try { + return JSON.parse(response.message).message + } catch { + return response.message + } + })() + + return ErrorHandler(JSON.stringify(response), { + translation: 'chainAdapters.errors.broadcastTransactionWithMessage', + options: { message }, + }) + } catch (err) { + return ErrorHandler(err, { + translation: 'chainAdapters.errors.broadcastTransaction', + }) + } +} + export const ErrorHandler = async (err: unknown, metadata?: ErrorMetadata): Promise => { if (err instanceof Error && err.message.toLowerCase().includes('blind sign')) { throw new ChainAdapterError(err, { @@ -60,10 +100,8 @@ export const ErrorHandler = async (err: unknown, metadata?: ErrorMetadata): Prom const response = JSON.stringify((err as AxiosError).response?.data) if (metadata) throw new ChainAdapterError(response, metadata) throw new Error(response) - } else if ((err as Error).name === 'ResponseError') { - // handle fetch api error coming from generated typescript client - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const response = JSON.stringify(await ((err as any).response as Response).json()) + } else if (isResponseError(err)) { + const response = JSON.stringify(await err.response.clone().json()) if (metadata) throw new ChainAdapterError(response, metadata) throw new Error(response) } else if (err instanceof Error || err instanceof ChainAdapterError) { diff --git a/packages/chain-adapters/src/evm/EvmBaseAdapter.ts b/packages/chain-adapters/src/evm/EvmBaseAdapter.ts index 2f2f523a395..670c67c95e0 100644 --- a/packages/chain-adapters/src/evm/EvmBaseAdapter.ts +++ b/packages/chain-adapters/src/evm/EvmBaseAdapter.ts @@ -30,7 +30,11 @@ import PQueue from 'p-queue' import { isAddress, toHex } from 'viem' import type { ChainAdapter as IChainAdapter } from '../api' -import { ChainAdapterError, ErrorHandler } from '../error/ErrorHandler' +import { + ChainAdapterError, + ErrorHandler, + handleBroadcastTransactionError, +} from '../error/ErrorHandler' import type { Account, BroadcastTransactionInput, @@ -523,19 +527,7 @@ export abstract class EvmBaseAdapter implements IChainAdap return txHash } catch (err) { - if ((err as Error).name === 'ResponseError') { - const response = await ((err as any).response as Response).json() - const error = JSON.parse(response.message) - - return ErrorHandler(JSON.stringify(response), { - translation: 'chainAdapters.errors.broadcastTransactionWithMessage', - options: { message: error.message }, - }) - } - - return ErrorHandler(err, { - translation: 'chainAdapters.errors.broadcastTransaction', - }) + return handleBroadcastTransactionError(err) } } diff --git a/packages/chain-adapters/src/solana/SolanaChainAdapter.ts b/packages/chain-adapters/src/solana/SolanaChainAdapter.ts index b3e2d6a5719..9dfc9571fc8 100644 --- a/packages/chain-adapters/src/solana/SolanaChainAdapter.ts +++ b/packages/chain-adapters/src/solana/SolanaChainAdapter.ts @@ -43,7 +43,11 @@ import { isUndefined } from 'lodash' import PQueue from 'p-queue' import type { ChainAdapter as IChainAdapter } from '../api' -import { ChainAdapterError, ErrorHandler } from '../error/ErrorHandler' +import { + ChainAdapterError, + ErrorHandler, + handleBroadcastTransactionError, +} from '../error/ErrorHandler' import type { Account, BroadcastTransactionInput, @@ -411,18 +415,7 @@ export class ChainAdapter implements IChainAdapter return txHash } catch (err) { - if ((err as Error).name === 'ResponseError') { - const response = await ((err as any).response as Response).json() - - return ErrorHandler(JSON.stringify(response), { - translation: 'chainAdapters.errors.broadcastTransactionWithMessage', - options: { message: response.message }, - }) - } - - return ErrorHandler(err, { - translation: 'chainAdapters.errors.broadcastTransaction', - }) + return handleBroadcastTransactionError(err) } } diff --git a/packages/chain-adapters/src/utxo/UtxoBaseAdapter.ts b/packages/chain-adapters/src/utxo/UtxoBaseAdapter.ts index 5562ba4a2ab..e5dd6a3dc47 100644 --- a/packages/chain-adapters/src/utxo/UtxoBaseAdapter.ts +++ b/packages/chain-adapters/src/utxo/UtxoBaseAdapter.ts @@ -18,7 +18,11 @@ import WAValidator from 'multicoin-address-validator' import PQueue from 'p-queue' import type { ChainAdapter as IChainAdapter } from '../api' -import { ChainAdapterError, ErrorHandler } from '../error/ErrorHandler' +import { + ChainAdapterError, + ErrorHandler, + handleBroadcastTransactionError, +} from '../error/ErrorHandler' import type { Account, BroadcastTransactionInput, @@ -591,19 +595,7 @@ export abstract class UtxoBaseAdapter implements IChainAd return txHash } catch (err) { - if ((err as Error).name === 'ResponseError') { - const response = await ((err as any).response as Response).json() - const error = JSON.parse(response.message) - - return ErrorHandler(JSON.stringify(response), { - translation: 'chainAdapters.errors.broadcastTransactionWithMessage', - options: { message: error.message }, - }) - } - - return ErrorHandler(err, { - translation: 'chainAdapters.errors.broadcastTransaction', - }) + return handleBroadcastTransactionError(err) } } diff --git a/packages/unchained-client/src/index.ts b/packages/unchained-client/src/index.ts index 639342fd7c1..0db9c168fd5 100644 --- a/packages/unchained-client/src/index.ts +++ b/packages/unchained-client/src/index.ts @@ -1,5 +1,7 @@ export * from './types' +export { ResponseError } from './generated/ethereum/runtime' + export * as ws from './websocket' export * as evm from './evm'