Skip to main content

Documentation Index

Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt

Use this file to discover all available pages before exploring further.

API Conventions

Consistent API design across all modules.

Naming Conventions

Constructors

PatternUsageExample
Type(value)Primary constructorAddress("0x...")
Type.from(value)Explicit variantAddress.from("0x...")
Type.fromX(value)From specific typeAddress.fromHex("0x...")
// ✅ Preferred - direct call
const addr = Address("0x742d35Cc6634C0532925a3b844Bc9e7595f251e3");

// ✅ Also valid - explicit
const addr = Address.from("0x742d35Cc6634C0532925a3b844Bc9e7595f251e3");

// ✅ Specific format
const addr = Address.fromHex("0x742d35Cc6634C0532925a3b844Bc9e7595f251e3");
const addr = Address.fromBytes(bytes);
const addr = Address.fromPublicKey(pubkey);

Converters

PatternUsageExample
Type.toX(value)Convert to XAddress.toHex(addr)
Type.asX(value)View as X (no copy)Uint256.asBigInt(uint)
// Convert (may allocate)
const hex = Address.toHex(addr);
const bytes = Address.toBytes(addr);
const checksummed = Address.toChecksummed(addr);

// View (no allocation, same underlying data)
const bigint = Uint256.asBigInt(uint);

Predicates

PatternUsageReturns
Type.is(value)Type guardvalue is Type
Type.isValid(value)Validationboolean
Type.isX(value)Specific checkboolean
// Type guard - narrows type
if (Address.is(value)) {
  // value is Address here
}

// Validation - just boolean
if (Address.isValid(input)) {
  const addr = Address(input);  // Safe to construct
}

// Specific checks
if (Address.isChecksum(addr)) { ... }
if (Address.isZero(addr)) { ... }

Comparisons

PatternUsage
Type.equals(a, b)Equality check
Type.compare(a, b)Ordering (-1, 0, 1)
Type.lt(a, b)Less than
Type.gt(a, b)Greater than
// Equality
Address.equals(a, b);  // true/false

// Ordering (for sortable types)
Uint256.compare(a, b);  // -1, 0, or 1
Uint256.lt(a, b);       // a < b
Uint256.gt(a, b);       // a > b

Function Signatures

Input Flexibility

Public functions accept flexible inputs:
// Public API - accepts various inputs
export function toHex(value: AddressInput): Hex {
  return _toHex(from(value));  // Converts internally
}

// AddressInput = Address | Hex | Uint8Array | `0x${string}`

Internal Functions

Internal functions require exact types:
// Internal - requires branded type
export function _toHex(address: Address): Hex {
  // No conversion needed
}

Naming Convention

// Public wrapper (flexible input)
export function toHex(value: AddressInput): Hex;

// Internal (strict input, underscore prefix)
export function _toHex(address: Address): Hex;

Error Handling

Error Types

Each module defines its own error class:
// primitives/Address/errors.ts
export class InvalidAddressError extends Error {
  readonly name = "InvalidAddressError";

  constructor(value: unknown) {
    super(`Invalid address: ${formatValue(value)}`);
  }
}

export class ChecksumMismatchError extends Error {
  readonly name = "ChecksumMismatchError";

  constructor(expected: string, actual: string) {
    super(`Checksum mismatch: expected ${expected}, got ${actual}`);
  }
}

When to Throw

// ✅ Throw on invalid input
export function fromHex(hex: string): Address {
  if (!isValidHex(hex)) {
    throw new InvalidAddressError(hex);
  }
  // ...
}

// ✅ Return boolean for validation
export function isValid(value: unknown): boolean {
  // Never throws
  return typeof value === "string" && isValidHex(value);
}

// ✅ Return null for "try" variants
export function tryFromHex(hex: string): Address | null {
  if (!isValid(hex)) return null;
  return fromHex(hex);
}

Error Messages

// ✅ Clear, actionable message
throw new InvalidAddressError("0x123");
// "Invalid address: 0x123"

// ✅ Truncate long values
throw new InvalidAddressError(veryLongString);
// "Invalid address: 0x742d35Cc6634C0532925a3b8... (truncated)"

