First Flight #21: KittyFi

First Flight #21
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

Not knowing the `cattyNips` of a user can unable users to withdraw their whole collateral

Description: Based on KittyVault::ExecuteDeposit function:

function executeDepawsit(address _user, uint256 _ameownt) external onlyPool {
uint256 _totalMeowllateral = getTotalMeowllateral();
uint256 _cattyNipGenerated;
if (_totalMeowllateral == 0) {
_cattyNipGenerated = _ameownt;
}
else {
_cattyNipGenerated = _ameownt.mulDiv(totalCattyNip, _totalMeowllateral);
}
userToCattyNip[_user] += _cattyNipGenerated;
totalCattyNip += _cattyNipGenerated;
totalMeowllateralInVault += _ameownt;
IERC20(i_token).safeTransferFrom(_user, address(this), _ameownt);
}

At first it seems that every user that deposits collateral they are going to get the equivalent (1:1) of cattyNips. But the situation changes when some interest is earned on the aavePool then is not going to be 1:1 relation. The new entrants they are going to get less cattyNips than the collateral they deposited. Is totally fair because it still represents your collateral deposited but the user don't know anything about the cattyNips, so if he wants to withdraw their total collateral they deposited, is going to revert as the function KittyPool::whiskdrawMeowllateral is going to take as a parameter the cattyNips not the amount of collateral deposited at the begining.

WHISKDRAWMEOWLATERAL FUNCTION

/**
* @notice Withdraws the collateral from the vault
* @param _token token address
* @param _ameownt amount of catty nip (shares), corresponding to which collateral is withdrawn
*/
function whiskdrawMeowllateral(address _token, uint256 _ameownt) external tokenExists(_token) {
IKittyVault(tokenToVault[_token]).executeWhiskdrawal(msg.sender, _ameownt);
require(_hasEnoughMeowllateral(msg.sender), KittyPool__NotEnoughMeowllateralPurrrr());
}

Impact: Unable to withdraw the total collateral for some users.

Proof of Concept: Proof of Code

  1. User1 and User2 deposits 100 ether to the vault.

    • They get 100 cattyNips each.

    • Total collateral balance of the vault: 200 ether.

  2. Meowntainer puts the total collateral to the aavePool

  3. After some time the aavePool generate 50 ether out of the 200 ether

    • Total collateral: 250 ether

    • Collateral of each user: 125 ether

  4. User3 deposits 100 ether.

    • Gets 80 cattyNips based on this line of code inside KittyVault::executeDepawsit function:

    _cattyNipGenerated = _ameownt.mulDiv(totalCattyNip, _totalMeowllateral);
    • Total collateral: 350 ether

    • Total cattyNips: 280

  5. User3 wants to withdraw the total collateral:

    whiskdrawMeowllateral(weth, 100);
    • Reverts with KittyPool__NotEnoughMeowllateralPurrrr() custom error.

Recommended Mitigation: Options:

  1. Create a getter function for the mapping mapping(address user => uint256 cattyNip) public userToCattyNip; so then every user can know his own cattyNips.

  2. Take the collateral they want to withdraw and then calculate the cattyNips inside the function to then substract the right amount of cattyNips based on the collateral they want to withdraw.

Updates

Lead Judging Commences

shikhar229169 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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