With chains moving to even lower block times ( see https://x.com/jessepollak/status/1911858196836483540 ) I think this EIP becomes even more important, if we don’t want to trace-debug 5 blocks per seconds to undertsand when ETH has been sent out of a Smart Wallet
This would be much easier to filter ETH transfers. ![]()
I think source address should be set to 0xeee…eee instead of 0xfffffffffffffffffffffffffffffffffffffffe . This is what ERC-7528: ETH (Native Asset) Address Convention recommends. Or to 0x000…000 for better compressibility
ERC-7528 doesn’t have consensus. Plenty of protocols (such as UniswapV4) use the zero address for native assets. I prefer zero or null for compression, but also because it can become a precompile in the future.
The rationale of 0xffff…e is that it is already used in finalized EIP-4788. I don’t really see the point of having multiple system addresses, but they seem to be used for validator operations as well (with arbitrary deployed contracts designated to be system relevant), so one could also use 0xeee.ee specifically for ETH transfers as well. There’s also the EIP-7799 interaction for getting a complete picture of the ETH balance history; one could also use the 0xeee.ee address for these. Or zero.
Was dealing with an issue one of our customers had today. To give context, we provide a smart-account based wallet. Our customer wanted to deposit on Bitfinex ETH, so he sent money and on the other side no money were received.
Deep diving I found this: https://support.bitfinex.com/hc/en-us/articles/214441685-Ethereum-Deposits-at-Bitfinex
We can argue it’s Bitfinex fault. But the reality is that if to track internal ETH transfer the only way is debug traceCall for each block, no one is gonna do that, affecting essentially Smart Contract adoption. This is why I think this EIP is a crucial one around Smart Contract adoption and overall improve UX.
This is an essential EIP to improve support massively, great discussion above that shows all the point of friction that exist today and some open questions that need closing.
Reading through the discussion, it seems we’ve reached a solid agreement on a few key points:
-
The ”Why” is clear: We all acknowledge the significant challenge of tracking ETH transfers from smart contract wallets. This hurts the user experience and creates real-world problems for users and services. This EIP is crucial for the adoption of smart accounts.
-
What should trigger a log: There’s a general agreement that, at a minimum, value-transferring
CALLandSELFDESTRUCToperations should emit a log. -
Log format: The idea to replicate the ERC-20
Transferevent format seems to have a good level of support, as it would simplify implementation for wallets and indexers that already handle ERC-20 tokens. Event is emitted by0xfffffffffffffffffffffffffffffffffffffffe -
Backfill The idea is to enable from a certain moment on, avoiding the backfill of all the past ETH transfers now covered by this EIP.
The primary unresolved issue remains the gas cost. While some argue that current operational costs could absorb the new logging cost, the prevailing view is that any new action must be accurately priced to reflect the resources it consumes. This is the critical point we need to resolve.
With the ongoing scalability efforts, it’s likely that any minor gas increase could be absorbed by senders as the overall cost per gas is expected to decrease. However, the path to formally evaluating and deciding on this cost increase isn’t clear to me.
Could anyone with experience in the EIP process share how this is typically handled when it comes to gas? Ideally with practical next-steps on what is the standard approach for analyzing and agreeing on gas cost adjustments. ( cc @MicahZoltu if you can help )
I still like 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE because many apps on Ethereum already use it, and eth_simulateV1 which is implemented in multiple clients uses it for logging ETH transfers already. I think these benefits of backwards compatibility outweigh the incredibly minor benefit of “coming from the system address”.
This should be easy (technically), just add the log costs to the intrinsic gas for non-0 value transfers. Sadly, in reality this will break sooo many things that it hurts my soul to even think about it.
Encode the correct gas costs into the EIP, propose it to Core Devs, but mention in the discussion with them all of the things that will break, then let them decide, of their own volition, to just ignore the gas costs of these new logs.
I have some comments regarding this EIP:
- Sending value with
CREATEorCREATE2is not considered here, I believe it should be added - When considering this EIP we should take into account this adds extra logs to the receipts and thus the gas limit to reach the 10 MiB devp2p limit is closer (we need: EIP-7975: eth/70 - partial block receipt lists to remove this limit/problem)
- The log origin address is saved per log, so we could omit the
sendertopic for normal transfers as this is already saved in the log. However this would not allow filtering on the sender address (so likely a bad idea) - Adding all ETH transfers to logs is, for UX, likely a good idea. This would mean adding withdrawals, fee payments, and eth burn to the logs (as somewhat asked in open questions already). This would allow to craft a complete net balance change per block by just inspecting the logs. It would add at most 3 logs per tx: one for the tx transfer, one for the fee payment, and one for the fee burn. Open question would be what the target address of the fee burn would be. Note: in practice creating the net balance change might be less trivial than initially thought, as any contract could craft the
LOG3stack to add logs which look like ETH transfers, but are not. - How to handle blob gas?
If we ship EIP-7668: Remove bloom filters we also don’t have to worry about these mandatory extra items to the filter.
I believe we should do all ETH transfers including fee payments/burn, but am not sure about the withdrawals since these are already in the block header and it feels like duplicating data to also add them to the logs. However, adding them to the logs does ensure that all transfers are accounted for.
Note that using a sender/target address for withdrawals/burn which uses an address larger than 20 bytes would work currently as it is not possible to target >20 byte addresses. However if we go to 32-byte addresses this is thus not the case anymore. So we should likely pick a designated sender/receiver for these, just as the topic, keeping in mind that any contract can fabricate these logs so these should be carefully treated anyways (to check for bogus transfer logs).
While not reflected in the EIP, this has been discussed in this thread and it is proposed to set the address of the log to be coming from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (my preference for reasons discussed above) or 0x0000000000000000000000000000000000000000000000000000000000000000 or 0xfffffffffffffffffffffffffffffffffffffffe.
@vbuterin @petertdavies Can we get the EIP updated to reflect the discussion that has occurred in this thread? Alternatively, if you two aren’t following along anymore could we get a new author added that can maintain this EIP and help push it through (not me)?
One risk with this EIP is that, if adopted alone, it does not fulfil what it aims for: removing the need for external indexers. The missing pieces are due to operations which change balances outside transactions, and I think that it makes sense to combine this EIP with sth like EIP-7799 which adds those pieces.
7799 provides a suggestion for batching priority fee credits to avoid hundreds of micro-credits per block. But it affects mevboost builders, as they cannot spend the prio fee in the same block anymore, as the credit would have to go at the end. Further, 7799 also extends the block header with a new system logs tree, so may be better suited for a fork when the block header gets cleaned up (e.g., EIP-7807).
But without sth like EIP-7799, I don’t think adding the logs should be done in isolation, as it doesn’t remove the indexers need. Would vote to defer it for H*, while recognizing it’s super high relevance.
Posted this on discord, but adding here for visibility:
EDIT: Never mind, this incorrectly describes the selfdestruct behavior under EIP-6780.
Maybe in general for the understanding of SELFDESTRUCT (so not SENDALL as in EIP-6780, i.e. 0xff SELFDESTRUCT in same transaction as the contract is being created). It does not work as the intuition might state, because it has multiple steps:
Upon invoking the opcode, mark current contract to-be selfdestructed and send all balance to the target. Exit current call frame.
After the transaction ends (I have to check when precisely, if this is AFTER the tx execution, but before or after the fee transfer to coinbase (this is thus also an test case which should be added: selfdestruct coinbase as the accounting for fees is interesting here)) destroy all the accounts marked as to-be-selfdestructed. This means deleting it from trie. (And thus also the only way to destroy ETH).
It does thus not mean, as intuition might lead one thinking, that it is immediately destroyed when invoking the opcode (the code which is deposited there thus keeps existing in the current transaction when it was created, as this is the only way to invoke SELFDESTRUCT; after the tx the invocation is SENDALL. (There is thus also a case where one does SELFDESTRUCT in initcode, and also SELFDESTRUCT after deposting the code in the same tx)
For EIP-7708: it should mark required EIPs: EIP-4788 (system address), EIP-1559 (fee transfer, EIP-6780 (only SELFDESTRUCT in same transaction)
I think using LOG2 for burning is a very good choice. The only case when this is thus invoked is “at the end of the transaction” (and either before or after sending priority fee).
It should (I think) be noted that for the SELFDESTRUCT AND SENDALL case (when sending ether) it should work as normal as LOG3 (and should not log when sending to self). Only in case of SELFDESTRUCT when burning ether it should invoke the LOG2
is there any chance of this getting included in the next hardfork? where is the best place to voice my support for it?
EIP-7708 is Considered for Inclusion in Glamsterdam upgrade.
It is in the spec for bal-devnet-3
bal-devnet-3 is live
yes I saw it was CFI’d, but I don’t really have a strong understanding of what that means in practice
being in a live devnet sounds very promising tho
Really interesting, how is the log going to look like? Is just going to mirror ERC20’s Tranfer event? But couldn’t this be solved at the implementatin level, letting the developer decide? Could be really useful
I think the goal here is solving the fact that smart accounts are basically cut off from many different traditional operations. Example: depositing to an exchange is not possible in most of the cases , as the exchange should debug trace all the blocks to listen for incoming txs to a deposit address. Leaving as an opt in feature for a smart contract developer would not solve the problem, with all the current implementations cut off from this critical feature.
Great to see this EIP finally coming to mainnet!
Why lexicographical order of the “final burn”? This is risky because requires dedicated sorting. If you have a state journal, you can emit these logs in the order of account selfdestruction.
EIP-7708 Update Proposal: Replace Burn Events with Balance-Preserving SELFDESTRUCT Finalization
Motivation
EIP-7708 introduces two kinds of ETH movement logs:
- Transfer logs — for nonzero-value transactions,
CALL, andSELFDESTRUCTto a different address. - Burn logs — for ETH that leaves the world state. Defined for two cases:
- A nonzero-balance
SELFDESTRUCTto self by a contract created in the same transaction, at opcode execution time. - Any nonzero-balance account marked for deletion by
SELFDESTRUCTthe contract created in the same transaction, at the time of removal during transaction finalization.
- A nonzero-balance
The burn log paths are exotic: post-EIP-6780, the only accounts that can be marked for deletion are contracts created in the same transaction, and the finalization case further requires that ETH be sent to such an account after it has already self-destructed. The examination of a small sample of Ethereum mainnet blocks (30 consecutive SELFDESTRUCT opcode executions) showed zero occurrences of either condition: all observed SELFDESTRUCT calls had zero balance and distinct beneficiaries.
Burn logs exist solely because ETH can be silently destroyed by the current SELFDESTRUCT semantics. If the underlying cause — ETH being destroyed — is eliminated, burn logs become unnecessary.
This proposal eliminates ETH burning by modifying how accounts marked for deletion are processed at transaction finalization. ETH is preserved by construction; only transfer logs are required.
Specification
Finalization of deleted accounts (replaces EIP-6780’s account removal for marked-for-deletion accounts)
At the point of transaction finalization, for each account that was marked for deletion during the transaction, the following mutations are applied to the State instead of removing the account:
- The account’s code is cleared: code hash is reset to
keccak256("")and the stored code becomes empty. - The account’s nonce is reset to
0. - The account’s storage is cleared (all slots reset to zero).
- The account’s balance is preserved.
After these mutations, the account is subject to the standard empty-account rule (EIP-161): if the resulting balance is zero and nonce is zero and code is empty, the account is removed. Otherwise, the account remains in the state trie holding only its balance.
SELFDESTRUCT to self
When a contract created in the same transaction executes SELFDESTRUCT with itself as the beneficiary, the opcode marks the account for deletion as before, but its balance is preserved.
This is consistent with the behavior of SELFDESTRUCT of the pre-existed accounts.
ETH transfer log
Unchanged.
ETH burn log
Removed. No burn log is emitted under any condition.
Rationale
Why not emit burn logs?
The only way ETH can be removed from the world state under the current EVM is through SELFDESTRUCT of a contract created in the same transaction (post-EIP-6780). This proposal redefines the finalization of such accounts so that their balance survives, at which point no ETH-destruction event exists to log.
Why this is safe for state consistency
An account marked for deletion has its effects confined to the current transaction. Clearing code, nonce, and storage at finalization is equivalent to the account never having been created for the purposes of future transactions, except for the retained balance. The transaction has already paid the creation cost (base, initcode, and code deposit), so the retained balance is not subsidized — it comes from ETH the caller explicitly transferred to the account.
Future CREATE2 at the same address
A future CREATE2 at the preserved account’s address would not collide under EIP-7610 rules:
- Nonce is 0.
- Code is empty.
- Initial storage is empty.
A nonzero balance alone does not constitute a collision. The address remains available for future deployment.
SELFDESTRUCT semantics
This proposal further nerfs SELFDESTRUCT beyond EIP-6780. Under EIP-6780, SELFDESTRUCT on a contract created in the same transaction still removes the account from the state; this proposal reduces that to a balance-preserving clear of the code, nonce, and storage. SELFDESTRUCT becomes, in effect, an opcode that transfers balance and resets contract state, without any path that destroys ETH.
Whether this change should be packaged as a separate EIP (a SELFDESTRUCT successor) or integrated into EIP-7708 is left as an open question.
Backwards Compatibility
Observable differences from EIP-6780
Under EIP-6780, a contract created in the same transaction that self-destructs is fully removed from the state at finalization. Under this proposal:
- If the self-destructed contract received additional ETH after
SELFDESTRUCTand before transaction end, that balance remains as a freestanding balance-only account (previously: the balance was burned). - If the self-destructed contract self-destructs to itself with nonzero balance, that balance remains (previously: the balance was burned).
- In all other cases, the net state diff is identical to EIP-6780: the account is removed (because the balance is zero and the EIP-161 empty-account rule applies).
Gas accounting
There are no gas refunds for SELFDESTRUCT since London, so no changes here.
Security Considerations
Gas griefing
A contract that sends ETH to a self-destructed contract no longer causes that ETH to be burned. Instead, the ETH becomes owned by a code-less address. In rare attack scenarios where a user’s contract relied on ETH being burned (for deflationary accounting or similar), this behavior change would be observable. Such designs would be unusual and rely on SELFDESTRUCT semantics that were already scheduled for further nerfing.
Dust accounts
In the edge case where a self-destructed contract accumulated dust from a later inbound transfer, a balance-only account is created. This is identical in form to any externally owned account with a balance and is not a new class of state entry.