// ❌ Vague message
throw new Error("Invalid input");

// ❌ Technical jargon
throw new Error("EIP-55 checksum validation failed for mixed-case input");

Return Types

Branded Types

Always return branded types, not plain arrays:
// ✅ Returns branded type
export function fromHex(hex: string): Address {
  // ...
  return bytes as Address;
}

// ❌ Returns plain Uint8Array
export function fromHex(hex: string): Uint8Array {
  // Loses type safety
}

Immutability

Returned values should be treated as immutable:
const addr = Address.fromHex("0x...");

// ❌ Don't mutate
addr[0] = 0x00;  // Type system doesn't prevent this, but don't do it

// ✅ Create new if needed
const modified = new Uint8Array(addr);
modified[0] = 0x00;

Documentation

JSDoc for .js Files

// toHex.js

/**
 * Convert address to checksummed hex string.
 *
 * @param {import('./AddressType.js').Address} address - The address to convert
 * @returns {string} EIP-55 checksummed hex string
 * @throws {TypeError} If address is not a valid Address
 *
 * @example
 * const hex = toHex(address);
 * // "0x742d35Cc6634C0532925a3b844Bc9e7595f251e3"
 */
export function toHex(address) {
  // ...
}

TypeScript Types in index.ts

// index.ts

/**
 * Convert address to checksummed hex string
 *
 * @example
 * ```ts
 * import * as Address from "@voltaire/primitives/Address";
 *
 * const hex = Address.toHex("0x742d35cc6634c0532925a3b844bc9e7595f251e3");
 * // "0x742d35Cc6634C0532925a3b844Bc9e7595f251e3"
 * ```
 */
export function toHex(value: AddressInput): string {
  return _toHex(from(value));
}

Constants

Named Constants

// constants.ts
export const ZERO_ADDRESS = Address(new Uint8Array(20));
export const MAX_ADDRESS = Address(new Uint8Array(20).fill(0xff));

// Precompile addresses
export const ECRECOVER_ADDRESS = Address.fromHex("0x0000000000000000000000000000000000000001");
export const SHA256_ADDRESS = Address.fromHex("0x0000000000000000000000000000000000000002");

Export in Index

// index.ts
export { ZERO_ADDRESS, MAX_ADDRESS } from "./constants.js";

Module Structure

Standard Exports

Every primitive module exports:
// Type
export type { Address } from "./AddressType.js";

// Constructors
export { from } from "./from.js";
export { from as Address } from "./from.js";
export { fromHex } from "./fromHex.js";
export { fromBytes } from "./fromBytes.js";

// Internal methods
export { toHex as _toHex } from "./toHex.js";
export { equals as _equals } from "./equals.js";

// Public wrappers
export function toHex(value: AddressInput): string { ... }
export function equals(a: AddressInput, b: AddressInput): boolean { ... }

// Predicates
export { is } from "./is.js";
export { isValid } from "./isValid.js";

// Constants
export { ZERO_ADDRESS } from "./constants.js";

Namespace Usage

// User imports as namespace
import * as Address from "@voltaire/primitives/Address";

// All functions available
Address.fromHex("0x...");
Address.toHex(addr);
Address.equals(a, b);
Address.isValid(input);
Address.ZERO_ADDRESS;

Async Conventions

Sync by Default

Most functions are synchronous:
// ✅ Sync - no I/O needed
export function hash(data: Uint8Array): Uint8Array { ... }
export function verify(sig: Signature): boolean { ... }

Async When Required

Use async only for I/O:
// ✅ Async - requires network
export async function fetchAddress(name: string): Promise<Address> {
  const response = await fetch(`https://api.ens.domains/${name}`);
  // ...
}

// ✅ Async - WASM loading
export async function loadWasm(): Promise<void> {
  await WebAssembly.instantiate(wasmBytes);
}

Naming for Async

// Sync version
export function hash(data: Uint8Array): Uint8Array;

// Async version (when both exist)
export async function hashAsync(data: Uint8Array): Promise<Uint8Array>;