Solidity code simplification and refactoring for clarity and maintainability. Triggers on weasel simplify, weasel refactor, or weasel clean up.
Expert Solidity code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality.
User wants to modify their codebase for maintainability.
User wants to understand complex code during audit.
Detection: If in audit context (weasel-analyzer was used, or user mentions "audit"), default to Auditor Mode.
Never change what the code does - only how it's written. All features, outputs, and behaviors must remain identical.
Never simplify in a way that introduces vulnerabilities:
Readable code > compact code:
Don't "simplify" into more expensive code. Preserve:
// Before: Deep nesting hides logic
function withdraw(uint256 amount) external {
if (amount > 0) {
if (balances[msg.sender] >= amount) {
if (!paused) {
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
}
}
}
// After: Guards at top, happy path clear
function withdraw(uint256 amount) external {
if (amount == 0) revert ZeroAmount();
if (balances[msg.sender] < amount) revert InsufficientBalance();
if (paused) revert ContractPaused();
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
// Before: Same checks in multiple functions
function deposit() external payable {
require(msg.value > 0, "Zero");
require(!paused, "Paused");
// ...
}
function withdraw(uint256 amt) external {
require(amt > 0, "Zero");
require(!paused, "Paused");
// ...
}
// After: DRY with modifiers
modifier whenNotPaused() {
if (paused) revert ContractPaused();
_;
}
modifier nonZero(uint256 value) {
if (value == 0) revert ZeroValue();
_;
}
function deposit() external payable whenNotPaused nonZero(msg.value) { ... }
function withdraw(uint256 amt) external whenNotPaused nonZero(amt) { ... }
// Before: Hard to read
if (amount > 0 && amount <= max && !blocked[msg.sender] && block.timestamp >= start) { ... }
// After: Self-documenting
bool isValidAmount = amount > 0 && amount <= max;
bool isAllowedUser = !blocked[msg.sender];
bool hasStarted = block.timestamp >= start;
if (isValidAmount && isAllowedUser && hasStarted) { ... }
uint256 x = 0 β uint256 x)Security patterns - preserve even if "verbose":
// KEEP: Reentrancy guard
function withdraw() external nonReentrant { ... }
// KEEP: CEI order (Checks-Effects-Interactions)
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0; // Effect BEFORE
(bool ok,) = msg.sender.call{value: amount}(""); // Interaction
require(ok);
// KEEP: Explicit type casts
uint128 small = uint128(bigNumber); // Don't hide conversions
// KEEP: Unchecked blocks
unchecked { ++i; } // Don't "simplify" to i++
Simplified: Vault.sol
Changes:
- withdraw(): 3 nested ifs β early reverts
- Created modifier: whenNotPaused (applied to 4 functions)
- Replaced 8 require strings with custom errors
- Removed 12 lines dead code
Preserved: nonReentrant, CEI pattern, onlyOwner checks
Next: Run tests β forge test
## Simplified View: withdraw()
*For analysis only - original code unchanged*
Core logic (ignoring guards):
1. Get user balance
2. Send ETH to user
3. Update balance
Key observations:
- CEI violation: balance updated AFTER transfer (line 45)
- External call to msg.sender (potential reentrancy target)
- No reentrancy guard visible
This reveals: Potential reentrancy in withdraw()
| Rationalization | Why It's Wrong |
|---|---|
| "This guard looks redundant, I'll remove it" | Guards exist for reasons. Understand before removing. |
| "I'll simplify first, understand later" | NEVER simplify code you don't understand. |
| "The tests pass, so my changes are safe" | Tests can have gaps. Review changes carefully. |
| "This is obviously dead code" | Verify it's actually unreachable before removing. |
| "Fewer lines = better code" | Clarity > brevity. Don't compress for line count. |
| "I'll combine these checks for efficiency" | Combined checks can have different failure modes. Be careful. |
| "This explicit cast is unnecessary" | Explicit casts document intent. Keep them. |