veToken Finance contest - Ruhum's results

Lock more veAsset permanently.

General Information

Platform: Code4rena

Start Date: 26/05/2022

Pot Size: $75,000 USDT

Total HM: 31

Participants: 71

Period: 7 days

Judge: GalloDaSballo

Total Solo HM: 18

Id: 126

League: ETH

veToken Finance

Findings Distribution

Researcher Performance

Rank: 11/71

Findings: 3

Award: $2,215.35

🌟 Selected for report: 1

πŸš€ Solo Findings: 1

Findings Information

🌟 Selected for report: kirk-baird

Also found by: Dravee, IllIllI, Koustre, Ruhum, VAD37, csanuragjain, gzeon, unforgiven, xiaoming90

Labels

bug
duplicate
2 (Med Risk)
disagree with severity

Awards

80.6857 USDT - $80.69

External Links

Lines of code

https://github.com/code-423n4/2022-05-vetoken/blob/main/contracts/VE3DRewardPool.sol#L134-L139 https://github.com/code-423n4/2022-05-vetoken/blob/main/contracts/VE3DRewardPool.sol#L214-L216

Vulnerability details

Impact

Whenever a user stakes or withdraws funds through the VE3DRewardPool contract, the contract loops over the array. It calls the stake()/withdraw() function for each of the addresses. If the size of the array is too big, the transaction might reach the block gas limit. The contract would be unusable until the array is cleaned up through clearExtraRewards().

SWC-128

Proof of Concept

  1. rewardManager calls addExtraReward() multiple times. At some point the array is too big.
  2. Calls to stake(), stakeFor(), and withdraw() by users will fail

Tools Used

none

Add a cap to the number of elements in the array. Same as in BaseRewardPool

#0 - jetbrain10

2022-06-15T15:56:00Z

will add 8 as cap for ve3d rewardpool

#1 - GalloDaSballo

2022-07-26T01:14:25Z

Dup of #136

Findings Information

🌟 Selected for report: Ruhum

Labels

bug
2 (Med Risk)
disagree with severity

Awards

2082.6377 USDT - $2,082.64

External Links

Lines of code

https://github.com/code-423n4/2022-05-vetoken/blob/main/contracts/VE3DRewardPool.sol#L134-L139 https://github.com/code-423n4/2022-05-vetoken/blob/main/contracts/VE3DRewardPool.sol#L214-L216 https://github.com/code-423n4/2022-05-vetoken/blob/main/contracts/BaseRewardPool.sol#L121

Vulnerability details

Impact

When the same address is included twice it might cause issues depending on the contract. I checked the current convex contract to see which addresses were added to the extraRewards array. For cvxCRV Rewards there's only 0x7091dbb7fcbA54569eF1387Ac89Eb2a5C9F6d2EA which is the VirtualBalanceRewardPool contract.

Proof of Concept

  1. rewardManager adds the same address twice through addExtraReward()
  2. VE3DRewardPool calls stake() twice with the same amount:
    function stake(uint256 _amount) public updateReward(msg.sender) {
        require(_amount > 0, "RewardPool : Cannot stake 0");

        //also stake to linked rewards
        uint256 length = extraRewards.length;
        for (uint256 i = 0; i < length; i++) {
            IRewards(extraRewards[i]).stake(msg.sender, _amount);
        }

        //add supply
        _totalSupply = _totalSupply.add(_amount);
        //add to sender balance sheet
        _balances[msg.sender] = _balances[msg.sender].add(_amount);
        //take tokens from sender
        stakingToken.safeTransferFrom(msg.sender, address(this), _amount);

        emit Staked(msg.sender, _amount);
    }

Tools Used

none

Prevent the same addresses from being added multiple times to the extraRewards array.

#0 - jetbrain10

2022-06-15T15:56:46Z

will add code to check if this is same reward address

#1 - GalloDaSballo

2022-07-26T01:53:42Z

The warden has shown how, due to a misconfiguration, rewards could be disbursed twice, breaking protocol invariants.

Because this is contingent on admin privilege, I believe Medium Severity to be appropriate

Gas Report

G-01: cache array length in for loops

When looping over an array the condition of the loop is checked for every iteration. If you read the length of a storage variable multiple times it can get quite expensive. Instead, cache the length of memory and check that.

// bad
for (uint i; i < arr.length; i++) {

}

// good
uint length = arr.length;
for (uint i; i < length; i++) {

}

There are quite a number of instances where this can be used. Just search for "for (" and you'll find them.

G-02: cache storage variables that are read multiple times within a function

Whenever you read the same storage variable twice, you should cache it in memory. It will save you a SLOAD.

An example would be platformFee in _earmarkRewards() L526-L528

#0 - GalloDaSballo

2022-07-18T23:27:20Z

Less than 200 gas saved

#1 - GalloDaSballo

2022-07-18T23:27:45Z

Very basic against even the other "less than 500 gas" reports

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