QuantAMM

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

Wrong implementation and use of uplift Fee in the protocol

Summary

The UpdateWeightRunner contract incorrectly uses the swap fee state variable (quantAMMSwapFeeTake) to manage uplift fees, leading to potential fee calculation errors in the UpliftOnlyExample contract. This confusion between uplift fees and swap fees could result in incorrect fee distributions and protocol revenue accounting.

Vulnerability Details

The uplift fee is designed to be a separate protocol fee for running costs, distinct from the swap fee. This is evidenced by:

  1. Comments indicating it's for "uplift only withdrawal fee hooks"

  2. Separate getter and setter functions specifically for uplift fees

  3. Usage in UpliftOnlyExample contract's withdrawal and swap hooks

The contract incorrectly manages uplift fees by:

  1. Incorrect State Variable Usage in Setter:
    UpdateWeightRunner.sol#L141-L148

function setQuantAMMUpliftFeeTake(uint256 _quantAMMUpliftFeeTake) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMUpliftFeeTake <= 1e18, "Uplift fee must be less than 100%");
uint256 oldSwapFee = quantAMMSwapFeeTake; // @audit - reads wrong variable
quantAMMSwapFeeTake = _quantAMMUpliftFeeTake; // @audit - writes to wrong variable
emit UpliftFeeTakeSet(oldSwapFee, _quantAMMUpliftFeeTake);
}
  1. Incorrect Getter Implementation:
    UpdateWeightRunner.sol#L151-L153

function getQuantAMMUpliftFeeTake() external view returns (uint256) {
return quantAMMSwapFeeTake; // @audit - returns swap fee instead of uplift fee
}

Impact in UpliftOnlyExample Contract

The issue manifests in two critical functions in UpliftOnlyExample:

  1. In onAfterRemoveLiquidity:
    UpliftOnlyExample.sol#L519

localData.adminFeePercent = IUpdateWeightRunner(_updateWeightRunner).getQuantAMMUpliftFeeTake();

Here, the contract retrieves what it thinks is the uplift fee but actually gets the swap fee, leading to incorrect fee calculations during liquidity removal.

  1. In onAfterSwap:
    UpliftOnlyExample.sol#L331

uint256 quantAMMFeeTake = IUpdateWeightRunner(_updateWeightRunner).getQuantAMMUpliftFeeTake();

The swap function uses the wrong fee rate for calculating protocol revenue share.

Impact

  1. Fee Calculation Errors:

  • Incorrect fee amounts being charged to users during withdrawals

  • Wrong distribution of fees between protocol admin and pool owner

  • Potential revenue loss for either the protocol or liquidity providers

Tools Used

Manual Review

Recommendations

To fix this, the contract should:

  1. Add a dedicated state variable for uplift fee:

uint256 public quantAMMUpliftFeeTake ; // Similar default as swap fee
  1. Modify the setter to use the correct variable:

function setQuantAMMUpliftFeeTake(uint256 _quantAMMUpliftFeeTake) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMUpliftFeeTake <= 1e18, "Uplift fee must be less than 100%");
uint256 oldUpliftFee = quantAMMUpliftFeeTake; // Use correct variable
quantAMMUpliftFeeTake = _quantAMMUpliftFeeTake; // Set correct variable
emit UpliftFeeTakeSet(oldUpliftFee, _quantAMMUpliftFeeTake);
}
  1. Fix the getter to return the correct fee:

function getQuantAMMUpliftFeeTake() external view returns (uint256) {
return quantAMMUpliftFeeTake; // Return correct variable
}
Updates

Lead Judging Commences

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

finding_quantAMMSwapFeeTake==quantAMMUplfitFeeTake

Likelyhood: High, calling setters or getters Impact: Low/Medium, both getters return `quantAMMSwapFeeTake` and `setQuantAMMUpliftFeeTake` modify `quantAMMUplfitFeeTake`. Real impact: those 2 values will be always the same.

Support

FAQs

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