Skip to main content

Try it Live

Run AccessList examples in the interactive playground

Manipulation

Operations for modifying AccessList instances (immutable).

AccessList.withAddress()

Add address to access list if not already present.
AccessList.withAddress(
  list: BrandedAccessList,
  address: AddressType
): BrandedAccessList
Parameters:
  • list: Original access list
  • address: Address to add
Returns: New access list with address added Example:
let list = AccessList.create();
list = list.withAddress(routerAddress);
list = list.withAddress(tokenAddress);
Behavior:
  • Returns new list (immutable)
  • No-op if address already exists
  • Adds with empty storageKeys array
  • O(n) operation (includes check)

AccessList.withStorageKey()

Add storage key for address (adds address if needed).
AccessList.withStorageKey(
  list: BrandedAccessList,
  address: AddressType,
  key: HashType
): BrandedAccessList
Parameters:
  • list: Original access list
  • address: Address to add key for
  • key: Storage key to add
Returns: New access list with key added Example:
let list = AccessList.create();
list = list.withStorageKey(tokenAddress, balanceSlot);
list = list.withStorageKey(tokenAddress, allowanceSlot);
Behavior:
  • Returns new list (immutable)
  • Adds address if not present
  • No-op if key already exists for address
  • O(n×m) operation

AccessList.deduplicate()

Remove duplicate addresses and storage keys.
AccessList.deduplicate(list: BrandedAccessList): BrandedAccessList
Parameters:
  • list: Access list to deduplicate
Returns: New access list with duplicates removed Example:
const list = AccessList([
  { address: token, storageKeys: [key1, key2] },
  { address: token, storageKeys: [key2, key3] },  // Duplicate address
  { address: router, storageKeys: [key1] }
]);

const deduped = list.deduplicate();
// Result: [
//   { address: token, storageKeys: [key1, key2, key3] },
//   { address: router, storageKeys: [key1] }
// ]
Behavior:
  • Merges duplicate addresses
  • Removes duplicate storage keys within merged addresses
  • Preserves original item order (first occurrence)
  • O(n²×m) operation (byte-by-byte comparison)

AccessList.merge()

Combine multiple access lists with automatic deduplication.
AccessList.merge(...lists: readonly BrandedAccessList[]): BrandedAccessList
Parameters:
  • ...lists: Access lists to merge
Returns: New merged and deduplicated access list Example:
const list1 = AccessList([
  { address: token1, storageKeys: [key1] }
]);
const list2 = AccessList([
  { address: token2, storageKeys: [key2] }
]);
const list3 = AccessList([
  { address: token1, storageKeys: [key3] }
]);

const merged = AccessList.merge(list1, list2, list3);
// Result: [
//   { address: token1, storageKeys: [key1, key3] },
//   { address: token2, storageKeys: [key2] }
// ]
Behavior:
  • Concatenates all lists
  • Automatically deduplicates result
  • Empty lists are ignored
  • O(k×n²×m) operation (k = number of lists)

Patterns

Incremental Building

let list = AccessList.create();

// Add contracts
list = list.withAddress(routerAddress);
list = list.withAddress(factoryAddress);
list = list.withAddress(tokenAddress);

// Add storage keys
list = list.withStorageKey(tokenAddress, balanceSlot);
list = list.withStorageKey(tokenAddress, allowanceSlot);
list = list.withStorageKey(tokenAddress, totalSupplySlot);

// Deduplicate at end
list = list.deduplicate();

Conditional Addition

function addIfMissing(
  list: BrandedAccessList,
  address: AddressType
): BrandedAccessList {
  if (list.includesAddress(address)) {
    return list;
  }
  return list.withAddress(address);
}

Bulk Addition

function withAddresses(
  list: BrandedAccessList,
  addresses: AddressType[]
): BrandedAccessList {
  let result = list;
  for (const addr of addresses) {
    result = result.withAddress(addr);
  }
  return result.deduplicate();
}

function withKeys(
  list: BrandedAccessList,
  address: AddressType,
  keys: HashType[]
): BrandedAccessList {
  let result = list;
  for (const key of keys) {
    result = result.withStorageKey(address, key);
  }
  return result;
}

Merge Transaction Lists

