Core Contracts

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

Inconsistent Scaling Logic in Token Conversion Functions in StabilityPool

Finding Description and Impact

The calculateDeCRVUSDAmount and calculateRcrvUSDAmount functions in the StabilityPool contract use inconsistent scaling logic:

  • calculateDeCRVUSDAmount divides by the exchange rate.

  • calculateRcrvUSDAmount divides by the scaling factor.

While this inconsistency does not currently cause issues because the exchange rate is hardcoded to 1e18, it introduces a potential vulnerability if the exchange rate ever becomes dynamic. The impact of this issue includes:

  • Incorrect token conversions if the exchange rate changes.

  • Potential loss of funds or unfair advantages for users.


Proof of Concept

Code References

  1. calculateDeCRVUSDAmount:

    function calculateDeCRVUSDAmount(uint256 rcrvUSDAmount) public view returns (uint256) {
    uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
    return (rcrvUSDAmount * scalingFactor) / getExchangeRate();
    }
  2. calculateRcrvUSDAmount:

    function calculateRcrvUSDAmount(uint256 deCRVUSDAmount) public view returns (uint256) {
    uint256 scalingFactor = 10**(18 + rTokenDecimals - deTokenDecimals);
    return (deCRVUSDAmount * getExchangeRate()) / scalingFactor;
    }

Example with Dynamic Exchange Rate

Assume:

  • rTokenDecimals = 18

  • deTokenDecimals = 18

  • getExchangeRate() = 2e18 (1 rToken = 2 deToken)

  • User deposits 100 rToken.

calculateDeCRVUSDAmount:

scalingFactor = 10**(18 + 18 - 18) = 1e18;
deCRVUSDAmount = (100 * 1e18) / 2e18 = 50 deToken;

The user receives only 50 deToken instead of the expected 200 deToken.

calculateRcrvUSDAmount:

If the user withdraws 50 deToken:

scalingFactor = 10**(18 + 18 - 18) = 1e18;
rcrvUSDAmount = (50 * 2e18) / 1e18 = 100 rToken;

The user receives 100 rToken, which is correct, but the initial deposit calculation was incorrect.


Recommended Mitigation Steps

To prevent future issues, update the functions to use consistent scaling logic, even if the exchange rate is currently 1e18. For example:

  1. calculateDeCRVUSDAmount:

    function calculateDeCRVUSDAmount(uint256 rcrvUSDAmount) public view returns (uint256) {
    uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
    return (rcrvUSDAmount * scalingFactor) / getExchangeRate();
    }
  2. calculateRcrvUSDAmount:

    function calculateRcrvUSDAmount(uint256 deCRVUSDAmount) public view returns (uint256) {
    uint256 scalingFactor = 10**(18 + rTokenDecimals - deTokenDecimals);
    return (deCRVUSDAmount * scalingFactor) / getExchangeRate();
    }

This ensures that the calculations remain correct even if the exchange rate changes in the future.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Incorrect scaling factor formula in StabilityPool::calculateRcrvUSDAmount function

Both tokens have 18 decimals. Info

Support

FAQs

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