QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: high
Invalid

FILO Withdrawal Implementation Allows Users to Bypass Majority of Uplift Fees

Vulnerability Details

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

localData.lpTokenDepositValueChange =
(int256(localData.lpTokenDepositValueNow) - int256(localData.lpTokenDepositValue)) /
int256(localData.lpTokenDepositValue);
if (localData.lpTokenDepositValueChange > 0) {
feePerLP =
(uint256(localData.lpTokenDepositValueChange) * (uint256(feeDataArray[i].upliftFeeBps) * 1e18)) /
10000;
}

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.

Impact

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.

Proof of Concept

Consider the following scenario:

  1. User deposits 100 tokens when token price is $1 (total value = $100)

    • Stored in poolsFeeData[pool][user] with lpTokenDepositValue = $100

  2. Price increases to $1.8

  3. User deposits additional 20 tokens at $1.8 (total value = $36)

    • Stored in poolsFeeData[pool][user] with lpTokenDepositValue = $36

  4. Price increases to $2

  5. 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.

Tools Used

Manual Review

Recommendation

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

Updates

Lead Judging Commences

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.