Core Contracts

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

`StabilityPool::__depositIntoVault` deposits tokens from the wrong source

Summary

The StabilityPool::_depositIntoVault function deposits tokens into the vault using the asset balance of the pool rather than pulling tokens from the correct source (i.e. the rToken contract). This causes an incorrect source of funds during liquidity rebalancing and may lead to transaction failures.

Vulnerability Details

The function is implemented as follows

function _depositIntoVault(uint256 amount) internal {
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}

When a user deposits assets, the funds are sent to the reserve’s rToken contract. The _rebalanceLiquidity function calculates the current buffer based on the balance of the reserve asset at the rToken’s address:

uint256 currentBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);

If the current buffer is above the desired level, excess funds are to be deposited into the vault by calling _depositIntoVault. However, the function attempts to pull tokens from the lending pool’s own balance (using reserve.reserveAssetAddress), not from the rToken contract where the assets actually reside. This mismatch in the expected source causes deposits to fail—as demonstrated by the following PoC—from the wrong sender.

Proof Of Concept
Place this under the
describe("Deposit and Withdraw", function () {
line in LendingPool.test.js

it("it fails when a crv vault is provided because of wrong sender to the vault", async function () {
const depositAmount = ethers.parseEther("100");
const Vault = await ethers.getContractFactory("MockCurveCrvUSDVault")
const vault = await Vault.deploy(
crvusd.target,
);
await lendingPool.setCurveVault(vault.target);
// this will rever because there is no enough amount to transfer from the lending pool to the vault
await expect(lendingPool.connect(user1).deposit(depositAmount)).to.be.reverted;
});

execute with npx hardhat test --grep "it fails when a crv vault is provided because of wrong sender to the vault"

Impact

  • Liquidity Rebalancing Failure: Deposits to the vault may revert if sufficient funds are not available from the lending pool contract’s balance.

  • Inaccurate Fund Accounting: The mismatch leads to incorrect liquidity tracking and can disturb the protocol’s balance between the lending pool and the vault.

Tools Used

  • Manual Code Review

  • Unit Testing (Foundry/Hardhat)

Recommendations

Modify the deposit logic to source funds correctly from the rToken’s balance rather than the lending pool contract. For example, instead of using the balance from reserve.reserveAssetAddress within the lending pool, use the rToken’s transfer function to move the assets from its own balance to the vault.

function _depositIntoVault(uint256 amount) internal {
- IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
+ IRToken(reserve.reserveRTokenAddress).transferAsset(address(curveVault), amount);
totalVaultDeposits += amount;
}
Updates

Lead Judging Commences

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

LendingPool::_depositIntoVault and _withdrawFromVault don't transfer tokens between RToken and LendingPool, breaking Curve vault interactions

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

LendingPool::_depositIntoVault and _withdrawFromVault don't transfer tokens between RToken and LendingPool, breaking Curve vault interactions

Support

FAQs

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