Core Contracts

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

Borrow More pay Less

Summary

The _repay function compares the repayment amount (provided by the caller) against the user’s scaled debt rather than their actual debt. In doing so, it caps the repayment amount at the scaled debt value (i.e. userDebt divided by the usage index) instead of using the full actual debt value. This miscalculation can lead to under-repayment because the scaled debt is typically lower than the actual debt when the usage index is greater than one.

Vulnerability Details

The root cause is the use of userScaledDebt (i.e. userDebt.rayDiv(reserve.usageIndex)) as the cap for the repayment amount. The repayment logic incorrectly assumes that scaling the debt for comparison is appropriate, but it inadvertently limits the repayable amount to a fraction of the actual debt when the usage index is greater than RAY (1e27). This arithmetic error in capping the repay amount is what leads to the under-repayment issue.

Explain in relevant detail using numbers and creating scenarios demonstrating the impact

Consider a scenario where:

The actual user debt (userDebt) is 1,000,000 units.

The reserve usage index is 2e27 (i.e. twice the RAY value), meaning the scaled debt (userScaledDebt) becomes 500,000 units (1,000,000 / 2).

A user attempts to repay 600,000 units.

With the current logic, the function compares 600,000 to the scaled debt of 500,000 and caps the repayment amount at 500,000 units.

Thus, even though the user intended to repay 600,000 units (which would be sufficient to cover the full 1,000,000 unit debt when properly accounted), the function only processes 500,000 units of repayment.

The remaining 500,000 units of actual debt remain unaddressed, leaving the protocol with an under-repayment issue.

Impact

As a consequence, users may end up repaying less than they intend or less than required to fully cover their outstanding debt. This under-repayment means that a portion of the debt remains unaccounted for in the system, potentially leading to inaccuracies in the debt records, prolonged indebtedness, or even systemic under-collateralization. This discrepancy can expose the protocol to additional risk, as the borrower's actual liability might not be fully cleared.

Recommendations

To resolve the issue, the repayment cap should be based on the actual user debt (userDebt) rather than the scaled debt (userScaledDebt). This can be done by modifying the comparison logic in the _repay function so that actualRepayAmount is capped using userDebt. For example, replace:

uint256 actualRepayAmount = amount > userScaledDebt ? userScaledDebt : amount;

with:

uint256 actualRepayAmount = amount > userDebt ? userDebt : amount;

This change ensures that the repay function correctly accounts for the full outstanding debt and prevents the under-repayment issue.

Updates

Lead Judging Commences

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

LendingPool::_repay caps actualRepayAmount at userScaledDebt instead of userDebt, preventing users from repaying full debt with interest in one transaction

That amount is not actually used.

Support

FAQs

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