Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Users delegating veCANTO may be forced into locking funds for more than the 5 years anticipated #116

Closed
code423n4 opened this issue Aug 9, 2023 · 12 comments
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate-182 satisfactory satisfies C4 submission criteria; eligible for awards upgraded by judge Original issue severity upgraded from QA/Gas by judge

Comments

@code423n4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-08-verwa/blob/a693b4db05b9e202816346a6f9cada94f28a2698/src/VotingEscrow.sol#L384

Vulnerability details

VotingEscrow has one check in place for avoiding vote manipulation: delegation can move funds only from a shorter to a longer-locking account, and this includes when the delegation is undone. This is the root cause of an issue that is below.

This presents the scenario of Alice locking her 1M CANTO in VotingEscrow, and delegating to Bob because she is not very into keeping an eye on the votings happening.

Bob, on the contrary, is likely to be an entity who uses VotingEscrow just for receiving delegations of many users and voting on their behalf.
Both of these motivations offer Bob a concrete incentive in keeping their lock as far in time as possible (i.e. keeping it at 5 years by increasing their funds by 1 wei per week), because:

  • if Bob does not shift their lock far in time, it will not be entitled to receive new delegations of freshly-locked funds (because funds can be delegated only to accounts locked for longer, and freshly-locked funds can delegate only to accounts that have in turn very recently refreshed their lock). On the contrary, increasing their funds by 1 wei per week, will enable anybody to delegate to them
  • if Bob does not shift their lock far in time, their voting power will shrink over time, and since Bob's purpose may be just about voting, Bob has all the interest in retaining more power

When Bob acts this way (which, as said, seems the most reasonable way to act for Bob), Alice may:

  • delegate 1M CANTO to Bob today
  • set an alarm on removing delegation in just before 5 years
  • at that point, just before the 5 years, Alice tries to remove the delegation
  • this action fails, because when un-delegating, funds have to flow to a longer-locked account

Impact

To withdraw the funds, Alice has only one option:

  • add 1 wei of veCanto,
  • un-delegate her 1M CANTO,
  • and wait 5 years without delegating

Proof of Concept

The situation can be showed in the following Foundry test:

    function testWithdrawAfterDelegation() public {
        uint256 currentTs = block.timestamp;

        vm.prank(alice);
        ve.createLock{value: 10 ether}(10 ether);

        vm.prank(bob);
        ve.createLock{value: 10 wei}(10 wei);

        vm.prank(alice);
        ve.delegate(bob);

        vm.warp(currentTs + LOCKTIME - 10 days);
        vm.prank(bob);
        ve.increaseAmount{value: 10 wei}(10 wei);

        // Alice can't withdraw
        vm.startPrank(alice);
        vm.expectRevert("Only delegate to longer lock");
        ve.delegate(alice);

        // The only option to get the CANTO back is to lock for 5 more years
        ve.increaseAmount{value: 10 wei}(10 wei);
        ve.delegate(alice);

        vm.warp(currentTs + 2 * LOCKTIME - 20 days);
        ve.withdraw();
    }

Tools Used

Code review, Foundry

Recommended Mitigation Steps

There is, unfortunately, no easy fix I can think of to this issue because simply removing the "Only delegate to longer lock" check, even only for un-delegating, can easily open the possibility for bypassing the desired vote power decay over time.

Maybe it could be worth considering a change in the design:

  • restore the original library's use of "balance" and remove the concept of "delegate balance"
  • maintain instead a map from delegatee to list of delegators
  • whenever the voting power of a user is calculated, do the calculation based on their own curve, and iteratively add the results of similar calculations done with the curves of each of their delegators

Doing so will make the voting power of each delegator decay according to the original (delegator's) lock, so funds can be withdrawn when the original lock expires without opening the possibility of voting manipulation.

Assessed type

Governance

@code423n4 code423n4 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Aug 9, 2023
code423n4 added a commit that referenced this issue Aug 9, 2023
@c4-pre-sort
Copy link

141345 marked the issue as primary issue

@c4-pre-sort
Copy link

141345 marked the issue as duplicate of #82

@c4-pre-sort c4-pre-sort added duplicate-82 and removed primary issue Highest quality submission among a set of duplicates labels Aug 13, 2023
@c4-pre-sort c4-pre-sort reopened this Aug 13, 2023
@c4-pre-sort
Copy link

141345 marked the issue as not a duplicate

@c4-pre-sort
Copy link

141345 marked the issue as duplicate of #178

@c4-pre-sort
Copy link

141345 marked the issue as not a duplicate

@c4-pre-sort
Copy link

141345 marked the issue as duplicate of #82

@c4-judge c4-judge added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value downgraded by judge Judge downgraded the risk level of this issue and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Aug 24, 2023
@c4-judge
Copy link

alcueca changed the severity to 2 (Med Risk)

@c4-judge
Copy link

alcueca marked the issue as satisfactory

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Aug 24, 2023
@c4-pre-sort c4-pre-sort reopened this Aug 24, 2023
@c4-pre-sort
Copy link

141345 marked the issue as not a duplicate

@c4-pre-sort
Copy link

141345 marked the issue as duplicate of #375

@c4-judge
Copy link

alcueca marked the issue as duplicate of #182

@c4-judge c4-judge added 3 (High Risk) Assets can be stolen/lost/compromised directly upgraded by judge Original issue severity upgraded from QA/Gas by judge and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value downgraded by judge Judge downgraded the risk level of this issue labels Aug 29, 2023
@c4-judge
Copy link

alcueca changed the severity to 3 (High Risk)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate-182 satisfactory satisfies C4 submission criteria; eligible for awards upgraded by judge Original issue severity upgraded from QA/Gas by judge
Projects
None yet
Development

No branches or pull requests

3 participants