-
-
owned this note
-
Published
Linked with GitHub
# Measurable benefits of EOF
We compared EVM bytecode size, gas usage and execution time of popular mainnet contracts (UniswapV3 and ENS DNSRegistrar). We used [Solidity compiler branch](https://github.com/ipsilon/solidity/commit/4e023040a08a5e0095c7bd97fa406269b6f144c2) which supports most of the EOF features.
## TLDR
For Uniswap contracts we achieved benefits in all measured stats.
- Deployed code and initcode size are `6.5%` smaller.
- Gas usage for [deploy](https://github.com/ipsilon/solidity/blob/eof-functions-rebased/test/libsolidity/semanticTests/UniswapV3Flattened.sol#L5095) and [call step](https://github.com/ipsilon/solidity/blob/eof-functions-rebased/test/libsolidity/semanticTests/UniswapV3Flattened.sol#L5156) is ``~14%`` and ``~9%`` lower.
- Gas usage for simple `swapExact0For1` is also `~5%` lower.
- Execution time on `evmone` fast EVM implementation also looks better
- For 100 calls of `swapExact0For1` (jump dest analysis enabled for legacy) execution time of EOF bytecode is `~15%` shorter than legacy.
- Benchmarks prepared in a form of state tests ([legacy](https://github.com/ipsilon/evm-benchmarks/blob/eof-legacy-comp-bench/benchmarks/main/uniswapv3_many_swaps_legacy.json), [EOF](https://github.com/ipsilon/evm-benchmarks/blob/eof-legacy-comp-bench/benchmarks/main/uniswapv3_many_swaps_eof.json)) (1000 `swapExact0For1` calls) also shows measurable benefits from using EOF:
- EOF: `35ms` (~10-15% faster than legacy w/o jump dest analysis)
- Legacy: `39ms`
- Legacy with jump dest analysis: `68ms`
For `DNSRegistrar` contract test case we also achieved benefits in all metricses.
- Deploy code and initcode size for [the test case](https://github.com/ipsilon/solidity/blob/ens-test/test/libsolidity/semanticTests/DNSRegistrarFlattened.sol) are accordingly`~6%` and `~1.5%` smaller.
- Gas usage for `proveAndClaim` function call is `~10%` lower.
- Also generated by `solc` compiler bytecode size of `DNSRegistrar` contract is `~10%` smaller.
## Uniswap-v3
Source: https://github.com/ipsilon/solidity/blob/eof-functions-rebased/test/libsolidity/semanticTests/UniswapV3Flattened.sol
Command:
**legacy**
`ETH_EVMONE=<PATH_TO_EVMONE_BUILD>/libevmone.dylib ./build/test/./soltest -t "semanticTests/UniswapV3Flattened" -- --optimize --evm-version cancun --show-messages`
**eof**
`ETH_EVMONE=<PATH_TO_EVMONE_BUILD>/libevmone.dylib ./build/test/./soltest -t "semanticTests/UniswapV3Flattened" -- --optimize --evm-version cancun --eof-version 1 --show-messages`
### Code size
**LEGACY:**
init code: `31 202` bytes
deployed code: `30 979` bytes
**EOF:**
init code: `29 236` bytes
deployed code: `29 048` bytes
### Summary:
init code: `~6.5%` less
deployed code: `~6.5%`less
### Gas Usage
Gas usage statistics for Uniswap V3 and simple run consists of:
1. deploy `UniswapV3Factory`
2. call `runTest`
- deploy ERC20 tokens
- deploy uniswap pool
- add liquidity
- simple swap
**LEGACY:**
deploy step: `6 832 734` total gas
call step: `8 815 561` total
**EOF:**
deploy step: `5 925 377` total gas
call step: `8 094 095` total
### Summary:
deploy step: `~14%` less
call step: `~9%` less
### Simple Swap `swapExact0For1`
```
Simple swap EOF:
gas used: 77389
gas used (without refund): 80189
Simple swap legacy:
gas used: 81329
gas used (without refund): 84129
```
#### Execution time 100 calls of `swapExact0For1`
Execution on evmone rev `d53b9e21cf39cec7f52253c141ea28572650a949`
EOF: `13870 microseconds`
legacy: `18539 microseconds`
#### Benchmarks for 1000 calls of `swapExact0For1` as state tests
Machine:
```
Apple M3 Pro
36GB RAM
```
evmone commands:
`build/bin/./evmone-statetest --trace-summary ./test/evm-benchmarks/benchmarks/main/uniswapv3_many_swaps_legacy.json`
`build/bin/./evmone-statetest --trace-summary ./test/evm-benchmarks/benchmarks/main/uniswapv3_many_swaps_eof.json`
State test jsons:
Legacy:
https://gist.github.com/rodiazet/28a50d5e67d25e8dd9d87ad5962c9f25
EOF:
https://gist.github.com/rodiazet/d9fbdb3f25ca77bb8ede133c1736e318
Summary:
Tx Execution
EOF: `35ms`
Legacy: `39ms`
Legacy with jump dest analysis: `68ms`
#### Additional comment
The code of this contract is bigger than UniswapV3Factory on mainnet because we added for test purpose `runTest` function which relies on ERC20 contract code and much more. But when running the test with empty `runTest` function with, EOF the bytecode is smaller by similar % than the one on mainnet.
## ENS DNSRegistrar
Custom soltest:
Source: https://github.com/ipsilon/solidity/tree/ens-test
DNSRegistrar semantic test: https://github.com/ipsilon/solidity/blob/ens-test/test/libsolidity/semanticTests/DNSRegistrarFlattened.sol
### Code size
**LEGACY:**
init code: `27 845` bytes
deployed code: `3 415` bytes
**EOF:**
init code: `26 171` bytes
deployed code: `3 375` bytes
#### Summary:
init code: `~6%` less
deployed code: `~1.5%`less
### Gas Usage
Gas usage statistics for `DNSRegistrar::proveAndClaim` method call:
**LEGACY:**
call `proveAndClaim`: `251 846` total
**EOF:**
call `proveAndClaim`: `228 466` total
#### Summary:
call step: `~10%` less gas used for EOF
#### Deployed code size comparison for clean [`DNSRegistrar` contract](https://github.com/ensdomains/ens-contracts/blob/staging/contracts/dnsregistrar/DNSRegistrar.sol)
- legacy optimized: `7 058` bytes
- eof optimized: `6 388` bytes
Diff `~10%`
**Compiler flags used:**
legacy
`--via-ir --bin-runtime --optimize`
eof
`--via-ir --bin-runtime --experimental-eof-version --optimize`