Vyper Vested Claims

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

Absence of Finalization of Vesting Function

Summary

Vulnerability Details

The contract VestedAirdrop.vy lacks a finalization mechanism for vesting, meaning it does not contain a function to complete the vesting process once the vesting period has ended. Without this function, users may not be able to fully claim their tokens after the vesting period has concluded.

Impact

Locked Tokens Post-Vesting: After the vesting period ends (vesting_end_time), the tokens that should be fully claimed remain locked in the contract. The absence of finalization means that fully vested tokens are left unavailable to the users, which can result in accumulated unclaimed tokens.

  • User Impact: Users expecting to claim their full token amount after the vesting period may find that they cannot, leading to frustration and dissatisfaction.

  • Missed Token Distribution: Without finalization, the contract’s token distribution process may be incomplete. Users might fail to receive their entire vested amount since the contract cannot finalize the process once the vesting period ends.

POC:

@external
def claim(user: address, total_amount: uint256, proof: DynArray[bytes32, 20]) -> bool:
"""
@notice This function is used to claim the tokens
@dev Anyone can claim for any user
"""
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

The above implementation does not provide any method to finalize the vesting once the end time is reached. A finalization function can fix this issue.

Tools Used

manual review

Recommendations

To mitigate this, a finalization function should be implemented that ensures any remaining vested tokens can be claimed once the vesting period ends.

@external
def finalize_vesting(user: address, total_amount: uint256):
"""
Finalizes the vesting for a specific user.
This can be invoked once the vesting period ends.
"""
assert block.timestamp >= self.vesting_end_time, "Vesting period not ended"
vested_amount: uint256 = self._calculate_vested_amount(total_amount)
self.claimed_amount[user] = vested_amount # Finalize the claimed amount
log FinalizedVesting(user, vested_amount)
Updates

Appeal created

bube Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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