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
.