Skip to main content

Try it Live

Run Hex examples in the interactive playground

Overview

Hex provides type-safe hex string primitives for Ethereum development. Unlike byte-array primitives, Hex values are branded 0x${string} types that preserve the string representation while providing compile-time type safety.
WASM performance note: Hex string conversions and lightweight helpers (toBytes, toNumber, toBigInt, toBoolean, concat/slice/pad, and toHex() from other primitives) rarely benefit from WASM. The JS↔WASM call overhead typically outweighs the work, and JavaScript built-ins for string/number formatting are already very fast. Prefer the default JS entrypoint for these operations; use WASM for compute-heavy tasks like Keccak256 hashing, ABI/RLP encoding/decoding, or elliptic-curve crypto.Voltaire’s WASM implementations optimize for a balance of performance and bundle size. If you need maximum performance, build from source with the performance-optimized WASM target. See /dev/build-system#typescript-targets and /dev/wasm#build-modes.
import type { brand } from './brand.js'

// Base unsized hex type
export type HexType = `0x${string}` & { readonly [brand]: "Hex" }

// Sized hex with specific byte count
export type Sized<TSize extends number = number> = `0x${string}` & {
  readonly [brand]: "Hex"
  readonly size: TSize
}

// Alias for Sized
export type Bytes<N extends number> = Sized<N>
Hex is a branded template literal type. TypeScript enforces type safety through a unique Symbol brand, preventing accidental mixing with regular strings while maintaining zero runtime overhead.

Quick Start

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

// Create from string or bytes
const hex = Hex('0x1234');
const fromBytes = Hex.fromBytes(new Uint8Array([0x12, 0x34]));

// Convert to bytes
const bytes = Hex.toBytes(hex); // Uint8Array([0x12, 0x34])

// Check size
console.log(Hex.size(hex)); // 2

// Validate hex string
console.log(Hex.isHex('0x1234')); // true
console.log(Hex.isHex('1234'));   // false (missing 0x)

API Methods

Constructors

Conversions

Validation

Manipulation

Comparison


Constructors

Hex Constructor

Create a hex value from a string or bytes.
import { Hex } from '@tevm/voltaire/Hex';

const hex = Hex('0x1234');
const fromBytes = Hex(new Uint8Array([0x12, 0x34]));

fromBytes

Convert a Uint8Array to hex string.
const hex = Hex.fromBytes(new Uint8Array([0x12, 0x34])); // '0x1234'

fromNumber

Convert a number to hex with optional size padding.
Hex.fromNumber(255);     // '0xff'
Hex.fromNumber(255, 2);  // '0x00ff'
Hex.fromNumber(0x1234);  // '0x1234'
Numbers must be non-negative safe integers. For values larger than Number.MAX_SAFE_INTEGER, use Hex.fromBigInt().

fromBigInt

Convert a bigint to hex with optional size padding.
Hex.fromBigInt(255n);      // '0xff'
Hex.fromBigInt(255n, 32);  // 32-byte hex (64 chars + 0x)

fromBoolean

Convert a boolean to single-byte hex.
Hex.fromBoolean(true);   // '0x01'
Hex.fromBoolean(false);  // '0x00'

random

Generate cryptographically random hex of specified size.
const random32 = Hex.random(32); // Random 32-byte hex

zero

Create zero-filled hex of specified size.
Hex.zero(4);  // '0x00000000'
Hex.zero(32); // 32 zero bytes

Conversions

toBytes

Convert hex to Uint8Array.
const bytes = Hex.toBytes(Hex('0x1234'));
// Uint8Array([0x12, 0x34])
Throws InvalidFormatError if missing 0x prefix or contains invalid characters. Throws InvalidLengthError if hex has odd number of digits.

toNumber

Convert hex to JavaScript number.
Hex.toNumber(Hex('0xff'));   // 255
Hex.toNumber(Hex('0x1234')); // 4660

toBigInt

Convert hex to bigint.
Hex.toBigInt(Hex('0xff'));   // 255n
Hex.toBigInt(Hex('0x' + 'ff'.repeat(32))); // Large number

toBoolean

Convert hex to boolean.
Hex.toBoolean(Hex('0x01')); // true
Hex.toBoolean(Hex('0x00')); // false

Validation

isHex

Check if a string is valid hex format.
Hex.isHex('0x1234');   // true
Hex.isHex('1234');     // false (no prefix)
Hex.isHex('0xZZZZ');   // false (invalid chars)
Hex.isHex('0x');       // false (empty)

validate

Validate and return typed hex, throws on invalid input.
const hex = Hex.validate('0x1234'); // HexType
Hex.validate('invalid'); // throws InvalidFormatError

isSized

Check if hex has specific byte size (type guard).
const hex = Hex('0x1234');
if (Hex.isSized(hex, 2)) {
  // hex is Sized<2>
}

assertSize

Assert hex has specific byte size, returns sized type.
const hex = Hex('0x1234');
const sized = Hex.assertSize(hex, 2); // Sized<2>
Hex.assertSize(hex, 4); // throws InvalidLengthError

