Flow

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

Gas Optimization

Summary

The current implementation of the NoDelegateCall contract may incur unnecessary gas costs due to the redundant use of the ORIGINAL state variable when checking for delegate calls.

Finding Description

The contract contains a private immutable variable ORIGINAL that stores the address of the deployed contract (address(this)). This variable is used in the _preventDelegateCall() function to verify whether the current execution context is a delegate call. Since address(this) can be used directly within the function, storing it as a state variable increases the contract's size and incurs additional gas costs during storage access.

This redundancy may lead to a higher transaction cost for users interacting with functions that utilize the noDelegateCall modifier. While it does not introduce a security vulnerability, it affects the contract's efficiency, especially in scenarios with high-frequency calls.

Vulnerability Details

  • Gas Cost: Every time a function using the noDelegateCall modifier is executed, the storage access to the ORIGINAL variable incurs a gas cost. This could be optimized by using address(this) directly in the _preventDelegateCall() function.

  • Efficiency: As the contract scales or is called frequently, the cumulative gas costs can become significant, impacting user experience and possibly discouraging interactions with the contract.

Impact

I assessed this impact as medium severity because, while it does not introduce a security risk or functional issue, it affects the operational costs associated with using the contract. Gas inefficiencies can lead to higher fees for users and can deter the use of the contract, impacting its adoption and overall usability.

Proof of Concept

Below is the original _preventDelegateCall() function that references the ORIGINAL state variable:

function _preventDelegateCall() private view {
if (address(this) != ORIGINAL) {
revert Errors.DelegateCall();
}
}

The comparison to the ORIGINAL variable can be replaced with a direct check to address(this):

function _preventDelegateCall() private view {
if (msg.sender != address(this)) {
revert Errors.DelegateCall();
}
}

Recommendations

To fix the issue, I recommend removing the ORIGINAL state variable and using address(this) directly in the _preventDelegateCall() function. Here’s the updated implementation:

/// @dev This function checks whether the current call is a delegate call, and reverts if it is.
function _preventDelegateCall() private view {
if (msg.sender != address(this)) {
revert Errors.DelegateCall();
}
}

By applying this change, the contract can save gas by eliminating unnecessary storage access, leading to more efficient execution of functions utilizing the noDelegateCall modifier.

File Location

NoDelegateCall.sol

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 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.