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.
Returns the underlying Uint8Array representation of CallData. Zero-copy operation that provides access to raw bytes.
Signature
function toBytes(calldata: CallDataType): Uint8Array
calldata.toBytes(): Uint8Array
Parameters
- calldata - CallData instance to convert
Returns
Uint8Array - Raw byte array (shares underlying buffer)
Examples
Basic Usage
Zero-Copy
Class API
import { CallData } from '@tevm/voltaire';
const calldata = CallData("0xa9059cbb...");
const bytes = CallData.toBytes(calldata);
console.log(bytes);
// Uint8Array(68) [169, 5, 156, 187, 0, 0, ...]
import { CallData } from '@tevm/voltaire';
const calldata = CallData.fromBytes(
new Uint8Array([0xa9, 0x05, 0x9c, 0xbb])
);
const bytes = CallData.toBytes(calldata);
// Same underlying buffer (zero-copy)
console.log(bytes.buffer === calldata.buffer); // true
import { CallData } from '@tevm/voltaire';
const calldata = CallData("0xa9059cbb");
const bytes = calldata.toBytes(); // Method on instance
console.log(bytes.length); // 4
Zero-Copy Behavior
toBytes returns the same underlying buffer:
import { CallData } from '@tevm/voltaire';
const original = new Uint8Array([0xa9, 0x05, 0x9c, 0xbb]);
const calldata = CallData.fromBytes(original);
const bytes = CallData.toBytes(calldata);
// All share same buffer
console.log(original.buffer === calldata.buffer); // true
console.log(calldata.buffer === bytes.buffer); // true
// Mutations visible across all views
bytes[0] = 0xff;
console.log(original[0]); // 0xff
console.log(calldata[0]); // 0xff
Important: Mutating bytes affects the original CallData.
Use Cases
Binary Protocols
import { CallData } from '@tevm/voltaire';
// Send over WebSocket
async function sendBinary(ws: WebSocket, calldata: CallDataType) {
const bytes = CallData.toBytes(calldata);
ws.send(bytes); // Direct binary transmission
}
// Receive and parse
ws.onmessage = (event) => {
const bytes = new Uint8Array(event.data);
const calldata = CallData.fromBytes(bytes);
};
File Operations
import { CallData } from '@tevm/voltaire';
import { writeFileSync } from 'fs';
// Write calldata to file
function saveCallData(calldata: CallDataType, path: string) {
const bytes = CallData.toBytes(calldata);
writeFileSync(path, bytes);
}
// Read from file
function loadCallData(path: string): CallDataType {
const buffer = readFileSync(path);
return CallData.fromBytes(new Uint8Array(buffer));
}
import { CallData } from '@tevm/voltaire';
// Extract selector without string conversion
function fastGetSelector(calldata: CallDataType): Uint8Array {
const bytes = CallData.toBytes(calldata);
return bytes.slice(0, 4); // Direct byte access
}
// Compare calldata
function fastEquals(a: CallDataType, b: CallDataType): boolean {
const bytesA = CallData.toBytes(a);
const bytesB = CallData.toBytes(b);
if (bytesA.length !== bytesB.length) return false;
for (let i = 0; i < bytesA.length; i++) {
if (bytesA[i] !== bytesB[i]) return false;
}
return true;
}
WASM Interop
import { CallData } from '@tevm/voltaire';
import { wasmModule } from './crypto.wasm';
// Pass bytes to WASM
function hashCallData(calldata: CallDataType): Uint8Array {
const bytes = CallData.toBytes(calldata);
// WASM operates on byte arrays
return wasmModule.keccak256(bytes);
}
toBytes is effectively zero-cost:
// Benchmark: 10M iterations
const calldata = CallData("0xa9059cbb...");
console.time("toBytes");
for (let i = 0; i < 10_000_000; i++) {
CallData.toBytes(calldata);
}
console.timeEnd("toBytes");
// ~50ms (just pointer return, no copy)
Compare with toHex:
console.time("toHex");
for (let i = 0; i < 10_000_000; i++) {
CallData.toHex(calldata);
}
console.timeEnd("toHex");
// ~1200ms (hex encoding overhead)
toBytes is ~24x faster than toHex for this workload.
Immutability Considerations
While CallData is conceptually immutable, toBytes exposes mutable buffer:
Defensive Copy
Direct Access
import { CallData } from '@tevm/voltaire';
// Create immutable copy
function toBytesCopy(calldata: CallDataType): Uint8Array {
const bytes = CallData.toBytes(calldata);
return new Uint8Array(bytes); // Copy
}
// Safe: Mutations don't affect original
const calldata = CallData("0xa9059cbb");
const copy = toBytesCopy(calldata);
copy[0] = 0xff;
console.log(calldata[0]); // 0xa9 (unchanged)
// Direct access (faster but mutable)
const bytes = CallData.toBytes(calldata);
// DANGER: Mutations affect original
bytes[0] = 0xff;
console.log(CallData.toHex(calldata));
// "0xff059cbb..." (modified!)
For public APIs, consider returning copies to maintain immutability guarantees.
Type Safety
Output is plain Uint8Array (no CallData brand):
import { CallData, type CallDataType } from '@tevm/voltaire';
const calldata: CallDataType = CallData("0xa9059cbb");
const bytes: Uint8Array = CallData.toBytes(calldata);
// Cannot use as CallData without constructor
const calldata2: CallDataType = bytes; // ❌ Type error
const calldata3: CallDataType = CallData.fromBytes(bytes); // ✅
Comparison with toHex
When to use toBytes
When to use toHex
Advantages:
- Zero-copy (24x faster)
- Binary protocols (WebSocket, files)
- WASM interop
- Direct byte manipulation
Use for:
- Performance-critical paths
- Binary I/O
- Cryptographic operations
- Memory-efficient processing
Advantages:
- Human-readable
- JSON-RPC compatible
- Standard Ethereum format
- Logging/debugging
Use for:
- Display to users
- JSON serialization
- RPC calls
- Block explorers