Manipulation

concat

Concatenate multiple hex strings.
Hex.concat(
  Hex('0x12'),
  Hex('0x34'),
  Hex('0x56')
); // '0x123456'

slice

Slice hex by byte indices.
const hex = Hex('0x123456');
Hex.slice(hex, 1);     // '0x3456' (from byte 1)
Hex.slice(hex, 0, 2);  // '0x1234' (bytes 0-1)
Hex.slice(hex, 1, 2);  // '0x34'   (byte 1 only)

pad

Left-pad hex to target byte size.
Hex.pad(Hex('0x1234'), 4);  // '0x00001234'
Hex.pad(Hex('0x1234'), 1);  // throws (exceeds target)

padRight

Right-pad hex to target byte size.
Hex.padRight(Hex('0x1234'), 4); // '0x12340000'

trim

Remove leading zero bytes.
Hex.trim(Hex('0x00001234')); // '0x1234'
Hex.trim(Hex('0x00000000')); // '0x'

xor

XOR two hex strings of same length.
Hex.xor(Hex('0x12'), Hex('0x34')); // '0x26'
Hex.xor(Hex('0xff'), Hex('0xff')); // '0x00'

clone

Create a copy of a hex string.
const hex1 = Hex('0x1234');
const hex2 = Hex.clone(hex1);
Hex.equals(hex1, hex2); // true

Comparison

equals

Check equality (case-insensitive).
Hex.equals(Hex('0x1234'), Hex('0x1234')); // true
Hex.equals(Hex('0xABCD'), Hex('0xabcd')); // true

size

Get byte size of hex.
Hex.size(Hex('0x1234'));   // 2
Hex.size(Hex('0x'));       // 0
Hex.size(Hex('0x123456')); // 3

Types

type HexType = `0x${string}` & { readonly [brand]: "Hex" }
Base branded hex type. Any length, validated at creation.

Error Handling

Hex operations throw typed errors for invalid inputs. All errors extend base classes from @tevm/voltaire/errors:
import { Hex } from '@tevm/voltaire/Hex';
import {
  InvalidFormatError,
  InvalidCharacterError,
  OddLengthError,
  SizeExceededError,
  InvalidBooleanHexError
} from '@tevm/voltaire/Hex/errors';

try {
  Hex.validate('invalid'); // missing 0x
} catch (e) {
  if (e instanceof InvalidFormatError) {
    console.log(e.name);    // 'InvalidHexFormatError'
    console.log(e.code);    // 'HEX_MISSING_PREFIX'
    console.log(e.value);   // 'invalid'
  }
}

try {
  Hex.validate('0xZZ'); // invalid characters
} catch (e) {
  if (e instanceof InvalidCharacterError) {
    console.log(e.name);  // 'InvalidHexCharacterError'
    console.log(e.code);  // 'HEX_INVALID_CHARACTER'
  }
}

try {
  Hex.pad(Hex('0x1234'), 1); // exceeds target size
} catch (e) {
  if (e instanceof SizeExceededError) {
    console.log(e.name);  // 'HexSizeExceededError'
    console.log(e.code);  // 'HEX_SIZE_EXCEEDED'
  }
}

Error Types

Error Classname PropertyCodeDescription
InvalidFormatErrorInvalidHexFormatErrorHEX_MISSING_PREFIXMissing 0x prefix
InvalidCharacterErrorInvalidHexCharacterErrorHEX_INVALID_CHARACTERNon-hex character found
OddLengthErrorOddLengthHexErrorHEX_ODD_LENGTHOdd number of hex digits
InvalidLengthErrorInvalidHexLengthErrorHEX_INVALID_LENGTHInvalid length
SizeExceededErrorHexSizeExceededErrorHEX_SIZE_EXCEEDEDSize exceeds target
InvalidBooleanHexErrorInvalidBooleanHexErrorHEX_INVALID_BOOLEANInvalid boolean value
NegativeNumberErrorNegativeNumberErrorHEX_NEGATIVE_NUMBERNegative number
UnsafeIntegerErrorUnsafeIntegerErrorHEX_UNSAFE_INTEGERExceeds MAX_SAFE_INTEGER
NonIntegerErrorNonIntegerErrorHEX_NON_INTEGERNon-integer value

Tree-Shaking

Import only what you need for optimal bundle size:
// Import specific functions (tree-shakeable)
import { fromBytes, toBytes, concat } from '@tevm/voltaire/Hex';

const hex = fromBytes(new Uint8Array([0x12, 0x34]));
const bytes = toBytes(hex);
const combined = concat(hex, hex);

// Only these 3 functions included in bundle
Importing from @tevm/voltaire/Hex instead of the main entry point enables tree-shaking. Functions like xor, random, and numeric conversions are excluded if unused.
  • Address - 20-byte Ethereum addresses (uses Hex internally)
  • Bytes - Fixed-size byte arrays
  • Keccak256 - Hash functions that produce hex output

Specification References