Core Contracts

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

ReserveLibrary::calculateUsageIndex() returns an incorrect index

Summary

The usage index returned by ReserveLibrary::calculateUsageIndex() is wrong because of incorrect usage of the WadRayMath library.

Vulnerability Details

The function ReserveLibrary::calculateUsageIndex() calls ReserveLibrary::calculateCompoundedInterest() to calculate the interestFactor by using WadRayMath::rayDiv() and WadRayMath::rayMul() with values which are not scaled to RAY.

If both SECONDS_PER_YEAR and time delta are not properly scaled to RAY(1e27) this discrepancy will eventually cancel out. The issue is that it "cancels out" when calculating the exponent using rayMul(), but in the intermediate step (calculating ratePerSecond using rayDiv()) the result of division is rounded up. This rounding up happens on the incorrectly scaled intermediate result.

Impact

ratePerSecond will be rounded up at the wrong position as the WadRayMath library is supposed to work with RAY values resulting in inflated usageIndex values. Since exponent is calculated as the ratePerSecond multiplied by the timeDelta this difference will be proportional to the amount of time passed from the last update.

POC

set up:

  1. run npm install and add .env file if you haven't already

  2. npm i --save-dev @nomicfoundation/hardhat-foundry - Install the hardhat-foundry plugin.

  3. Add require("@nomicfoundation/hardhat-foundry"); to the top of your hardhat.config.js file.

  4. Run npx hardhat init-foundry in your terminal. This will generate a foundry.toml file based on your Hardhat project’s existing configuration, and will install the forge-std library.

  5. mkdir test/foundry

  6. Create *.t.sol file inside /test/foundry and paste the POC inside.

  7. In foundry.toml update test = 'test/foundry'

running test:

forge test --match-test testCalculateCompoundedInterest -vv

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "../../lib/forge-std/src/Test.sol";
import "../../lib/forge-std/src/console.sol";
import "../../contracts/libraries/math/WadRayMath.sol";
contract CompoundInterest is Test {
using WadRayMath for uint256;
uint256 internal constant SECONDS_PER_YEAR_SCALED = 31536000e27;
uint256 internal constant SECONDS_PER_YEAR = 31536000;
function testCalculateCompoundedInterest() public {
//Set the rate to 0.1(as in deploy script) and timeDelta to 12 seconds(one block)
uint256 rate = 1e26;
uint256 timeDelta = 12;
//This simulates a call to calculateCompoundedInterest without scaling(the way it is currently working)
uint256 ratePerSecondNoScale = rate.rayDiv(SECONDS_PER_YEAR);
uint256 exponentNoScale = ratePerSecondNoScale.rayMul(timeDelta);
uint256 interestNoScale = WadRayMath.rayExp(exponentNoScale);
//This simulates a call to calculateCompoundedInterest with scaling(the way it is supposed to work)
uint256 ratePerSecondScale = rate.rayDiv(SECONDS_PER_YEAR_SCALED);
uint256 exponentScale = ratePerSecondScale.rayMul(timeDelta * 10 ** 27);
uint256 interestScale = WadRayMath.rayExp(exponentScale);
/*This results in 1000000038051751104485366497 when the timeDelta is set to 12 seconds(one block)
and results in 1000000761035297197564942343 when the time delta is set to 240 seconds(20 blocks)*/
console.log("Compounded interest without scaling: %d", interestNoScale);
/*This results in 1000000038051751104485366492 when the timeDelta is set to 12 seconds(one block)
and results in 1000000761035297197564942239 when the time delta is set to 240 seconds(20 blocks)*/
console.log("Compounded interest with scaling: %d", interestScale);
}
}

Tools Used

Manual review

Recommendations

Scale the SECONDS_PER_YEAR and timeDelta values that are being used in ReserveLibrary::calculateCompoundedInterest() to 1e27(RAY)

Updates

Lead Judging Commences

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

ReserveLibrary::calculateCompoundedInterest uses rayDiv with unscaled SECONDS_PER_YEAR, causing incorrect interest calculation and inflated debt accumulation

Appeal created

anonymousjoe Auditor
7 months ago
inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

ReserveLibrary::calculateCompoundedInterest uses rayDiv with unscaled SECONDS_PER_YEAR, causing incorrect interest calculation and inflated debt accumulation

Support

FAQs

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

Give us feedback!