Event logs
Smart contracts can emit events when certain operations happen, e.g., an ERC-20 token transfer. In Solidity, the event
and emit
keywords are used for this purpose. The compiler then transforms emit
instances to one of the LOG*
opcodes: LOG0
, LOG1
, LOG2
, LOG3
, or LOG4
. These opcodes solely differ by the number of indexed
topics. To enable interoperability between smart contracts written in different programming languages or compiled using different versions, the smart contract ABI specification defines how events should be mapped to LOG*
opcodes.
LOG* opcodes
LOG*
opcodes operate on a simple structure consisting of:
address
: the address that's using the opcode; indexed for searchtopics
: a list of up through four 32-byte values; indexed for searchdata
: arbitrary data of arbitrary length; not indexed
When using Solidity, the smart contract ABI applies to all topics
and data
values, and topics[0]
is implicitly set to keccak(event_signature)
over the event name and all argument types (including non-indexed arguments), unless the event
is marked as anonymous
. External databases can be consulted to reverse look up event signatures by their hash.
Note that smart contracts are not required to follow the ABI. For example, this transaction packs data more compactly into a LOG0
opcode using the assembly
keyword; with ABI encoding, the data length would be a multiple of 32, increasing gas cost but simplifying interoperability with other smart contracts. The ethereum.org documentation currently does not mention this possibility.
eth_getLogs
Logs that have been emitted can be queried using the eth_getLogs
JSON-RPC API. The API supports filtering by address
and indexed topics
. For the topics
, the filter is positional, meaning that separate calls are needed to query matches for topics[0]
, topics[1]
, topics[2]
and topics[3]
. Further, for both the address
and each of the topics
, the query can either specify an individual string or an array of strings. Each result will match the individual string or one of the array items at every position. If an empty array is specified, it is treated as a wildcard for that position; this allows searching for matches in later topic positions while ignoring earlier ones.
For example, this filter:
address in [
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"0x4200000623d0242cccd4e907008583dcb4af6472",
] and topics[1] in [
"0x00000000000000000000000066a9893cc07d91d95644aedd05d03f95e1dba8af",
"0x000000000000000000000000001087bc197aa40bb0c6893112fec044e32156c4",
] and topics[2] == (
"0x00000000000000000000000066a9893cc07d91d95644aedd05d03f95e1dba8af"
)
can be queried using:
curl "https://docs-demo.quiknode.pro" \
-X POST -H "Content-Type: application/json" --data @- <<EOF | jq .
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_getLogs",
"params": [
{
"address": [
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"0x4200000623d0242cccd4e907008583dcb4af6472"
],
"topics": [
[],
[
"0x00000000000000000000000066a9893cc07d91d95644aedd05d03f95e1dba8af",
"0x000000000000000000000000001087bc197aa40bb0c6893112fec044e32156c4"
],
"0x00000000000000000000000066a9893cc07d91d95644aedd05d03f95e1dba8af"
],
"blockHash": "0xd8cb79ef9860a7a7f16558270786ca8c58c4b8bf0807f604a1887717064374ad"
}
]
}
EOF