Function decoding transforms raw transaction calldata into structured, typed rows. When configured, the pipeline matches each transaction’s input data against ABI function signatures and produces decoded rows in {chain_name}_fn_{function_name} tables.
How It Works
- The normalizer produces rows for the
transactions table, each containing an input_data field (hex-encoded calldata)
- The decoder matches the first 4 bytes of
input_data (the function selector) against ABI function entries
- Parameters are decoded from
input_data[4:] using ABI type definitions
- Each decoded call is emitted to a
{chain_name}_fn_{function_name_snake_case} table
Only function ABI entries with stateMutability of nonpayable or payable are used. View and pure functions are excluded since they do not appear in transaction calldata.
Output Schema
Each decoded function table includes envelope columns from the source transaction plus the ABI-defined parameters:
| Column | Type | Source |
|---|
block_height | UINT64 | From transactions envelope |
block_signed_at | TIMESTAMP | From transactions envelope |
tx_hash | STRING | From transactions envelope |
tx_offset | UINT32 | From transactions envelope |
from_address | STRING | From transactions envelope |
to_address | STRING | From transactions envelope |
value | STRING | From transactions envelope |
gas_limit | UINT64 | From transactions envelope |
receipt_status | STRING | From transactions envelope |
| (ABI parameters) | (mapped type) | Decoded from calldata |
Example
For an ERC-20 transfer function call on Base:
function transfer(address to, uint256 amount) external returns (bool);
The output table base_fn_transfer would contain:
| Column | Type |
|---|
block_height | UINT64 |
block_signed_at | TIMESTAMP |
tx_hash | STRING |
tx_offset | UINT32 |
from_address | STRING |
to_address | STRING |
value | STRING |
gas_limit | UINT64 |
receipt_status | STRING |
to | STRING |
amount | STRING |
Configuration
Function decoding is activated by setting the abi section in your pipeline config and using a transactions topic entity:
topic: "base.mainnet.ref.block.transactions"
abi:
path: "/etc/pipeline-api/erc20.json"
contract_addresses:
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
unmatched: "skip"
Contract address filtering matches against the to_address field (the contract being called).
When to Use Function Decoding vs Event Decoding
| Event Decoding | Function Decoding |
|---|
| Source | logs topic entity | transactions topic entity |
| Decodes | Emitted event logs | Transaction calldata |
| Output tables | {chain_name}_evt_{name} | {chain_name}_fn_{name} |
| Best for | Tracking state changes, transfers, approvals | Analyzing what functions were called and with what parameters |
| Includes failed txs | No (failed txs don’t emit events) | Yes (calldata exists even if tx reverted) |
Most use cases are better served by event decoding. Use function decoding when you specifically need to analyze calldata - for example, tracking MEV bot calls, analyzing governance proposals, or monitoring specific function invocations regardless of success.