VTVL contest - hyh's results

Building no-code token management tools to empower web3 founders and investors, starting with token vesting.

General Information

Platform: Code4rena

Start Date: 20/09/2022

Pot Size: $30,000 USDC

Total HM: 12

Participants: 198

Period: 3 days

Judge: 0xean

Total Solo HM: 2

Id: 164

League: ETH

VTVL

Findings Distribution

Researcher Performance

Rank: 47/198

Findings: 1

Award: $116.68

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Labels

bug
duplicate
2 (Med Risk)
old-submission-method

Awards

116.6755 USDC - $116.68

External Links

Lines of code

https://github.com/code-423n4/2022-09-vtvl/blob/f68b7f3e61dad0d873b5b5a1e8126b839afeab5f/contracts/VTVLVesting.sol#L360-L377

Vulnerability details

Rebasing tokens has the ability to use all the funds before all the recipients fulfilled their vestings.

This can happen as the system records balance in nominals terms, while it can be rebased thereafter, which will create a discrepancy with system's accounting.

Proof of Concept

System aims to support all types of tokens, fom readme:

VTVLVesting contract supports any ERC20 token, so any other token can be substituted for this one.

But vesting logic assumes that there will no rebasement of the VTVLVesting's balances:

https://github.com/code-423n4/2022-09-vtvl/blob/f68b7f3e61dad0d873b5b5a1e8126b839afeab5f/contracts/VTVLVesting.sol#L360-L377

    /**
    @notice Withdraw the full claimable balance.
    @dev hasActiveClaim throws off anyone without a claim.
     */
    function withdraw() hasActiveClaim(_msgSender()) external {
        // Get the message sender claim - if any

        Claim storage usrClaim = claims[_msgSender()];

        // we can use block.timestamp directly here as reference TS, as the function itself will make sure to cap it to endTimestamp
        // Conversion of timestamp to uint40 should be safe since 48 bit allows for a lot of years.
        uint112 allowance = vestedAmount(_msgSender(), uint40(block.timestamp));

        // Make sure we didn't already withdraw more that we're allowed.
        require(allowance > usrClaim.amountWithdrawn, "NOTHING_TO_WITHDRAW");

        // Calculate how much can we withdraw (equivalent to the above inequality)
        uint112 amountRemaining = allowance - usrClaim.amountWithdrawn;

If there be one, for example it was amountRemaining = 100, but the token rebased it to be just 50, the first recipients to call for the vesting will obtain all the funds. Others will end up with nothing this way as 0 will not be rebased futher.

Rebasing tokens aren't that rare, say AMPL, https://www.ampleforth.org/, is an old and widely enough used one.

Consider at least describing the limitation.

#0 - 0xean

2022-09-25T14:19:58Z

dupe of #278

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter