{"_id":"@abiregistry/error-decoder","_rev":"2-7284fddefdc46105d91ca62d9cdaa478","name":"@abiregistry/error-decoder","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@abiregistry/error-decoder","version":"0.1.0","keywords":["solidity","ethereum","error","decoder","custom-error","revert","foundry","viem","abi","abiregistry"],"author":{"name":"ABI Registry"},"license":"MIT","_id":"@abiregistry/error-decoder@0.1.0","maintainers":[{"name":"eborrallo","email":"borrallorodriguez@gmail.com"}],"homepage":"https://github.com/eborrallo/error-decoder#readme","bugs":{"url":"https://github.com/eborrallo/error-decoder/issues"},"bin":{"error-decoder":"dist/cli/generate.js"},"dist":{"shasum":"3802d0553715356ee0c971cd486a9c05da04ede6","tarball":"https://registry.npmjs.org/@abiregistry/error-decoder/-/error-decoder-0.1.0.tgz","fileCount":59,"integrity":"sha512-iDwzsbPl/4I5GEY1YXhMGQ+O13VvatEv167DzNrMJxTlrQYjnG3/o19iWL8KT2dRiMpB8Px181XKMXcCpLAEEA==","signatures":[{"sig":"MEYCIQDTBphaRwQGb4tnpyBDINbJACwMnUAWnNlfbHnq6Yw8twIhAIRl6mFSvy5E0jok/SpBPViq/clbN4k1+QHT+XzWlQoT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":212309},"main":"./dist/index.cjs","type":"module","_from":"file:abiregistry-error-decoder-0.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./viem":{"types":"./dist/viem/index.d.ts","import":"./dist/viem/index.js","require":"./dist/viem/index.cjs"},"./decode":{"types":"./dist/decode/index.d.ts","import":"./dist/decode/index.js","require":"./dist/decode/index.cjs"},"./format":{"types":"./dist/format/index.d.ts","import":"./dist/format/index.js","require":"./dist/format/index.cjs"},"./extract":{"types":"./dist/extract/index.d.ts","import":"./dist/extract/index.js","require":"./dist/extract/index.cjs"}},"scripts":{"dev":"tsup --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsup","format":"biome format --write .","example":"tsx example/run.ts","test:watch":"vitest","format:check":"biome check .","example:generate":"node dist/cli/generate.js generate --foundry ./example-contracts/out --output ./example/generated --contracts"},"_npmUser":{"name":"eborrallo","email":"borrallorodriguez@gmail.com"},"_resolved":"/tmp/eba92c52128d7db6862a49dba4babf90/abiregistry-error-decoder-0.1.0.tgz","_integrity":"sha512-iDwzsbPl/4I5GEY1YXhMGQ+O13VvatEv167DzNrMJxTlrQYjnG3/o19iWL8KT2dRiMpB8Px181XKMXcCpLAEEA==","repository":{"url":"git+https://github.com/eborrallo/error-decoder.git","type":"git"},"_npmVersion":"10.8.2","description":"Decode Solidity custom errors from revert data. Extracts errors from Foundry/Hardhat artifacts, builds a fast selector registry, and produces human-readable output.","directories":{},"_nodeVersion":"20.20.0","dependencies":{"chalk":"^5.6.2","commander":"^14.0.3"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","tsup":"^8.5.1","vitest":"^4.0.18","typescript":"^5.9.3","@types/node":"^25.3.3","@viem/anvil":"^0.0.10","@biomejs/biome":"^2.4.5"},"peerDependencies":{"viem":">=2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/error-decoder_0.1.0_1772549289670_0.08861693329762899","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@abiregistry/error-decoder","version":"0.1.3","description":"Decode Solidity custom errors from revert data. Extracts errors from Foundry/Hardhat artifacts, builds a fast selector registry, and produces human-readable output.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./extract":{"types":"./dist/extract/index.d.ts","import":"./dist/extract/index.js","require":"./dist/extract/index.cjs"},"./decode":{"types":"./dist/decode/index.d.ts","import":"./dist/decode/index.js","require":"./dist/decode/index.cjs"},"./format":{"types":"./dist/format/index.d.ts","import":"./dist/format/index.js","require":"./dist/format/index.cjs"},"./viem":{"types":"./dist/viem/index.d.ts","import":"./dist/viem/index.js","require":"./dist/viem/index.cjs"}},"bin":{"error-decoder":"dist/cli/generate.js"},"keywords":["solidity","ethereum","error","decoder","custom-error","revert","foundry","viem","abi","abiregistry"],"repository":{"type":"git","url":"git+https://github.com/eborrallo/error-decoder.git"},"bugs":{"url":"https://github.com/eborrallo/error-decoder/issues"},"homepage":"https://github.com/eborrallo/error-decoder#readme","author":{"name":"ABI Registry"},"license":"MIT","engines":{"node":">=18.0.0"},"peerDependencies":{"viem":">=2.0.0"},"dependencies":{"chalk":"^5.6.2","commander":"^14.0.3"},"devDependencies":{"@biomejs/biome":"^2.4.5","@types/node":"^25.3.3","@viem/anvil":"^0.0.10","tsup":"^8.5.1","tsx":"^4.21.0","typescript":"^5.9.3","vitest":"^4.0.18"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","lint":"tsc --noEmit","format":"biome format --write .","format:check":"biome check .","example:generate":"npm run generate:short-codes && node dist/cli/generate.js generate --foundry ./example-contracts/out --output ./example/generated --contracts","generate:short-codes":"tsx src/cli/generate.ts generate-short-codes --input ./example-contracts/src/ProtocolErrorCodes.sol,./example-contracts/src/FileLevelErrorCodes.sol --output ./example/generated/shortStringCodes.ts","example":"tsx --tsconfig example/tsconfig.json example/run.ts","release:patch":"pnpm version patch && pnpm publish --access public","release:minor":"pnpm version minor && pnpm publish --access public","release:major":"pnpm version major && pnpm publish --access public"},"_id":"@abiregistry/error-decoder@0.1.3","_integrity":"sha512-HKFEZIBplMKQOSDqctkPRgfbolZlZ1KEaUAtgrsJyYkQym0Abvr38/GMWtXqcjHqVZ9lZpDNr4JphcM48ViVrw==","_resolved":"/tmp/1d63cd83654cba18f05c3e2f5c9ca250/abiregistry-error-decoder-0.1.3.tgz","_from":"file:abiregistry-error-decoder-0.1.3.tgz","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-HKFEZIBplMKQOSDqctkPRgfbolZlZ1KEaUAtgrsJyYkQym0Abvr38/GMWtXqcjHqVZ9lZpDNr4JphcM48ViVrw==","shasum":"afd340b34670ac3e1bbecc118df457085c8949c6","tarball":"https://registry.npmjs.org/@abiregistry/error-decoder/-/error-decoder-0.1.3.tgz","fileCount":59,"unpackedSize":250107,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBE/C+c0x6llKtqJXJF0s2a3IKiTxgVs7Q0AOlQLvg0+AiAji2Etbh65ef8Tt+V/nPanv102xASnhKhlFNmuJZLVgQ=="}]},"_npmUser":{"name":"eborrallo","email":"borrallorodriguez@gmail.com"},"directories":{},"maintainers":[{"name":"eborrallo","email":"borrallorodriguez@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/error-decoder_0.1.3_1774182106136_0.4660218725113414"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-03T14:48:09.597Z","modified":"2026-03-22T12:21:46.427Z","0.1.0":"2026-03-03T14:48:09.850Z","0.1.3":"2026-03-22T12:21:46.289Z"},"bugs":{"url":"https://github.com/eborrallo/error-decoder/issues"},"author":{"name":"ABI Registry"},"license":"MIT","homepage":"https://github.com/eborrallo/error-decoder#readme","keywords":["solidity","ethereum","error","decoder","custom-error","revert","foundry","viem","abi","abiregistry"],"repository":{"type":"git","url":"git+https://github.com/eborrallo/error-decoder.git"},"description":"Decode Solidity custom errors from revert data. Extracts errors from Foundry/Hardhat artifacts, builds a fast selector registry, and produces human-readable output.","maintainers":[{"name":"eborrallo","email":"borrallorodriguez@gmail.com"}],"readme":"# @abiregistry/error-decoder\n\nDecode Solidity custom errors from raw revert data. Extracts errors from Foundry/Hardhat build artifacts, builds an O(1) selector registry, and produces human-readable output. Includes a viem plugin for transparent error decoding.\n\n## Install\n\n```bash\nnpm install @abiregistry/error-decoder viem\n```\n\n## Quick Start\n\n```ts\nimport { createDecoder } from \"@abiregistry/error-decoder\";\n\nconst decoder = createDecoder({\n  foundryOut: \"./out\",\n});\n\nconst result = decoder.decode(revertData);\n\nif (result) {\n  console.log(result.name);           // \"InsufficientBalance\"\n  console.log(result.args.user);      // \"0x000...dEaD\"\n  console.log(result.args.requested); // 1000n\n  console.log(result.args.available); // 500n\n}\n```\n\n## Features\n\n- **Viem plugin** — extend `PublicClient` / `WalletClient` for transparent error decoding\n- **Foundry & Hardhat support** — scans `out/` or `artifacts/` directories\n- **O(1) selector lookup** — Map-based registry, not linear ABI scan\n- **Builtin error handling** — `Error(string)` and `Panic(uint256)` with human-readable panic descriptions\n- **Short string revert codes** — CLI generates a lookup map in **your** repo; pass `createShortStringResolver(map)` to `createDecoder` / the viem plugin (nothing bundled in the SDK)\n- **Multiple output formats** — one-line, detailed, and ANSI-colored\n- **CLI tool** — generate TypeScript types, contract artifacts, and decode errors from the terminal\n- **Runtime registration** — add ABIs dynamically\n- **Tree-shakeable** — subpath exports for minimal bundles\n\n## Viem Plugin\n\nThe plugin overrides `call`, `simulateContract`, `writeContract`, and `sendTransaction` so that reverts throw a `DecodedRevertError` instead of a generic viem error. Extend both public and wallet clients for full coverage.\n\n### Setup\n\n```ts\nimport { createPublicClient, createWalletClient, http } from \"viem\";\nimport { errorDecoder, DecodedRevertError } from \"@abiregistry/error-decoder/viem\";\nimport { ERROR_ABI } from \"./generated/index.js\";\n\nconst plugin = errorDecoder({ errorAbis: [ERROR_ABI] });\n\nconst client = createPublicClient({ chain, transport: http() }).extend(plugin);\nconst wallet = createWalletClient({ account, chain, transport: http() }).extend(plugin);\n```\n\nFor gas-optimized `Error(string)` short codes, pass `resolveShortStringMessage` (see [Short string revert codes](#short-string-revert-codes)) — same option as `createDecoder`.\n\n### Usage\n\nEvery revert is now a `DecodedRevertError` with `.decoded`, `.revertData`, and `.originalError`:\n\n```ts\n// simulateContract\ntry {\n  await client.simulateContract({\n    address, abi, functionName: \"withdraw\", args: [99999n], account,\n  });\n} catch (err) {\n  if (err instanceof DecodedRevertError) {\n    console.log(err.decoded.name);  // \"InsufficientBalance\"\n    console.log(err.decoded.args);  // { user: \"0x...\", requested: 99999n, available: 5000n }\n  }\n}\n\n// writeContract — wallet client is extended too\ntry {\n  await wallet.writeContract({\n    address, abi, functionName: \"withdraw\", args: [99999n],\n  });\n} catch (err) {\n  if (err instanceof DecodedRevertError) {\n    console.log(err.decoded.name);\n  }\n}\n\n// raw call\ntry {\n  await client.call({ to: address, data: calldata });\n} catch (err) {\n  if (err instanceof DecodedRevertError) {\n    console.log(err.revertData); // raw hex\n  }\n}\n```\n\n### Helper Methods\n\nThe extended client also exposes utility methods:\n\n```ts\nclient.decodeError(revertHex);       // DecodedError | null\nclient.tryDecodeError(revertHex);    // always returns something\nclient.formatError(revertHex);       // { oneline, detailed, colored }\nclient.logError(revertHex);          // prints colored output to console\nclient.registerErrorAbi(newAbi);     // register more ABIs at runtime\nclient.errorRegistrySize;            // number of registered selectors\n```\n\n### `DecodedRevertError`\n\n```ts\nclass DecodedRevertError extends Error {\n  decoded: DecodedError;    // name, selector, signature, args, rawArgs\n  revertData: Hex;          // raw revert bytes\n  originalError: unknown;   // the original viem error\n}\n```\n\n## Standalone API\n\n### `createDecoder(options)`\n\n```ts\nconst decoder = createDecoder({\n  foundryOut: \"./out\",             // Foundry out/ path\n  hardhatArtifacts: \"./artifacts\", // Hardhat artifacts/ path\n  abis: [myAbi],                  // Raw ABI arrays\n  includeBuiltins: true,           // Error(string), Panic(uint256) — default: true\n  resolveShortStringMessage: createShortStringResolver(SHORT_STRING_ERROR_CODES), // optional, client-generated map\n});\n```\n\n### `decoder.decode(data)`\n\nReturns a `DecodedError` or `null`:\n\n```ts\ninterface DecodedError {\n  name: string;                       // \"InsufficientBalance\"\n  selector: string;                   // \"0xdb42144d\"\n  signature: string;                  // \"InsufficientBalance(address,uint256,uint256)\"\n  args: Record<string, unknown>;      // { user: \"0x...\", requested: 1000n, available: 500n }\n  rawArgs: readonly unknown[];        // [\"0x...\", 1000n, 500n]\n  contractName?: string;              // \"Vault\"\n}\n```\n\n### `decoder.tryDecode(data)`\n\nAlways returns something — `DecodedError` or `{ name: \"UnknownError\", selector, raw }`.\n\n### `decoder.decodeAndFormat(data)`\n\nReturns all three formatted representations:\n\n```ts\ninterface FormattedError {\n  oneline: string;   // \"Vault.InsufficientBalance(user=0x..., requested=1000, available=500)\"\n  detailed: string;  // multi-line with labels\n  colored: string;   // ANSI-colored for terminals\n}\n```\n\n### `decoder.decodeAndLog(data)`\n\nDecodes and logs to console with colors.\n\n### `decoder.registerAbi(abi, contractName?)`\n\nRegister additional ABIs at runtime.\n\n## CLI\n\n### Generate TypeScript types and contract artifacts\n\n```bash\nnpx @abiregistry/error-decoder generate --foundry ./out --output ./generated --contracts\n```\n\nThis creates:\n- `errors.types.ts` — TypeScript interfaces for every custom error\n- `errors.abi.ts` — ABI registry you can import in your code\n- `<ContractName>.ts` — per-contract ABI and bytecode (with `--contracts`)\n- `index.ts` — barrel file re-exporting everything (also re-exports `SHORT_STRING_ERROR_CODES` if you generate `shortStringCodes.ts` into the same output directory first; see `generate-short-codes` below)\n\n### Generate short-string lookup map\n\n```bash\nnpx error-decoder generate-short-codes --input ./contracts/Codes.sol --output ./generated/shortStringCodes.ts\n```\n\nSee [Short string revert codes](#short-string-revert-codes) for Solidity shapes and merging multiple files.\n\n### Decode from terminal\n\n```bash\nnpx @abiregistry/error-decoder decode 0xdb42144d000...01f4 --foundry ./out\n```\n\nOutput:\n```\nVault.InsufficientBalance\n  selector: 0xdb42144d\n  signature: InsufficientBalance(address,uint256,uint256)\n  args:\n    user: \"0x000000000000000000000000000000000000dEaD\"\n    requested: 1000\n    available: 500\n```\n\n## Advanced Usage\n\n### Direct imports (tree-shaking)\n\n```ts\nimport { scanFoundryOut } from \"@abiregistry/error-decoder/extract\";\nimport { decodeRevertData } from \"@abiregistry/error-decoder/decode\";\nimport { formatError } from \"@abiregistry/error-decoder/format\";\n```\n\n### Build your own registry\n\n```ts\nimport { ErrorRegistry } from \"@abiregistry/error-decoder\";\n\nconst registry = new ErrorRegistry();\nregistry.registerAbi(myContractAbi, \"MyContract\");\n\nconst entry = registry.getBySelector(\"0xdb42144d\");\n```\n\n### Multi-protocol bot\n\n```ts\nconst decoder = createDecoder({ includeBuiltins: true });\n\ndecoder.registerAbi(uniswapAbi, \"Uniswap\");\ndecoder.registerAbi(aaveAbi, \"Aave\");\ndecoder.registerAbi(compoundAbi, \"Compound\");\n\nconst error = decoder.decode(revertData);\n```\n\n## Panic Codes\n\nBuilt-in `Panic(uint256)` codes are automatically annotated:\n\n| Code | Description |\n|------|-------------|\n| 0x00 | Generic compiler panic |\n| 0x01 | Assert failed |\n| 0x11 | Arithmetic overflow/underflow |\n| 0x12 | Division or modulo by zero |\n| 0x21 | Conversion to invalid enum value |\n| 0x22 | Incorrectly encoded storage byte array |\n| 0x31 | pop() on empty array |\n| 0x32 | Array index out of bounds |\n| 0x41 | Too much memory allocated |\n| 0x51 | Call to zero-initialized internal function |\n\n## Short string revert codes\n\nContracts sometimes use **short revert strings** (for example `revert(\"A1\")`) to save gas, with the meaning defined beside them in Solidity as `string constant ErrorText1 = \"A1\";`.\n\nThe SDK **does not ship** a generated protocol table — only **CLI** (`generate-short-codes`) and **helpers** (`createShortStringResolver`, Solidity→TS codegen in `src/helpers/`). Generate the map **in your app** (or in this repo under **`example/`**), then pass a resolver into the decoder.\n\n### Layout in this repo\n\n| Path | Role |\n|------|------|\n| `src/cli/` | CLI entry (`error-decoder` binary) |\n| `src/helpers/` | Short-string codegen + `createShortStringResolver` |\n| `example/` | Demos; `example/tsconfig.json` maps `@example/*` → this folder and `@example-contracts/*` → `../example-contracts` |\n| `example/run.ts` | End-to-end script: `createDecoder`, raw `eth_call`, short-string reverts (`npm run example` after generate) |\n| `example/viem_run.ts` | Same contracts via `viem` + `errorDecoder()` (`npx tsx example/viem_run.ts`) |\n| `tests/e2e.test.ts` | Vitest: Foundry `out/` + `SHORT_STRING_ERROR_CODES` on `Error(string)` (`_shortStringDescription`) |\n| `example-contracts/` | Sample Foundry project (`ProtocolErrorCodes.sol` in a `library`, `FileLevelErrorCodes.sol` at file scope) |\n\n**Generate example artifacts (from repo root):** run `forge build` in `example-contracts/`, then `npm run build && npm run example:generate`. That runs `generate:short-codes` (writes `example/generated/shortStringCodes.ts`) and the main `generate` command (error ABI + contract ABIs/bytecode). Then `npm run example` or `npx tsx example/viem_run.ts`.\n\n### CLI: generate `SHORT_STRING_ERROR_CODES`\n\nSupported Solidity shapes (scanner walks the whole file):\n\n- **File-level:** `string constant Name = \"A1\";` (after `pragma`)\n- **Library / contract:** `string internal|public|private constant Name = \"A1\";`\n\nMerge multiple files (e.g. library in one file, file-level codes in another) with a **comma-separated** `--input`:\n\n```bash\nnpx error-decoder generate-short-codes \\\n  --input ./contracts/LibraryCodes.sol,./contracts/FileLevelCodes.sol \\\n  --output ./src/generated/shortStringCodes.ts\n```\n\n```bash\nnpx error-decoder generate-short-codes \\\n  --input ./contracts/ProtocolErrorCodes.sol \\\n  --output ./src/generated/shortStringCodes.ts\n```\n\nIn this repository, `npm run generate:short-codes` merges **`example-contracts/src/ProtocolErrorCodes.sol`** (library) and **`example-contracts/src/FileLevelErrorCodes.sol`** (file-level) into **`example/generated/shortStringCodes.ts`**.\n\nThis writes a module that exports `SHORT_STRING_ERROR_CODES` (short code → constant name). Regenerate whenever the `.sol` file(s) change.\n\n### Use with `createDecoder`\n\n```ts\nimport {\n\tcreateDecoder,\n\tcreateShortStringResolver,\n} from \"@abiregistry/error-decoder\";\nimport { SHORT_STRING_ERROR_CODES } from \"./generated/shortStringCodes.js\";\n// In this repo’s example: `from \"@example/generated/shortStringCodes.js\"` (see example/tsconfig.json)\n\nconst decoder = createDecoder({\n\tfoundryOut: \"./out\",\n\tresolveShortStringMessage: createShortStringResolver(SHORT_STRING_ERROR_CODES),\n});\n```\n\n### Viem plugin\n\n```ts\nimport { errorDecoder } from \"@abiregistry/error-decoder/viem\";\nimport { createShortStringResolver } from \"@abiregistry/error-decoder\";\nimport { SHORT_STRING_ERROR_CODES } from \"./generated/shortStringCodes.js\";\n\nconst plugin = errorDecoder({\n\terrorAbis: [ERROR_ABI],\n\tresolveShortStringMessage: createShortStringResolver(SHORT_STRING_ERROR_CODES),\n});\n```\n\nWhen a builtin `Error(string)` message matches a key in your map, decoding adds `_shortStringDescription`, and formatters append a `[short: …]` line.\n\n### Low-level API\n\n`decodeRevertData(data, registry, { resolveShortStringMessage })` accepts the same optional resolver.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}