eth-trace-inspector
v2.3.6
Published
A zero-config TypeScript library for automatically decoding, tracing, and debugging EVM transactions. Provides human-readable call stacks, event logs, and state changes for any transaction hash across all major EVM networks, even without the contract ABI.
Maintainers
Readme
eth-trace-inspector
A zero-config TypeScript library for automatically decoding, tracing, and debugging EVM transactions. Provides human-readable call stacks, event logs, and state changes for any transaction hash across all major EVM networks, even without the contract ABI.
Features
- 🔍 Automatic ABI Discovery: Fetches contract ABIs from block explorer APIs (Etherscan, Polygonscan, etc.)
- 🧩 ABI Inference: Falls back to 4-byte signature database when official ABIs aren't available
- 📊 Human-Readable Output: Converts raw EVM traces into structured, hierarchical call stacks
- 🎯 Multi-Chain Support: Works with Ethereum, Polygon, BSC, Arbitrum, Optimism, Avalanche, Base, and more
- 🐛 Debug-Friendly: Identifies exactly where transactions revert and provides error messages
- 📝 Flexible Output: Structured JSON for programmatic use or pretty-print for CLI debugging
Installation
npm install eth-trace-inspectorEnvironment Variables
The library supports environment variables for configuration. Copy .env.example to .env and fill in your values:
cp .env.example .envAvailable environment variables:
TEST_TX_HASH- Transaction hash for testingETHERSCAN_API_KEY- Etherscan API key (recommended to avoid rate limits)POLYGONSCAN_API_KEY- Polygonscan API keyBSCSCAN_API_KEY- BSCscan API keyARBISCAN_API_KEY- Arbiscan API keyOPTIMISTIC_ETHERSCAN_API_KEY- Optimistic Etherscan API keySNOWTRACE_API_KEY- Snowtrace API keyBASESCAN_API_KEY- Basescan API keyETH_RPC_URL- Custom Ethereum RPC URLPOLYGON_RPC_URL- Custom Polygon RPC URLBSC_RPC_URL- Custom BSC RPC URLARBITRUM_RPC_URL- Custom Arbitrum RPC URLOPTIMISM_RPC_URL- Custom Optimism RPC URLAVALANCHE_RPC_URL- Custom Avalanche RPC URLBASE_RPC_URL- Custom Base RPC URL
Note: The .env file is gitignored. Use .env.example as a template.
Quick Start
import { inspectTransaction, prettyPrint } from 'eth-trace-inspector';
const report = await inspectTransaction('0x...', {
chainId: 1, // Ethereum mainnet
apiKey: 'your-api-key', // Optional, but recommended for rate limits
});
prettyPrint(report);
const json = JSON.stringify(report, null, 2);
console.log(json);Usage
Basic Usage
import { inspectTransaction } from 'eth-trace-inspector';
const report = await inspectTransaction('0x1234...', {
chainId: 1,
});With Custom RPC Provider
import { JsonRpcProvider } from 'ethers';
import { inspectTransaction } from 'eth-trace-inspector';
const provider = new JsonRpcProvider('https://your-rpc-url.com');
const report = await inspectTransaction('0x1234...', {
provider,
});With Custom ABIs
const report = await inspectTransaction('0x1234...', {
chainId: 1,
customABIs: {
'0xContractAddress': [
],
},
});Options
interface InspectorOptions {
rpcUrl?: string; // Custom RPC URL
provider?: Provider; // Custom ethers provider
chainId?: number; // Chain ID (auto-detected if not provided)
apiKey?: string; // Block explorer API key
includeGasDetails?: boolean; // Include gas usage (default: true)
includeStorageChanges?: boolean; // Include storage changes (default: false)
customABIs?: Record<string, any[]>; // Custom ABIs by address
fetchABI?: boolean; // Attempt ABI fetching (default: true)
useSignatureDatabase?: boolean; // Use 4-byte signature DB (default: true)
}Output Format
The inspectTransaction function returns a TransactionReport object:
interface TransactionReport {
txHash: string;
blockNumber: number;
transactionIndex: number;
from: string;
to: string | null;
value: bigint;
gasPrice: bigint;
gasLimit: bigint;
gasUsed: bigint;
status: boolean;
callStack: DecodedCall[];
events: DecodedEvent[];
revertReason?: string;
chainId: number;
timestamp?: number;
}Decoded Call Structure
interface DecodedCall {
to: string;
functionName: string;
args: any[];
calldata: string;
signature: string;
inferred?: boolean; // true if function name was inferred
gasUsed?: bigint;
value?: bigint;
calls?: DecodedCall[]; // Nested calls
reverted?: boolean;
revertReason?: string;
}Decoded Event Structure
interface DecodedEvent {
address: string;
eventName: string;
args: any[];
data: string;
topics: string[];
signature: string;
inferred?: boolean;
blockNumber: number;
transactionIndex: number;
logIndex: number;
}Supported Networks
- Ethereum Mainnet (1)
- Ethereum Sepolia (11155111)
- Polygon (137)
- BNB Smart Chain (56)
- Arbitrum One (42161)
- Optimism (10)
- Avalanche (43114)
- Base (8453)
Requirements
- Node.js 18+
- An RPC provider that supports
debug_traceTransaction(required for full trace analysis) - Full nodes (Geth, Erigon, etc.)
- Alchemy
- Infura (with tracing enabled)
- Other providers with tracing support
Limitations
- RPC Provider Support: The library requires an RPC provider that supports
debug_traceTransaction. Public RPC endpoints often don't support this method. Consider using:
- A local full node
- Alchemy (supports tracing)
- Infura (with tracing enabled)
- Other specialized providers
ABI Availability: While the library attempts to fetch ABIs automatically, not all contracts have verified source code on block explorers.
Signature Database: The built-in 4-byte signature database is limited. For better coverage, the library attempts to fetch from 4byte.directory, but this requires internet connectivity.
Examples
Inspect a Failed Transaction
const report = await inspectTransaction('0x...', { chainId: 1 });
if (!report.status) {
console.log('Transaction failed!');
console.log('Revert reason:', report.revertReason);
const findRevertedCall = (calls: DecodedCall[]): DecodedCall | null => {
for (const call of calls) {
if (call.reverted) return call;
if (call.calls) {
const nested = findRevertedCall(call.calls);
if (nested) return nested;
}
}
return null;
};
const revertedCall = findRevertedCall(report.callStack);
if (revertedCall) {
console.log('Reverted in:', revertedCall.functionName);
}
}Analyze Event Logs
const report = await inspectTransaction('0x...', { chainId: 1 });
const transfers = report.events.filter(e => e.eventName === 'Transfer');
console.log(`Found ${transfers.length} Transfer events`);
const eventNames = new Set(report.events.map(e => e.eventName));
console.log('Event types:', Array.from(eventNames));Pretty Print Output
import { inspectTransaction, prettyPrint } from 'eth-trace-inspector';
const report = await inspectTransaction('0x...', { chainId: 1 });
prettyPrint(report);This will output a formatted, human-readable report to the console.
API Reference
inspectTransaction(txHash: string, options?: InspectorOptions): Promise<TransactionReport>
Main function to inspect a transaction.
Parameters:
txHash: Transaction hash to inspectoptions: Optional configuration (seeInspectorOptions)
Returns: Promise resolving to TransactionReport
prettyPrint(report: TransactionReport): void
Pretty print a transaction report to the console.
toJSON(report: TransactionReport, pretty?: boolean): string
Convert a transaction report to JSON string.
Parameters:
report: Transaction report to convertpretty: Whether to format JSON with indentation (default: true)
getSummary(report: TransactionReport): string
Get a one-line summary of the transaction report.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
