Precompile allowing ETH to directly be treated as and transferred as an ERC20 token, without intermediary wrapping / unwrapping steps.
WETH is a very popular contract, almost constantly in the “top 30-40 gas guzzlers” according to etherscan. WETH provides the very useful ability for contracts to have a unified interface to transact in both ERC20 tokens and the native EVM asset (Ether ETH on Ethereum). Furthermore it gives ETH some added features due to its compliance with the ERC20 standard:
- Safe force send: When WETH is transferred it does not trigger any code in the recipient meaning the transfer cannot be rejected or lead to reentrancy
- Approvals: WETH can be transferred from an account without its explicit action via
transferFromif it has approved a spender
- Events: Transfers of WETH emit events allowing off-chain applications to more easily track the flow of funds
However because this abstraction is not native to the EVM but a distinct contract it creates some friction for EOAs and overhead for application developers: EOAs need to submit an added transaction to “wrap” their ETH before it can be used with ERC20 only contracts. Developers who want to make that step seamless must implement additional logic to handle both ETH & WETH paths, increasing code size, complexity and as a result the attack surface of the contract. An example of this is the Uniswap Router which has duplicate methods to handle a user’s desire for ETH / WETH input / output.
- Proposal is implemented as a hard fork at some
- Adds a precompile to the EVM at address
eth_as_erc20_precompile_addresswhich can be called as an ERC20 + ERC2612 token
- Transfers of the “token” at
eth_as_erc20_precompile_addresslead to “parallel” transfers of the actual balance of accounts, enforcing the invariant
a.balance == IERC20(eth_as_erc20_precompile_address).balanceOf(a)
- Transferring ETH via the new precompile does not trigger the code of the recipient unlike transfers with
- All transfers of ETH via
CALLs and via the precompile after the
introduction_blockmust emit a
- Besides the standard methods dictated by the
ERC2612standards the precompile has
optIntoETHasERC20() nonpayable returns ()and
usingETHasERC20(address) view returns(bool)methods
- Contracts created before the
introduction_blockmust opt-into the “ETH as ERC20” behavior by calling an added
usingETHasERC20method returns whether or not the passed address has access to the “ETH as ERC20” behavior, defaults to
truefor all contracts created post
The above precompile breaks the invariant that
ETH cannot be transferred out of an account unless it 1. Submits a valid transaction or 2. Executes a
CALLcall directly or indirectly in a valid sub-context initiated by
Therefore, for the sake of backwards compatibility the “ETH as ERC20” behavior should be opt-in for contracts created prior to the implementation of such a precompile. Older contracts may still be vulnerable, even with the “required opt-in” protection if they do not expect the above invariant to be broken and are somehow able to trigger the precompile’s opt-in method via an arbitrary external call method or selector collision. To protect such contracts an alternative approach may be to altogether disable access to the precompile for older contracts.
Another security consideration would be the ability to receive ETH without having triggered although this is already a possibility today with the
SELFDESTRUCT opcode and is likely to remain even after its “deactivation” when it’s changed to
SENDALL for the sake of backwards compatibility.
One important consideration that hasn’t been mentioned above is what the cost of the different methods of the precompile should be. Considering that the precompile could safely be more tightly integrated with client implementations it’s likely fair to price the cost of some methods cheaper than what an ERC20 implementation would be. Furthermore the tradeoff of “protocol complexity vs. application users & developers” is also important to consider. I’ve left this considerations open for discussion as I’m not a client dev and think it’d be sensible to get some feedback before implementing a more fleshed out proposal.
Allowing users and contracts to worry less if at all about the difference between ETH / ERC20 tokens would greatly improve UX & DX and make newer contracts simpler, more efficient and more secure.
Note this is not entirely a new idea, credit to this older discussion: Add to ether the ERC20 token logics (get rid of WETH)
Interested in hearing your feedback! Thx