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

Unused Code in `FjordStaking::onStreamCanceled` Function

Summary

The FjordStaking::onStreamCanceled function in the contract contains a ternary conditional statement that determines the amount variable. However, due to the nature of the contract's logic, this conditional check results in dead code, as senderAmount will always be less than nftData.amount. This results in the amount being always equal to senderAmount, making the ternary condition redundant.

Vulnerability Details

In the FjordStaking::stakeVested function, the _amount is calculated as follows:

uint256 _amount = depositedAmount - (withdrawnAmount + refundedAmount);

Given the following example(As stream is not yet cancelled):

  1. depositedAmount = 100

  2. withdrawnAmount = 10

  3. refundedAmount = 0

The calculated _amount is:

_amount = 100 - (10 + 0) = 90

So if now consider stream is cancelled sender(Sender of stream) would receive:

Note: senderAmount is calculated in sablier contract SablierV2LockupLinear::_cancel function.

100(Deposited amount to stream) - streamed amount =senderAmount

Here to senderAmount be greater than staked amount through stream streamed amount should be less than 10 which is not possible as we are considering withdrawn amount as 10. So in function FjordStaking::onStreamCanceled FjordStaking::_amount would never be assigned to nftData.amount.

When a stream is canceled, the senderAmount should be less than or equal to the _amount to ensure the refund does not exceed the staked amount. In this scenario, the senderAmount will always be less than the _amount if:

senderAmount < _amount
Since streamedAmount is less than withdrawnAmount, and refundedAmount is zero, the amount variable in onStreamCanceled will always be equal to senderAmount. This makes the ternary condition redundant, as uint256(senderAmount) will always be less than or equal to nftData.amount.

Impact

The redundant ternary conditional check introduces unnecessary complexity into the contract and results in unwanted code execution. While this does not pose a direct security risk, it affects gas efficiency and code maintainability.

Tools Used

Manual

Recommendations

function onStreamCanceled(
uint256 streamId,
address sender,
uint128 senderAmount,
uint128 /*recipientAmount*/
) external override onlySablier checkEpochRollover {
address streamOwner = _streamIDOwners[streamId];
if (streamOwner == address(0)) revert StreamOwnerNotFound();
_redeem(streamOwner);
NFTData memory nftData = _streamIDs[streamOwner][streamId];
- uint256 amount = uint256(senderAmount) > nftData.amount
- ? nftData.amount
- : uint256(senderAmount);
+ uint256 amount = uint256(senderAmount);
_unstakeVested(streamOwner, streamId, amount);
emit SablierCanceled(streamOwner, streamId, sender, amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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