Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Precision Loss in Fee Distribution: Impact and Mitigation Strategies

Summary

This report analyzes a precision loss issue in the FeeCollector::_calculateDistribution function, which is responsible for distributing protocol fees among multiple recipients (veRAAC, burn, repair, and treasury). The function suffers from cumulative rounding errors due to multiple integer divisions, leading to:

  1. Users Receiving Less Than Expected – Rewards for veRAAC stakers, burn mechanisms, and repair funds are systematically reduced.

  2. Unintended Treasury Accumulation – Truncated values create a remainder, which is always allocated to the treasury, leading to unfair distribution over time.

  3. Potential Transaction Reverts – Precision loss may cause the total allocated fees to be slightly lower than totalFees, triggering a revert (InvalidFeeAmount()).

Vulnerability Details

Multiple Integer Divisions Causing Precision Loss

The `_calculateDistribution` function performs integer division three times, compounding precision loss at each step. Since Solidity truncates decimal values instead of rounding, small fractions of fees are lost in every calculation.

Relevant Code:
uint256 weight = (feeAmount * BASIS_POINTS) / totalFees; // First division
shares[0] += (weight * feeType.veRAACShare) / BASIS_POINTS; // Second division
shares[0] = (totalFees * shares[0]) / BASIS_POINTS; // Third division

Impact

  • The more divisions, the greater the loss of precision.

  • The final shares distributed are less than the intended amount.

  • Users receive less rewards, weakening the incentive structure of the protocol.

Real-World Impact Breakdown of Precision Loss in _calculateDistribution

Assumptions for This Example

  • Total Fees Collected: 1,000,000 tokens

  • Fee Categories: veRAAC (30%), Burn (20%), Repair (25%), Treasury (25%)

  • BASIS_POINTS = 10,000

If calculated with perfect precision:

Category Expected Tokens
veRAAC 300,000
Burn 200,000
Repair 250,000
Treasury 250,000

Where Precision Loss Occurs

Step 1: Weight Calculation Precision Loss

Relevant Code:

uint256 weight = (feeAmount * 10000) / totalFees; solidity

Example Calculation:
If feeAmount = 333,333 and totalFees = 1,000,000:

(333,333×10,000)÷1,000,000=3333.3(333,333 \times 10,000) \div 1,000,000 = 3333.3(333,333×10,000)÷1,000,000=3333.3

Solidity truncates this to 3333, losing 0.3.

Impact:

  • This rounding loss occurs for each fee type (up to 8 times).

  • If each iteration loses 0.3 tokens, the total loss compounds.


Step 2: Share Allocation Precision Loss

Relevant Code:

shares[0] += (weight * feeType.veRAACShare) / 10000;

Using weight = 3333 and veRAACShare = 30%:

(3333×30)÷10,000=999.9(3333 \times 30) \div 10,000 = 999.9(3333×30)÷10,000=999.9

Solidity truncates this to 999, losing 0.9 tokens per iteration.

Impact:

  • Each category suffers small losses per iteration.

  • Across 8 iterations, hundreds of tokens are lost.


Step 3: Final Scaling Precision Loss

Relevant Code:

shares[0] = (totalFees * shares[0]) / 10000;

If shares[0] was expected to be 300,000, but precision loss reduced it to 299,800, then:

(1,000,000×299,800)÷10,000=29,980(1,000,000 \times 299,800) \div 10,000 = 29,980(1,000,000×299,800)÷10,000=29,980

Solidity truncates again, resulting in further token loss.

Impact:

  • The veRAAC share is reduced below 300,000, unfairly lowering rewards.

  • The same happens for Burn and Repair categories.

Tools Used

Recommendations

Reduce scaling and Use 1e18 precision instead of BASIS_POINTS (10,000)

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

FeeCollector distributes too much to treasury when fee amounts are small relative to total due to precision loss in (feeAmount * BASIS_POINTS) / totalFees

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

FeeCollector distributes too much to treasury when fee amounts are small relative to total due to precision loss in (feeAmount * BASIS_POINTS) / totalFees

Support

FAQs

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

Give us feedback!