QuantAMM

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

Shared Variable `quantAMMSwapFeeTake` Used for Both Swap Fee and Uplift Fee Causes Incorrect Fee Calculations and Potential Loss of Funds

Summary:

In the UpdateWeightRunner contract, the variable quantAMMSwapFeeTake is incorrectly used for both the swap fee take and the uplift fee take, due to a missing separate state variable for quantAMMUpliftFeeTake. This oversight leads to the incorrect handling of fees, causing unintended overwriting of fee values and potential financial losses for the protocol and its users.


Root Cause:

The contract declares a single variable quantAMMSwapFeeTake for storing the percentage of swap fees allocated to the protocol. However, both the setQuantAMMSwapFeeTake and setQuantAMMUpliftFeeTake functions modify this same variable. This results in one fee setting overwriting the other, leading to incorrect fee application throughout the contract.

Vulnerable Code:

uint256 public quantAMMSwapFeeTake = 0.5e18;
//...
function setQuantAMMSwapFeeTake(uint256 _quantAMMSwapFeeTake) external override {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMSwapFeeTake <= 1e18, "Swap fee must be less than 100%");
uint256 oldSwapFee = quantAMMSwapFeeTake;
quantAMMSwapFeeTake = _quantAMMSwapFeeTake;
emit SwapFeeTakeSet(oldSwapFee, _quantAMMSwapFeeTake);
}
//...
function setQuantAMMUpliftFeeTake(uint256 _quantAMMUpliftFeeTake) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMUpliftFeeTake <= 1e18, "Uplift fee must be less than 100%");
uint256 oldSwapFee = quantAMMSwapFeeTake;
quantAMMSwapFeeTake = _quantAMMUpliftFeeTake;
emit UpliftFeeTakeSet(oldSwapFee, _quantAMMUpliftFeeTake);
}
//...
function getQuantAMMUpliftFeeTake() external view returns (uint256) {
return quantAMMSwapFeeTake;
}

Attack Path:

  1. Fee Misconfiguration:

    • The quantammAdmin calls setQuantAMMSwapFeeTake to set the swap fee take to 50%.

    • Later, the quantammAdmin calls setQuantAMMUpliftFeeTake to set the uplift fee take to 20%.

    • Due to both functions modifying quantAMMSwapFeeTake, setting the uplift fee overwrites the swap fee take.

  2. Incorrect Fee Collection:

    • The protocol now collects swap fees at 20% instead of the intended 50%.

    • The intended uplift fee may not function correctly due to the shared variable.

  3. Financial Impact:

    • The protocol loses revenue from not collecting the intended swap fees.

    • Users may be overcharged or undercharged, leading to a loss of trust and potential disputes.


Proof of Concept (PoC):

  1. Initial State:

    • quantAMMSwapFeeTake = 0.5e18 (50%)

    • No separate variable for quantAMMUpliftFeeTake.

  2. Admin Sets Uplift Fee:

    updateWeightRunner.setQuantAMMUpliftFeeTake(0.2e18); // Intends to set uplift fee to 20%
  3. Effect:

    • quantAMMSwapFeeTake is now set to 0.2e18, reducing the swap fee take to 20% inadvertently.

    • The uplift fee take is not managed separately and cannot be retrieved or applied correctly.

  4. Result:

    • Swap fees are collected at 20% instead of the intended 50%.

    • Uplift fees may not be applied at all or are incorrectly calculated.


Recommendation:

Introduce a separate state variable for quantAMMUpliftFeeTake to distinguish it from quantAMMSwapFeeTake. Ensure that all functions and events related to the uplift fee use this new variable. Review and update any parts of the contract that reference quantAMMSwapFeeTake when they should reference quantAMMUpliftFeeTake.

Modified Code:

uint256 public quantAMMSwapFeeTake = 0.5e18;
uint256 public quantAMMUpliftFeeTake = 0.5e18; // Add a new variable for uplift fee take
//...
function setQuantAMMSwapFeeTake(uint256 _quantAMMSwapFeeTake) external override {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMSwapFeeTake <= 1e18, "Swap fee must be less than 100%");
uint256 oldSwapFee = quantAMMSwapFeeTake;
quantAMMSwapFeeTake = _quantAMMSwapFeeTake;
emit SwapFeeTakeSet(oldSwapFee, _quantAMMSwapFeeTake);
}
function setQuantAMMUpliftFeeTake(uint256 _quantAMMUpliftFeeTake) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMUpliftFeeTake <= 1e18, "Uplift fee must be less than 100%");
uint256 oldUpliftFee = quantAMMUpliftFeeTake;
quantAMMUpliftFeeTake = _quantAMMUpliftFeeTake;
emit UpliftFeeTakeSet(oldUpliftFee, _quantAMMUpliftFeeTake);
}
function getQuantAMMUpliftFeeTake() external view returns (uint256) {
return quantAMMUpliftFeeTake;
}
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.

Give us feedback!