First Flight #21: KittyFi

First Flight #21
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Users Can't Withdraw When All Collateral Is Supplied to Aave

[H-01] Users Can't Withdraw When All Collateral Is Supplied to Aave

Summary

Users should always be able to withdraw their funds without interruption, even in the face of maintainer actions. However, there's a critical issue with KittyVault::executeWhiskdrawal when the withdrawal request exceeds the available amount in the vault (totalMeowllateralInVault). Consequently, this function reverts due to underflow or insufficient balance for the transfer.

Vulnerability Details

The KittyPool::whiskdrawMeowllateral function makes a call to KittyVault::executeWhiskdrawal, but when there's insufficient collateral available, this function reverts. This issue arises because the withdrawal amount requested is higher than the actual amount available in the vault.

function executeWhiskdrawal(
address _user,
uint256 _cattyNipToWithdraw
) external onlyPool {
uint256 _ameownt = _cattyNipToWithdraw.mulDiv(
getTotalMeowllateral(),
totalCattyNip
);
userToCattyNip[_user] -= _cattyNipToWithdraw;
totalCattyNip -= _cattyNipToWithdraw;
@> totalMeowllateralInVault -= _ameownt;
@> IERC20(i_token).safeTransfer(_user, _ameownt);
}

Impact

This flaw prevents users from withdrawing their funds when all collateral or more than the requested withdrawal amount is supplied to the Aave pool, disrupting normal operations and potentially causing financial loss.

Proof of Concept

The following test case illustrates the issue:

function test_CantWithdrawWhenSupplied() public userDepositsCollateral {
uint256 totalDepositedInVault = 5 ether;
// meowntainer transfers collateral in eth vault to Aave to earn interest
uint256 toSupply = 5 ether;
vm.prank(meowntainer);
wethVault.purrrCollateralToAave(toSupply);
assertEq(
wethVault.totalMeowllateralInVault(),
totalDepositedInVault - toSupply
);
uint256 totalCollateralBase = wethVault.getTotalMeowllateralInAave();
assert(totalCollateralBase > 0);
vm.startPrank(user);
uint256 toWithdraw = wethVault.userToCattyNip(user);
vm.expectRevert(); //underflow because totalMeowllateralInVault is 0
kittyPool.whiskdrawMeowllateral(weth, toWithdraw);
}

Tools Used

Manual Review

Recommendations

  • Implement logic in executeWhiskdrawal to handle cases where the requested withdrawal amount exceeds totalMeowllateralInVault. This can involve transferring additional collateral from the Aave pool if necessary.

  • Grant the pool contract access to the purrrCollateralFromAave function alongside the maintainer, allowing for automated management of collateral supply and withdrawal.

function executeWhiskdrawal(
address _user,
uint256 _cattyNipToWithdraw
) external onlyPool {
uint256 _ameownt = _cattyNipToWithdraw.mulDiv(
getTotalMeowllateral(),
totalCattyNip
);
+ if( _ameownt > totalMeowllateralInVault){
+ IKittyVault(tokenToVault[_token]).purrrCollateralFromAave(_ameownt - totalMeowllateralInVault);
+ }
userToCattyNip[_user] -= _cattyNipToWithdraw;
totalCattyNip -= _cattyNipToWithdraw;
totalMeowllateralInVault -= _ameownt;
IERC20(i_token).safeTransfer(_user, _ameownt);
}
Updates

Lead Judging Commences

shikhar229169 Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Users can't withdraw meowllateral if requested amount is not present in vault as it is supplied to Aave

Support

FAQs

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