Vyper Vested Claims

First Flight #34
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: medium
Invalid

Lack of Access Control on claim() Function

Summary

The claim() function allows anyone to call it on behalf of any user, without any access control. This means that an attacker can claim tokens on behalf of another user, potentially interfering with the vesting process.

Vulnerability Details

In the claim() function:

@external
def claim(user: address, total_amount: uint256, proof: DynArray[bytes32, 20]) -> bool:
...
assert self.verify_proof(user, total_amount, proof), "Invalid proof"
assert block.timestamp >= self.vesting_start_time, "Claiming is not available yet"
claimable: uint256 = 0
current_amount: uint256 = self.claimed_amount[user]
vested: uint256 = self._calculate_vested_amount(total_amount)
if vested > current_amount:
claimable = vested - current_amount
assert claimable > 0, "Nothing to claim"
self.claimed_amount[user] += claimable
_success: bool = extcall IERC20(self.token).transfer(user, claimable)
assert _success, "Transfer failed"
return True

There is no access control in place, meaning anyone can call claim(user, total_amount, proof), even if they are not the intended recipient. While the function ensures tokens are transferred to the correct user, an attacker can:

  1. Front-run legitimate claims by submitting a claim for a user before they do.

  2. Disrupt user experience by triggering claims at unintended times.

  3. Potentially interfere with gas optimizations or batching mechanisms by claiming at inopportune times.

Impact

While the tokens are still sent to the correct user, this allows attackers to interfere with the expected user flow, execute front-running strategies, and create unnecessary network congestion.

Tools Used

Manual Review

Recommendations

Implement access control by ensuring that only the user themselves can call the claim() function. Modify the function to enforce this restriction:

@external
def claim(total_amount: uint256, proof: DynArray[bytes32, 20]) -> bool:
user: address = msg.sender # Ensure only the user can claim
assert self.verify_proof(user, total_amount, proof), "Invalid proof"
...
Updates

Appeal created

bube Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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