Skip to main content

Try it Live

Run Keccak256 examples in the interactive playground
Future Plans: This page is planned and under active development. Examples are placeholders and will be replaced with accurate, tested content.

Ethereum Methods

Specialized Keccak256 methods for Ethereum protocol operations: function selectors, event topics, and contract address derivation (CREATE/CREATE2).

selector(signature)

Compute function selector (first 4 bytes of Keccak256 hash). Signature:
function selector(signature: string): Uint8Array
Parameters:
  • signature (string) - Function signature (e.g., "transfer(address,uint256)")
Returns: Uint8Array (4 bytes) - Function selector Throws: Never throws for valid signature string
import { Keccak256 } from '@tevm/voltaire/Keccak256';

const selector = Keccak256.selector('transfer(address,uint256)');
// Uint8Array(4) [0xa9, 0x05, 0x9c, 0xbb]

console.log(selector.length); // 4
Technical Notes:
  • Returns first 4 bytes of Keccak256.hashString(signature)
  • Signature format: functionName(type1,type2,...) (no spaces, no param names)
  • Canonical types required: uint256 not uint, address not address payable
  • Case-sensitive - Transfertransfer
Signature normalization critical:
  • "transfer(address,uint256)" - Correct
  • "transfer(address, uint256)" - Space causes different selector
  • "transfer(address to, uint256 amount)" - Param names cause different selector
  • "transfer(address,uint)" - Use canonical uint256

topic(signature)

Compute event topic (32-byte Keccak256 hash). Signature:
function topic(signature: string): Keccak256Hash
Parameters:
  • signature (string) - Event signature (e.g., "Transfer(address,address,uint256)")
Returns: Keccak256Hash (32 bytes) - Event topic hash Throws: Never throws for valid signature string
import { Keccak256 } from '@tevm/voltaire/Keccak256';

const topic = Keccak256.topic('Transfer(address,address,uint256)');
// Uint8Array(32) [full 32-byte hash]

console.log(topic.length); // 32
Technical Notes:
  • Returns full 32 bytes (unlike selector which returns 4 bytes)
  • Used as topics[0] in Ethereum event logs
  • Indexed event parameters become additional topics (topics[1], topics[2], etc.)
  • Non-indexed parameters in log data field
Event Log Structure:
interface Log {
  topics: string[];  // [topic0=eventHash, topic1=indexed1, topic2=indexed2, ...]
  data: string;      // ABI-encoded non-indexed parameters
}

contractAddress(sender, nonce)

Compute contract address from deployer and nonce (CREATE opcode). Signature:
function contractAddress(sender: Uint8Array, nonce: bigint): Uint8Array
Parameters:
  • sender (Uint8Array) - Deployer address (20 bytes)
  • nonce (bigint) - Transaction nonce
Returns: Uint8Array (20 bytes) - Contract address Throws:
  • InvalidLengthError - Sender not 20 bytes
import { Keccak256 } from '@tevm/voltaire/Keccak256';
import { Address } from '@tevm/voltaire/Address';

const deployer = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e');
const nonce = 5n;

const contractAddr = Keccak256.contractAddress(deployer, nonce);
console.log(contractAddr.length); // 20
Algorithm:
address = keccak256(rlp([sender, nonce]))[12:]
Technical Notes:
  • Formula defined in Ethereum Yellow Paper
  • RLP encoding: [sender, nonce] where sender is 20 bytes, nonce is minimal big-endian
  • Last 20 bytes of hash become contract address
  • Nonce increments with each transaction from sender
  • Deterministic - same sender + nonce always produces same address

create2Address(deployer, salt, initCodeHash)

Compute contract address using CREATE2 opcode (EIP-1014). Signature:
function create2Address(
  deployer: Uint8Array,
  salt: Uint8Array,
  initCodeHash: Uint8Array
): Uint8Array
Parameters:
  • deployer (Uint8Array) - Deployer address (20 bytes)
  • salt (Uint8Array) - 32-byte salt
  • initCodeHash (Uint8Array) - 32-byte hash of initialization code
