Core Contracts

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

Lack of yield claiming mechanism leads to permanent loss of Curve vault yield

Summary

The LendingPool contract lacks functionality to claim yield accrued in the Curve vault, resulting in permanently locked yield even after all users withdraw their liquidity.

Vulnerability Details

The LendingPool contract integrates with a Curve vault to earn additional yield on deposited funds. However, the implementation only handles withdrawing principal amounts when users borrow or withdraw liquidity, with no mechanism to claim the accrued yield.

The root cause is that the Curve vault accrues yield by increasing the share price over time, but the LendingPool::_withdrawFromVault() function only withdraws specific amounts needed for user operations:

function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}

This means that even if all users withdraw their liquidity, the protocol will still have vault shares representing the accrued yield that cannot be accessed.

Proof of Concept

  1. Users deposit 100 tokens into LendingPool

  2. LendingPool deposits 80 tokens into Curve vault (keeping 20% buffer)

  3. Over time, vault shares appreciate in value due to yield

  4. Users withdraw their 100 tokens through normal operations

  5. The yield portion of vault shares remains locked in the contract with no way to withdraw it

  6. Protocol permanently loses access to the accrued yield

Impact

  • Protocol permanently loses access to yield earned in Curve vault

  • Value locked increases over time as more yield accrues

Recommendations

  1. Add a yield claiming function that can be called by admin. It will calculate the amount of shares that represents the total deposits into the vault, and then will subtract it from the total shares, to get the yield:

+ function claimVaultYield() external onlyOwner {
+ uint256 shareBalance = curveVault.balanceOf(address(this));
+ uint256 sharesForDeposits = curveVault.convertToShares(totalVaultDeposits);
+ uint256 yieldShares = shareBalance - sharesForDeposits;
+
+ if (yieldShares > 0) {
+ uint256 yieldAmount = curveVault.redeem(
+ yieldShares,
+ reserve.reserveRTokenAddress,
+ address(this),
+ 0,
+ new address[](0)
+ );
+ emit YieldClaimed(yieldAmount);
+ }
+ }
Updates

Lead Judging Commences

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

LendingPool earns yield from Curve Vault deposits but lacks systematic distribution mechanism, leading to protocol-owned value with unclear extraction path

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

LendingPool earns yield from Curve Vault deposits but lacks systematic distribution mechanism, leading to protocol-owned value with unclear extraction path

Support

FAQs

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