Summary
The FeeCollector::updateFeeType has a condition where it checks that the amount of the total fees is not equal to BASIS_POINTS.
This implementation is totally wrong, if FEE_MANAGER_ROLE passes fees whose total amount is greater than BASIS_POINTS then it will lead the protocol into an incorrect state.
Vulnerability Details
* @notice Updates parameters for a specific fee type
* @param feeType Fee type to update
* @param newFee New fee parameters
*/
function updateFeeType(uint8 feeType, FeeType calldata newFee) external override {
if (!hasRole(FEE_MANAGER_ROLE, msg.sender)) revert UnauthorizedCaller();
if (feeType > 7) revert InvalidFeeType();
๐๐ if (newFee.veRAACShare + newFee.burnShare + newFee.repairShare + newFee.treasuryShare != BASIS_POINTS) { ๐๐
revert InvalidDistributionParams();
}
feeTypes[feeType] = newFee;
emit FeeTypeUpdated(feeType, newFee);
}
Impact
The contract uses basis points for percentage calculations (10000 = 100%) , see on the doc.
If the fee amount total is greater than 10000, then it will lead the contract into an incorrect state.
Tools Used
Manual review
Recommendations
/**
* @notice Updates parameters for a specific fee type
* @param feeType Fee type to update
* @param newFee New fee parameters
*/
function updateFeeType(uint8 feeType, FeeType calldata newFee) external override {
if (!hasRole(FEE_MANAGER_ROLE, msg.sender)) revert UnauthorizedCaller();
if (feeType > 7) revert InvalidFeeType();
// Validate fee shares total to 100%
- if (newFee.veRAACShare + newFee.burnShare + newFee.repairShare + newFee.treasuryShare != BASIS_POINTS) {
+ if (newFee.veRAACShare + newFee.burnShare + newFee.repairShare + newFee.treasuryShare > BASIS_POINTS) {
revert InvalidDistributionParams();
}
feeTypes[feeType] = newFee;
emit FeeTypeUpdated(feeType, newFee);
}