Agnostic data decoding: EVM ABIs and Stellar Formats
Agnostic data decoding uses ClickHouse user-defined functions for EVM ABI payloads and Stellar formats. EVM transaction calldata and event logs require different decoders because they carry parameters in different layouts. Use evm_decode_calldata for call input and evm_decode_event for log topics and data. An ABI, or application binary interface, supplies the types needed to interpret those bytes. The decoder choice follows the record format; the signature description must also match the contract interface responsible for that record.
Record Formats and Decoder Inputs
A raw record's format determines the decoder and its inputs; ABI-encoded contract parameters also require the applicable ABI. Agnostic's ch-stellar includes stellar_xdr_decode and stellar_strkey_decode for Stellar formats. XDR, or External Data Representation, encodes ledger and transaction structures; StrKey represents addresses and other identifiers. The corresponding installed function must support the input's type and representation.
Agnostic's EVM toolset also lists
evm_decode_call
for calls and
ethereum_decode_tx
for transaction parsing. Serialized transaction bytes concern the enclosing transaction format; ABI decoding concerns contract parameters within a call. For successful ABI calls, return data uses the function's output types. Revert data may encode an error and its parameters. Transaction envelopes, call inputs, call outputs, and event logs therefore require distinct interpretations. For an event, supply its topics and data alongside candidate event descriptions. Successful event decoding exposes the matched signature and parameter values in the function's response.
Selectors and ABI Descriptions
ABI descriptions identify parameter types and their order; event descriptions also specify which arguments use topics.
Function Selectors
An ABI function selector consists of the first four bytes of the Keccak-256 hash of its canonical signature. Calldata then carries encoded arguments. Return types do not participate in that selector. Different function signatures can share selector bytes, so a lookup can yield several candidates. The called contract's interface and argument layout determine which candidate applies. A selector match alone does not establish the contract's identity or the meaning of its parameters.
Event Fullsigs
An event's canonical signature captures its name and parameter types, leaving out the indexed modifiers. Agnostic's
fullsig
descriptions retain indexed placement so the event decoder can separate topic values from data values. Two event declarations can share a canonical signature while assigning indexed parameters differently. A signature dictionary can supply several candidate descriptions, while the emitting contract's ABI establishes which declaration applies. Keep each candidate associated with the contract interface it represents.
The Go event interface also accepts references to JSON ABI documents as decoder inputs. A fullsig keeps its declaration directly in the query. A remote ABI document introduces a retrieval dependency: document reachability and contents affect which descriptions the decoder can obtain. This option belongs to the Go interface; availability in another build depends on that build's supported decoder inputs.
Hex Text and Binary Arguments
Hexadecimal text and raw bytes are different representations even when they describe the same payload. The Go event interface expects topics as
Array(FixedString(32)), event data as
String, and decoder descriptions as
Array(String). The 32 specifies bytes in each binary topic, rather than printed characters. Agnostic's
evm_hex_decode
converts hexadecimal input before decoding; a type cast alone does not convert its characters into raw bytes. Columns already storing binary strings do not need that conversion. Preserve topic order because indexed parameter positions follow that order.
Validate topic lengths before forcing a fixed-width type, because ClickHouse can pad shorter strings with null bytes.
Decoded Values and Execution Context
A successful decode interprets the supplied bytes under the chosen ABI; transaction execution and contract identity require their own context.
Result Structure
The Go
evm_decode_event
interface returns a JSON
Result
envelope, with decoded fields inside
value. Its
signature
field identifies the matched event signature, and
inputs
holds the parameters. Unnamed arguments can appear under positional keys such as
arg0. Agnostic's Rust-based
ch-evm
also includes event decoding. Its JSON interface can differ from the Go implementation, so extraction expressions must fit the installed response. Inspect the decoded object before converting its parameters into persistent columns, preserving any decoding error separately from successful values.
Integer Values and Record Identity
Decoded integers may appear as decimal strings in JSON. Preserve their exact values until the query chooses a compatible numeric type. ClickHouse's
UInt256
can represent an ABI
uint256
value, while
UInt64
cannot cover that full range. Signed parameters require signed interpretation. Floating-point conversion can lose integer precision. SQL queries can use extracted fields to filter or group records, with measurement units coming from the contract's meaning.
Keep the network, contract address, block reference, and transaction or log position beside decoded fields. Proxy upgrades can change the implementation a stable address uses, so historical rows may need historical ABI context. Calldata describes the supplied function and arguments; it does not prove execution completed successfully. A transaction receipt's status records the overall transaction outcome when that field exists. The receipt's status, decoded input parameters, and returned output values describe different parts of the interaction.
Can an Indexed String Be Recovered From Its Topic?
An indexed ABI string parameter contributes a Keccak-256 hash of its special in-place encoding to the log topic; the topic alone cannot recover the original text. Arrays, dynamic bytes, and tuples also have hashed indexed representations. A contract can expose the text by emitting it in a non-indexed parameter as well. A complete ABI explains that layout; it cannot supply plaintext the event omits. Access to a readable copy depends on the data the contract actually emits.
Correcting an Event Description's Indexed Placement
A mismatched indexed modifier changes where a decoder expects to find an event parameter. Consider a hypothetical, complete log from a non-anonymous event with an indexed address parameter and a non-indexed
uint256
parameter. Assume the applicable contract ABI confirms this layout and the Go event decoder is installed. The selected dictionary entry omits the address parameter's indexed modifier.
The first decode fails because its description expects both values in the data payload. Correct the event declaration to mark the address as indexed, then pass the unchanged topics, data, and corrected candidate to
evm_decode_event.
The corrected call returns a decoded
value
containing the event signature and an
inputs
object. The address now comes from its topic, and the integer comes from data. Comparing these fields with the known ABI confirms the intended parameter order. The corrected description applies to this log's layout.
An upgrade changing this event's indexed placement would invalidate the description for new logs. Associate the corrected entry with the contract and block range its ABI covers. Historical logs retain their earlier layout even if a later implementation changes the event declaration.
Installed UDFs and Prepared Columns
Decoder availability depends on the functions registered in the connected ClickHouse environment. An executable UDF configuration declares its command, argument types, return type, and data exchange format. Agnostic distributes binaries with registration files and SQL functions in bundles. Its Go and Rust implementations can differ in data transport and result structure. Keep the binary and function configuration from the same implementation together. An installed function name alone does not establish the arguments or output format its binary expects.
Prepared event and call collections already expose decoded parameter columns. Agnostic's v1 event schema combines parameter position and derived type in input column names; its v1 call schema also has output columns. Those collections provide a stored representation, while decoder functions interpret raw payloads during a query. Existing decoded fields suit analysis when their ABI context and types fit the question. Retaining raw bytes permits later reinterpretation when a description changes or a stored representation lacks a needed field.
Agnostic data decoding questions worth asking
-
Does Decoding Stored Calldata Require a Wallet Signature?
- Decoding calldata already available to a query does not require a wallet signature. The operation interprets existing bytes using an ABI description inside the database environment. Signing authorizes a blockchain transaction, which is a separate action. Database access permissions still govern who can read the stored records and execute the query.
-
Which Resources Determine the Cost of Decoding Stored Rows?
- Decoding stored rows consumes database processing resources, including CPU time and memory. The row volume, parameter complexity, executable function configuration, and query shape affect the work involved. Parsing bytes does not itself submit a gas-paying transaction. Charges for a hosted database or other infrastructure depend on the deployment and its billing terms.
-
How Do Anonymous Events Change Signature Lookup?
- Anonymous events omit the event-signature hash from their topic list. A lookup treating the first topic as that hash therefore cannot identify them through the ordinary signature route. Their indexed parameters still occupy topics. Decoding requires the correct anonymous event description and an implementation supporting that layout; generic EVM compatibility does not establish that support.
-
Can an Event Have Empty Data and Still Contain Parameters?
- An event can legitimately have empty data when all its parameters are indexed. Its topics then carry the indexed representations, and a non-anonymous event also includes its signature hash. Empty data alone therefore does not establish an incomplete log. The event declaration determines whether any non-indexed arguments should appear in the data payload.
-
Do Agnostic's v1 Collection Limits Define the Maximum ABI Size?
- Agnostic's v1 collection limits describe those stored schemas, rather than every ABI or decoder implementation. The v1 event collection documents support for up to 12 inputs. The v1 call collection documents up to 12 inputs and 3 outputs. These limits do not establish a universal ceiling for raw ABI decoding; compatibility depends on the selected decoder's supported types and interface.
-
What Does an Overloaded Function Change About Decoder Selection?
- An overloaded function requires the decoder to distinguish declarations sharing a name through their parameter types. The canonical signature includes those types in order, so selecting only the function name leaves the input layout unresolved. Return types do not disambiguate the function selector. Use the declaration matching the call's selector, argument layout, and applicable contract ABI.
-
Is an Empty JSONExtractString Result Proof of a Decode Error?
- An empty JSONExtractString result does not prove the decoder failed. ClickHouse also returns an empty string when the requested string field does not exist. A wrong extraction path can therefore resemble an empty value. JSONHas can check field presence, while the decoder's own response determines whether decoding succeeded. Interpret both within the installed implementation's result structure.
-
Are Token Transfer Parameters the Same as Transaction Value?
- Token transfer parameters and transaction value describe different quantities. A transfer argument belongs to the token contract's interface, while transaction value records native currency attached to the transaction. The ABI integer type alone does not establish display units. Token-scale conversion requires the relevant token's unit convention, and neither field substitutes for the other.