Core Contracts

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

Incorrect Emission Rate Calculations in GaugeController: Conflict with Gauge-Specific Emission Constants

Summary

The GaugeController contract contains two internal functions—_calculateRWAEmission and _calculateRAACEmission—which are intended to compute the monthly and weekly emission amounts for RWA and RAAC gauges, respectively. These functions currently return hardcoded values:

  • RWA emission: 1000000 * 10 ** 18 tokens (i.e., 1,000,000 tokens per month)

  • RAAC emission: 250000 * 10 ** 18 tokens (i.e., 250,000 tokens per week)

However, the intended emission values according to the protocol’s tokenomics are:

  • RWA: 2,500,000 tokens per month

  • RAAC: 500,000 tokens per week

More importantly, the gauge-specific contracts—RAACGauge and RWAGauge—already define the correct constants:

  • RAACGauge.MAX_WEEKLY_EMISSION = 500000e18

  • RWAGauge.MAX_MONTHLY_EMISSION = 2500000e18

This discrepancy indicates that the emission calculation functions in GaugeController are outdated or redundant. Their presence risks inconsistent reward distribution if they are ever used in place of the gauge-specific constants.

Vulnerability Details

Issue Overview

The GaugeController contract’s internal functions for emission rate calculation are implemented as follows:

/**
* @notice Calculates RWA emission rate
* @dev Monthly emission rate for RWA gauges
* @return Monthly emission amount
*/
function _calculateRWAEmission() internal view returns (uint256) {
// Monthly RWA emission calculation
// @info: wrong RWA emission amount
// should be: 2500000 or 2.5M
return 1000000 * 10 ** 18; // Example value
}
/**
* @notice Calculates RAAC emission rate
* @dev Weekly emission rate for RAAC gauges
* @return Weekly emission amount
*/
function _calculateRAACEmission() internal view returns (uint256) {
// Weekly RAAC emission calculation
// @info: wrong RAAC emission amount
// should be: 500000 or 500K
return 250000 * 10 ** 18; // Example value
}

The comments indicate that the correct values should be 2.5M tokens (for RWA) and 500K tokens (for RAAC). In practice, the Gauge-specific contracts define these constants correctly:

  • RAACGauge.sol

    uint256 public constant WEEK = 7 days;
    uint256 public constant MAX_WEEKLY_EMISSION = 500000e18; // Maximum weekly emission
  • RWAGauge.sol

    uint256 public constant MONTH = 30 days;
    uint256 public constant MAX_MONTHLY_EMISSION = 2500000e18; // 2.5M tokens

Root Cause

The core of the issue is that the GaugeController contract uses hardcoded, outdated emission rate values rather than leveraging the correct constants defined in the gauge contracts. This redundancy creates a conflict between different parts of the protocol, risking:

  • Inconsistent Reward Distribution: If the GaugeController’s emission functions are used anywhere, they will provide lower emission amounts than expected.

  • Maintenance Overhead: Having multiple sources of truth for emission rates increases the risk of errors and makes the protocol harder to maintain.

Proof of Concept

