Unfair Fee Accrual Due to Locker Pause in Protected Listing Unlock Process
Summary
The unlockProtectedListing function calculates an unlock fee based on a compounded interest formula tied to the duration of the lock. However, if the locker is paused for an extended period (e.g., 24 hours), users are unfairly charged additional fees for that period, even though they cannot unlock their listings while the locker is paused. This creates a discrepancy, leading to higher fees than expected.
Vulnerability Detail
The unlock fee is calculated using the function unlockPrice, which compounds the interest based on the listing’s tokenTaken and the time difference between the initialCheckpoint and _currentCheckpoint. The _currentCheckpoint is updated based on the time elapsed and the utilization rate of the collection.
However, if the locker is paused (e.g., for 24 hours), users are unable to unlock their listings during the paused period. Despite this, the compounded interest continues to accrue for the paused period, resulting in higher fees. This unfairly penalizes users who could not interact with the protocol during the pause.
Impact
A user lists an NFT with tokenTaken = 1 ether at a time when the locker is functioning normally.
Pause Event: The locker is paused for 24 hours due to maintenance or some other reason.
Fee Calculation Before Pause: Prior to the pause, let’s assume the interest rate is 5% per year (converted to per-second rate) and the user is expected to unlock the listing after 7 days. The fee is calculated based on the compounded interest rate over this 7-day period.
During the Pause: If the locker is paused for 24 hours during this 7-day period, the user is unable to unlock their listing. However, when the locker is unpaused, the fee is still calculated as if the listing was active during the pause, resulting in additional fees for the 24-hour pause.
Fee Without Pause: Assume the user would pay a fee of 0.05 ether for a 7-day unlock period.
Fee With 24-hour Pause: The user is forced to pay for an extra day (due to the pause), increasing the fee by 1/7th of the original amount. The new fee becomes approximately 0.0571 ether (an additional 0.0071 ether).
This discrepancy unfairly burdens users with higher fees due to circumstances beyond their control.
function unlockPrice(
address _collection,
uint _tokenId
) public view returns (uint unlockPrice_) {
// Get the information relating to the protected listing
ProtectedListing memory listing = _protectedListings[_collection][
_tokenId
];
// Calculate the final amount using the compounded factors and principle amount
@> unlockPrice_ = locker.taxCalculator().compound({
_principle: listing.tokenTaken,
@> _initialCheckpoint: collectionCheckpoints[_collection][
listing.checkpoint
],
@> _currentCheckpoint: _currentCheckpoint(_collection)
});
}
function _currentCheckpoint(
address _collection
) internal view returns (Checkpoint memory checkpoint_) {
(, uint _utilizationRate) = utilizationRate(_collection);
Checkpoint memory previousCheckpoint = collectionCheckpoints[
_collection
][collectionCheckpoints[_collection].length - 1];
checkpoint_ = Checkpoint({
compoundedFactor: locker.taxCalculator().calculateCompoundedFactor({
_previousCompoundedFactor: previousCheckpoint.compoundedFactor,
_utilizationRate: _utilizationRate,
//@audit when the locker is paused, there's an increase in this duration
@> _timePeriod: block.timestamp - previousCheckpoint.timestamp
}),
timestamp: block.timestamp
});
}
## Tool used
Manual Review
## Recommendation
To resolve this issue, the protocol should avoid compounding interest or increasing the fee during periods when the locker is paused. This can be achieved by implementing a mechanism that tracks the pause period and excludes it from the fee calculation. For example, the following steps could be taken:
- Track Pause Periods: Introduce a variable to track the last time the locker was paused and the total duration of the pause.
- Adjust Fee Calculation: When calculating the unlock fee, subtract the total paused duration from the time difference used to calculate compounded interest.
- Implement a Modifier: Ensure that when the locker is paused, any attempt to calculate the unlock fee does not penalize users for the paused duration.
Raspy Azure Dragonfly
Medium
Unfair Fee Accrual Due to Locker Pause in Protected Listing Unlock Process
Summary
The
unlockProtectedListing
function calculates an unlock fee based on a compounded interest formula tied to theduration
of the lock. However, if the locker is paused for an extended period (e.g., 24 hours), users are unfairly charged additional fees for that period, even though they cannot unlock their listings while the locker is paused. This creates a discrepancy, leading to higher fees than expected.Vulnerability Detail
The unlock fee is calculated using the function
unlockPrice
, which compounds the interest based on the listing’stokenTaken
and the time difference between theinitialCheckpoint
and_currentCheckpoint
. The_currentCheckpoint
is updated based on the time elapsed and the utilization rate of the collection.However, if the
locker
is paused (e.g., for 24 hours), users are unable to unlock their listings during the paused period. Despite this, the compounded interest continues to accrue for the paused period, resulting in higher fees. This unfairly penalizes users who could not interact with the protocol during the pause.Impact
A user lists an NFT with tokenTaken = 1 ether at a time when the locker is functioning normally.
Pause Event: The locker is paused for 24 hours due to maintenance or some other reason.
Fee Calculation Before Pause: Prior to the pause, let’s assume the interest rate is 5% per year (converted to per-second rate) and the user is expected to unlock the listing after 7 days. The fee is calculated based on the compounded interest rate over this 7-day period.
During the Pause: If the locker is paused for 24 hours during this 7-day period, the user is unable to unlock their listing. However, when the locker is unpaused, the fee is still calculated as if the listing was active during the pause, resulting in additional fees for the 24-hour pause.
Fee Without Pause: Assume the user would pay a fee of 0.05 ether for a 7-day unlock period.
Fee With 24-hour Pause: The user is forced to pay for an extra day (due to the pause), increasing the fee by 1/7th of the original amount. The new fee becomes approximately 0.0571 ether (an additional 0.0071 ether). This discrepancy unfairly burdens users with higher fees due to circumstances beyond their control.
Code Snippet
https://github.com/sherlock-audit/2024-08-flayer/blob/0ec252cf9ef0f3470191dcf8318f6835f5ef688c/flayer/src/contracts/ProtectedListings.sol#L304 https://github.com/sherlock-audit/2024-08-flayer/blob/0ec252cf9ef0f3470191dcf8318f6835f5ef688c/flayer/src/contracts/ProtectedListings.sol#L607 https://github.com/sherlock-audit/2024-08-flayer/blob/0ec252cf9ef0f3470191dcf8318f6835f5ef688c/flayer/src/contracts/ProtectedListings.sol#L592