> ## 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

> Naming conventions, error handling, and API design patterns

# API Conventions

Consistent API design across all modules.

## Naming Conventions

### Constructors

| Pattern             | Usage               | Example                    |
| ------------------- | ------------------- | -------------------------- |
| `Type(value)`       | Primary constructor | `Address("0x...")`         |
| `Type.from(value)`  | Explicit variant    | `Address.from("0x...")`    |
| `Type.fromX(value)` | From specific type  | `Address.fromHex("0x...")` |

```typescript theme={null}
// ✅ 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

| Pattern           | Usage               | Example                  |
| ----------------- | ------------------- | ------------------------ |
| `Type.toX(value)` | Convert to X        | `Address.toHex(addr)`    |
| `Type.asX(value)` | View as X (no copy) | `Uint256.asBigInt(uint)` |

```typescript theme={null}
// 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

| Pattern               | Usage          | Returns         |
| --------------------- | -------------- | --------------- |
| `Type.is(value)`      | Type guard     | `value is Type` |
| `Type.isValid(value)` | Validation     | `boolean`       |
| `Type.isX(value)`     | Specific check | `boolean`       |

```typescript theme={null}
// 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

| Pattern              | Usage               |
| -------------------- | ------------------- |
| `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        |

```typescript theme={null}
// 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:

```typescript theme={null}
// 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:

```typescript theme={null}
// Internal - requires branded type
export function _toHex(address: Address): Hex {
  // No conversion needed
}
```

### Naming Convention

```typescript theme={null}
// 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:

```typescript theme={null}
// 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

```typescript theme={null}
// ✅ 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

```typescript theme={null}
// ✅ 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:

```typescript theme={null}
// ✅ 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:

```typescript theme={null}
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

```javascript theme={null}
// 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

````typescript theme={null}
// 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

```typescript theme={null}
// 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

```typescript theme={null}
// index.ts
export { ZERO_ADDRESS, MAX_ADDRESS } from "./constants.js";
```

## Module Structure

### Standard Exports

Every primitive module exports:

```typescript theme={null}
// 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

```typescript theme={null}
// 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:

```typescript theme={null}
// ✅ 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:

```typescript theme={null}
// ✅ 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

```typescript theme={null}
// Sync version
export function hash(data: Uint8Array): Uint8Array;

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