Scenario Walkthrough

  1. Deployment and Initialization:

    • The GaugeController contract is deployed.

    • The internal functions _calculateRWAEmission and _calculateRAACEmission return their hardcoded values (1M and 250K tokens, respectively).

  2. Gauge-Specific Constants:

    • In contrast, RAACGauge and RWAGauge contracts define:

      • MAX_WEEKLY_EMISSION = 500000e18

      • MAX_MONTHLY_EMISSION = 2500000e18

  3. Test Case:
    The following Foundry test suite demonstrates that the GaugeController functions return incorrect emission amounts compared to the gauge-specific constants. (Note: In a complete system, the GaugeController should ideally reference the gauge contracts’ constants or these functions should be removed.)

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    import {Test, console} from "forge-std/Test.sol";
    import {GaugeController} from "../src/core/governance/gauges/GaugeController.sol";
    contract GaugeEmissionTest is Test {
    GaugeController gaugeController;
    // Dummy deployment of GaugeController with a placeholder address for veRAACToken.
    function setUp() public {
    // address(1) as veRAACToken
    gaugeController = new GaugeController(address(1));
    }
    // Expose the internal functions via public wrappers for testing.
    function testCalculateRWAEmission() public {
    uint256 rwaEmission = gaugeController.calculateRWAEmission();
    console.log("GaugeController RWA Emission:", rwaEmission);
    uint256 expectedRWAEmission = 2500000 * 10 ** 18; // Correct value as per RWAGauge
    assertEq(rwaEmission, expectedRWAEmission, "RWA emission does not match expected value");
    }
    function testCalculateRAACEmission() public {
    uint256 raacEmission = gaugeController.calculateRWAEmission();
    console.log("GaugeController RAAC Emission:", raacEmission);
    uint256 expectedRAACEmission = 500000 * 10 ** 18; // Correct value as per RAACGauge
    assertEq(raacEmission, expectedRAACEmission, "RAAC emission does not match expected value");
    }
    }

    Both functions calculateRWAEmission and calculateRWAEmission, currently doesn't exist in GaugeController contract. To simulate the test, you would need to add those functions returning thier respected internal variants.

How to Run the Test Suite

  1. Step 1: Create a new Foundry project:

    forge init my-foundry-project
  2. Step 2: Remove any unnecessary files.

  3. Step 3: Place your GaugeController contract and dependencies in the src directory.

  4. Step 4: Create a test directory adjacent to src and add the above test file (e.g., GaugeEmissionTest.t.sol).

  5. Step 5: Run the tests:

    forge test --mt testCalculateRWAEmission -vv
    forge test --mt testCalculateRAACEmission -vv
  6. Expected Output:
    Initially, the tests would fail because the GaugeController functions return incorrect values (1M and 250K tokens). Once the functions are updated (or removed), the tests should pass by returning 2.5M and 500K tokens, respectively.

Impact

  • Reward Distribution Issues:
    Emission rates determine how many tokens are distributed as rewards. Incorrect, lower-than-intended emissions will undercompensate participants, leading to a reduced incentive to lock tokens or participate in governance.

  • Tokenomics Imbalance:
    The overall inflation and token supply dynamics of the protocol can be significantly affected, potentially undermining the long-term economic sustainability.

  • Governance and Incentive Misalignment:
    Lower emissions might discourage participation in governance and reduce the effective distribution of power, potentially skewing decision-making processes.

  • Maintenance Complexity:
    Having redundant and conflicting sources for emission rates increases the risk of errors and complicates future upgrades or audits.

Tools Used

  • Manual Review

  • Foundry

Recommendations

To resolve this issue, the GaugeController contract should be updated to either remove the redundant emission calculation functions or modify them to reference the correct constants from RAACGauge and RWAGauge contracts. For example, the updated functions might directly return the gauge-specific constants:

Option 1: Remove Redundant Functions

If the emission rates are managed solely within the gauge contracts, consider removing the internal functions _calculateRWAEmission and _calculateRAACEmission from GaugeController.

Option 2: Update Functions to Reference Gauge Constants

Diff for _calculateRWAEmission

function _calculateRWAEmission() internal view returns (uint256) {
- return 1000000 * 10 ** 18; // Incorrect value
+ return 2500000 * 10 ** 18; // Correct value
}

Diff for _calculateRAACEmission

function _calculateRAACEmission() internal view returns (uint256) {
- return 250000 * 10 ** 18; // Incorrect value
+ return 500000 * 10 ** 18; // Correct value
}
Updates

Lead Judging Commences

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

GaugeController uses hardcoded placeholder emission values in _calculateRWAEmission() and _calculateRAACEmission() instead of actual tokenomics-based rates

Support

FAQs

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

Give us feedback!