Summary
protocol takes broker fees when a sender creates a stream. Broker fees is a one of the revenue source of protocol. As a traditional DeFi rule says rounding should be in the favor of the protocol but in our case it's not in the favor of protocol which allows zero broker fees for tiny amount
Vulnerability Details
File: v2-core/src/libraries/Helpers.sol
function checkAndCalculateBrokerFee(
uint128 totalAmount,
UD60x18 brokerFee,
UD60x18 maxBrokerFee
)
internal
pure
returns (Lockup.CreateAmounts memory amounts)
{
if (totalAmount == 0) {
return Lockup.CreateAmounts(0, 0);
}
if (brokerFee.gt(maxBrokerFee)) {
revert Errors.SablierV2Lockup_BrokerFeeTooHigh(brokerFee, maxBrokerFee);
}
amounts.brokerFee = uint128(ud(totalAmount).mul(brokerFee).intoUint256());
assert(totalAmount > amounts.brokerFee);
amounts.deposit = totalAmount - amounts.brokerFee;
}
amounts.brokerFee = uint128(ud(totalAmount).mul(brokerFee).intoUint256())
here we can see that brokerFee
is calculated by rounding down which is not in the favor of protocol.
Users can use this to make brokerFee
zero for tiny amount where protocol will incurred loss
Impact
protocol will incur tiny loss in every stream creation
Tools Used
Manual
Recommendations
Instead of rounding down brokerfee
, round down deposit amount and then subtract from total amount to get broker Fees.
A good example can be seen below
function checkAndCalculateBrokerFee(
uint128 totalAmount,
UD60x18 brokerFee,
UD60x18 maxBrokerFee
)
internal
pure
returns (Lockup.CreateAmounts memory amounts)
{
// When the total amount is zero, the broker fee is also zero.
if (totalAmount == 0) {
return Lockup.CreateAmounts(0, 0);
}
if (brokerFee.gt(maxBrokerFee)) {
revert Errors.SablierV2Lockup_BrokerFeeTooHigh(brokerFee, maxBrokerFee);
}
// amounts.brokerFee = uint128(ud(totalAmount).mul(brokerFee).intoUint256());
amounts.deposit= uint128(ud(totalAmount).mul(UD60x18.wrap(1e18)-brokerFee).intoUint256());
assert(totalAmount > amounts.deposit);
amounts.brokerFee = totalAmount - amounts.deposit;
}