eth.zig

Comptime Selectors

Function selectors and event topics that work at both compile time and runtime.

eth.zig provides unified keccak.selector() and keccak.hash() functions that work at both compile time and runtime. The caller decides when to evaluate -- the library never restricts you.

Function Selectors

A Solidity function selector is the first 4 bytes of the Keccak-256 hash of the function signature. Use comptime for zero runtime cost:

const eth = @import("eth");

// Evaluated at compile time -- zero runtime cost
const transfer_sel = comptime eth.keccak.selector("transfer(address,uint256)");
// transfer_sel == [4]u8{ 0xa9, 0x05, 0x9c, 0xbb }

const approve_sel = comptime eth.keccak.selector("approve(address,uint256)");
// approve_sel == [4]u8{ 0x09, 0x5e, 0xa7, 0xb3 }

The same function also works at runtime with dynamic strings:

// Runtime -- useful when the signature is only known at runtime
const runtime_sel = eth.keccak.selector(some_signature);

Event Topics

Event topics (used for log filtering) work the same way:

const eth = @import("eth");

const transfer_topic = comptime eth.keccak.hash("Transfer(address,address,uint256)");
// transfer_topic == keccak256("Transfer(address,address,uint256)")

const approval_topic = comptime eth.keccak.hash("Approval(address,address,uint256)");

Why This Matters

ApproachWhen It RunsCost
comptime eth.keccak.selector(...)Compile time0 ns at runtime
eth.keccak.selector(runtime_str)Runtime~128 ns per hash

For hot paths (MEV bots, indexers, high-frequency DeFi), eliminating per-call hashing overhead adds up.

ERC-20 Precomputed Selectors

The ERC-20 wrapper provides all standard selectors as comptime constants:

const selectors = eth.erc20.selectors;

selectors.name;          // name()
selectors.symbol;        // symbol()
selectors.decimals;      // decimals()
selectors.totalSupply;   // totalSupply()
selectors.balanceOf;     // balanceOf(address)
selectors.transfer;      // transfer(address,uint256)
selectors.approve;       // approve(address,uint256)
selectors.allowance;     // allowance(address,address)
selectors.transferFrom;  // transferFrom(address,address,uint256)

Custom Selectors

Define selectors for any contract function:

const eth = @import("eth");

// UniswapV2 Router
const swap_sel = comptime eth.keccak.selector(
    "swapExactTokensForTokens(uint256,uint256,address[],address,uint256)"
);

// Aave V3 Pool
const supply_sel = comptime eth.keccak.selector(
    "supply(address,uint256,address,uint16)"
);

// Any custom function
const my_sel = comptime eth.keccak.selector(
    "myFunction(uint256,bytes32,bool)"
);