Core Contracts

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

Incorrect logic when withdrawing from Curve Vault

Summary

During withdrawals from the Curve vault, the protocol incorrectly specifies the msg.sender (user) as the owner of the shares to burn and the LendingPool (address(this)) as the receiver of the withdrawn assets. This is incorrect because:

  1. Shares Ownership: Curve vault shares are minted to the LendingPool (address(this)) during deposits, so the LendingPool should be the owner of the shares to burn during withdrawals.

  2. Receiver of Assets: The withdrawn assets should be sent to the RToken contract, not the LendingPool, as users burn their RTokens to redeem the underlying assets (crvUSD).

This misconfiguration prevents the RToken contract from receiving the withdrawn assets, leading to insufficient liquidity for users to burn their RTokens and redeem crvUSD.

Vulnerability Details

  1. Deposit Flow:

    • When a user deposits crvUSD, the funds are sent to the RToken contract.

    • A portion of the funds (based on the liquidity buffer ratio) is kept in the RToken contract, and the remainder is deposited into the Curve vault.

    • Curve vault shares are minted to the LendingPool (address(this)), as the LendingPool is the entity interacting with the vault.

  2. Withdrawal Flow:

    • When a user requests a withdrawal, the protocol checks the available liquidity in the RToken contract.

    • If the RToken contract lacks sufficient liquidity, the protocol attempts to withdraw the required amount from the Curve vault.

    • The _withdrawFromVault function calls the Curve vault's withdraw method with the following parameters:

      solidity

      Copy

      curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
      • address(this): Specifies the LendingPool as the receiver of the shares to burn.

      • msg.sender: Specifies the user as the owner of the withdrawn assets.

  3. Issue: The LendingPool (address(this)) is the address with the actual shares. The withdrawn assets are sent to the user (msg.sender) instead of the RToken contract. This is incorrect because:

    • The RToken contract needs to receive the withdrawn assets to fulfill the user's redemption request.

    • The user burns their RTokens to redeem crvUSD from the RToken contract, not directly from the Curve vault.

Impact

The RToken contract does not receive the withdrawn assets, leading to insufficient liquidity for users to burn their RTokens and redeem crvUSD. The withdrawal transaction reverts, and users cannot withdraw their funds.

Tools Used

Manual Review

POC

function testDepositAndWithdraw() public {
vm.startPrank(address(user1));
IERC20(crvUSD).approve(address(lendingPool), type(uint256).max);
lendingPool.deposit(10_000e18);
vm.stopPrank();
vm.startPrank(address(user1));
lendingPool.withdraw(5_000e18);
vm.stopPrank();
}

Recommendations

/**
* @notice Internal function to withdraw liquidity from the Curve vault
* @param amount The amount to withdraw
*/
function _withdrawFromVault(uint256 amount) internal { //@audit-check - Know issues with withdrawal from Curve Vaults.
curveVault.withdraw(amount, address(reserve.reserveRTokenAddress), address(this), 0, new address[](0)); //@audit-issue - Curve vault shares are minted to ths address during deposits. During withdrawals, the field to burn shares from is the user (msg.sender) and the receiver is this address. This is wrong as the shares should be burned from this address and the receiver should be the RToken contract so users can burn their rTokens to redeem the crvUSD.
totalVaultDeposits -= amount;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 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

LendingPool::_withdrawFromVault incorrectly uses msg.sender instead of address(this) as the owner parameter, causing vault withdrawals to fail

inallhonesty Lead Judge 7 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

LendingPool::_withdrawFromVault incorrectly uses msg.sender instead of address(this) as the owner parameter, causing vault withdrawals to fail

Support

FAQs

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

Give us feedback!