In the veRAACToken
contract, there is a function named veRAACToken::increase
that enables users to increase the amount of their locked RAAC tokens. When a user calls this function, it issues a proportional amount of veRaacTokens
corresponding to the additional RAAC tokens being locked. This mechanism is designed to provide users with increased flexibility, allowing them to enhance their voting power for proposal voting. The issuance of veRaacTokens
is calculated using a predefined formula intended to maintain balance and fairness within the protocol.
However, a critical bug has been discovered in the veRAACToken::increase
function. Instead of issuing the correct proportion of veRaacTokens
, the bug results in the doubling of the token amount relative to the RAAC tokens locked. This means that users receive twice the intended number of veRaacTokens
when they increase their locked RAAC token amount. Additionally, this bug slows down the decay rate of the veRaacToken
, creating a more gradual reduction in voting power over time. The combined effect is an unintended flexibility in the voting power decay slope, which significantly deviates from the protocol's original design.
The presence of this vulnerability has far-reaching implications for the governance of the protocol. By inadvertently granting users excessive voting power, the bug undermines the integrity of the governance system. Malicious users could exploit this flaw to cast disproportionately influential votes, thereby swaying proposals either in their favor or against proposals that would otherwise benefit the broader community. Such manipulation distorts quorum calculations and compromises the fairness of the decision-making process. Ultimately, this vulnerability erodes trust in the protocol, as it enables scenarios where governance outcomes do not accurately reflect the intended distribution of voting power among users.
veRAACToken::increase:
When a user wishes to increase their locked token amount, the veRAACToken::increase
function is called, and it subsequently invokes the _lockState.increaseLock
function, passing the specified amount
as an argument.
This internal call to _lockState.increaseLock
is integral to the protocol’s lock management system. Within the LockManager
, the function updates the user's lock state by incrementing the existing locked amount by the provided value. This update ensures that the internal record accurately reflects the new total of RAAC tokens locked by the user. By increasing the lock state in this manner, the protocol maintains an up-to-date and consistent view of each user's locked token balance.
```LockManager::increaseLock:`
After updating the lock state, the user's lock struct is retrieved and stored in memory. This is done with the following line:
At this point, the contract uses the updated lock data to calculate and update the user's voting power by invoking the _votingState.calculateAndUpdatePower
function. However, the parameters passed to this function are incorrect. The RAAC Development Team has provided the parameters as msg.sender
, userLock.amount + amount
, and userLock.end
.
The issue arises with the parameter userLock.amount + amount
. Since the user's locked amount has already been updated internally within the _lockState.increaseLock
function, adding amount
again effectively doubles the actual locked amount. This erroneous calculation is used for determining the user's voting power as well as the slope, or decay rate, of the voting power.
As a result, the user's voting power is erroneously doubled, and the decay rate becomes slower than intended. This miscalculation undermines the integrity of the protocol’s voting mechanism by providing users with inflated influence, which may lead to significant governance imbalances.
The protocol determines a user's voting power and decay slope using two specific formulas.
Voting Power Formula:
In this formula, the product of the amount and the duration is divided by MAX_LOCK_DURATION
, ensuring that a user who locks tokens for the maximum duration receives the highest possible voting power, while shorter lock durations yield proportionally less voting power.
Slope (Decay Rate) Formula:
The decay slope, which represents how quickly the voting power diminishes over time, is calculated by taking the ratio of the initial power to the duration. The slope is stored as an int128
value and is defined as follows:
This formula indicates that the voting power decays linearly over the duration of the lock. The decay rate, or slope, is essentially the voting power lost per second, so a lower slope means that the voting power diminishes more slowly over time.
According to these formulas, if the voting power is mistakenly doubled due to an error in parameter passing (as discussed in previous sections), the initial power will be significantly inflated. Consequently, because the slope is directly derived from the inflated initial power, the decay rate will also be slower than intended. This means that not only does the user receive a higher voting power than they should, but the voting power will also decay at a reduced rate, further exacerbating the imbalance.
Such a miscalculation can undermine the governance mechanism by granting users disproportionate influence over protocol decisions, potentially skewing outcomes and destabilizing the intended distribution of power within the system.
To demonstrate this vulnerability, the following Proof of Concept (PoC) is provided. The PoC is written using the Foundry tool.
Step 1: Create a Foundry project and place all the contracts in the src
directory.
Step 2: Create a test
directory and a mocks
folder within the src
directory (or use an existing mocks folder).
Step 3: Create all necessary mock contracts, if required.
Step 4: Create a test file (with any name) in the test
directory.
Step 5: Add the following test PoC in the test file, after the setUp
function.
Step 6: To run the test, execute the following commands in your terminal:
Step 7: Review the output. The expected output should indicate that users get double voting power and slower decay rate (slope) if they calls veRAACToken::increase
function.
As demonstrated, the test confirms that the veRAACToken::increase
in buggy and doubles the users voting power and slows down their voting power decay rate (flexible slope).
Inflated Voting Power:
The miscalculation doubles the user's initial voting power by erroneously adding the additional amount twice. This inflated voting power gives users an unfair and disproportionate influence over governance decisions, potentially allowing a single user or group of users to sway proposals beyond their intended stake.
Slower Voting Power Decay:
Since the decay slope is directly derived from the initial voting power, the error also results in a slower decay rate. As a consequence, the inflated voting power persists longer than intended, further amplifying its impact over time and undermining the intended temporal balance of influence.
Distorted Governance Dynamics:
The combination of exaggerated voting power and a reduced decay rate distorts critical governance parameters such as quorum and voting thresholds. This imbalance may lead to skewed proposal outcomes, affecting the overall fairness and effectiveness of the decision-making process within the protocol.
Increased Risk of Exploitation:
Malicious users could deliberately exploit this vulnerability to manipulate voting outcomes. By artificially boosting their voting power, they can force proposals to pass or fail contrary to the collective interest, thereby compromising the democratic integrity of the governance system.
Erosion of Stakeholder Trust:
The inconsistency between the intended and actual behavior of the voting power mechanism undermines confidence in the protocol. Stakeholders may lose trust in the governance process, leading to decreased participation and potentially harming the protocol's reputation and long-term viability.
Manual Review
Foundry
Console Log (foundry)
Mitigating this vulnerability is straightforward. The extra addition of the amount—which duplicates the already updated locked amount—should be removed. One possible solution is as follows:
veRAACToken::increase:
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.