Precision loss prevents harvesting fees
Description
In the current implementation, the computeHarvestFee
function returns a percentage of the fee based on the time elapsed since the last harvest. The fee is calculated as a yearly rate using 10000
as the denominator for the fee calculation.
For example, if the fee is 100
(1%) per year, approximately 0.0027% would be charged per day, as the fee is divided by SECONDS_IN_YEAR
(31,536,000).
With this implementation, the time must elapse at least 315,360 seconds (approximately 3.65 days) to harvest the minimum fee of one basis point. This means that if no one interacts with the vault for this period, only then would the minimum fee be harvested.
function computeHarvestFee() public view returns (uint256) {
uint256 timeElapsed = block.timestamp - lastStamp;
uint256 mgmtFeeNum = config.managementFee * timeElapsed ;
uint256 perfFeeNum = config.performanceFee * timeElapsed;
// [...]
uint256 fee =
(totalUnderlyingStamp * mgmtFeeNum + gain * perfFeeNum) / (currentTotalUnderlying * SECONDS_IN_YEAR);
return fee;
}
Impact
This leads to precision loss for the short-term fee calculation, preventing the vault from harvesting fees as expected.
Recommendations
We recommend several approaches to address this issue:
Restrict the
harvest()
function to be callable only by the owner.Implement a minimum time threshold between harvests (e.g., one day) to ensure fee accumulation.
Remediation
This issue has been acknowledged by StakeKit, and fixes were implemented in the following commits: