eth-event-decoder
v1.0.0
Published
Type-safe Ethereum event log decoder with ABI-to-TypeScript codegen
Downloads
151
Maintainers
Readme
eth-event-decoder
Type-safe Ethereum event log decoder with ABI-to-TypeScript codegen.
A minimal, production-ready library for decoding raw Ethereum event logs into strongly-typed objects — with zero boilerplate. Includes a CLI that generates TypeScript type definitions from any Solidity ABI.
Why?
Every backend that reads Ethereum events does the same tedious work: parse ABI, match topics, decode logs, cast types. eth-event-decoder does it in one line with full TypeScript type safety and no runtime dependencies beyond ethers.
Prerequisites
- Node.js
>= 18 - ethers
^6.0.0(peer dependency)
Installation
npm install eth-event-decoder
# ethers is a peer dep — install it if you haven't already
npm install ethersQuick Start
import { EventDecoder, BatchDecoder, buildEventFilter } from 'eth-event-decoder';
import { JsonRpcProvider } from 'ethers';
// 1. Create a decoder with your contract ABIs
const decoder = new EventDecoder({
contracts: {
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': [
'event Transfer(address indexed from, address indexed to, uint256 value)',
'event Approval(address indexed owner, address indexed spender, uint256 value)',
],
},
});
// 2. Decode a full transaction receipt
const provider = new JsonRpcProvider('https://eth.llamarpc.com');
const batch = new BatchDecoder(decoder, provider);
const events = await batch.fromTransaction('0x...');
for (const event of events) {
console.log(`${event.name}: ${event.args.from} → ${event.args.to}: ${event.args.value}`);
}
// 3. Build a filtered getLogs query
const filter = buildEventFilter(
['event Transfer(address indexed from, address indexed to, uint256 value)'],
'Transfer',
{ from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' }, // exact match
{ fromBlock: 18_000_000, toBlock: 18_001_000 },
);
const logs = await provider.getLogs(filter);
const decoded = decoder.decodeLogs(logs);API Reference
EventDecoder
Core decoder class. Takes a DecoderConfig and decodes ethers.Log objects.
const decoder = new EventDecoder({
contracts: {
// Key = contract address (checksummed or lowercase) or any name
'0xA0b8...': ['event Transfer(address indexed from, address indexed to, uint256 value)'],
},
ignoreUnknown: true, // default: true — silently skip unrecognised logs
});| Method | Returns | Description |
|--------|---------|-------------|
| decode<T>(log) | DecodedEvent<T> \| null | Decode a single log |
| decodeLogs<T>(logs) | DecodedEvent<T>[] | Decode an array, filtering nulls |
| getEventDescriptors() | EventDescriptor[] | List all registered events |
DecodedEvent<T>
{
name: string; // "Transfer"
signature: string; // "Transfer(address,address,uint256)"
topic: string; // "0xddf252ad..."
args: T; // Typed arguments
log: {
blockNumber: number;
blockHash: string;
transactionHash: string;
logIndex: number;
address: string;
removed: boolean;
};
}BatchDecoder
Batch-decode events from transaction receipts or block ranges.
const batch = new BatchDecoder(decoder, provider);| Method | Returns | Description |
|--------|---------|-------------|
| fromTransaction<T>(txHash) | Promise<DecodedEvent<T>[]> | Decode all events in a tx |
| fromBlockRange<T>(from, to, addresses?) | Promise<DecodedEvent<T>[]> | Decode a block range |
| stream<T>(from, to, batchSize?, addresses?) | AsyncGenerator<DecodedEvent<T>[]> | Stream in chunks |
// Stream 1,000-block chunks over a large range
for await (const events of batch.stream(18_000_000, 19_000_000)) {
process(events);
}buildEventFilter
Build a topic filter object for provider.getLogs.
const filter = buildEventFilter(
abi,
'Transfer',
{ from: '0x...' }, // exact match
{ address: '0x...', fromBlock: 18_000_000, toBlock: 18_001_000 },
);Indexed args support three modes:
- Exact:
{ from: '0x...' }— match one address - OR:
{ from: ['0xA...', '0xB...'] }— match any of the addresses - Wildcard:
{ from: null }(or omit) — match all
generateEventTypes
Generate TypeScript type definitions from an ABI.
import { generateEventTypes } from 'eth-event-decoder';
import { writeFileSync } from 'fs';
const types = generateEventTypes(erc20Abi, 'ERC20');
writeFileSync('./types/erc20-events.ts', types);Output sample:
// Auto-generated by eth-event-decoder
// Do not edit manually
import type { DecodedEvent } from 'eth-event-decoder';
export interface ERC20TransferArgs {
from: string; // indexed
to: string; // indexed
value: bigint;
}
export type ERC20TransferEvent = DecodedEvent<ERC20TransferArgs>;parseAbiFile
Read an ABI from a JSON file (Hardhat artifact or plain array format).
import { parseAbiFile } from 'eth-event-decoder';
const abi = parseAbiFile('./artifacts/contracts/ERC20.sol/ERC20.json');CLI — Type Generation
# Generate TypeScript event types from any ABI file
npx eth-event-types --abi ./abis/ERC20.json --name ERC20 --out ./types/erc20-events.ts| Flag | Required | Description |
|------|----------|-------------|
| --abi, -a | ✓ | Path to ABI JSON file |
| --name, -n | ✓ | Contract name prefix (e.g., ERC20) |
| --out, -o | ✓ | Output .ts file path |
The CLI accepts both Hardhat artifact format ({ abi: [...] }) and plain ABI arrays.
Development
git clone https://github.com/ChainPrimitives/eth-event-decoder
cd eth-event-decoder
npm install
npm run build # Compile → dist/
npm run test # Run all tests (Vitest)
npm run test:coverage # Coverage with v8 (80%+ target)
npm run lint # tsc --noEmit
npm run clean # Remove dist/ and coverage/Contributing
Contributions are welcome!
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/eth-event-decoder - Branch:
git checkout -b feat/my-feature - Make changes and ensure tests pass:
npm run lint && npm run test - Commit (Conventional Commits):
feat: add support for tuple types - Push and open a Pull Request against
main
Guidelines
- Tests are required for all new features
- TypeScript strict mode — no untyped
anycasts - Keep PRs focused — one feature or fix per PR
- Update the README if CLI or API behavior changes
- For security issues, email [email protected] directly
Changelog
v1.0.0
- 🚀 Initial release
EventDecoder— single log and batch log decodingBatchDecoder— fromTransaction, fromBlockRange, stream (async generator)buildEventFilter— topic filters with exact, OR, and wildcard modesgenerateEventTypes— ABI → TypeScript type codegenparseAbiFile— Hardhat artifact + plain array ABI supporteth-event-typesCLI for standing-alone type generation- GitHub Actions CI — Node 18/20/22
License
MIT © 2026 Subaskar Sivakumar
