EIP-7702 Gas Sponsorship with Anvil
In this guide, we will walk you through a demo of gas sponsorship accomplished with EIP-7702, all on a local anvil fork. EIP-7702 is one of the improvement proposals implemented in the Bectra upgrade, on Bepolia, mirroring the changes made within Ethereum Mainnet with Pectra. Gas Sponsorship simply entails:- An EOA authorizing an implementation contract at its own address
- Use of EIP-7702 transaction type, 0x04, to carry out transactions with this implementation logic
- The EOA signing an authorized transaction offchain and passing the details to a Sponsor to broadcast it to the chain, where the transaction
tovariable is actually the EOA itself
Gas Sponsorship with EIP 7702 vs EIP 4337 and Pre-Signed Transactions
Before getting into the guide, it is important to highlight key distinctions between the alternative methods for gas sponsorship. The three main options today include:- Pre-signed transactions with relayers
- EIP-4337 with account abstraction and a complex system
- EIP-7702 where an EOA acts like a smart account offering gas sponsorship methods
Gas Sponsorship Flow Diagram with EIP-7702
Gas Sponsorship with EIP-7702 is an interesting design space. We have gone ahead and made this simple “Part 1” where the main flow of carrying out a gas sponsorship is highlighted. We will publish more parts outlining:- Gas Sponsorship with ERC20s, where the EOA authorizes a transaction that transfers ERC20 to the Sponsor as a payment for the Sponsor to cover the gas required for the transaction.
- Using on-chain checks to ensure that the signer of the contract is the EOA itself. This will use solidity scripts leveraging Foundry.
:::tip
For further information on Bectra, make sure to follow our berachaindevs twitter as we publish more content!
:::
Requirements
Before starting, ensure that you have carried out the following:- Install Foundry
v1.0.0or greater - Clone the guides repo and make your way to the
apps/eip-7702-gas-sponsorshipdirectory to find the Gas Sponsorship Guide and associated code we’ll walk through today.
Guide Walk Through
Run all the commands within this guide while at the file path:./apps/eip-7702-gas-sponsorship.
Step 1 - Setup
Install dependencies for the project:anvil test addresses and private keys there. For this guide, keep it as is until you have walked through everything. Afterwards, feel free to use your own of course for your own testing.
Start anvil fork at hard fork prague:
Step 2 - Deploy the SimpleDelegate.sol Contract
Deploy the SimpleDelegate.sol contract and populate .env with contract address. This contract logic will be what is assigned to the EOA to leverage EIP-7702. The below bash code will automatically update the .env with the new SimpleDelegate.sol CONTRACT_ADRESS.
Step 3 - Get the Nonce to Use for the Authorized Transaction
As mentioned, gas sponsorship with EIP-7702 requires:- The
SPONSORto actually send enough gas to cover the transaction in the broadcasted call. - Onchain checks for replay attacks, including across different chains, is recommended as well.
getNonceToUse(). It is a simple function where you just pass the actual current EOA nonce to it as a param, and it will return a nonce that is ahead of the EOA nonce. The hope is to provide a nonce that is a good deal larger than the current EOA nonce so the “Service” can order transactions as needed without concern that the EOA will have done numerous transactions causing a pre-authorized transaction to become stale.
Get current EOA nonce, EOA_NONCE, and query contract for getNonceToUse(). The .env is updated with the value EOA_NONCE.
EOA_NONCE, it should be 10 less than NONCE_TO_USE that you’ll see in your .env. You can do this with this cast call:
Step 4 - Prepare the Offchain Transaction Details to be Broadcast
Now that you have the correct nonce to use in your.env, the next step is to use sign-auth to have the EOA authorize the transaction to be broadcast by the SPONSOR.
The bash command provided does the following:
Obtains the output from the cast wallet sign-auth call, AUTH_SIG. This variable will be used when the SPONSOR broadcasts the EOA’s transaction as it specifies the details of the actual transaction, and has implicit proof within it that the transaction is signed by the EOA.
Then, it prepares callData that directly invokes the execute() function in the smart account logic, passing no inner call for now. This is enough to test sponsorship, nonce, and signature checks implicitly using cast and -auth.
Then it carries out the transaction using cast send, where the to is the $EOA_ADDRESS, and the $AUTH_SIG has been signed offchain by the EOA_PK. The call is being carried out by the SPONSOR though to pay the gas!
Logs are output afterwards showcasing the results, which will be expanding on more in the next step!
Step 5 - Assessing the Results
The output from running the last command will provide twocast commands to assess the results. If you prefer, just run the following commands though and copy and paste the transaction hash in accordingly.
- To see the Authorization List and other details signifying that the EIP-7702 transaction was successful, run:
to specified should be the EOA address, and the from address should be the SPONSOR address. These will be the same for you too assuming you followed the guide and are using the anvil test wallets 1 and 2:
- To see the transaction receipt, run:
SPONSOR address, whereas the EOA has not spent any gas at all.
That’s it! Congrats you’ve walked through a high level example of gas sponsorship using EIP-7702 and Foundry Cast. Feel free to add comments or suggestions on our guides repo or reach out via Discord.
Part 2 - Using Foundry Solidity Scripts and Implementing EOA Signer Checks
The guide so far walked through the high level transaction flow when working with EIP-7702 to leverage gas sponsorship for an EOA. In this second part of the guide, we will cover the usage of Foundry Solidity Scripts and changes within the authorized implementation logic,SimpleDelegatePart2.sol. The below steps walk through each core lesson, and the commands to run the entire guide is in step #5.
The files used include:
SimpleDelegatePart2.sol- An expansion onSimpleDelegate.solcontract where it showcases signer recovery, nonce management, and use of inner calls with calldata.SimpleDelegatePart2.s.sol- A solidity script that is used to enact deployment of the implementation contract, authorization of the implementation logic for the EOA as per EIP-7702, and the broadcast of the sponsored transaction from theSPONSORon behalf of theEOA.
Step 1 - Signer Checks with EIP-7702
It is important to check that the authorized transaction is originally signed by the EOA. Changes have been made to the Part 1SimpleDelegate.sol contract where:
- The address of the signer is recovered using the
callinformation and the providedsignature.
cast calls to deploy and interact with the contract and accounts, the solidity script carries out all the steps within the code.
The main gotcha with the script code and the changed implementation code is that the implementation code checks if the recovered address, and thus the signer, is the EOA itself. Only then will it pass and allow the transaction to carry out.vm.signDelegationandvm.attachDelegationare cheatcodes from Foundry that allow EOAs and Sponsors to carry out EIP-7702 transactions when broadcast to networks. Please note that within simulations, such as withforge testor where solidity scripts are ran but not broadcast, Foundry is still working to support EIP-7702 transactions in full. For this tutorial, we will simply test against a local anvil forked network or the network directly.
address(this) value is actually the EOA in the context of the EIP-7702 transaction. Therefore, any call and transaction enacted through it, must be signed by the EOA_PK itself.
This check ensures that no malicious transactions are carried through.
Step 2 - Replay Attacks Prevention via Nonce Management
Replay attacks can be prevented with EIP-7702 transactions by having proper checks within the authorized implementation logic. Essentially if there is no check for the nonce being used in the authorized transaction, it could be re-used, which of course is a huge attack vector. Expanding on part 1, where the high level transaction flow was shown for Gas Sponsorship with EIP-7702, we now use the persistent storage of the EOA to our advantage and keep track of the arbitrary nonces used from the “service” preparing transactions signed by the EOA. Recall that the EOA nonce is not the same as the nonce used in these checks. The nonce used in these checks correspond to the arbitrary nonce that the offchain service uses to prepare transactions signed by the EOA ultimately. One reason for these arbitrary nonces is to prevent replay attacks by marking the nonce as used within a mapping in the implementation logic itself.A key lesson here is that the storage of the EOA persists when it comes to using authorized implementation logic via EIP-7702. It can be transient as well.The changes made with respect to nonce management include:
- A mapping of nonces to bool values, signifying when a nonce has been used.
- Conditional logic that reverts if the mapping of the proposed transaction nonce shows that it is a used nonce already.
Step 3 - Crosschain Replay Attack Prevention via ChainID Management
Crosschain replay attacks occur when an authorized, signed, transaction is replayed on a separate network then from where it originated. This exposes risks to funds on different networks, and more. ChainIDs are used in the implementation logic as a way to prevent these crosschain attacks. Combined with the nonce mapping mentioned before, chainIDs can be used to ensure the transaction can only occur once on the specified network, and no where else.Step 4 - Using Actual calldata via burnNative() with EIP-7702 Calls
Within the first part of this guide, we sent empty calldata to focus in on the use of EIP-7702 for gas sponsorship. Typically, transactions will not have empty calldata. An additional expansion for part 2 of this guide is to include a burnNative() function to showcase the execution of an internal call within the authorized transaction.
With EIP-7702, it’s especially important to validate that inner calldata works as expected because the EOA is executing the smart logic directly at its own address. This means:
- The logic inside the calldata is executed in the context of the EOA.
- The storage, balance, and even msg.sender will reflect this.
- Verifying that a function like burnNative() executes properly ensures the EIP-7702 delegation, signature recovery, and calldata routing are working together correctly.
- It visibly changes state (burns funds by sending them to address(0) or similar),
- It involves value transfer and storage updates,
- It lets us confirm that calldata isn’t just routed, but actually executed properly within the EOA’s own contract context.
Step 5 - Understanding and Running the Solidity Script
We have discussed the changes made to the implementation logic inSimpleDelegatePart2.sol. Within this section, we will walk through the main components within the Solidity Script. First we must expand our .env, and stop the anvil network that you started in Part 1, and create another network that forks off of Bepolia, to ensure we get the full features offered by BECTRA.
You have to update your .env so you can broadcast properly to Bepolia. You will need to have $tBERA within your wallets that you are using for both the EOA and the SPONSOR.
If you need $tBERA, you can get some from our faucet, or contact us directly.
anvil fork with Bepolia at “hardfork prague.”
cast, we use a full Foundry Solidity script to handle everything: deployment, delegation, authorization, broadcasting, and even checking for replay and signature mismatches. This is a great way to simulate what a service or wallet might actually do when working with EIP-7702.
Using a Foundry Solidity script gives you a lot:
- You get full control over both the EOA and the sponsor inside one flow
- Cheatcodes like
vm.sign,vm.envAddress,vm.startBroadcastmake this super clean - You can easily simulate replay, forged signatures, chain ID mismatches
- You can inspect balances, gas deltas, and storage at the EOA address directly
SimpleDelegatePart2.s.sol, and the main entry point is the SimpleDelegate2Script contract. You can run it using:
.env has the right test keys and enough $tBERA.
What the Script Does
The Solidity script does the entire 7702 lifecycle in one flow:- Deploys the
SimpleDelegatePart2contract - Signs a delegation from the EOA to itself
- Constructs a call to
burnNative()using the implementation logic - Signs the transaction offchain using the EOA private key
- Has the sponsor broadcast the transaction using
execute(...) - Logs balances, costs, and verifies the result
- Replay attack: Try sending the same tx again → should revert due to
nonceUsed[nonce]being true. - Cross-chain replay: Try a forged signature using the wrong chain ID → should fail signature recovery.
Core Lessons in the Script
There are a few key things this script shows:address(this)inside the implementation contract equals the EOA, since EIP-7702 executes the logic at the EOA’s address- Storage writes like
nonceUsed[nonce] = truepersist at the EOA - Including
block.chainidin the digest ensures signatures only work on the intended chain
Step 6 - Assessing the New Final Results
The contract has been successfully interacted with at the EOA’s address by observing the following: Below you can see theto address is the EOA, the from address is the SPONSOR, and the implementation address is seen under the authorizationList.
NonceAlreadyUsed() and Invalid Signer.