Summary
Vulnerability Details
_calculateDistribution will not work well with 6th and 7th distribution, as they don't sum up to 100% like the rest:
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/collectors/FeeCollector.sol#L372-L394
feeTypes[5] = FeeType({
veRAACShare: 7000,
burnShare: 0,
repairShare: 0,
treasuryShare: 3000
});
feeTypes[6] = FeeType({
veRAACShare: 500,
burnShare: 500,
repairShare: 1000,
treasuryShare: 0
});
feeTypes[7] = FeeType({
veRAACShare: 500,
burnShare: 0,
repairShare: 1000,
treasuryShare: 500
});
This can be seen when we start the for loop.
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/collectors/FeeCollector.sol#L431-L457
for (uint8 i = 0; i < 8; i++) {
uint256 feeAmount = _getFeeAmountByType(i);
if (feeAmount == 0) continue;
FeeType memory feeType = feeTypes[i];
totalCollected += feeAmount;
uint256 weight = (feeAmount * BASIS_POINTS) / totalFees;
shares[0] += (weight * feeType.veRAACShare) / BASIS_POINTS;
shares[1] += (weight * feeType.burnShare) / BASIS_POINTS;
shares[2] += (weight * feeType.repairShare) / BASIS_POINTS;
shares[3] += (weight * feeType.treasuryShare) / BASIS_POINTS;
}
The formula we use would calculate each distribution against it's weight to make it distribute the full 100% allocated to it, but for that each distribution needs to sum up to 100%. However the problem is that 6th and 7th don't, which would mean that they distribute only a tiny fraction of their amounts and leave the rest stuck inside the contract.
Example:
/**
* totalFees = 1000
*
* feeAmount1 = 100
* feeAmount2 = 500
* feeAmount3 = 250
* feeAmount6 = 150
*
* w1 = 100 * 10k / 1000 = 1000
* shares[0] += 1000 * 8000 / 10k = 800
* shares[3] += 1000 * 2000 / 10k = 200
*
* w2 = 500 * 10k / 1000 = 5000
* shares[0] += 5000 * 7000 / 10k = 3500
* shares[3] += 5000 * 3000 / 10k = 1500
*
* w3 = 250 * 10k / 1000 = 2500
* shares[0] += 2500 * 6000 / 10k = 1500
* shares[3] += 2500 * 4000 / 10k = 1000
*
* w6 = 150 * 10k / 1000 = 1500
* shares[0] += 1500 * 500 / 10k = 75
* shares[1] += 1500 * 500 / 10k = 75
* shares[2] += 1500 * 1000 / 10k = 150
*
* shares[0] = 5875
* shares[1] = 75
* shares[2] = 150
* shares[3] = 2700
*
* total = 8800
*
*/
As we can see from this drawn out example the total does not sum up to 10k, meaning that when we perform the bellow 1200 or 12% of the weight is not gonna be distributed and it's gonna end up in shares[3]
shares[0] = (totalFees * shares[0]) / BASIS_POINTS;
shares[1] = (totalFees * shares[1]) / BASIS_POINTS;
shares[2] = (totalFees * shares[2]) / BASIS_POINTS;
shares[3] = (totalFees * shares[3]) / BASIS_POINTS;
uint256 remainder = totalFees - (shares[0] + shares[1] + shares[2] + shares[3]);
if (remainder > 0) shares[3] += remainder;
Impact
For is flawed, does not distribute amounts correctly
Assigns a huge percentage toward the treasury fee, where this percentage should have been distributed to the rest of the allocations
Tools Used
Manual review
Recommendations
Make sure all of the values sum up to 100%