QuantAMM

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

Critical fee evasion vulnerability through position transfer value reset

Summary

The UpliftOnlyExample contract's position transfer mechanism allows users to evade uplift fees on profitable positions by manipulating the deposit value transfers.

Vulnerability Details

The issue lies in the UpliftOnlyExample contract's afterUpdate method, which manages NFT transfers between addresses. The contract attempts to mitigate deposit/withdrawal attacks with a minimum charge, but this does not provide effective protection against uplift fee evasion:

// Attempted mitigation with minimum fee
if (localData.lpTokenDepositValueChange > 0) {
feePerLP = (uint256(localData.lpTokenDepositValueChange) *
(uint256(feeDataArray\[i].upliftFeeBps) \* 1e18)) / 10000;
} else {
// Minimum fee applied, but significantly lower than uplift fee
feePerLP = (uint256(minWithdrawalFeeBps) * 1e18) / 10000;
}

Comment in code explicitly states the intention:

//there always must be at least the swap fee amount to avoid deposit/withdraw attack surface.

Attack Path

  1. User deposits when pool value is low (e.g., 1000)

  2. Pool value increases significantly (e.g., to 1500)

  3. User transfers position to another address (possibly self-controlled)

  4. New deposit value is recorded as 1500

  5. If pool value decreases slightly (e.g., to 1400)

  6. System sees this as a loss (-100) rather than actual gain (+400)

  7. Only minimum fee is charged (minWithdrawalFeeBps) instead of the much higher uplift fee (upliftFeeBps)

Fee Comparison Example

Assuming:

  • upliftFeeBps = 500 (5%)

  • minWithdrawalFeeBps = 50 (0.5%)

  • Actual profit = 400 (40% gain)

Normal case:

  • Uplift fee = 400 * 5% = 20 units

Attack case:

  • Minimum fee = 1400 * 0.5% = 7 units

Fee reduction = ~65% despite position being profitable

Impact

The vulnerability allows users to:

  1. Pay only minimum fee (minWithdrawalFeeBps) instead of the higher uplift fee (upliftFeeBps)

  2. Significantly reduce protocol revenue

  3. Create unfair advantage over users paying proper uplift fees

Tools Used

  • Manual code review

  • Economic model analysis

  • Fee calculation simulation

Recommendations

Preserve original deposit context during transfers:

function afterUpdate(address _from, address _to, uint256 _tokenID) public {
// ... validation code ...
if (tokenIdIndexFound) {
if (_to != address(0)) {
// Transfer existing FeeData without updating deposit value
poolsFeeData[poolAddress][_to].push(feeDataArray[tokenIdIndex]);
// Remove from original owner's array...
}
}
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_afterUpdate_bypass_fee_collection_updating_the_deposited_value

Likelihood: High, any transfer will trigger the bug. Impact: High, will update lpTokenDepositValue to the new current value without taking fees on profit.

Support

FAQs

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