Skip to main content

Try it Live

Run Transaction examples in the interactive playground

getAccessList

Extract access list from transaction.

Access List Structure

type AccessList = readonly Item[]

type Item = {
  address: AddressType       // 20-byte contract address
  storageKeys: readonly Hash[]  // 32-byte storage slot keys
}

Transaction Types

TypeAccess List Support
Legacy (0x00)Returns []
EIP-2930 (0x01)Returns tx.accessList
EIP-1559 (0x02)Returns tx.accessList
EIP-4844 (0x03)Returns tx.accessList
EIP-7702 (0x04)Returns tx.accessList

Usage Patterns

Pre-warming Storage

import { getAccessList } from 'tevm/Transaction'

async function prewarmStorage(tx: Transaction.Any) {
  const accessList = getAccessList(tx)

  for (const item of accessList) {
    // Mark address as warm (2600 gas vs 100 gas)
    await markAddressWarm(item.address)

    // Mark storage slots as warm (2100 gas vs 100 gas)
    for (const key of item.storageKeys) {
      await markStorageWarm(item.address, key)
    }
  }
}

Gas Cost Calculation

import { getAccessList } from 'tevm/Transaction'

function calculateAccessListGasCost(tx: Transaction.Any): bigint {
  const accessList = getAccessList(tx)

  let cost = 0n

  for (const item of accessList) {
    cost += 2400n  // Per address (TU_DATA + TU_ACCESS_LIST_ADDRESS_COST)

    for (const _ of item.storageKeys) {
      cost += 1900n  // Per storage key (TU_ACCESS_LIST_STORAGE_KEY_COST)
    }
  }

  return cost
}

// Usage
const accessListCost = calculateAccessListGasCost(tx)
console.log(`Access list adds ${accessListCost} gas`)

Access List Analysis

import { getAccessList } from 'tevm/Transaction'

function analyzeAccessList(tx: Transaction.Any) {
  const accessList = getAccessList(tx)

  const uniqueAddresses = new Set(
    accessList.map(item => Address.toHex(item.address))
  )

  const totalStorageKeys = accessList.reduce(
    (sum, item) => sum + item.storageKeys.length,
    0
  )

  return {
    addressCount: uniqueAddresses.size,
    storageKeyCount: totalStorageKeys,
    isEmpty: accessList.length === 0,
    gasCost: calculateAccessListGasCost(tx)
  }
}

Merging Access Lists

import { getAccessList } from 'tevm/Transaction'
import * as AccessList from 'tevm/AccessList'

function mergeTransactionAccessLists(
  transactions: Transaction.Any[]
): AccessList.AccessList {
  const lists = transactions.map(getAccessList)
  return AccessList.merge(...lists)
}

// Usage
const merged = mergeTransactionAccessLists([tx1, tx2, tx3])

Validation

import { getAccessList } from 'tevm/Transaction'

function validateAccessList(tx: Transaction.Any): boolean {
  const accessList = getAccessList(tx)

  for (const item of accessList) {
    // Check address is valid
    if (item.address.length !== 20) {
      return false
    }

    // Check storage keys are valid
    for (const key of item.storageKeys) {
      if (key.length !== 32) {
        return false
      }
    }

    // Check for duplicates
    const uniqueKeys = new Set(item.storageKeys.map(k => Hash.toHex(k)))
    if (uniqueKeys.size !== item.storageKeys.length) {
      return false  // Duplicate storage keys
    }
  }

  return true
}

Building Access Lists

import { getAccessList } from 'tevm/Transaction'
import * as AccessList from 'tevm/AccessList'

function buildOptimalAccessList(
  existingTx: Transaction.Any,
  additionalAddresses: AddressType[]
): AccessList.AccessList {
  // Start with existing access list
  let list = getAccessList(existingTx)

  // Add additional addresses
  for (const addr of additionalAddresses) {
    list = AccessList.withAddress(list, addr)
  }

  // Remove duplicates and optimize
  return AccessList.deduplicate(list)
}

Gas Savings

Access lists pre-declare storage access to save gas:
// Without access list
const coldAddressAccess = 2600n  // COLD_ACCOUNT_ACCESS_COST
const coldStorageAccess = 2100n  // COLD_SLOAD_COST

// With access list
const accessListAddress = 2400n      // Per address in list
const accessListStorage = 1900n      // Per storage key in list
const warmAddressAccess = 100n       // WARM_STORAGE_READ_COST
const warmStorageAccess = 100n       // WARM_STORAGE_READ_COST

// Net savings per access (if accessed multiple times)
const addressSavings = coldAddressAccess - (accessListAddress + warmAddressAccess)
// = 2600 - (2400 + 100) = 100 gas

const storageSavings = coldStorageAccess - (accessListStorage + warmStorageAccess)
// = 2100 - (1900 + 100) = 100 gas
Access lists are beneficial when addresses/slots accessed 2+ times.

See Also

References