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

# AccessList

> EIP-2930 access lists for gas optimization in Ethereum transactions

Access lists (EIP-2930) specify which addresses and storage slots a transaction will access, enabling gas savings by pre-warming these locations before execution.

## Overview

AccessList is a [branded](/getting-started/branded-types) array type representing EIP-2930 access lists. Each entry contains a contract address and the storage keys that will be accessed at that address.

<Tabs>
  <Tab title="Type Definition">
    ```typescript theme={null}
    export type Item = {
      address: AddressType;
      storageKeys: readonly HashType[];
    };

    export type BrandedAccessList = readonly Item[] & {
      readonly __brand?: typeof accessListSymbol;
    };
    ```
  </Tab>

  <Tab title="Gas Constants">
    ```typescript theme={null}
    // EIP-2930 costs
    ADDRESS_COST = 2400n;           // Per address in access list
    STORAGE_KEY_COST = 1900n;       // Per storage key in access list

    // Cold access costs (without access list)
    COLD_ACCOUNT_ACCESS_COST = 2600n;
    COLD_STORAGE_ACCESS_COST = 2100n;

    // Warm access cost (after first access)
    WARM_STORAGE_ACCESS_COST = 100n;
    ```
  </Tab>
</Tabs>

## Quick Start

<Tabs>
  <Tab title="Create Access List">
    ```typescript theme={null}
    import * as AccessList from '@tevm/voltaire/AccessList';
    import * as Address from '@tevm/voltaire/Address';
    import * as Hash from '@tevm/voltaire/Hash';

    // Create empty access list
    const empty = AccessList.create();

    // Create from items
    const list = AccessList.from([
      {
        address: Address("0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e"),
        storageKeys: [
          Hash("0x0000000000000000000000000000000000000000000000000000000000000001"),
          Hash("0x0000000000000000000000000000000000000000000000000000000000000002"),
        ]
      }
    ]);
    ```
  </Tab>

  <Tab title="Calculate Gas Savings">
    ```typescript theme={null}
    import * as AccessList from '@tevm/voltaire/AccessList';

    const list = AccessList.from([
      { address, storageKeys: [key1, key2] }
    ]);

    // Calculate total access list cost
    const cost = AccessList.gasCost(list);
    // = ADDRESS_COST + (2 * STORAGE_KEY_COST)
    // = 2400n + 3800n = 6200n

    // Calculate net savings vs cold access
    const savings = AccessList.gasSavings(list);
    // Savings per address: 2600n - 2400n = 200n
    // Savings per key: 2100n - 1900n = 200n
    // Total: 200n + (2 * 200n) = 600n

    // Check if access list is beneficial
    if (AccessList.hasSavings(list)) {
      // Include access list in transaction
    }
    ```
  </Tab>

  <Tab title="Build Incrementally">
    ```typescript theme={null}
    import * as AccessList from '@tevm/voltaire/AccessList';

    let list = AccessList.create();

    // Add addresses
    list = AccessList.withAddress(list, contractAddress);
    list = AccessList.withAddress(list, tokenAddress);

    // Add storage keys for specific address
    list = AccessList.withStorageKey(list, contractAddress, slot0);
    list = AccessList.withStorageKey(list, contractAddress, slot1);

    // Merge multiple access lists
    const merged = AccessList.merge(list1, list2, list3);
    ```
  </Tab>
</Tabs>

## API Reference

### Constructors

| Method                 | Description                             |
| ---------------------- | --------------------------------------- |
| `create()`             | Create empty access list                |
| `from(items \| bytes)` | Create from array of items or RLP bytes |
| `fromBytes(bytes)`     | Decode from RLP-encoded bytes           |

### Gas Calculation

| Method             | Description                             |
| ------------------ | --------------------------------------- |
| `gasCost(list)`    | Total gas cost of access list itself    |
| `gasSavings(list)` | Net gas savings vs cold access          |
| `hasSavings(list)` | Returns `true` if access list saves gas |

### Queries

| Method                                   | Description                             |
| ---------------------------------------- | --------------------------------------- |
| `includesAddress(list, address)`         | Check if address is in list             |
| `includesStorageKey(list, address, key)` | Check if storage key is accessible      |
| `keysFor(list, address)`                 | Get all storage keys for address        |
| `addressCount(list)`                     | Count of addresses in list              |
| `storageKeyCount(list)`                  | Total storage keys across all addresses |
| `isEmpty(list)`                          | Check if list has no entries            |

### Manipulation

| Method                               | Description                         |
| ------------------------------------ | ----------------------------------- |
| `withAddress(list, address)`         | Add address (returns new list)      |
| `withStorageKey(list, address, key)` | Add storage key (returns new list)  |
| `merge(...lists)`                    | Combine multiple access lists       |
| `deduplicate(list)`                  | Remove duplicate addresses and keys |

