QuantAMM

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

Low issues collection

L-01 ChannelFollowingUpdateRule is different from whitepaper formula

Summary

When calculating trendPortion (or m(t) in whitepaper), base number absGradient is divided by preExpScaling parameter multiplied by 2. This is a clear difference between implementation and whitepaper

Vulnerability Details

m(t) aka trendShare has the following formula in the whitepaper (page 6, eq (12))

trendShare formula

In a more simple term:

m(t) = (1-v(t) * sign(gradient) * (abs(gradient) ^ q)

However, in ChannelFollowingUpdateRule.sol, abs(gradient) is divided by preExpScaling * 2 beforehand:

int256 absGradient = locals.newWeights[locals.i] >= 0
? locals.newWeights[locals.i]
: -locals.newWeights[locals.i];
int256 scaledAbsGradient = absGradient.div(locals.preExpScaling[0].mul(TWO));

So m(t) is implemented like the following:

m(t) = (1-v(t) * sign(gradient) * ((abs(gradient) / (2 * preExpScaling)) ^ q)

Impact

  • Incorrect weight calculation

  • preExpScaling parameter is unknown to end users, and it might cause confusion or unexpected behavior

NOTE

Although it's difference between implementation and whitepaper, it can be mitigated by setting all preExpScaling parameter to 0.5e18

Tools Used

N/A

Recommendations

Fix whitepaper and note about this silent extended implementation and unknown parameter preExpScaling

L-02 Missing negative weight checks when calculating weights with scalar kappa

Summary

In most of the Rule weight calculations, negative weight check is missing for params with scalar kappa

Vulnerability Details

In AntimomentumUpdateRule.sol:120, negative weight check is done if kappa param is a vector:

int256 res = int256(_prevWeights[locals.i]) +
int256(locals.kappa[locals.i]).mul(locals.normalizationFactor - locals.newWeights[locals.i]);
require(res >= 0, "Invalid weight");

However, the above check is missing when kappa param is scalar:

int256 res = int256(_prevWeights[locals.i]) +
int256(locals.kappa[0]).mul(locals.normalizationFactor - locals.newWeights[locals.i]);
newWeightsConverted[locals.i] = res;

Similar issue observed in ChannelFollowingUpdateRule, DifferenceMomentumUpdateRule, MomentumUpdateRule and PowerChannelUpdateRule

Impact

  • Incorrect weight calculation

  • Inconsistent weight update behavior between scalar and vector kappas

Tools Used

N/A

Recommendation

Use the same check for scalar and vector kappas

Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_weights_can_be_negative_or_extreme_values

_clampWeights will check that these weights are positive and in the boundaries before writing them in storage.

invalid_ChannelFollowingUpdateRule_whitepaper_incorrect_implementation

The formula here is the one in Whitepaper page 11, which is right and the division is explained on the last line : "Finally note …".

Appeal created

glightspeed2 Submitter
10 months ago
n0kto Lead Judge
10 months ago
n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_weights_can_be_negative_or_extreme_values

_clampWeights will check that these weights are positive and in the boundaries before writing them in storage.

invalid_ChannelFollowingUpdateRule_whitepaper_incorrect_implementation

The formula here is the one in Whitepaper page 11, which is right and the division is explained on the last line : "Finally note …".

Support

FAQs

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

Give us feedback!