@jhubbardsf/ethers-decode-error
Version:
Decode ethers.js smart contract errors into human-readable messages
1 lines • 7.57 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/enums.ts","../src/decode-error.ts","../src/panic.ts"],"sourcesContent":["export enum ErrorType {\n UserError,\n EmptyError,\n RevertError,\n PanicError,\n UnknownError,\n CustomError,\n}\n","import { Interface } from '@ethersproject/abi'\nimport { BigNumber, utils } from 'ethers'\nimport { panicErrorCodeToReason } from './panic'\nimport { ErrorType } from './enums'\nimport { DecodedError } from './types'\n\n// Error(string)\nconst ERROR_STRING_PREFIX = '0x08c379a0'\n\n// Panic(uint256)\nconst PANIC_CODE_PREFIX = '0x4e487b71'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getReturnDataFromError(error: any): string {\n const errorData = error.data ?? error.error?.data\n\n if (errorData === undefined) {\n throw error\n }\n\n let returnData = typeof errorData === 'string' ? errorData : errorData.data\n\n if (typeof returnData === 'object' && returnData.data) {\n returnData = returnData.data\n }\n\n if (returnData === undefined || typeof returnData !== 'string') {\n throw error\n }\n\n return returnData\n}\n\nexport const decodeError = <T extends Interface>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n abiOrInterface?: T | ConstructorParameters<typeof utils.Interface>[0],\n): DecodedError => {\n if (!(error instanceof Error)) {\n return {\n type: ErrorType.UnknownError,\n error: error.message ?? 'Unexpected error',\n data: undefined,\n }\n }\n\n let returnData\n try {\n returnData = getReturnDataFromError(error)\n } catch (e) {\n if (error.message) {\n if (error.message.includes('user rejected transaction')) {\n return {\n type: ErrorType.UserError,\n error: 'User has rejected the transaction',\n data: returnData,\n }\n }\n return {\n type: ErrorType.UnknownError,\n error: error.message,\n data: returnData,\n }\n }\n return {\n type: ErrorType.UnknownError,\n error: 'Unknown error',\n data: returnData,\n }\n }\n\n if (returnData === '0x') {\n return {\n type: ErrorType.EmptyError,\n error: 'Empty error data returned',\n data: returnData,\n }\n } else if (returnData.startsWith(ERROR_STRING_PREFIX)) {\n const encodedReason = returnData.slice(ERROR_STRING_PREFIX.length)\n try {\n const reason = utils.defaultAbiCoder.decode(['string'], `0x${encodedReason}`)[0]\n return {\n type: ErrorType.RevertError,\n error: reason,\n data: returnData,\n }\n } catch (e) {\n return {\n type: ErrorType.UnknownError,\n error: 'Unknown error returned',\n data: returnData,\n }\n }\n } else if (returnData.startsWith(PANIC_CODE_PREFIX)) {\n const encodedReason = returnData.slice(PANIC_CODE_PREFIX.length)\n try {\n const code = utils.defaultAbiCoder.decode(['uint256'], `0x${encodedReason}`)[0] as BigNumber\n const reason = panicErrorCodeToReason(code) ?? 'Unknown panic code'\n return {\n type: ErrorType.PanicError,\n error: reason,\n data: returnData,\n }\n } catch (e) {\n return {\n type: ErrorType.UnknownError,\n error: 'Unknown panic error',\n data: returnData,\n }\n }\n } else {\n if (!abiOrInterface) {\n return {\n type: ErrorType.CustomError,\n error: returnData.slice(0, 10),\n data: returnData,\n }\n }\n let iface: Interface\n if (abiOrInterface instanceof utils.Interface) {\n iface = abiOrInterface\n } else {\n iface = new utils.Interface(abiOrInterface)\n }\n const customError = iface.parseError(returnData)\n return {\n type: ErrorType.CustomError,\n error: customError.name,\n args: customError.args,\n data: returnData,\n }\n }\n}\n","import { BigNumber } from 'ethers'\n\n// From Hardhat's panic codes\nexport const panicErrorCodeToReason = (errorCode: BigNumber): string | undefined => {\n switch (errorCode.toNumber()) {\n case 0x1:\n return 'Assertion error'\n case 0x11:\n return 'Arithmetic operation underflowed or overflowed outside of an unchecked block'\n case 0x12:\n return 'Division or modulo division by zero'\n case 0x21:\n return 'Tried to convert a value into an enum, but the value was too big or negative'\n case 0x22:\n return 'Incorrectly encoded storage byte array'\n case 0x31:\n return '.pop() was called on an empty array'\n case 0x32:\n return 'Array accessed at an out-of-bounds or negative index'\n case 0x41:\n return 'Too much memory was allocated, or an array was created that is too large'\n case 0x51:\n return 'Called a zero-initialized variable of internal function type'\n default:\n return undefined\n }\n}\n"],"names":["ErrorType","error","abiOrInterface","_error$message","returnData","Error","type","UnknownError","message","data","undefined","_error$data","_error$error","errorData","getReturnDataFromError","e","includes","UserError","EmptyError","startsWith","encodedReason","slice","ERROR_STRING_PREFIX","reason","utils","defaultAbiCoder","decode","RevertError","CustomError","customError","Interface","parseError","name","args","PANIC_CODE_PREFIX","_panicErrorCodeToReas","errorCode","toNumber","panicErrorCodeToReason","PanicError"],"mappings":"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"}