Simple Summary
Precompile allowing ETH to directly be treated as and transferred as an ERC20 token, without intermediary wrapping / unwrapping steps.
Motivation
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
transferFrom
if 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
- Proposal is implemented as a hard fork at some
introduction_block
- Adds a precompile to the EVM at address
eth_as_erc20_precompile_address
which can be called as an ERC20 + ERC2612 token - Transfers of the “token” at
eth_as_erc20_precompile_address
lead to “parallel” transfers of the actual balance of accounts, enforcing the invarianta.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
CALL
- All transfers of ETH via
CALL
s and via the precompile after theintroduction_block
must emit aTransfer
event - Besides the standard methods dictated by the
ERC20
andERC2612
standards the precompile hasoptIntoETHasERC20() nonpayable returns ()
andusingETHasERC20(address) view returns(bool)
methods - Contracts created before the
introduction_block
must opt-into the “ETH as ERC20” behavior by calling an addedoptIntoETHasERC20()
method - The
usingETHasERC20
method returns whether or not the passed address has access to the “ETH as ERC20” behavior, defaults totrue
for all contracts created postintroduction_block
Security Considerations
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
CALL
call directly or indirectly in a valid sub-context initiated byDELEGATECALL
orCALLCODE
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.
Other Considerations
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.
Conclusion
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