UNPKG

@bcoders.gr/abi-codec

Version:

High-performance ABI encoding/decoding for Ethereum with receipt log processing - now supports tuple decoding

226 lines (170 loc) 5.82 kB
# High-Performance ABI Codec A blazing-fast Node.js module for encoding/decoding Ethereum ABI data compatible with Geth. Optimized for maximum performance with zero-copy Buffer operations. ## Features - ✅ **Function encoding/decoding** - All Solidity types supported - ✅ **Event log decoding** - Individual logs and full receipts - ✅ **Receipt processing** - Decode all matching logs from transaction receipts - ✅ **Maximum performance** - Direct Buffer operations, minimal hex conversions - ✅ **Geth compatibility** - 100% compatible with Ethereum node outputs - ✅ **Minimal dependencies** - Only ethers.js utils for keccak256 ## Installation ```bash npm install ``` ## Quick Start ```javascript const { ABICodec } = require('./index'); // Your contract ABI const contractABI = [ { "type": "function", "name": "transfer", "inputs": [ {"name": "to", "type": "address"}, {"name": "amount", "type": "uint256"} ], "outputs": [{"name": "success", "type": "bool"}] }, { "type": "event", "name": "Transfer", "inputs": [ {"name": "from", "type": "address", "indexed": true}, {"name": "to", "type": "address", "indexed": true}, {"name": "value", "type": "uint256", "indexed": false} ] } ]; const codec = new ABICodec(contractABI); ``` ## API Reference ### Function Encoding/Decoding ```javascript // Encode function call const calldata = codec.encodeFunction('transfer', [ '0x742d35Cc6634C0532925a3b8D8e9eED89B7A6de6', BigInt('1000000000000000000') ]); // Decode function call const params = codec.decodeFunction('transfer', calldata); // Returns: ['0x742d35Cc6634C0532925a3b8D8e9eED89B7A6de6', 1000000000000000000n] // Decode function result const result = codec.decodeFunctionResult('transfer', '0x0000...0001'); // Returns: [true] ``` ### Event Log Decoding ```javascript // Decode single event log const decodedLog = codec.decodeLog(logData, topics, 'Transfer'); // Returns: { name: 'Transfer', args: { from: '0x...', to: '0x...', value: 1000n } } // Decode all logs from a transaction receipt const decodedLogs = codec.decodeReceiptLogs(receipt); // Returns: Array of decoded logs that match ABI events // Decode multiple receipts at once const allLogs = codec.decodeMultipleReceipts([receipt1, receipt2, receipt3]); // Filter logs by event name const transferLogs = codec.filterLogsByEvent(decodedLogs, 'Transfer'); ``` ### Utility Functions ```javascript // Get function selector (4-byte signature) const selector = codec.getFunctionSelector('transfer'); // Returns: '0xa9059cbb' // Get event selector (32-byte topic hash) const eventTopic = codec.getEventSelector('Transfer'); // Returns: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' // Get all event topics this codec can decode const knownTopics = codec.getKnownEventTopics(); // Returns: ['0xddf252...', '0x8c5be1...', ...] ``` ## Supported Types | Solidity Type | Supported | Notes | |---------------|-----------|-------| | `uint8` to `uint256` | ✅ | Including `uint` (defaults to `uint256`) | | `int8` to `int256` | ✅ | Including `int` (defaults to `int256`) | | `bool` | ✅ | | | `address` | ✅ | | | `bytes1` to `bytes32` | ✅ | Fixed-size byte arrays | | `bytes` | ✅ | Dynamic byte arrays | | `string` | ✅ | UTF-8 encoded | | `uint256[]` | ✅ | Dynamic arrays | | `uint256[5]` | ✅ | Fixed-size arrays | | `tuple` | 🔄 | Coming soon (structs) | ## Performance Benchmarked on typical hardware: - **10,000 function encodings**: ~96ms (0.0096ms per encoding) - **1,000 receipt decodings**: ~12ms (0.012ms per receipt) - **Zero-copy operations** where possible for maximum speed ## Real-World Usage ### Processing Transaction Receipts ```javascript // Process multiple transaction receipts function processTransactions(receipts, codec) { const results = { totalLogs: 0, decodedLogs: 0, events: {} }; for (const receipt of receipts) { results.totalLogs += receipt.logs?.length || 0; const decoded = codec.decodeReceiptLogs(receipt); results.decodedLogs += decoded.length; // Count events by type decoded.forEach(log => { results.events[log.name] = (results.events[log.name] || 0) + 1; }); } return results; } const stats = processTransactions(receipts, codec); console.log(\`Decoded \${stats.decodedLogs}/\${stats.totalLogs} logs\`); ``` ### Event Filtering and Analysis ```javascript // Get all Transfer events from multiple receipts const allLogs = codec.decodeMultipleReceipts(receipts); const transfers = codec.filterLogsByEvent(allLogs, 'Transfer'); // Analyze transfer patterns const transferAnalysis = transfers.map(log => ({ from: log.args.from, to: log.args.to, amount: log.args.value, blockNumber: log.blockNumber, txHash: log.transactionHash })); ``` ## Error Handling The codec throws descriptive errors for invalid inputs: ```javascript try { const result = codec.encodeFunction('unknownFunction', []); } catch (error) { console.error('Function not found:', error.message); } try { const result = codec.decodeReceiptLogs(invalidReceipt); } catch (error) { console.error('Invalid receipt format:', error.message); } ``` ## Testing Run the test suite: ```bash # Basic functionality tests node test/basic.test.js # Receipt decoding tests node test/receipt.test.js # Usage examples node example.js node receipt-example.js ``` ## License MIT ## Contributing This module is optimized for performance. When contributing: 1. Maintain zero-copy Buffer operations where possible 2. Avoid unnecessary hex string conversions 3. Pre-compile and cache expensive operations 4. Add performance benchmarks for new features --- Built for maximum performance with Ethereum/Geth compatibility in mind. 🚀