function combineTransactionLists(
  ...txs: Transaction[]
): BrandedAccessList {
  const lists = txs.map(tx => tx.accessList);
  return AccessList.merge(...lists);
}

Optimize After Building

function buildOptimized(): BrandedAccessList {
  let list = AccessList.create();

  // Build without worrying about duplicates
  list = list.withAddress(addr1);
  list = list.withAddress(addr1);  // Duplicate
  list = list.withStorageKey(addr1, key1);
  list = list.withStorageKey(addr1, key1);  // Duplicate

  // Deduplicate once at end
  return list.deduplicate();
}

Builder Pattern

class AccessListBuilder {
  private list: BrandedAccessList;

  constructor() {
    this.list = AccessList.create();
  }

  addAddress(address: AddressType): this {
    this.list = this.list.withAddress(address);
    return this;
  }

  addKey(address: AddressType, key: HashType): this {
    this.list = this.list.withStorageKey(address, key);
    return this;
  }

  build(): BrandedAccessList {
    return this.list.deduplicate();
  }
}

const list = new AccessListBuilder()
  .addAddress(router)
  .addKey(token, balanceSlot)
  .addKey(token, allowanceSlot)
  .build();

Safe Merge

function safeMerge(
  ...lists: (BrandedAccessList | undefined)[]
): BrandedAccessList {
  const valid = lists.filter(
    (l): l is BrandedAccessList => l !== undefined && !l.isEmpty()
  );

  if (valid.length === 0) {
    return AccessList.create();
  }

  return AccessList.merge(...valid);
}

Immutable Updates

// All operations return new lists
const list1 = AccessList.create();
const list2 = list1.withAddress(addr);
const list3 = list2.withStorageKey(addr, key);

// Original unchanged
console.log(list1.isEmpty());  // true
console.log(list2.addressCount());  // 1
console.log(list3.storageKeyCount());  // 1

Performance Considerations

OperationComplexityNotes
withAddressO(n)Check + copy array
withStorageKeyO(n×m)Check + copy nested
deduplicateO(n²×m)Byte comparison
mergeO(k×n²×m)k lists merged
Optimization Strategies:
  1. Deduplicate once at end
    // Good: O(n²×m) once
    list = list.withAddress(a1);
    list = list.withAddress(a2);
    list = list.deduplicate();
    
    // Bad: O(n²×m) twice
    list = list.withAddress(a1).deduplicate();
    list = list.withAddress(a2).deduplicate();
    
  2. Check before adding
    // Good: Avoid unnecessary copy
    if (!list.includesAddress(addr)) {
      list = list.withAddress(addr);
    }
    
    // Bad: Always copies even if present
    list = list.withAddress(addr);
    
  3. Batch operations
    // Good: Build then deduplicate
    for (const addr of addresses) {
      list = list.withAddress(addr);
    }
    list = list.deduplicate();
    
    // Bad: Deduplicate each time
    for (const addr of addresses) {
      list = list.withAddress(addr).deduplicate();
    }
    
  4. Merge once instead of repeated withAddress
    // Good: O(k×n²×m) once
    const merged = AccessList.merge(...lists);
    
    // Bad: O(n) per addition
    let combined = lists[0];
    for (let i = 1; i < lists.length; i++) {
      for (const item of lists[i]) {
        combined = combined.withAddress(item.address);
      }
    }
    

Best Practices

  1. Always deduplicate before using
    const list = buildAccessList();
    const optimized = list.deduplicate();
    tx.accessList = optimized;
    
  2. Use immutable pattern
    // Good: Reassign
    list = list.withAddress(addr);
    
    // Bad: Ignoring return value
    list.withAddress(addr);  // Original unchanged!
    
  3. Build incrementally, optimize once
    let list = AccessList.create();
    list = list.withAddress(a1);
    list = list.withAddress(a2);
    list = list.withStorageKey(a1, k1);
    list = list.deduplicate();  // Once at end
    
  4. Merge before deduplicating
    // Good: Merge handles deduplication
    const list = AccessList.merge(l1, l2, l3);
    
    // Unnecessary: merge already deduplicates
    const list = AccessList.merge(l1, l2, l3).deduplicate();
    
  5. Check before expensive operations
    if (!list.isEmpty()) {
      list = list.deduplicate();
    }
    

See Also