### Validation & Conversion

| Method              | Description                    |
| ------------------- | ------------------------------ |
| `is(value)`         | Type guard for AccessList      |
| `isItem(value)`     | Type guard for AccessList Item |
| `assertValid(list)` | Throws if list is invalid      |
| `toBytes(list)`     | RLP-encode to bytes            |

### Constants

| Constant                   | Value   | Description                    |
| -------------------------- | ------- | ------------------------------ |
| `ADDRESS_COST`             | `2400n` | Gas per address in access list |
| `STORAGE_KEY_COST`         | `1900n` | Gas per storage key            |
| `COLD_ACCOUNT_ACCESS_COST` | `2600n` | Gas for cold account access    |
| `COLD_STORAGE_ACCESS_COST` | `2100n` | Gas for cold storage access    |
| `WARM_STORAGE_ACCESS_COST` | `100n`  | Gas for warm storage access    |

## Practical Examples

### Transaction with Access List

```typescript theme={null}
import * as AccessList from '@tevm/voltaire/AccessList';
import * as Transaction from '@tevm/voltaire/Transaction';
import * as Address from '@tevm/voltaire/Address';

// Build access list for Uniswap swap
const accessList = AccessList.from([
  {
    address: Address("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), // Router
    storageKeys: []
  },
  {
    address: Address("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH
    storageKeys: [
      Hash("0x..."), // balanceOf[sender]
      Hash("0x..."), // balanceOf[pair]
    ]
  },
  {
    address: Address("0x..."), // Token
    storageKeys: [
      Hash("0x..."), // balanceOf[sender]
      Hash("0x..."), // balanceOf[pair]
      Hash("0x..."), // allowance[sender][router]
    ]
  }
]);

// Verify savings before including
if (AccessList.hasSavings(accessList)) {
  const tx = Transaction.create({
    type: 1, // EIP-2930
    accessList,
    // ... other fields
  });
}
```

### Merging Access Lists from Simulation

```typescript theme={null}
import * as AccessList from '@tevm/voltaire/AccessList';

// Simulate multiple calls and collect access lists
const swap1Access = await simulateSwap(tokenA, tokenB, amount1);
const swap2Access = await simulateSwap(tokenB, tokenC, amount2);

// Merge and deduplicate
const combined = AccessList.merge(swap1Access, swap2Access);

console.log(`Combined: ${AccessList.addressCount(combined)} addresses`);
console.log(`Storage keys: ${AccessList.storageKeyCount(combined)}`);
console.log(`Net savings: ${AccessList.gasSavings(combined)} gas`);
```

### Finding Accessed Storage

```typescript theme={null}
import * as AccessList from '@tevm/voltaire/AccessList';

const list = AccessList.from(simulatedAccessList);

// Check if specific contract is accessed
if (AccessList.includesAddress(list, proxyContract)) {
  const keys = AccessList.keysFor(list, proxyContract);
  console.log(`Proxy accesses ${keys?.length ?? 0} storage slots`);
}

// Check for specific storage slot access
const balanceSlot = Hash("0x...");
if (AccessList.includesStorageKey(list, tokenContract, balanceSlot)) {
  console.log("Transaction reads token balance");
}
```

## When to Use Access Lists

Access lists provide net gas savings when:

1. **Multiple cold accesses**: Accessing the same address/slot multiple times
2. **Complex DeFi operations**: Swaps, lending, multi-hop transactions
3. **Batch operations**: Multiple transfers or contract interactions
4. **Contract calls with many SLOAD**: Storage-heavy operations

The break-even point:

* Address: Saves 200 gas per address (2600 - 2400)
* Storage key: Saves 200 gas per key (2100 - 1900)

Use `hasSavings()` to verify before including in transactions.

## RLP Encoding

Access lists encode as RLP for transaction serialization:

```typescript theme={null}
// Format: [[address, [storageKey1, storageKey2, ...]], ...]
const bytes = AccessList.toBytes(list);
const decoded = AccessList.fromBytes(bytes);
```

## Related

<CardGroup cols={2}>
  <Card title="Transaction" icon="paper-plane" href="/primitives/transaction">
    Ethereum transactions with access list support
  </Card>

  <Card title="Address" icon="wallet" href="/primitives/address">
    Ethereum addresses for access list entries
  </Card>

  <Card title="Hash" icon="hashtag" href="/crypto/keccak256">
    32-byte storage keys
  </Card>

  <Card title="RLP" icon="layer-group" href="/primitives/rlp">
    Recursive Length Prefix encoding
  </Card>
</CardGroup>
