Try it Live
Run AccessList examples in the interactive playground
Usage Patterns
Common patterns and best practices for working with AccessList.Building Access Lists
Incremental Construction
Copy
Ask AI
// Start empty and build up
let list = AccessList.create();
// Add contracts one by one
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);
// Optimize once at end
list = list.deduplicate();
Batch Construction
Copy
Ask AI
// From known items
const items: Item[] = [
{ address: router, storageKeys: [] },
{ address: token0, storageKeys: [balanceSlot, allowanceSlot] },
{ address: token1, storageKeys: [balanceSlot] }
];
const list = AccessList(items).deduplicate();
Conditional Building
Copy
Ask AI
function buildAccessList(config: Config): BrandedAccessList {
let list = AccessList.create();
// Required contracts
list = list.withAddress(config.router);
// Optional contracts
if (config.needsFactory) {
list = list.withAddress(config.factory);
}
if (config.needsPriceOracle) {
list = list.withAddress(config.oracle);
list = list.withStorageKey(config.oracle, config.priceSlot);
}
return list.deduplicate();
}
Builder Pattern
Copy
Ask AI
class AccessListBuilder {
private list: BrandedAccessList = AccessList.create();
addAddress(address: AddressType): this {
this.list = this.list.withAddress(address);
return this;
}
addStorageKey(address: AddressType, key: HashType): this {
this.list = this.list.withStorageKey(address, key);
return this;
}
addKeys(address: AddressType, keys: HashType[]): this {
for (const key of keys) {
this.list = this.list.withStorageKey(address, key);
}
return this;
}
build(): BrandedAccessList {
return this.list.deduplicate();
}
}
// Usage
const list = new AccessListBuilder()
.addAddress(router)
.addKeys(token, [balanceSlot, allowanceSlot])
.build();
DeFi Patterns
Uniswap V2 Swap
Copy
Ask AI
function buildSwapAccessList(
router: AddressType,
pair: AddressType,
token0: AddressType,
token1: AddressType,
user: AddressType
): BrandedAccessList {
const balanceSlot0 = calculateBalanceSlot(token0, user);
const balanceSlot1 = calculateBalanceSlot(token1, user);
const allowanceSlot0 = calculateAllowanceSlot(token0, user, router);
const reserve0Slot = Hash('0x08'); // reserves slot
const reserve1Slot = Hash('0x08');
let list = AccessList.create();
// Router
list = list.withAddress(router);
// Pair contract
list = list.withAddress(pair);
list = list.withStorageKey(pair, reserve0Slot);
// Token0
list = list.withStorageKey(token0, balanceSlot0);
list = list.withStorageKey(token0, allowanceSlot0);
// Token1
list = list.withStorageKey(token1, balanceSlot1);
return list.deduplicate();
}
Aave Borrow
Copy
Ask AI
function buildBorrowAccessList(
pool: AddressType,
asset: AddressType,
user: AddressType
): BrandedAccessList {
// Calculate storage slots
const userConfig = calculateUserConfigSlot(pool, user);
const reserve = calculateReserveSlot(pool, asset);
const debt = calculateDebtSlot(asset, user);
const balance = calculateBalanceSlot(asset, user);
return AccessList.create()
.withAddress(pool)
.withStorageKey(pool, userConfig)
.withStorageKey(pool, reserve)
.withStorageKey(asset, debt)
.withStorageKey(asset, balance)
.deduplicate();
}
ERC-20 Batch Transfer
Copy
Ask AI
function buildBatchTransferAccessList(
token: AddressType,
sender: AddressType,
recipients: AddressType[]
): BrandedAccessList {
let list = AccessList.create();
// Token contract
list = list.withAddress(token);
// Sender balance
const senderSlot = calculateBalanceSlot(token, sender);
list = list.withStorageKey(token, senderSlot);
// Recipient balances
for (const recipient of recipients) {
const recipientSlot = calculateBalanceSlot(token, recipient);
list = list.withStorageKey(token, recipientSlot);
}
return list.deduplicate();
}
Transaction Integration
Before Sending
Copy
Ask AI
async function sendWithAccessList(
tx: Transaction
): Promise<TransactionReceipt> {
// Build access list
let list = buildAccessListForTransaction(tx);
// Optimize
list = list.deduplicate();
// Check if beneficial
if (!list.hasSavings()) {
console.log('Skipping unprofitable access list');
list = AccessList.create();
}
// Encode and send
return await provider.sendTransaction({
...tx,
type: 2, // EIP-1559
accessList: list
});
}
Auto-detection
Copy
Ask AI
async function detectAccessList(
tx: Transaction
): Promise<BrandedAccessList> {
// Use eth_createAccessList RPC
const detected = await provider.send('eth_createAccessList', [
{
from: tx.from,
to: tx.to,
data: tx.data,
gas: tx.gasLimit
}
]);
// Convert to our format
const list = AccessList(detected.accessList);
// Validate and optimize
AccessList.assertValid(list);
return list.deduplicate();
}
Gas Estimation
Copy
Ask AI
async function estimateWithAccessList(
tx: Transaction
): Promise<{ withList: bigint; without: bigint; beneficial: boolean }> {
// Build access list
const list = buildAccessListForTransaction(tx);
// Estimate with access list
const withList = await provider.estimateGas({
...tx,
accessList: list
});
// Estimate without
const without = await provider.estimateGas({
...tx,
accessList: []
});
return {
withList,
without,
beneficial: withList < without
};
}
Optimization Patterns
Merge Multiple Lists
Copy
Ask AI
function combineAccessLists(
...txs: Transaction[]
): BrandedAccessList {
const lists = txs
.map(tx => tx.accessList)
.filter(list => list && !list.isEmpty());
if (lists.length === 0) {
return AccessList.create();
}
return AccessList.merge(...lists);
}
Deduplicate Strategy
Copy
Ask AI
// Strategy 1: Deduplicate at end
function strategy1(): BrandedAccessList {
let list = AccessList.create();
for (const addr of addresses) {
list = list.withAddress(addr);
}
return list.deduplicate(); // Once at end
}
// Strategy 2: Check before adding
function strategy2(): BrandedAccessList {
let list = AccessList.create();
for (const addr of addresses) {
if (!list.includesAddress(addr)) {
list = list.withAddress(addr);
}
}
return list; // No deduplication needed
}
// Strategy 1 faster for many items
// Strategy 2 faster for few items
Size Limits
Copy
Ask AI
function limitAccessListSize(
list: BrandedAccessList,
maxGas: bigint
): BrandedAccessList {
const cost = list.gasCost();
if (cost <= maxGas) {
return list;
}
// Sort by value (most keys first)
const sorted = [...list].sort(
(a, b) => b.storageKeys.length - a.storageKeys.length
);
// Build up to budget
let result = AccessList.create();
for (const item of sorted) {
const withItem = result.withAddress(item.address);
for (const key of item.storageKeys) {
const withKey = withItem.withStorageKey(item.address, key);
if (withKey.gasCost() <= maxGas) {
result = withKey;
} else {
break;
}
}
if (result.gasCost() >= maxGas) {
break;
}
}
return result;
}
Analysis Patterns
Complete Analysis
Copy
Ask AI
function analyzeAccessList(list: BrandedAccessList) {
const addresses = list.addressCount();
const keys = list.storageKeyCount();
const cost = list.gasCost();
const savings = list.gasSavings();
const net = savings - cost;
return {
addresses,
keys,
avgKeysPerAddress: addresses > 0 ? keys / addresses : 0,
cost,
savings,
net,
beneficial: net > 0n,
costPerAddress: addresses > 0 ? cost / BigInt(addresses) : 0n,
costPerKey: keys > 0 ? cost / BigInt(keys) : 0n
};
}
Comparison
Copy
Ask AI
function compareAccessLists(
lists: BrandedAccessList[]
): BrandedAccessList {
const analyses = lists.map(list => ({
list,
...analyzeAccessList(list)
}));
// Sort by net benefit
analyses.sort((a, b) => {
const diff = a.net - b.net;
return diff > 0n ? -1 : diff < 0n ? 1 : 0;
});
return analyses[0].list;
}
Debug Output
Copy
Ask AI
function debugAccessList(list: BrandedAccessList): void {
console.log('Access List Summary:');
console.log(` Addresses: ${list.addressCount()}`);
console.log(` Storage Keys: ${list.storageKeyCount()}`);
console.log(` Gas Cost: ${list.gasCost()}`);
console.log(` Gas Savings: ${list.gasSavings()}`);
console.log(` Net: ${list.gasSavings() - list.gasCost()}`);
console.log(` Beneficial: ${list.hasSavings()}`);
console.log('\nDetailed Items:');
for (const item of list) {
console.log(` ${item.address.toHex()}:`);
console.log(` Keys: ${item.storageKeys.length}`);
for (const key of item.storageKeys) {
console.log(` ${key.toHex()}`);
}
}
}
Error Handling
Safe Construction
Copy
Ask AI
function safeConstruction(data: unknown): BrandedAccessList {
try {
// Try to construct
if (data instanceof Uint8Array) {
const list = AccessList(data);
AccessList.assertValid(list);
return list;
}
if (Array.isArray(data)) {
const list = AccessList(data);
AccessList.assertValid(list);
return list;
}
throw new Error('Invalid data type');
} catch (err) {
console.error('Failed to construct access list:', err);
return AccessList.create();
}
}
Fallback Strategies
Copy
Ask AI
function buildWithFallback(
primary: () => BrandedAccessList,
fallback: () => BrandedAccessList
): BrandedAccessList {
try {
const list = primary();
AccessList.assertValid(list);
return list.deduplicate();
} catch (err) {
console.warn('Primary strategy failed, using fallback:', err);
try {
const list = fallback();
AccessList.assertValid(list);
return list.deduplicate();
} catch {
return AccessList.create();
}
}
}
Testing Patterns
Test Fixtures
Copy
Ask AI
const fixtures = {
empty: AccessList.create(),
singleAddress: AccessList([
{ address: testAddr1, storageKeys: [] }
]),
withKeys: AccessList([
{ address: testAddr1, storageKeys: [testKey1, testKey2] }
]),
multipleAddresses: AccessList([
{ address: testAddr1, storageKeys: [testKey1] },
{ address: testAddr2, storageKeys: [testKey2] }
])
};
Invariant Checks
Copy
Ask AI
function checkInvariants(list: BrandedAccessList): void {
// Valid structure
AccessList.assertValid(list);
// Deduplicated
const deduped = list.deduplicate();
assert.equal(deduped.length, list.length, 'Should be deduplicated');
// Consistent counts
const manual = list.reduce(
(sum, item) => sum + item.storageKeys.length,
0
);
assert.equal(list.storageKeyCount(), manual, 'Key count mismatch');
}
See Also
- Gas Optimization - Gas analysis
- Manipulation - Building lists
- Queries - Inspecting lists

