Skip to main content

EventSignature

An EventSignature is a 32-byte identifier used as the first topic (topic[0]) in Ethereum event logs. It’s computed as the full Keccak-256 hash of the event signature.

Type Definition

const primitives = @import("primitives");
// EventSignature is a 32-byte array: [32]u8
const EventSignature = primitives.EventSignature.EventSignature;

Creating Event Signatures

From Signature String

const primitives = @import("primitives");
const topic = primitives.EventSignature.fromSignature(
    "Transfer(address,address,uint256)",
);
const hex = primitives.EventSignature.toHex(topic);
// 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

From Hex String

const primitives = @import("primitives");
const sig = try primitives.EventSignature.fromHex(
    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
);

From Bytes

const primitives = @import("primitives");
var bytes: [32]u8 = [_]u8{0} ** 32;
const sig = try primitives.EventSignature.fromBytes(&bytes);

Operations

Convert to Hex

const primitives = @import("primitives");
const hex = primitives.EventSignature.toHex(sig); // "0xddf252ad..."

Compare Signatures

const primitives = @import("primitives");
const e1 = primitives.EventSignature.fromSignature("Transfer(address,address,uint256)");
const e2 = primitives.EventSignature.fromSignature("Approval(address,address,uint256)");
const equal = primitives.EventSignature.equals(e1, e2); // false

Common Event Signatures

ERC-20

const primitives = @import("primitives");
const transfer = primitives.EventSignature.fromSignature(
    "Transfer(address,address,uint256)",
);
// 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

const approval = primitives.EventSignature.fromSignature(
    "Approval(address,address,uint256)",
);
// 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925

ERC-721

// Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
const transfer = EventSignature.fromSignature('Transfer(address,address,uint256)');
// Same signature as ERC-20 Transfer!

// Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)
const approval = EventSignature.fromSignature('Approval(address,address,uint256)');
// Same signature as ERC-20 Approval!

Uniswap V2

const primitives = @import("primitives");
const swap = primitives.EventSignature.fromSignature(
    "Swap(address,uint256,uint256,uint256,uint256,address)",
);
// 0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822

Event Log Structure

Event signatures appear as the first topic in event logs:
const primitives = @import("primitives");
const Hash = @import("primitives").Hash.Hash;

const topic0 = primitives.EventSignature.fromSignature(
    "Transfer(address,address,uint256)",
);

var log = primitives.EventLog.EventLog{
    .address = try primitives.Address.fromHex("0x0000000000000000000000000000000000000000"),
    .topics = &[_]Hash{ topic0 },
    .data = &[_]u8{},
    .block_number = null,
    .transaction_hash = null,
    .transaction_index = null,
    .log_index = null,
    .removed = false,
};

Signature Format

Event signatures must use canonical type names: ✅ Correct:
  • Transfer(address,address,uint256)
  • Swap(address,uint256,uint256,uint256,uint256,address)
  • Deposit(address,(uint256,uint256))
❌ Incorrect:
  • Transfer(address, address, uint256) (has spaces)
  • Transfer(address,address,uint) (should be uint256)
  • transfer(address,address,uint256) (wrong capitalization)
Note: Unlike function signatures, event names conventionally start with uppercase.

How Event Signatures Work

  1. Event Signature: Start with the canonical event signature
  2. Hash: Compute keccak256(signature)
  3. Use Full Hash: Unlike function selectors, use all 32 bytes
Transfer(address,address,uint256)
  ↓ keccak256
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
  ↓ (no truncation)
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

Indexed vs Non-Indexed Parameters

Event parameters can be indexed or non-indexed:
event Transfer(
  address indexed from,   // topic[1]
  address indexed to,     // topic[2]
  uint256 value           // data
);
The signature does not include the indexed keyword:
  • Signature: Transfer(address,address,uint256)
  • The indexed keyword only affects where data appears in the log

Anonymous Events

Anonymous events don’t include the event signature as topic[0]:
event Transfer(
  address indexed from,
  address indexed to,
  uint256 value
) anonymous;
For anonymous events:
  • No topic[0] (no event signature)
  • Indexed params use topic[0], topic[1], topic[2]…
  • Saves gas but harder to identify the event

Filtering Events

Use event signatures to filter logs:
const primitives = @import("primitives");
const topic0 = primitives.EventSignature.toHex(
    primitives.EventSignature.fromSignature("Transfer(address,address,uint256)"),
);
// Use topic0 in eth_getLogs filter:
// {"method":"eth_getLogs","params":[{"address":"0x...","topics":[topic0]}]}

API Reference

Constructors

  • fromBytes(bytes: []const u8) !EventSignature - Create from bytes
  • fromHex(hex: []const u8) !EventSignature - Create from hex string
  • fromSignature(signature: []const u8) EventSignature - Compute from event signature

Operations

  • toHex(sig: EventSignature) [66]u8 - Convert to hex string
  • equals(a: EventSignature, b: EventSignature) bool - Compare signatures

See Also