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

# toBytes

> Convert CallData to Uint8Array

Returns the underlying Uint8Array representation of CallData. Zero-copy operation that provides access to raw bytes.

## Signature

<Tabs>
  <Tab title="Namespace">
    ```typescript theme={null}
    function toBytes(calldata: CallDataType): Uint8Array
    ```
  </Tab>

  <Tab title="Class">
    ```typescript theme={null}
    calldata.toBytes(): Uint8Array
    ```
  </Tab>
</Tabs>

## Parameters

* **calldata** - CallData instance to convert

## Returns

`Uint8Array` - Raw byte array (shares underlying buffer)

## Examples

<Tabs>
  <Tab title="Basic Usage">
    ```typescript theme={null}
    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, ...]
    ```
  </Tab>

  <Tab title="Zero-Copy">
    ```typescript theme={null}
    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
    ```
  </Tab>

  <Tab title="Class API">
    ```typescript theme={null}
    import { CallData } from '@tevm/voltaire';

    const calldata = CallData("0xa9059cbb");
    const bytes = calldata.toBytes(); // Method on instance

    console.log(bytes.length); // 4
    ```
  </Tab>
</Tabs>

## Zero-Copy Behavior

`toBytes` returns the same underlying buffer:

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

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

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

### Performance-Critical Operations

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

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

## Performance

`toBytes` is effectively zero-cost:

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

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

<Tabs>
  <Tab title="Defensive Copy">
    ```typescript theme={null}
    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)
    ```
  </Tab>

  <Tab title="Direct Access">
    ```typescript theme={null}
    // Direct access (faster but mutable)
    const bytes = CallData.toBytes(calldata);

    // DANGER: Mutations affect original
    bytes[0] = 0xff;
    console.log(CallData.toHex(calldata));
    // "0xff059cbb..." (modified!)
    ```
  </Tab>
</Tabs>

For public APIs, consider returning copies to maintain immutability guarantees.

## Type Safety

Output is plain Uint8Array (no CallData brand):

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

<Tabs>
  <Tab title="When to use toBytes">
    **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
  </Tab>

  <Tab title="When to use toHex">
    **Advantages:**

    * Human-readable
    * JSON-RPC compatible
    * Standard Ethereum format
    * Logging/debugging

    **Use for:**

    * Display to users
    * JSON serialization
    * RPC calls
    * Block explorers
  </Tab>
</Tabs>

## Related

* [toHex](/primitives/calldata/to-hex) - Convert to hex string
* [fromBytes](/primitives/calldata/from-bytes) - Create from Uint8Array
* [getSelector](/primitives/calldata/get-selector) - Extract selector bytes
* [equals](/primitives/calldata/equals) - Compare calldata instances
