跳转至

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 search
  • topics: a list of up through four 32-byte values; indexed for search
  • data: 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