The UpliftOnlyExample
contract implements a liquidity provision system where users can deposit tokens into pools and withdraw them later, paying fees based on the value appreciation (uplift) of their position. The contract uses a FILO (First-In-Last-Out) withdrawal system implemented in the onAfterRemoveLiquidity()
function, where withdrawals are processed starting from the most recent deposit.
The core issue lies in how the uplift fees are calculated during withdrawals. When a user withdraws liquidity, the contract calculates fees based on the value appreciation from the specific deposit being withdrawn from, rather than considering the user's entire position:
UpliftOnlyExample.sol#L474-L484
This implementation allows users to strategically structure their deposits and withdrawals to minimize fees by always withdrawing from deposits made at higher price points, effectively bypassing the uplift fee mechanism that's meant to capture value appreciation.
Critical economic issue that allows users to significantly reduce uplift fees (up to 90% reduction demonstrated in PoC), leading to substantial protocol revenue loss and creating an unfair advantage for sophisticated users.
Consider the following scenario:
User deposits 100 tokens when token price is $1 (total value = $100)
Stored in poolsFeeData[pool][user]
with lpTokenDepositValue = $100
Price increases to $1.8
User deposits additional 20 tokens at $1.8 (total value = $36)
Stored in poolsFeeData[pool][user]
with lpTokenDepositValue = $36
Price increases to $2
User withdraws 20 tokens
Due to FILO, withdrawal comes from second deposit
Fee calculated on price change from $1.8 to $2 (11.11% increase)
Actual fee paid: 20 tokens * (11.11% * upliftFeeBps)
If the fee was calculated fairly on the first deposit:
Fee should be on price change from $1 to $2 (100% increase)
Fair fee would be: 20 tokens * (100% * upliftFeeBps)
With upliftFeeBps = 100
(1%), the user pays 0.0222 tokens in fees instead of 0.2 tokens, an ~90% reduction.
Manual Review
Implement a weighted average entry price system that tracks the aggregate cost basis across all deposits for each user, ensuring fees are calculated on the true value appreciation of the entire position rather than individual deposits
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.