Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Lack of Events for State-Changing Functions (e.g., `receive()`)

Root + Impact

Description

In Ethereum smart contracts, emitting events for state-changing operations is a standard best practice. This enables off-chain indexers, explorers (e.g., Etherscan), and analytics tools (e.g., The Graph) to track and display contract activity in a transparent and observable way.

In this contract, the receive() function accepts Ether but does not emit any event to log this action. As a result, ETH transfers to the contract are not traceable through event logs, which degrades observability and hinders debugging, accounting, or forensic tracing.

receive() external payable {
@> // Missing event emission for received ETH
}

Risk

Likelihood Low:

  • The receive() function will trigger whenever the contract is sent ETH with no data, which is common in DeFi and DAO contracts.

  • In most protocols, contracts receive ETH via fallback or receive() from user wallets, wrappers (e.g., WETH unwrapping), or other smart contracts.

  • Without an event, these deposits will appear in the balance but lack a traceable event log unless explicitly logged via external monitoring tools.

Impact Low:

  • Poor off-chain visibility: Indexers, wallets, and analytics dashboards won't show the incoming ETH properly.

  • Reduced auditability: Missing event logs make it harder to trace financial flows for accounting, dispute resolution, or governance auditing.

  • Protocol monitoring tools may fail to detect critical flows, especially in DAO or treasury use cases.


Proof of Concept

contract EtherSink {
// No event is emitted when Ether is received
receive() external payable {
// Funds are accepted but invisible to indexers
}
}

Explanation

  • In the above PoC, if a user sends ETH directly to the contract using:

sendTransaction({ to: <contract_address>, value: 1 ether })
  • There will be no emitted event capturing the sender or amount. This makes it:

  • Difficult to index such transfers via The Graph or Etherscan.

  • Hard to verify receipt of funds without directly parsing transaction traces.


External actor:

// Send ETH to contract
(bool sent,) = address(silentReceiver).call{value: 1 ether}("");
require(sent, "failed");

On-chain state changes (ETH balance updates) occur, but no event is emitted, so tools like Etherscan won't show what address sent how much ETH.


Recommended Mitigation

Emit an event inside the receive() function to make ETH transfers transparent.

receive() external payable {
+ emit Received(msg.sender, msg.value);
}
+
+event Received(address indexed sender, uint256 amount);

This small addition significantly improves contract observability and helps downstream tools.


Justification for "Low" Severity (not Informational):

  • This is not merely informational because it affects traceability of real financial flows.

  • It qualifies for Low severity due to:

    • Low likelihood of exploit or direct loss, but

    • High relevance for debugging, monitoring, and compliance, especially in DeFi/DAO environments.


Updates

Appeal created

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
thesandf Submitter
about 2 months ago
inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.