crates/lint/docs/delegatecall-loop.md
Severity: Low
ID: delegatecall-loop
Flags delegatecall operations inside loops in externally callable payable functions.
Reports delegatecall expressions that appear in the body of a for, while, or do while
loop when the enclosing function is public payable or external payable.
delegatecall executes another contract's code in the caller's storage context and preserves
the original msg.sender and msg.value. In a payable function, a loop can therefore expose the
same msg.value to multiple delegatecalls even though Ether was only transferred once.
If the delegated code accounts for msg.value, one transaction can credit the same payment
multiple times or repeatedly mutate the caller's storage in unexpected ways.
function batch(address[] calldata receivers) external payable {
for (uint256 i; i < receivers.length; ++i) {
address(this).delegatecall(abi.encodeWithSignature("credit(address)", receivers[i]));
}
}
function batch(address[] calldata receivers) external payable {
uint256 share = msg.value / receivers.length;
for (uint256 i; i < receivers.length; ++i) {
_credit(receivers[i], share);
}
}
Review each occurrence manually. If delegatecall is required, ensure delegated code cannot
reuse msg.value or unexpectedly modify caller storage across loop iterations.