Summary
Additional collateral deposited in KittyPool will just serve as backing the KittyCoin but won't get extra yield when the supply limitation is hit in Aave pool causing user to mistakenly think their deposits earn them additional interest.
Vulnerability Details
User will be able to earn yield from their deposits only when meowntainer perform KittyValut:purrrCollateralToAave
function. However, there is a supply limitation which is not clearly known to the end user. If the total supply handled in Aepool is exceeded, meowntainer will no longer be able to perform the KittyValut:purrrCollateralToAave
function, resulting any extra collateral deposited to KittyPool that has yet to transfer to Aave pool won't be earning any yield.
Proof of Concept:
In test/KittyFiTest.t.sol
, add usdc
related setup and run test on test_audit_purrrCollateralToAave_supplyLimitation()
function setUp() external {
HelperConfig helperConfig = new HelperConfig();
config = helperConfig.getNetworkConfig();
weth = config.weth;
usdc = config.usdc;
deal(weth, user, AMOUNT);
deal(usdc, user, AMOUNT);
kittyPool = new KittyPool(meowntainer, config.euroPriceFeed, config.aavePool);
vm.startPrank(meowntainer);
kittyPool.meownufactureKittyVault(config.weth, config.ethUsdPriceFeed);
kittyPool.meownufactureKittyVault(config.usdc, config.ethUsdPriceFeed);
vm.stopPrank();
kittyCoin = KittyCoin(kittyPool.getKittyCoin());
wethVault = KittyVault(kittyPool.getTokenToVault(config.weth));
usdcVault = KittyVault(kittyPool.getTokenToVault(config.usdc));
}
function test_audit_purrrCollateralToAave_supplyLimitation() public {
uint256 toDeposit = 5 ether;
vm.startPrank(user);
IERC20(usdc).approve(address(usdcVault), toDeposit);
kittyPool.depawsitMeowllateral(usdc, toDeposit);
vm.stopPrank();
vm.startPrank(meowntainer);
uint256 xferAmount = 1e14;
usdcVault.purrrCollateralToAave(xferAmount);
assert(usdcVault.getTotalMeowllateralInAave() > 0);
uint256 xferBiggerAmount = 1e16;
vm.expectRevert();
usdcVault.purrrCollateralToAave(xferBiggerAmount);
vm.stopPrank();
}
The test will pass with forge test --via-ir --fork-url $SEPOLIA_RPC_URL --match-test test_audit_purrrCollateralToAave_supplyLimitation -vvvv
In the console, the followings will be displayed:
Ran 1 test for test/KittyFiTest.t.sol:KittyFiTest
[PASS] test_audit_purrrCollateralToAave_supplyLimitation() (gas: 479253)
Traces:
[479253] KittyFiTest::test_audit_purrrCollateralToAave_supplyLimitation()
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return]
├─ [24619] TestnetERC20::approve(KittyVault: [0xE84c9bd544D87642DD01E7415f2a54fc08061FB0], 5000000000000000000 [5e18])
│ ├─ emit Approval(owner: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], spender: KittyVault: [0xE84c9bd544D87642DD01E7415f2a54fc08061FB0], value: 5000000000000000000 [5e18])
│ └─ ← [Return] true
.......
│ │ │ │ ├─ [3176] InitializableImmutableAdminUpgradeabilityProxy::getSupplyData() [staticcall]
│ │ │ │ │ ├─ [2615] StableDebtToken::getSupplyData() [delegatecall]
│ │ │ │ │ │ └─ ← [Return] 3246908447782 [3.246e12], 3249282345040 [3.249e12], 55884533678440988670555868 [5.588e25], 1722520872 [1.722e9]
│ │ │ │ │ └─ ← [Return] 3246908447782 [3.246e12], 3249282345040 [3.249e12], 55884533678440988670555868 [5.588e25], 1722520872 [1.722e9]
│ │ │ │ ├─ [924] InitializableImmutableAdminUpgradeabilityProxy::scaledTotalSupply() [staticcall]
│ │ │ │ │ ├─ [375] AToken::scaledTotalSupply() [delegatecall]
│ │ │ │ │ │ └─ ← [Return] 116924875644443 [1.169e14]
│ │ │ │ │ └─ ← [Return] 116924875644443 [1.169e14]
│ │ │ │ └─ ← [Revert] revert: 51
│ │ │ └─ ← [Revert] revert: 51
│ │ └─ ← [Revert] revert: 51
│ └─ ← [Revert] revert: 51
├─ [0] VM::stopPrank()
│ └─ ← [Return]
└─ ← [Return]
In the first transfer of 1e14 usdc
, the process will go through and successfully move collateral to Aavepool. However, the second transfer of 1e16 usdc
will revert with error code 51
which is related to ReserveLogic - Liquidity index overflows
(doc). In the Aave protocol github repo related to ValidationLogic.sol
(ref), there is a maximum supply for a given type of collateral which cannot be exceeded.
Impact
Any additional collateral deposited to KittyPool which exceeds the Aaeve supply limit, can't be moved to Aave to earn yield and just stay in the KittyVault serving solely as a backing to KittyCoin, deviating from the protocol statement to enable user to earn yield from their deposits.
Tools Used
Manual review with forge test
Recommendations
To implement control check on the collateral supply limit to Aave pool and additional functions enable both meowntainer and user to know the state of the current supply.