Summary
The wrong calculation involving PRECISION
and EXTRA_DECIMALS
in function KittyVault:getTotalMeowllateralInAave
assumes all collaterals deposited are with the same constant of decimals. This causes the final calculated amount of collateral in Aave pool is wrongly returned for collaterals that come with different decimals.
Vulnerability Details
In function KittyVault:getTotalMeowllateralInAave
, it factors in a constant PRECISION
of 1e18 and constant EXTRA_DECIMALS
of 1e10 for the calculation of total amount of collateral in Aave pool for all collateral types. With this wrong calculation method, collaterals with less than 8 decimals will have more amount of collateral returned than it supposed to be in the final result while collaterals with more than 8 decimals will have lesser amount of collateral returned. The inaccury in the final calculated value breaks of protocol intended operation / functions.
function getTotalMeowllateralInAave() public view returns (uint256) {
(uint256 totalCollateralBase, , , , , ) = i_aavePool.getUserAccountData(address(this));
(, int256 collateralToUsdPrice, , , ) = i_priceFeed.latestRoundData();
<@@> ! return totalCollateralBase.mulDiv(PRECISION, uint256(collateralToUsdPrice) * EXTRA_DECIMALS);
}
Proof of Concept:
In order to test various collaterals, a correction in script/HelperConfig.s.sol
has to be made as follow as the btcUsdPriceFeed
address was wrongly specified. The corrected address was reference from chainlink price feed
function getSepoliaConfig() internal pure returns (NetworkConfig memory) {
return NetworkConfig ({
aavePool: 0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951,
euroPriceFeed: 0x1a81afB8146aeFfCFc5E50e8479e826E7D55b910,
ethUsdPriceFeed: 0x694AA1769357215DE4FAC081bf1f309aDC325306,
+ btcUsdPriceFeed: 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43,
- btcUsdPriceFeed: 0x694AA1769357215DE4FAC081bf1f309aDC325306,
usdcUsdPriceFeed: 0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E,
weth: 0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c,
wbtc: 0x29f2D40B0605204364af54EC677bD022dA425d03,
usdc: 0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8
});
}
After the above amendment, in test/KittyFiTest.t.sol
, add the following test test_audit_getTotalMeowllateralInAave_decimalPrecision()
:
function test_audit_getTotalMeowllateralInAave_decimalPrecision() public {
uint256 depositAmountWeth = 2e18;
uint256 xferToAeveAmountWeth = 1e18;
uint256 depositAmountWbtc = 2e8;
uint256 xferToAeveAmountWbtc = 1e8;
uint256 depositAmountUsdc = 2e6;
uint256 xferToAeveAmountUsdc = 1e6;
vm.startPrank(user);
IERC20(weth).approve(address(wethVault), depositAmountWeth);
kittyPool.depawsitMeowllateral(weth, depositAmountWeth);
IERC20(wbtc).approve(address(wbtcVault), depositAmountWbtc);
kittyPool.depawsitMeowllateral(wbtc, depositAmountWbtc);
IERC20(usdc).approve(address(usdcVault), depositAmountUsdc);
kittyPool.depawsitMeowllateral(usdc, depositAmountUsdc);
vm.stopPrank();
vm.startPrank(meowntainer);
wethVault.purrrCollateralToAave(xferToAeveAmountWeth);
wbtcVault.purrrCollateralToAave(xferToAeveAmountWbtc);
usdcVault.purrrCollateralToAave(xferToAeveAmountUsdc);
vm.stopPrank();
vm.startPrank(user);
uint256 totalMeowllateralInAave_weth = wethVault.getTotalMeowllateralInAave();
console.log("weth: ");
console.log("xferAmountToAave_weth: ", xferToAeveAmountWeth);
console.log("totalMeowllateralInAave_weth: ", totalMeowllateralInAave_weth);
uint256 totalMeowllateralInAave_wbtc = wbtcVault.getTotalMeowllateralInAave();
console.log("wbtc: ");
console.log("xferAmountToAave_wbtc: ", xferToAeveAmountWbtc);
console.log("totalMeowllateralInAave_wbtc: ", totalMeowllateralInAave_wbtc);
uint256 totalMeowllateralInAave_usdc = usdcVault.getTotalMeowllateralInAave();
console.log("usdc: ");
console.log("xferAmountToAave_usdc: ", xferToAeveAmountUsdc);
console.log("totalMeowllateralInAave_usdc: ", totalMeowllateralInAave_usdc);
vm.stopPrank();
}
After the test run at timestamp when this report is made, will have the followings printout in console: ( totalMeowllateralInAave will fluctuate depending on the priceFeed upon test time)
Logs:
weth:
xferAmountToAave_weth: 1000000000000000000
totalMeowllateralInAave_weth: 158114750
wbtc:
xferAmountToAave_wbtc: 100000000
totalMeowllateralInAave_wbtc: 107274624
xferAmountToAave_usdc: 1000000
totalMeowllateralInAave_usdc: 100000479
From the console, collateral of more than 8 decimals (weth with 18 decimals) have the returned totalMeowllateral value that is way too small which is only 158114750 (10e9 less) whilst collateral of less than 8 decimals (usdc with 6 decimals) have the returned value of too big at 100000479 (10e2 more). This deviates from the function objective stated in natspec * @notice Gets the total sum of collateral deposited in Aave and the collateral earned by interest from Aave
.
Impact
The calculated total amount of collateral in Aave pool for collaterals of different decimals results in different values which could either be too big or too small than the actual value breaks the function initial objective of getting the total sum of collateral deposited in Aave and the collateral earned by interest from Aave.
Tools Used
Manual review with forge test
Recommendations
Revisit the intended yield coming from the aave pool and formulate the function with correct calculation