Function _previewAccrueInterest and function _accrueInterest calculate the fee shares in different ways
Description
The function _previewAccrueInterest is used to preview the result of accruing interest before calling a function of the contract AvonPool, while the function _accrueInterest is the one invoked by the contract AvonPool during actual execution. However, there are discrepancies between the function _previewAccrueInterest and function _accrueInterest in the calculation of managerFeeShares and protocolFeeShares.
In the function _accrueInterest, it's like treating managerFeeAmount and protocolFeeAmount as a whole, and calculating managerFeeShares and protocolFeeShares based on totalSupplyShares and assetsWithoutFees. While in the function _previewAccrueInterest, the calculations of managerFeeShares and protocolFeeShares are based on the different total amounts of assets.
function _previewAccrueInterest(PoolStorage.PoolState storage s) internal view returns (PoolData memory previewPool) {
// [...]
uint256 managerFeeAmount;
uint256 protocolFeeAmount;
if (s.managerFee != 0) {
managerFeeAmount = accruedInterest.mulDiv(s.managerFee, PoolConstants.WAD);
uint256 managerFeeShares = managerFeeAmount.mulDiv(s.totalSupplyShares, previewPool.totalSupplyAssets - managerFeeAmount);
previewPool.totalSupplyShares += managerFeeShares;
}
protocolFeeAmount = accruedInterest.mulDiv(IPoolImplementation(address(this)).getProtocolFee(), PoolConstants.WAD);
uint256 protocolFeeShares = protocolFeeAmount.mulDiv(s.totalSupplyShares, previewPool.totalSupplyAssets - protocolFeeAmount);
previewPool.totalSupplyShares += protocolFeeShares;
// [...]
}
function _accrueInterest(PoolStorage.PoolState storage s) internal returns (uint256 managerFeeShares, uint256 protocolFeeShares) {
// [...]
uint256 totalNewShares;
uint256 managerFeeAmount = accruedInterest.mulDiv(managerFee, PoolConstants.WAD);
uint256 protocolFeeAmount = accruedInterest.mulDiv(IPoolImplementation(address(this)).getProtocolFee(), PoolConstants.WAD);
uint256 assetsWithoutFees = totalSupplyAssets - managerFeeAmount - protocolFeeAmount;
// Calculate manager fee shares if applicable
if (managerFee != 0 && accruedInterest > 0) {
managerFeeShares = managerFeeAmount.mulDiv(totalSupplyShares, assetsWithoutFees);
totalNewShares += managerFeeShares;
}
// Calculate protocol fee shares if there's interest
if (accruedInterest > 0) {
protocolFeeShares = protocolFeeAmount.mulDiv(totalSupplyShares, assetsWithoutFees);
totalNewShares += protocolFeeShares;
}
// Only update if there are new shares
if (totalNewShares > 0) {
totalSupplyShares += totalNewShares;
}
// [...]
}Impact
If the time elapsed is the same, this will cause the fee shares calculated by the function _previewAccrueInterest to be slightly smaller than that from the function _accrueInterest.
Recommendations
Consider keeping the calculation of managerFeeShares and protocolFeeShares consistent between function _previewAccrueInterest and function _accrueInterest.