QuantAMM

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

Uplift Fee Incorrectly Set to Swap Fee: Oversight Distorts Protocol's Swap and Uplift Fee Mechanisms

Summary

In the UpdateWeightRunner contract, there is a function called setQuantAMMUpliftFeeTake, which is supposed to set the quantAMMUpliftFeeTake. However, due to a critical oversight, this function is instead modifying quantAMMSwapFeeTake, resulting in a severe disruption of the protocol's swap and uplift fee mechanisms. To make matters worse, the state variable quantAMMUpliftFeeTake doesn’t even exist in the protocol, compounding the problem.

This oversight affects both the setter and getter functions, rendering the uplift fee mechanism completely dysfunctional.

Vulnerability Details

Code Analysis

UpdateWeightRunner::setQuantAMMUpliftFeeTake

function setQuantAMMUpliftFeeTake(uint256 _quantAMMUpliftFeeTake) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
// @info: _quantAMMUpliftFeeTake should be less than 1e18 aka 100%, hence the condition should be _quantAMMUpliftFeeTake < 1e18
require(_quantAMMUpliftFeeTake <= 1e18, "Uplift fee must be less than 100%");
@> // @info: Missing quantAMMUpliftFeeTake variable declaration
@> // @info: Incorrect assignment, should be: uint256 oldUpliftFee = quantAMMUpliftFeeTake
uint256 oldSwapFee = quantAMMSwapFeeTake;
@> // @info: Assigning _quantAMMUpliftFeeTake to quantAMMSwapFeeTake instead of quantAMMUpliftFeeTake
quantAMMSwapFeeTake = _quantAMMUpliftFeeTake;
@> // @info: Emitting incorrect parameter oldSwapFee; should emit oldUpliftFee
emit UpliftFeeTakeSet(oldSwapFee, _quantAMMUpliftFeeTake);
}

UpdateWeightRunner::getQuantAMMUpliftFeeTake

function getQuantAMMUpliftFeeTake() external view returns (uint256) {
@> // @info: Missing quantAMMUpliftFeeTake variable declaration
@> // @info: Returning the wrong variable quantAMMSwapFeeTake instead of quantAMMUpliftFeeTake
return quantAMMSwapFeeTake;
}

Observations

  1. Setter Function Issue:

    • The setQuantAMMUpliftFeeTake function updates quantAMMSwapFeeTake instead of quantAMMUpliftFeeTake.

    • There is no state variable quantAMMUpliftFeeTake, which makes it impossible to store uplift fee values.

  2. Getter Function Issue:

    • The getQuantAMMUpliftFeeTake function incorrectly returns quantAMMSwapFeeTake instead of the intended uplift fee value.

Proof of Concept (PoC)

Steps to Reproduce:

  1. Admin sets quantAMMSwapFeeTake to >80%.

  2. Admin intends to set quantAMMUpliftFeeTake to <30%.

  3. Admin calls the setQuantAMMUpliftFeeTake function.

  4. The function executes incorrectly, setting quantAMMSwapFeeTake to <30% while leaving the intended quantAMMUpliftFeeTake unset.

  5. A separate function calls getQuantAMMUpliftFeeTake.

  6. Instead of returning the intended uplift fee, it returns quantAMMSwapFeeTake.

Result:

  • Swap fee (quantAMMSwapFeeTake) is misconfigured to <30%.

  • Uplift fee (quantAMMUpliftFeeTake) cannot be set, as the variable doesn’t exist.

  • Both swap and uplift fees are disrupted, leading to incorrect protocol behavior.

Your test suit already has a test for this.

Impact

  1. Disruption of Protocol Fee Mechanisms:

    • Swap fee and uplift fee values are misconfigured, distorting the protocol's fee mechanisms.

  2. Inaccurate Fee Charging:

    • Users could be charged incorrect fees for swaps and uplifts, undermining trust in the protocol.

  3. Medium Severity:

    • Although the fees remain within the acceptable range (<1e18), the misconfiguration disrupts the intended functionality.

Tools Used

Manual Review

Recommendations

Code Fix

UpdateWeightRunner Contract

Add the missing state variable quantAMMUpliftFeeTake:

contract UpdateWeightRunner is Ownable2Step, IUpdateWeightRunner {
.
.
...
uint256 public quantAMMSwapFeeTake = 0.5e18;
+ uint256 public quantAMMUpliftFeeTake = 0.5e18;
.
.
...
}

Updated setQuantAMMUpliftFeeTake

function setQuantAMMUpliftFeeTake(uint256 _quantAMMUpliftFeeTake) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
require(_quantAMMUpliftFeeTake <= 1e18, "Uplift fee must be less than 100%");
- uint256 oldSwapFee = quantAMMSwapFeeTake;
+ uint256 oldUpliftFee = quantAMMUpliftFeeTake;
- quantAMMSwapFeeTake = _quantAMMUpliftFeeTake;
+ quantAMMUpliftFeeTake = _quantAMMUpliftFeeTake;
- emit UpliftFeeTakeSet(oldSwapFee, _quantAMMUpliftFeeTake);
+ emit UpliftFeeTakeSet(oldUpliftFee, _quantAMMUpliftFeeTake);
}

Updated getQuantAMMUpliftFeeTake

function getQuantAMMUpliftFeeTake() external view returns (uint256) {
- return quantAMMSwapFeeTake;
+ return quantAMMUpliftFeeTake;
}

Benefits

  • Ensures the uplift fee is correctly configured and stored.

  • Restores the intended functionality of both swap and uplift fee mechanisms.

  • Avoids incorrect fee calculations, maintaining user trust in the protocol.

Identical fees and stricly less than 1e18 < 1e18, both issues are addressed and acknowledged in a different finding. I'm a bit less confident about that finding because of admin-input-validation but i think that's also worth to be a valid one.


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!