Optimizing Ethereum Transactions with eth_createAccessList
Discover how eth_createAccessList, an Ethereum JSON-RPC method, can help optimize gas costs, reduce out-of-gas errors, verify clients for infrastructure access, and more.
Discover how eth_createAccessList, an Ethereum JSON-RPC method, can help optimize gas costs, reduce out-of-gas errors, verify clients for infrastructure access, and more.
In this article we'll provide an overview of the eth_createAccessList feature, an Ethereum JSON-RPC method that generates an access list for a Type 1 transaction, and demonstrate five use cases this method can be applied to:
- Optimizing Gas Costs and Reducing Out-of-Gas Errors
- Smart Contract Deployment
- Interacting with DeFi Protocols
- EIP-4337 (Account Abstraction) Contract Development
- Verifying Clients
Documentation for eth_createAccessList can be found here.
What is eth_createAccessList?
Type 1 Transactions are part of EIP-2930 introduced by the Berlin hard fork). These transactions include an “access list,” a feature designed to mitigate the challenges raised by EIP 2929, which increased gas costs for certain operations to mitigate against potential denial-of-service (DoS) attacks. An access list is a record of addresses and certain storage keys that the transaction plans to access. By specifying these elements in advance, the transaction becomes more predictable in terms of its gas consumption.
Here's where eth_createAccessList comes in. The function is an Ethereum JSON-RPC method designed to generate an access list for a transaction. By using this method, developers can specify a list of addresses and storage keys the transaction will access, which essentially gives developers a deeper view of how a specific transaction (or call) is going to affect the overall state tree. This feature helps reduce gas costs for developers by attaching an access list to a raw transaction, simplifies the process of managing smart contract interactions, and minimizes out-of-gas errors. Access lists aim to improve the network's scalability by specifying an explicit list of addresses and storage keys that a transaction intends to access.
Use Case 1: Optimizing Gas Costs and Reducing Out-of-Gas Errors
With eth_createAccessList, developers can generate access lists for their transactions to optimize gas costs and reduce the risk of out-of-gas errors. By explicitly specifying the addresses and storage keys a transaction will access, developers can avoid paying additional gas fees for accessing "cold" storage slots and take advantage of the gas discount for "warm" addresses.
Use Case 2: Smart Contract Deployment
When deploying a smart contract, developers can use eth_createAccessList to generate an access list specifying the addresses and storage keys that the contract will interact with, helping reduce the gas costs associated with the deployment.
Example
Consider a simple contract deployment that interacts with an ERC20 token contract.
Request Code:
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_createAccessList",
"params": [
{
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"gas": "0x76c0",
"data": "0x606060...",
"value": "0x9184e72a"
}
]
}
Response Code:
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"accessList": [
{
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"storageKeys": []
}
],
"gasUsed": "0x30d40",
"gasRefund": "0x0"
}
}
In this example, we created an access list for a simple contract deployment that interacts with an ERC20 token contract. By specifying the ERC20 contract address in the access list, we reduced the gas cost of the deployment.
Use Case 3: Interacting with DeFi Protocols
Developers can use eth_createAccessList when interacting with DeFi protocols to optimize gas usage by specifying the addresses and storage keys involved in the transaction, allowing for more predictable gas costs and reduced risk of unexpected state growth.
Example
Consider a user interacting with a decentralized exchange (DEX) to swap tokens.
Request Code
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_createAccessList",
"params": [
{
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"to": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", // Uniswap V2 Router
"gas": "0x76c0",
"data": "0x7ff36ab5...", // swapExactTokensForTokens function call
"value": "0x0"
}
]
}
Response Code
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"accessList": [
{
"address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
"storageKeys": []
},
{
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"storageKeys": []
},
{
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"storageKeys": []
}
],
"gasUsed": "0x61a80",
"gasRefund": "0x0"
}
}
In this example, we created an access list for a token swap transaction on a decentralized exchange (DEX) like Uniswap. By specifying the DEX router and the token contract addresses in the access list, we reduced the gas cost of the transaction.
Use Case 4: EIP-4337 (Account Abstraction) Smart Contract Development
eth_createAccessList can be used to optimize gas usage when interacting with smart contracts that utilize account abstraction as specified in EIP-4337.
Example
Consider a developer interacting with an account abstraction-enabled contract to deploy a new instance of the contract.
Request Code
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_createAccessList",
"params": [
{
"from": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"to": "0xABCD...", // Account abstraction contract
"gas": "0x76c0",
"data": "0x606060...", // Deploy new instance
"value": "0x0"
}
]
}
Response Code
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"accessList": [
{
"address": "0xABCD...",
"storageKeys": []
}
],
"gasUsed": "0x50d40",
"gasRefund": "0x0"
}
}
In this example, we created an access list for a transaction that deploys a new instance of an account abstraction-enabled contract. By specifying the account abstraction contract address in the access list, we reduced the gas cost of the transaction.
Use Case 5: Verifying Clients
Client verification is more of a niche use case explored in a February 2023 blog post: How to use Ethereum Proofs. The eth_createAccessList method is used for finding the storage slot in the ENS contract map variables.
With the rollout of this feature, we will also be able to add a16z’s Helios client on our infrastructure, which is the missing component for utilizing the getProofs.
Web3.js Example embedding eth_createAccessList:
Here's a simple example of how to use the eth_createAccessList method with web3.js:
const Web3 = require("web3");
const web3 = new Web3("<INFURA_API_ENDPOINT>");
const sender = "<SENDER_ADDRESS>";
const contractAddress = "<CONTRACT_ADDRESS>";
const inputData = "<INPUT_DATA>";
(async () => {
try {
const accessList = await web3.eth.createAccessList({
from: sender,
to: contractAddress,
data: inputData,
});
console.log("Access List:", accessList);
} catch (error) {
console.error("Error generating access list:", error);
}
})();
To use the generated access list in a transaction, simply include it in the transaction object:
const privateKey = "<SENDER_PRIVATE_KEY>";
const gasPrice = "<GAS_PRICE>";
const nonce = await web3.eth.getTransactionCount(sender);
const tx = {
from: sender,
to: contractAddress,
data: inputData,
gasPrice: gasPrice,
nonce: nonce,
accessList: accessList,
};
const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
console.log("Transaction Receipt:", receipt);
Ethers.js Example embedding eth_createAccessList:
Here’s an example of how to use eth_createAccessList method with ethers.js:
const ethers = require("ethers");
const provider = new ethers.providers.JsonRpcProvider("<INFURA_API_ENDPOINT>");
const wallet = new ethers.Wallet("<SENDER_PRIVATE_KEY>", provider);
const contractAddress = "<CONTRACT_ADDRESS>";
const inputData = "<INPUT_DATA>";
const transaction = {
from: wallet.address,
to: contractAddress,
data: inputData,
};
async function generateAccessList() {
try {
const accessList = await provider.send("eth_createAccessList", [
transaction,
]);
console.log("Access List:", accessList);
} catch (error) {
console.error("Error generating access list:", error);
}
}
generateAccessList();
The process to use the generated access list in a transaction would look like this:
const gasPrice = ethers.utils.parseUnits("<GAS_PRICE_IN_GWEI>", "gwei");
const nonce = await wallet.getTransactionCount();
const tx = {
from: wallet.address,
to: contractAddress,
data: inputData,
gasPrice: gasPrice,
nonce: nonce,
accessList: accessList,
};
const signedTx = await wallet.signTransaction(tx);
const txResponse = await provider.sendTransaction(signedTx);
const receipt = await txResponse.wait();
console.log("Transaction Receipt:", receipt);
Optimize Gas Usage and More with eth_createAccessList
With the addition of eth_createAccessList, Infura continues to enhance the developer experience on Ethereum. This new feature simplifies smart contract interactions, helps reduce gas costs, and minimizes out-of-gas errors.
As Ethereum continues to evolve and more complex applications emerge, the use of access lists will become increasingly important in optimizing gas usage and ensuring the robustness of the network.
Note that Infura is providing access to eth_createAccessList for all customers subscribed, free and paid.
Try it out today here and share your feedback with us.