This document describes EOF’s impact on the most popular existing libraries. We prepared prototypes of changes required to compile their source code. We describe unresolved issues and propose possible solutions. “Required changes to the source code” does not contain unresolved issues but sometimes contains TODO comments added to the source code.
ⓘ Note: The prototypes make use of local paths in configuration and depend on a local build of the experimental Solidity compiler branch enabling block deduplicator on EOF rebased on the parallel branch enabling the constant optimizer.
The first section addresses issues found in specific projects, and is followed by a categorical list of the kinds of changes authors will need to make.
This document is based on the EOF scope approved in March of 2025. However, based on the findings of this report and the community feedback aroud these changes, Team Ipsilon recommends changes to the spec to reflect “Option D - Introspecting EOF”. The adoption of this option will remove most of the required code changes listed in this report.
3 files +9 -6 lines changed
call()
to use extcall()
instead and adjust to new return semantics. All calls pass in all available gas.
PAY
opcode, simplifying the code base.This issue is present only in project’s test suite and is actually an issue of a dependency (forge-std
), whose compatibility is explored in more detail in a later section.
Possible solutions:
vm.getCode()
cheat that does things beyond what a real EVM allows. Introducing a more powerful cheat seems in line with this approach.forge-std
dependency and have the framework directly deploy the contract as a part of test setup rather than require the code under test to do it.TXCREATE
or EOFCREATE
.
InitcodeTransation
and provide a list of initcodes
accessible via hash, which then would be deployable with TXCREATE
.EOFCREATE
.Only test code is affected and the issue is in a dependency (forge-std
).
No repo because the fix was to adjust one call
(all gas passed) in src/base/Notifier.sol:129
Dependency: v4-core
and forge-std
Possible solution:
gas
.In this case we used Hardhat to build the library as it doesn’t depend on forge-std
8 files changed +49 -12 lines changed
call()
to use extcall()
and adjust to new return semantics. All calls pass in all available gas.delegatecall()
to use extdelegatecall()
and adjust to new return semantics. All calls pass in all available gas.staticcall()
to use extsaticcall()
and adjust to new return semantics. All calls pass in all available gas.A library that supports “meta transactions” (a precursor to EIP-4337 AA wallets).
Possible solutions:
gas
.Support for various CREATE2
tasks.
Possible solutions:
TXCREATE
-based equivalent for counterfactual deployment use-cases. It would expect the bytecode to be provided in an InitcodeTransaction
rather than passed in via arguments.EOFCREATE
-based equivalent for deployment of predefined bytecode blobs. This would rely on the verbatim contract feature to be introduced in Solidity.A library that supports lightweight delegate contracts, including facilities to customize the clone with immutable data.
Possible solutions:
EOFCREATE
-based variant of Create2
with a verbatim contract. This would be straighforward for the base case of a deterministic clone with no args. The library also provides extra varieties of the clone pattern that need additional consideration:
CREATE
rather than CREATE2
). EOF intentionally does away with nonce-based contract deployment, so non-deterministic variant should be retired. If desired, it can still be simulated using an independently managed nonce in storage, mixed into the salt.RETURNCONTRACT
, so this is a matter of changing the clone implementation to make use of this mechanism instead. Then the immutable values need to be passed to the initcode, which can be achieved in a variety of ways (// FIXME: needs research, talk to OpenZeppelin):
EXTDATACOPY
operation (no EIP)A hard coded 30k gas limit is included in the ERC-165 check call, as recommended by the ERC.
gas
.Forge uses a customized EVM to provide a lot of Solidity-focused testing support. This customization is where most of the changes need to be made.
+17 -9 lines changed
staticcall()
to use extstaticcall()
and adjust to new return semantics. All calls pass in all available gas.Forge uses “cheats” for building and testing, which involves a customized VM that allows it to break the sandbox and load local system files and load them as contracts.
Cheat EOF bytecode into the “initcodes” portion of the transaction, or the equivalant.
TXCREATE
code. In addition to looking in the InitcodeTransaction
’s initcodes
field, look in a standard ‘pre-image’ pool where contracts are indexed by hash.keccak
is performed, store the result in the preimage pool. This has the added benefit of test-generated EOF code.CREATE
TXCREATE
, but the hash id comes from the pre-image pool.This preserves the magic of “cheating” in a contract from the local filesystem.
Low to moderate. Depends on amount of work to do in VMSafe
interface implementation.
The nature of this library is in using low level assembly optimizations. This makes it sensitive on any EVM assembly change. Since EOF is an EVM format change, supporting it requires changes in many places in the library. Nevertheless the solady team has prepared well defined Solady EOF plan.
The team estimates that they need a month to start supporting EOF.
All projects will require an updated version of Solidity. As many projects lock in to a specific version of Solidity for code reproducibility reasons, this is a standard change.
To support the “Ban Gas Introspection” goal EOF introduces a new series of CALL instructions that do not allow gas to be limited. These instructions also implement another long-requested optimization to not require output data in memory but to just use the returndata buffer.
The adoption of “Option D - Introspecting EOF” will address all these concerns.
Hard-coding gas values runs counter to the “Ban Gas Introspection” theme.
In general this is considered a bad practice as there are major gas schedule changes on the horizon for Glamsterdam, and has been an auditor’s “do not” recommendation for more than 5 years. More durable solutions outside of EOF would involve storing the value in contract storage and providing APIs to update the value, but that would incur a cold SLOAD
gas charge.
The adoption of “Option D - Introspecting EOF” will address all these concerns.
Limiting gas values runs counter to the “Ban Gas Introspection” theme and would not be supported in EOF.
These variants are trickier. Examples in this doc likely involve values that come from “outside” the VM.
Options not addressed in this document include the EIP-4337 entrypoint contract. But in this case the EIP-4337 team said they would rely on non-EOF entry points to provide this service. AA wallets can be written in EOF code and called by the existing entrypoint code.
The adoption of “Option D - Introspecting EOF” will address all these concerns.
Using EXTCODESIZE
is a common technique to determine if an address is a contract. Contracts will use it as a sanity check to ensure they are not trying to treat an EOA as a contract and execute its (non-existent) functions. Removing this opcode is a part of the “Ban Code Introspection” theme.
The adoption of “Option D - Introspecting EOF” will address all these concerns.
EOF changes the contract creation pathway, as an essential part of the vision in Vitalik’s EOF proposal: Ban Code introspection in EOF accounts. CREATE/2 depends on code entering contract memory, which makes long term JIT and AOT compilation difficult to impossible depending on if and how the code is altered from its original source.
OpenZeppelin’s Create2
libraries are intended to promote safe usage. A similiar library can be written for EOFCREATE
and TXCREATE
.
Depending on the use cases, the new EOFCREATE
and TXCREATE
may be able to handle it if the contracts being deployed are “factory” contracts. Other uses cases such as initializing immutable values would be handled by the new DATA series opcodes and use of the data section. However, dynamically assembling code on the fly would not be possible. Users are encouraged to use libraries like is currently done with CREATE2
and OpenZeppelin and to roll their own TXCREATE
solutions with great care.
Special thanks to Kamil from the Solidity team for help in preparing this report