Returns: Uint8Array (20 bytes) - Contract address Throws:
  • InvalidLengthError - Deployer not 20 bytes
  • InvalidLengthError - Salt not 32 bytes
  • InvalidLengthError - initCodeHash not 32 bytes
import { Keccak256 } from '@tevm/voltaire/Keccak256';
import { Address } from '@tevm/voltaire/Address';
import { Bytes32 } from '@tevm/voltaire/Bytes32';
import { Bytecode } from '@tevm/voltaire/Bytecode';

const deployer = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e');
const salt = Bytes32('0x0000000000000000000000000000000000000000000000000000000000000001');
const initCode = Bytecode('0x60806040...');
const initCodeHash = Keccak256.hash(initCode);

const contractAddr = Keccak256.create2Address(deployer, salt, initCodeHash);
console.log(contractAddr.length); // 20
Algorithm:
address = keccak256(0xff ++ deployer ++ salt ++ keccak256(initCode))[12:]
Technical Notes:
  • Defined in EIP-1014
  • Enables deterministic deployment independent of nonce
  • Same deployer + salt + initCode always produces same address
  • 0xff prefix distinguishes from CREATE (prevents collision)
  • initCode hashed separately (allows large bytecode)
  • Commonly used for counterfactual instantiation, proxy factories
Comparison with CREATE:
FeatureCREATECREATE2
Depends on nonceYesNo
Depends on initCodeIndirectly (via nonce)Yes (hashed)
PredictableRequires knowing nonceAlways predictable
RedeployableNo (nonce increments)No (same address)
Use caseNormal deploymentCounterfactual, upgradeable proxies

Usage Examples

Full Contract Deployment Flow

import { Keccak256 } from '@tevm/voltaire/Keccak256';
import { Address } from '@tevm/voltaire/Address';
import { Bytes32 } from '@tevm/voltaire/Bytes32';
import { Bytecode } from '@tevm/voltaire/Bytecode';

// 1. Predict CREATE address
const deployer = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e');
const currentNonce = await provider.getTransactionCount(deployer);
const createAddr = Keccak256.contractAddress(deployer, BigInt(currentNonce));

// 2. Predict CREATE2 address
const factory = Address('0x4e59b44847b379578588920ca78fbf26c0b4956c');
const salt = Bytes32('0x0000000000000000000000000000000000000000000000000000000000000001');
const initCode = Bytecode('0x60806040...');
const initCodeHash = Keccak256.hash(initCode);
const create2Addr = Keccak256.create2Address(factory, salt, initCodeHash);

console.log('CREATE address:', createAddr);
console.log('CREATE2 address:', create2Addr);

Function Call Decoding

import { Keccak256 } from '@tevm/voltaire/Keccak256';
import { Hex } from '@tevm/voltaire/Hex';

// Decode transaction calldata
const calldata = '0xa9059cbb000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000de0b6b3a7640000';

// Extract selector
const selector = calldata.slice(0, 10);

// Compare with known selectors
const transferSel = Hex.fromBytes(Keccak256.selector('transfer(address,uint256)'));

if (selector === transferSel) {
  console.log('This is a transfer call');
  // Decode parameters from calldata.slice(10)
}

Event Log Processing

import { Keccak256 } from '@tevm/voltaire/Keccak256';
import { Hex } from '@tevm/voltaire/Hex';

// Process Transfer event logs
const transferTopic = Hex.fromBytes(
  Keccak256.topic('Transfer(address,address,uint256)')
);

const logs = await provider.getLogs({
  topics: [transferTopic],
  fromBlock: 0,
  toBlock: 'latest'
});

for (const log of logs) {
  console.log('Transfer event:');
  console.log('From:', log.topics[1]); // indexed from address
  console.log('To:', log.topics[2]);   // indexed to address
  console.log('Amount:', log.data);    // non-indexed amount
}