QuantAMM

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

QuantAdmin or Protocol owners gets fees on non upLifted positions

Summary

NOTE!: its assumed that pool creator fees here is the adminFeePercent that is sent QuantAMMAdmin since there are no other logic of distributing fees to pool creators

The UpliftOnlyExample contract charges a minimum withdrawal fee which is not totally wrong

But the problem is that fees are sent to pool creators from those minimum, contradicting the whitepaper's statement that pool creators should only earn fees when providing above-HODL returns.

Vulnerability Details

In onAfterRemoveLiquidity(), the contract enforces a minimum fee through minWithdrawalFeeBps that gets charged regardless of pool performance:

// if the pool has decreased in value since the deposit, the fee is calculated based on the base value
else {
//in most cases this should be a normal swap fee amount.
//there always myst be at least the swap fee amount to avoid deposit/withdraw attack surgace.
feePerLP = (uint256(minWithdrawalFeeBps) * 1e18) / 10000;
}

This minimum fee is split between:

  1. Pool donation (proportional to 1 - adminFeePercent)

  2. QuantAMM admin / Pool creator (proportional to adminFeePercent)

if (localData.adminFeePercent > 0) {
_vault.addLiquidity(
AddLiquidityParams({
pool: localData.pool,
to: IUpdateWeightRunner(_updateWeightRunner).getQuantAMMAdmin(),
maxAmountsIn: localData.accruedQuantAMMFees,
minBptAmountOut: localData.feeAmount.mulDown(localData.adminFeePercent) / 1e18,
kind: AddLiquidityKind.PROPORTIONAL,
userData: bytes("")
})
);
emit ExitFeeCharged(
userAddress,
localData.pool,
IERC20(localData.pool),
localData.feeAmount.mulDown(localData.adminFeePercent) / 1e18
);
}
if (localData.adminFeePercent != 1e18) {
// Donates accrued fees back to LPs.
_vault.addLiquidity(
AddLiquidityParams({
pool: localData.pool,
to: msg.sender, // It would mint BPTs to router, but it's a donation so no BPT is minted
maxAmountsIn: localData.accruedFees, // Donate all accrued fees back to the pool (i.e. to the LPs)
minBptAmountOut: 0, // Donation does not return BPTs, any number above 0 will revert
kind: AddLiquidityKind.DONATION,
userData: bytes("") // User data is not used by donation, so we can set it to an empty string
})
);
}

Impact

  • Pool creators receive fees even when providing negative returns

Tools Used

Manual review

Recommendations

  • For security considerations Keep minimum fee but direct 100% to pool donation when returns are negative

  • Only split fees with admin/pool creators when pool provides positive returns (as intended)

Updates

Lead Judging Commences

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

Support

FAQs

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

Give us feedback!