Flow

Sablier
FoundryDeFi
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

Batch::batch will fail if one the calls throws an error

Summary

The batch function in this contract allows execution of multiple transactions within a single call using delegatecall. However, the function has a critical flaw: if any one of the calls fails, it reverts the entire batch transaction. This behavior can cause issues, especially in systems that require partial execution of successful calls even if one fails.

Vulnerability Details

The batch function iterates through an array of function call data (calls) and executes each item in sequence using delegatecall, which runs each function in the context of the calling contract. This preserves msg.sender and enables sharing of state variables between calls. Here, however, if any of the calls within the batch revert or throw an error, the entire batch reverts. This behavior is controlled by the following logic:

function batch(bytes[] calldata calls) external {
uint256 count = calls.length;
for (uint256 i = 0; i < count; ++i) {
(bool success, bytes memory result) = address(this).delegatecall(calls[i]);
if (!success) {
@> revert Errors.BatchError(result);
}
}
}

This means that any failure will stop the execution of the remaining calls and roll back all previous successful calls, making the transaction atomic but potentially causing unwanted behavior in cases where partial execution would be acceptable.

Impact

Lack of Partial Execution: The entire transaction reverts if even one call fails, preventing successful calls from being processed if partial execution is desired.

Gas Wastage: If one call in the sequence fails after several successful executions, all previous state changes are reverted, wasting gas for the sender.

Vulnerability to Denial of Service (DoS): An attacker could craft a failing call within the batch to intentionally cause the entire batch to revert, potentially disrupting contract operations or causing financial losses for users.

Tools Used

Manual Review

Recommendations

Non-Reverting Calls: Modify the function to catch errors individually, log them, and continue executing the remaining calls. For instance:

for (uint256 i = 0; i < count; ++i) {
(bool success, bytes memory result) = address(this).delegatecall(calls[i]);
if (!success) {
emit CallFailed(i, result); // Emit an event to log the error
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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