SQL UDF
A concise reference for SQL syntax and UDFs used in Amp dataset queries.
Core UDFs
Section titled “Core UDFs”evm_decode()
Section titled “evm_decode()”Decodes Ethereum event log data into a structured format.
Syntax
evm_decode(topic1, topic2, topic3, data, signature_string)Parameters:
topic1, topic2, topic3- Indexed event parameters (or NULL)data- Non-indexed event data from logsignature_string- Event signature with parameter names and types
Returns Struct matching the event signature.
Example
Section titled “Example”evm_decode( l.topic1, l.topic2, l.topic3, l.data, 'Supply(address indexed reserve,address user,address indexed onBehalfOf,uint256 amount,uint16 indexed referral)') AS eventAccess Fields
Section titled “Access Fields”event['reserve']event['amount']event['referral']Signature Patterns
Section titled “Signature Patterns”| Solidity Type | Signature Syntax |
|---|---|
| Address | address, address indexed |
| Unsigned int | uint256, uint128, uint64, uint32, uint16, uint8 |
| Signed int | int256, int128, etc. |
| Boolean | bool |
| String | string |
| Bytes | bytes, bytes32, bytes20 |
| Array | uint256[], address[], uint256[2] (fixed size) |
Notes
- `indexed` parameters appear in topic1/topic2/topic3- Non-indexed parameters appear in data field- Event signature determines which is whichevm_topic()
Section titled “evm_topic()”Computes the keccak256 hash of an event signature.
Syntax:
evm_topic(event_signature)Parameters:
event_signature- Event signature WITHOUT parameter names
Returns 32-byte hash (topic0)
Example
Section titled “Example”WHERE l.topic0 = evm_topic('Transfer(address,address,uint256)')IMPORTANT Rules
- Do NOT include parameter names:
'Transfer(address,address,uint256)' - Do NOT use spaces:
'Transfer(address, address, uint256)' - Match parameter order exactly with contract ABI
Common Event Signatures
Section titled “Common Event Signatures”evm_topic('Transfer(address,address,uint256)')evm_topic('Approval(address,address,uint256)')evm_topic('Swap(address,uint256,uint256,uint256,uint256,address)')evm_topic('Supply(address,address,address,uint256,uint16)')evm_topic('Withdraw(address,address,address,uint256)')arrow_cast()
Section titled “arrow_cast()”Converts values between Apache Arrow types.
Syntax:
arrow_cast(value, 'target_type')Common Conversions
Section titled “Common Conversions”| Use Case | Example |
|---|---|
| Hex to address | arrow_cast(x'1234...', 'FixedSizeBinary(20)') |
| Hex to tx hash | arrow_cast(x'abcd...', 'FixedSizeBinary(32)') |
| Field to address | arrow_cast(l.address, 'FixedSizeBinary(20)') |
| Event field to address | arrow_cast(event['token'], 'FixedSizeBinary(20)') |
| String to uint | arrow_cast(event['amount'], 'UInt64') |
| String to uint256 | Keep as Utf8 (too large for UInt64) |
Address Filter
Section titled “Address Filter”WHERE l.address = arrow_cast(x'1234567890abcdef...', 'FixedSizeBinary(20)')Type Casting in SELECT
Section titled “Type Casting in SELECT”SELECT arrow_cast(event['token0'], 'FixedSizeBinary(20)') AS token0, arrow_cast(event['pair_index'], 'UInt64') AS pair_indexStandard Query Pattern
Section titled “Standard Query Pattern”Basic Event Query
Section titled “Basic Event Query”WITH decoded AS ( SELECT l.block_num, l.timestamp, l.tx_hash, l.log_index, l.address AS contract_address, evm_decode( l.topic1, l.topic2, l.topic3, l.data, 'EventName(param1_type indexed param1_name,param2_type param2_name,...)' ) AS event FROM eth_firehose.logs l WHERE l.address = x'CONTRACT_ADDRESS_HEX' AND l.topic0 = evm_topic('EventName(param1_type,param2_type,...)'))SELECT block_num, timestamp, tx_hash, log_index, contract_address, event['param1_name'] AS param1, event['param2_name'] AS param2FROM decodedSystem adds
_block_numautomatically; do not select it.
Log Fields
Section titled “Log Fields”l.block_num -- UInt64l.timestamp -- Timestamp(Nanosecond, "+00:00")l.tx_hash -- FixedSizeBinary(32)l.log_index -- UInt32l.address -- FixedSizeBinary(20) - contract addressl.topic0 -- Event signature hashl.topic1 -- First indexed parameterl.topic2 -- Second indexed parameterl.topic3 -- Third indexed parameterl.data -- Non-indexed parameters (encoded)Common SELECT Fields
Section titled “Common SELECT Fields”SELECT block_num, -- Always include timestamp, -- Always include tx_hash, -- Always include log_index, -- Always include for uniqueness contract_address, -- Or pool_address, factory_address, etc. event['field1'] AS field1, -- Decoded event fields event['field2'] AS field2FROM decodedFiltering Patterns
Section titled “Filtering Patterns”Single Contract
Section titled “Single Contract”WHERE l.address = x'CONTRACT_HEX' AND l.topic0 = evm_topic('EventName(...)')Multiple Contracts (OR)
Section titled “Multiple Contracts (OR)”WHERE l.address IN ( arrow_cast(x'CONTRACT1_HEX', 'FixedSizeBinary(20)'), arrow_cast(x'CONTRACT2_HEX', 'FixedSizeBinary(20)') ) AND l.topic0 = evm_topic('EventName(...)')Multiple Events (OR)
Section titled “Multiple Events (OR)”WHERE l.address = arrow_cast(x'CONTRACT_HEX', 'FixedSizeBinary(20)') AND l.topic0 IN ( evm_topic('Event1(...)'), evm_topic('Event2(...)') )Filter by Indexed Parameter
Section titled “Filter by Indexed Parameter”WHERE l.address = x'CONTRACT_HEX' AND l.topic0 = evm_topic('Transfer(address,address,uint256)') AND l.topic1 = x'FROM_ADDRESS_HEX'Indexed addresses are 32-byte padded.
Array and Complex Types
Section titled “Array and Complex Types”Fixed-Size Arrays
Section titled “Fixed-Size Arrays”Signature example:
'AddLiquidity(address indexed provider,uint256[2] token_amounts,uint256[2] fees,...)'Access:
event['token_amounts'] -- Returns array as-isevent['fees'] -- Returns array as-isType Safety Tips
Section titled “Type Safety Tips”| Data | Type | Reason |
|---|---|---|
| uint8, uint16, uint32, uint64 | UInt64 | Fits in 64 bits |
| uint128, uint256 | Utf8 | Too large for UInt64 |
| Token amounts | Utf8 | Usually uint256, avoid precision loss |
| Counts, IDs < 2^64 | UInt64 | Safe for integer operations |
| Addresses | FixedSizeBinary(20) | 20 bytes |
| Transaction hashes | FixedSizeBinary(32) | 32 bytes |
Using Decimal Types for Large Numbers
Section titled “Using Decimal Types for Large Numbers”For arithmetic operations on large integers, use Decimal or Double types:
| Solidity Type | Decimal Type | Notes |
|---|---|---|
| uint128 | Decimal128(38,0) | Up to 38 digits |
| uint256 | Decimal256(76,0) | Up to 76 digits |
-- Cast Utf8 to Decimal for arithmeticSELECT arrow_cast(token_amount, 'Decimal256(76,0)') * price AS valueFROM transfersThe 0 scale means no decimal places (integer math).
There is no perfect conversion of Solidity uint256 to Arrow. Decimal256(76,0) preserves full precision, however does not capture the full numeric range of the binary Solidity uint256. Any realistic monetary value will fit in a Decimal256, but if your uint256 is a random identifier it might be best represented as Utf8. FLOAT or DOUBLE can lose precision but may be suitable for aggregations.
Mismatched Signature in decode
Section titled “Mismatched Signature in decode”evm_decode( l.topic1, l.topic2, l.topic3, l.data, 'Supply(address reserve,address user,...)' -- Missing 'indexed')Correct - Match ABI
Section titled “Correct - Match ABI”evm_decode( l.topic1, l.topic2, l.topic3, l.data, 'Supply(address indexed reserve,address user,...)' -- Matches which params are indexed)Incorrect Address Type
Section titled “Incorrect Address Type”WHERE l.address = '0x1234...' -- String literalCorrect Type
Section titled “Correct Type”WHERE l.address = x'1234...'Advanced Patterns
Section titled “Advanced Patterns”Multiple CTEs
Section titled “Multiple CTEs”WITH decoded_supply AS ( SELECT ... FROM eth_firehose.logs l WHERE ...),decoded_withdraw AS ( SELECT ... FROM eth_firehose.logs l WHERE ...)SELECT * FROM decoded_supplyUNION ALLSELECT * FROM decoded_withdrawNested Subqueries
Section titled “Nested Subqueries”SELECT outer_field, transformed_fieldFROM ( SELECT block_num, event['amount'] AS amount, arrow_cast(event['amount'], 'UInt64') AS amount_numeric FROM ( WITH decoded AS (...) SELECT * FROM decoded ))WHERE amount_numeric > 1000Quick Examples
Section titled “Quick Examples”Transfer Event
Section titled “Transfer Event”WITH decoded AS ( SELECT l.block_num, l.timestamp, l.tx_hash, l.log_index, evm_decode( l.topic1, l.topic2, l.topic3, l.data, 'Transfer(address indexed from,address indexed to,uint256 value)' ) AS event FROM eth_firehose.logs l WHERE l.address = x'TOKEN_ADDRESS' AND l.topic0 = evm_topic('Transfer(address,address,uint256)'))SELECT block_num, timestamp, tx_hash, log_index, arrow_cast(event['from'], 'FixedSizeBinary(20)') AS from_address, arrow_cast(event['to'], 'FixedSizeBinary(20)') AS to_address, event['value'] AS valueFROM decodedEvent with Multiple Indexed Parameters
Section titled “Event with Multiple Indexed Parameters”WITH decoded AS ( SELECT l.block_num, l.timestamp, l.tx_hash, l.log_index, evm_decode( l.topic1, l.topic2, l.topic3, l.data, 'Swap(address indexed sender,uint256 amount0In,uint256 amount1In,uint256 amount0Out,uint256 amount1Out,address indexed to)' ) AS event FROM eth_firehose.logs l WHERE l.address = x'PAIR_ADDRESS' AND l.topic0 = evm_topic('Swap(address,uint256,uint256,uint256,uint256,address)'))SELECT block_num, timestamp, tx_hash, log_index, arrow_cast(event['sender'], 'FixedSizeBinary(20)') AS sender, event['amount0In'] AS amount0_in, event['amount1In'] AS amount1_in, event['amount0Out'] AS amount0_out, event['amount1Out'] AS amount1_out, arrow_cast(event['to'], 'FixedSizeBinary(20)') AS to_addressFROM decoded