Flow

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

Variable Shadowing

Summary : The protocolFee variable in the _withdraw function of the SablierFlow contract shadows the protocolFee state variable in the SablierFlowBase contract and the protocolFee function in the ISablierFlowBase interface.

Impact : This issue may cause confusion and make the code harder to understand and maintain. It may also lead to unexpected behavior if the wrong protocolFee variable is accessed or modified.

Proof of Concept Code:

Here is a proof of concept code that demonstrates the variable shadowing issue:

SablierFlow.sol

pragma solidity ^0.8.0;
import "./SablierFlowBase.sol";
import "./ISablierFlowBase.sol";
contract SablierFlow is SablierFlowBase {
function \_withdraw(
uint256 streamId,
address to,
uint128 amount
)
internal
returns (uint128 withdrawnAmount, uint128 protocolFeeAmount)
{
// Load the variables in memory.
IERC20 token = \_streams\[streamId].token;
UD60x18 protocolFee = protocolFee\[token]; // This line may cause unexpected behavior
// Use the protocolFee variable
uint128 fee = protocolFee * amount; // This line may use the wrong protocolFee variable
// Rest of the code...
}
}

SablierFlowBase.sol

pragma solidity ^0.8.0;
contract SablierFlowBase {
mapping(IERC20 token => UD60x18 fee) public override protocolFee;
// Rest of the code...
}

ISablierFlowBase.sol

pragma solidity ^0.8.0;
interface ISablierFlowBase {
function protocolFee(IERC20 token) external view returns (UD60x18);
}

ExploitContract.sol

pragma solidity ^0.8.0;
import "./SablierFlow\.sol";
contract ExploitContract {
SablierFlow public sablierFlow;
constructor(address sablierFlowAddress) public {
sablierFlow = SablierFlow(sablierFlowAddress);
}
function exploit() public {
// Call the _withdraw function with a specific streamId and token
uint256 streamId = 1;
address to = address(this);
uint128 amount = 100;
// Set the protocolFee variable to a different value
sablierFlow.protocolFee(IERC20(token)) = 1000;
// Call the _withdraw function
sablierFlow._withdraw(streamId, to, amount);
// Check if the protocolFee variable was used correctly
uint128 fee = sablierFlow.protocolFee(IERC20(token)) * amount;
require(fee == 1000 * amount, "Incorrect protocol fee");
}

}

Tools Used : VS code

Recommendations : To fix this issue, it is recommended to rename the protocolFee variable in the _withdraw function to a unique name that does not shadow any other variables.

**Example Fix: **

function \_withdraw(
uint256 streamId,
address to,
uint128 amount
)
internal
returns (uint128 withdrawnAmount, uint128 protocolFeeAmount)
{
// Rename the protocolFee variable to a unique name
UD60x18 withdrawalProtocolFee = protocolFee\[token];
// Use the withdrawalProtocolFee variable
uint128 fee = withdrawalProtocolFee * amount;
// Rest of the code...
}
Updates

Lead Judging Commences

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