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

# Type-Safe Ethereum Values

> Prevent denomination confusion and type mixing with compile-time safety

Voltaire uses distinct types for Ethereum values that other libraries treat as generic `bigint` or `string`. This prevents bugs that have caused real financial losses.

## The Problem

Consider this ethers.js code:

```typescript theme={null}
// ethers/viem: Everything is bigint
const gasPrice = 20000000000n;  // Is this wei? gwei? ether?
const value = 1000000000000000000n;  // 1 ETH? or 1 wei?

// Easy to make mistakes
await wallet.sendTransaction({
  to: recipient,
  value: 1n,  // Oops! Sent 1 wei instead of 1 ETH
  gasPrice: gasPrice  // Hope the units are right...
});
```

This code compiles and runs. The bug won't be caught until someone loses funds.

## The Solution

Voltaire makes denomination a type-level concern:

```typescript theme={null}
import { Wei, Gwei, Ether } from '@tevm/voltaire'

const gasPrice = Gwei(20n);
const value = Ether(1n);

// Type error: GweiType is not assignable to WeiType
const wrong: WeiType = gasPrice;

// Explicit conversion required
const correct: WeiType = Gwei.toWei(gasPrice);
```

If you have a `WeiType`, you *know* it's in wei. The type system enforces it.

## Beyond Denominations

The same pattern applies to other Ethereum concepts that look similar but aren't interchangeable:

### Address vs Hash

Both are hex strings. Both are fixed-size bytes. But mixing them is always a bug:

```typescript theme={null}
import { Address, Hash } from '@tevm/voltaire'

const addr = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e');
const txHash = Hash('0x' + 'ab'.repeat(32));

// Type error: HashType is not assignable to AddressType
function transfer(to: AddressType) { /* ... */ }
transfer(txHash);  // Caught at compile time
```

### Numeric Types

Block numbers, chain IDs, and nonces are all numbers—but semantically distinct:

```typescript theme={null}
import { BlockNumber, ChainId, Nonce } from '@tevm/voltaire'

const block = BlockNumber(12345678n);
const chain = ChainId(1);
const nonce = Nonce(42n);

// These won't compile
const badChain: ChainIdType = block;  // Type error
const badNonce: NonceType = chain;    // Type error
```

### Crypto Types

Private keys, public keys, and signatures have critical security implications:

```typescript theme={null}
import { PrivateKey, PublicKey, Signature } from '@tevm/voltaire'

const privateKey = PrivateKey('0x...');
const publicKey = PublicKey.fromPrivateKey(privateKey);
const signature = Secp256k1.sign(messageHash, privateKey);

// Type system prevents dangerous operations
function logData(data: PublicKeyType) {
  console.log(data.toHex());  // Safe to log
}
logData(privateKey);  // Type error - PrivateKey is not PublicKey
```

## Comparison with Other Libraries

| Operation    | ethers.js | viem          | Voltaire                              |
| ------------ | --------- | ------------- | ------------------------------------- |
| Gas price    | `bigint`  | `bigint`      | `GweiType` or `WeiType`               |
| ETH value    | `bigint`  | `bigint`      | `WeiType`, `GweiType`, or `EtherType` |
| Address      | `string`  | `0x${string}` | `AddressType` (Uint8Array)            |
| Hash         | `string`  | `0x${string}` | `HashType` (Uint8Array)               |
| Block number | `number`  | `bigint`      | `BlockNumberType`                     |

The difference: Voltaire catches misuse at compile time. Other libraries catch it at runtime (or not at all).

## Parse, Don't Validate

Once you have a typed value, it's guaranteed valid. This enables a powerful pattern:

```typescript theme={null}
// Business logic doesn't need validation
function calculateFee(gasPrice: GweiType, gasUsed: Uint256Type): WeiType {
  // No validation needed - types guarantee valid inputs
  const priceInWei = Gwei.toWei(gasPrice);
  return Wei(priceInWei * gasUsed);
}

// Validation happens at the boundary
function handleUserInput(input: string): WeiType {
  // Throws if invalid - validation happens once
  const gwei = Gwei(input);
  return Gwei.toWei(gwei);
}
```

This is the "parse, don't validate" philosophy: validate at system boundaries, then work with guaranteed-valid types throughout your code.

## All Typed Values

| Category      | Types                                                             |
| ------------- | ----------------------------------------------------------------- |
| Denominations | `WeiType`, `GweiType`, `EtherType`                                |
| Identifiers   | `AddressType`, `HashType`, `TransactionHashType`, `BlockHashType` |
| Numbers       | `BlockNumberType`, `ChainIdType`, `NonceType`, `GasLimitType`     |
| Crypto        | `PrivateKeyType`, `PublicKeyType`, `SignatureType`                |
| Bytes         | `Bytes1` through `Bytes32`, `Bytes64`, `BlobType`                 |
| Integers      | `Uint8` through `Uint256`, `Int8` through `Int256`                |

## Learn More

<CardGroup cols={2}>
  <Card title="Branded Types" icon="tag" href="/concepts/branded-types">
    How the type system implements these guarantees
  </Card>

  <Card title="Denomination" icon="coins" href="/primitives/denomination">
    Complete Wei/Gwei/Ether API reference
  </Card>
</CardGroup>
