Addressing Issues in Our C4 Contest

Our Code4rena contest results were released on August 8, 2022 and are available here.

Below details how our team addressed these issues prior to our mainnet deploy.

High Risk (6)

[H-01] Users can get unlimited votes

[H-02] VotingEscrow's merge and withdraw aren't available for approved users

  • Still exists in our mainnet deploy, VoterEscrow.sol:L510.
  • However does not result in major disruptions to user needs, also will not impact our future product plans.

[H-03] User rewards stop accruing after any _writeCheckpoint calling action

  • Got rid of tracking user votes with a prevVoteStatus boolean, Gauge.sol.

[H-04] Bribe Rewards Struck In Contract If Deposited During First Epoch

  • Got rid of the deliverBribes() method, also did not experience issue in prod. ExternalBribe.sol.

[H-05] Voting overwrites checkpoint.voted in last checkpoint, so users can just vote right before claiming rewards

  • Got rid of tracking user votes with a prevVoteStatus boolean, Gauge.sol.

[H-06] Attacker can block LayerZero channel

Medium Risk (17)

[M-01] Gauge set can be front run if bribe and gauge constructors aren't run atomically

[M-02] VeloGovernor: proposalNumerator and team are updated by team, not governance

  • “Issue” is expected behavior.

[M-03] Alter velo receptions computation

  • See judge’s comments, attack could only be pulled by deployer and wasn’t.

[M-04] Malicious user can populate rewards array with tokens of their interest reaching limits of MAX_REWARD_TOKENS

  • Judge’s comment is accurate, does allow team to change real reward tokens (but so far non-issue).

[M-05] Bribe.sol is not meant to handle fee-on-transfer tokens

[M-06] Voting tokens may be lost when given to non-EOA accounts

  • Confirmed, see judge’s comment.

[M-07] RedemptionSender should estimate fees to prevent failed transactions

[M-08] Temporary DOS by calling notifyRewardAmount() in Bribe/Gauge with malicious tokens

[M-09] Owner's delegates should be decreased in _burn()

[M-10] Rewards aren't updated before user's balance change in Gauge's withdrawToken

[M-11] Griefing Attack By Extending The Reward Duration

  • Addressed in mainnet deploy by reverting to original implementation, Gauge.sol:L546.

[M-12] Rewards can be locked in Bribe contract because distributing them depends on base token reward amount and Gauge.deliverBribes() is not always called by Voter.distribute()

  • Addressed in mainnet deploy by decoupling bribe delivery from gauge reward distribution, Voter.sol:L369.

[M-13] Bribe Rewards Not Collected In Current Period Will Be Lost Forever

  • Addressed in mainnet by reverting to an implementation more similar to Solidly’s, which does not couple gauge and bribe rewards. ExternalBribe.sol.

[M-14] Wrong reward distribution in Bribe because deliverReward() won't set tokenRewardsPerEpoch[token][epochStart] to 0

  • Will be addressed with an upcoming fix (will be linked here once contracts are live). In the interim, relevant parties (i.e. protocols who wish to bribe) should get in touch with our team.

[M-15] Wrong calculation for the new rewardRate[token] can cause some of the late users can not get their rewards

  • Addressed in mainnet deploy as we reverted to a duration of 7 days instead of 5, Gauge.sol#L535.

[M-16] Wrong DOMAIN_TYPEHASH definition

  • Not addressed in mainnet deploy, but see judge’s comment.

[M-17] WeVE (FTM) may be lost forever if redemption process is failed

  • Error won’t happen as long as contracts were initialized correctly (which they were in prod).