Locking up AURA Token does not increase voting power of individual #186
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
sponsor disputed
Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue
Lines of code
https://github.com/code-423n4/2022-05-aura/blob/4989a2077546a5394e3650bf3c224669a0f7e690/contracts/AuraLocker.sol#L258
Vulnerability details
Background
Per the documentation, AURA tokens can be locked in the AuraLocker to recieve vlAURA. vlAURA is voting power in the AURA ecosystem.
It is also possible for the users to delegate their voting power to a specific address by calling the
AuraLocker.delegate(address account)
function.However, after users locked up their AURA tokens in exchange for vlAURA tokens, their voting power did not increase.
Proof of Concept
The following shows an example of Alice attempting to get
some voting power by locking up her AURA tokens, but her voting power did not increase:
At this point, Alice has not locked any AURA token into the AuraLocker yet. Thus, when
AuraLocker.getVotes(Alice.address)
is called, it returned “0” (No voting power. This is expected).Alice decided to get some voting power. So, Alice locked 100 AURA tokens by calling the
AuraLocker._lock()
function, and gain 100 vlAURA in return.Alice understand that as per the design, voting power will be 0 after depositing until the next epoch. So, she waited for around 1 week.
After a week has passed, the
AuraLocker.getVotes(Alice.address)
is called again. Alice expected it to return"100", but it still returned “0” (Still no voting power).Alice has locked up her AURA tokens for a week and hold 100 vlAURA, yet she has no voting power.
The following snippet of test script demonstrates the above issue, showing that the vote power remains the same after locking up the AURA tokens for a week.
Following is the output of the test script.
The first section shows that user has 800563688188805506352 vlAURA after locking up their AURA tokens
The second section shows that after a week, the user has 0 voting power even though the user has
800557536376417310407
vlAURA tokens. Note that these vlAURA tokens are all properly locked tokens that have not been expired.(Note: vlAURA == vlCVX and AURA == CVX in this context)
Aura Finance has implemented a checkpointing mechanism for determine user's voting power. Therefore, accounting for the votes will only
happens during checkpoint when
AuraLocker.checkpointDelegate()
function is beingcalled. Therefore, the
AuraLocker.getVotes()
function will only consider the locked AURA tokensthat have been “checkpointed” as votes. In other words, if the locked AURA tokens have
not been “checkpointed” yet, it will simply remain as a balance in the AuraLocker
contract, and the user’s locked AURA tokens effectively have no voting power.
Based on the source code, the root cause of this issue is that if a user does not have a delegatee, the system will not perform any checkpointing, and user's locked AURA token will not be accounted as voting power.
Following code from
AuraLocker._lock()
shows that checkpointing will only be performed if the user has a delegatee. Otherwise, no checkpointing will be performed when users locked their AURA tokens.The only way for Alice could get back her voting power is to delegate to herself after locking her AURA tokens. This is a workaround.
AuraLocker.delegate()
sole purpose should only serve to delegate one’s voting power to another user, and should not be used as a workaround to force the system to perform checkpointing to gain voting power.For Alice to get back her voting power, she must call the
AuraLocker.delegate(Alice.address)
function, which will delegate to herself. This function will in turn call theAuraLocker._checkpointDelegate()
function, which will “checkpointed” Alice’s locked tokens to become votes. Only after this step, Alice’s voting power will be updated and callingAuraLocker.getVotes(Alice.address)
should return “100” now.Additionally, documentation did not mention that a user is required to delegate to oneself in order to get the voting power. Thus, it is very likely that majority of the users would not know how to get their voting power unless they review the source code or is aware of this workaround.
Impact
The impact of this issue is that users might miss the opportunity to vote on critical protocol
decisions or flow of incentives (Gauge voting) due to lack of voting power as voting
power is not assigned to them after locking up AURA tokens.
If the users only realised this issue in the current epoch,
they would miss the chance to vote in current epoch. This is because by calling
the
AuraLocker.delegate(address account)
function to fix the issue, the votes will only be effective in the nextepoch.
The outcome of the governance or gauge voting might be impacted and might not reflect the true consensus of the community as affected users are not able to participate in the vote or have inaccurate voting power, thus affecting the protocol.
Tools Used
Manual Inspection
Recommended Mitigation Steps
In Convex Finance, users lock their CVX tokens by calling
CvxLocker._lock()
function and voting power will be allocated to the users immediately. Similar strategy should be adopted.It is recommended to update the
AuraLocker._lock()
function so that the user’s locked AURA tokens are “checkpointed” and converted to voting power immediately after locking up if a user has not assigned a delegatee yet. This will trigger the accounting for votes and translate the newly locked tokens into voting power immediately.Original Code
Suggested Modification
The text was updated successfully, but these errors were encountered: