First Flight #21: KittyFi

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

User can not withdraw collateral while all the collateral is in aave earning yield

Description: If all the collateral of a vault is in the protocol Aave earning yield and someone wants to withdraw their collateral is not going to be possible, is going to throw an error of overflow / underflow because the vault contract itself doesn't have any collateral at all, all is in Aave.
In the function KittyVault::executeWhiskdrawal():

/**
* @param _user The user who wants to withdraw collateral
* @param _cattyNipToWithdraw The amount of shares corresponding to collateral to withdraw
*/
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);
}

AS you can see the transfer happens from the vault contract to the address of the user, can not be done if all the collateral is in Aave.

Impact: User have to wait to withdraw collateral until the Meowntainer withdraws some from Aave to the vault contract.

Proof of Concept: Couple of steps to execute:

  • Paste this modifier to the KittyFiTest.t.sol:

    1. Four users deposit collateral and mint from the protocol KittyFi

MODIFIER

address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
address user4 = makeAddr("user4");
modifier usersDepositAndMint {
uint256 toDeposit = 5 ether;
uint256 amountToMint = 20e18; // 20 KittyCoin
deal(weth, user2, 10 ether);
deal(weth, user3, 10 ether);
deal(weth, user4, 10 ether);
// Deposits and mint collateral of the four users
vm.startPrank(user);
IERC20(weth).approve(address(wethVault), toDeposit);
kittyPool.depawsitMeowllateral(weth, toDeposit);
kittyPool.meowintKittyCoin(amountToMint);
vm.stopPrank();
vm.startPrank(user2);
IERC20(weth).approve(address(wethVault), toDeposit);
kittyPool.depawsitMeowllateral(weth, toDeposit);
kittyPool.meowintKittyCoin(amountToMint);
vm.stopPrank();
vm.startPrank(user3);
IERC20(weth).approve(address(wethVault), toDeposit);
kittyPool.depawsitMeowllateral(weth, toDeposit);
kittyPool.meowintKittyCoin(amountToMint);
vm.stopPrank();
vm.startPrank(user4);
IERC20(weth).approve(address(wethVault), toDeposit);
kittyPool.depawsitMeowllateral(weth, toDeposit);
kittyPool.meowintKittyCoin(amountToMint);
vm.stopPrank();
_;
}
  • Paste this test below the modifier on the same file:

    1. Once the four users deposited the collateral.

    2. Meowntainer puts all the collateral to Aave to start earning yield.

    3. If one user tries to withdraw all the collateral it has from the vautl is going to revert.

TEST

function testWithdrawalReverts() public usersDepositAndMint {
uint256 oneUserDeposit = 5 ether;
uint256 oneUserMint = 20e18; // 20 KittyCoin
uint256 toSupply = 5 ether;
// Put collateral to ave
vm.prank(meowntainer);
wethVault.purrrCollateralToAave(toSupply*4);
vm.startPrank(user);
// Burn the amount of kitty coin
kittyPool.burnKittyCoin(user, oneUserMint);
// Withdraw the collateral
vm.expectRevert();
kittyPool.whiskdrawMeowllateral(weth, oneUserDeposit);
vm.stopPrank();
}

Recommended Mitigation: You have some options:

  1. Make a new function KittyPool::requestWithdraw() to let know the Meowntainer that has to withdraw some collateral from the Aave protocol in order execute KittyPool::whiskdrawMeowllateral().

  2. Modify the function KittyVault::executeWhiskdrawal in order that when it is called, it has to withdraw first from the Aave the amount requested to withdraw and then transfer the amount to the user. (Assuming of course that you first check for KittyPool::_hasEnoughMeowllateral, and calculate the right amount of collateral to withdraw based on the cattyNips).

  3. Put some extra value in the vault of the same collateral token of the vault in order to make withdraws directly and then you can fill up again the contract vault withdrawing from Aave.

Updates

Lead Judging Commences

shikhar229169 Lead Judge about 1 year 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.