This report analyzes a vulnerability in the getCurrentPower function, where unsafe typecasting is employed during voting power calculations. The vulnerability primarily arises from a dual-type mismatch and lack of proper overflow checks, which can lead to critical miscalculations and potential exploits in governance mechanisms.
Dual-Type Mismatch
Signed vs. Unsigned: The point.bias variable is declared as an int128 (signed), yet voting power inherently must be non-negative.
Unsafe Casting: Casting from int128 to uint128 (and subsequently to uint256) can lead to improper sign handling. For instance, a negative bias value, due to incorrect calculations, would convert to a large positive number when cast, thereby inflating a user’s voting power erroneously.
Calculation Risks
Overflow During Initialization: In calculateAndUpdatePower, the bias is derived from an initialPower (a uint256) via:
If initialPower exceeds 2^127 - 1, the downcast overflows, causing bias to become negative.
Incorrect Result Example: For instance, an initialPower of 2^127 results in bias being set to -2^127. When subsequently cast to uint128, this negative value converts to 2^127, drastically distorting the voting power calculation.
Missing Safety Checks
Validation Gaps: There is no validation to ensure that bias remains non-negative or fits within the uint128 range.
Silent Truncation/Overflow: The lack of explicit checks can cause silent overflow or truncation, corrupting the intended voting power values without triggering any errors.
Incorrect Voting Power: Users might experience massively inflated or erroneously reduced voting power. Negative bias values, when misinterpreted as large positive numbers, can lead to incorrect token voting weights.
Governance Attacks: Malicious actors may exploit these miscalculations to manipulate voting outcomes, undermining the protocol’s integrity.
Fund Locking: The miscalculation may result in tokens being permanently locked or misallocated, disrupting the overall tokenomics and governance structure.
Use uint128 for Bias
Redesign the RAACVoting.Point structure to store bias as uint128 since voting power should always be non-negative:
Update all related calculations to consistently use uint128.
Add Overflow Checks
Incorporate explicit validations when setting bias:
This ensures that values do not exceed the permissible range and prevents silent overflow.
Adjust Return Logic
With bias stored as uint128, the return logic in getCurrentPower can be simplified:
This eliminates the need for unsafe casts and guarantees correct interpretation of the voting power.
Fix calculateInitialPower
Remove redundant casts once the bias type is updated:
Consider a scenario where a user locks tokens resulting in:
Initial Condition: initialPower = 2^128
Current Code Behavior:
bias = int128(2^128) overflows, resulting in bias = -2^127.
When cast via uint256(uint128(point.bias)), the negative value -2^127 becomes 2^127, erroneously granting an excessively high voting power.
Fixed Code Behavior:
The check require(2^128 <= type(uint128).max) would fail, reverting the transaction and preventing invalid locks.
Alternatively, if properly bounded, the new design with uint128 would correctly handle the calculation without misinterpretation.
The unsafe typecast in the getCurrentPower function, combined with the use of a signed type for inherently unsigned voting power calculations, introduces a significant vulnerability. This mismanagement of data types can lead to either inflated or deflated voting power, posing risks of governance attacks and token misallocation. Addressing this issue requires restructuring the data types, adding robust overflow checks, and revising related calculations to ensure the integrity of the voting mechanism. Implementing these changes is critical to maintaining protocol security and preventing potential exploits.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.