-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Summary
Extend dead code detection to comprehensively identify unused custom errors, events, and modifiers in Solidity contracts, providing developers with a complete picture of removable code to optimize contract size and deployment costs.
Motivation
Current dead code detection in many analyzers focuses primarily on unused functions and variables, but misses other important unused elements:
- Custom Errors (introduced in Solidity 0.8.4) - Can accumulate during refactoring
- Events - Often left behind after removing functionality
- Modifiers - May become obsolete as access control evolves
Removing unused code elements provides significant benefits:
- Reduced deployment costs - Smaller bytecode means lower deployment gas
- Improved maintainability - Less code to understand and maintain
- Better security posture - Eliminates potential attack surface
- Cleaner interfaces - Removes confusion about which elements are actually used
Detection Targets
1. Unused Custom Errors
contract Example {
error UnusedError(address user); // DETECT: Never used
error UsedError(uint256 amount); // OK: Used below
function doSomething(uint256 val) external {
if (val == 0) revert UsedError(val);
}
}
2. Unused Events
contract Example {
event UnusedEvent(address indexed user); // DETECT: Never emitted
event UsedEvent(uint256 value); // OK: Emitted below
function action() external {
emit UsedEvent(100);
}
}
3. Unused Modifiers
contract Example {
modifier unusedModifier() { // DETECT: Never applied
require(msg.sender == owner);
_;
}
modifier usedModifier() { // OK: Used below
require(msg.value > 0);
_;
}
function pay() external payable usedModifier {
// ...
}
}
Implementation Approach
The detector should:
- Track all custom error, event, and modifier definitions
- Find all references/uses throughout the codebase
- Check inheritance chains for usage in child contracts
- Verify interface compliance requirements
- Calculate bytecode impact of unused elements
- Report with actionable recommendations
Expected Output
Comprehensive Dead Code Analysis Results
Unused Custom Errors (3):
- UnusedError1 at Contract.sol:10
Impact: Adds 200 bytes to bytecode
Safe to remove: Yes
- UnusedError2 at Contract.sol:15
Impact: Adds 150 bytes to bytecode
Safe to remove: Check inheritance
Unused Events (2):
- OldTransfer at Contract.sol:25
Impact: Adds 300 bytes to bytecode
Note: May be required by external tools/indexers
Unused Modifiers (1):
- legacyOnlyOwner at Contract.sol:40
Impact: Adds 400 bytes to bytecode
Replaced by: newAccessControl modifier
Total potential savings: ~1050 bytes
Estimated deployment gas saved: ~210,000 gas
Advanced Features
Cross-Contract Analysis
- Check if items are used in child contracts
- Verify interface compliance
- Track library usage
Inheritance Chain Analysis
contract Base {
error BaseError(); // Check usage in entire tree
modifier baseModifier() virtual { _; }
}
contract Child is Base {
modifier baseModifier() override { _; } // OK: Override in use
}
Test Cases
// Test contract with various unused elements
contract TestUnused {
// Unused elements (should be detected)
error Never_Used(string message);
event Never_Emitted(uint256 value);
modifier never_Applied() { _; }
// Used elements (should not be detected)
error Actually_Used(uint256 code);
event Actually_Emitted(address user);
modifier actually_Applied() { _; }
function testFunction() external actually_Applied {
emit Actually_Emitted(msg.sender);
revert Actually_Used(404);
}
}
// Interface compliance test
interface ITest {
event Required_Event(uint256 id);
}
contract TestImpl is ITest {
event Required_Event(uint256 id); // Should not be flagged
event Extra_Event(address user); // Should be flagged if unused
}
Benefits
- Significant gas savings - Each removed element reduces deployment cost
- Improved code clarity - Only active code remains
- Better maintainability - Less code to review and understand
- Reduced attack surface - Fewer code paths to audit
- Optimization insights - Identifies refactoring opportunities
Priority
Medium-High - While not a security vulnerability, unused code significantly impacts deployment costs and contract maintainability. With the 24KB contract size limit, removing dead code can be critical for complex contracts. The detector provides immediate value with actionable results and quantifiable benefits.