QuantAMM

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

Pool Weights are non-updatable After Updating `updateWeightRunner` address

Summary

The setUpdateWeightRunnerAddress function in QuantAMMWeightedPool allows changing the UpdateWeightRunner contract address, but the pool has no way to set rules on the new contract since _setRule() is only callable during initialization. This is particularly problematic because UpdateWeightRunner maintains multiple pool-specific mappings keyed by msg.sender.

Vulnerability Details

The vulnerability exists because:

1- UpdateWeightRunner mappings keyed to msg.sender (pool address):

rules[msg.sender] = _poolSettings.rule; //Only pool can set its own rules
poolOracles[msg.sender] = optimisedHappyPathOracles; //Pool oracle settings
poolBackupOracles[msg.sender] = _poolSettings.oracles; //Pool backup oracles
poolRuleSettings[msg.sender] = PoolRuleSettings({ //Pool rule configuration
lambda: _poolSettings.lambda,
epsilonMax: _poolSettings.epsilonMax,
absoluteWeightGuardRail: _poolSettings.absoluteWeightGuardRail,
ruleParameters: _poolSettings.ruleParameters,
timingSettings: PoolTimingSettings({ updateInterval: _poolSettings.updateInterval, lastPoolUpdateRun: 0 }),
poolManager: _poolSettings.poolManager
});

2- Rules are set through _setRule() which is only called during initialize() function with initializer modifier

3- When setUpdateWeightRunnerAddress() changes the UpdateWeightRunner:

function setUpdateWeightRunnerAddress(address _updateWeightRunner) external override {
require(msg.sender == quantammAdmin, "ONLYADMIN");
updateWeightRunner = UpdateWeightRunner(_updateWeightRunner);
emit UpdateWeightRunnerAddressUpdated(address(updateWeightRunner), _updateWeightRunner);
}

The pool has no mechanism to call setRuleForPool() on the new contract since:

  • _setRule() is locked behind initializer

  • No other function exists to set rules post-initialization

Since the pool can't call setRuleForPool(), then the new UpdateWeightRunner contract will have no way to interact or call the pool since almost in every action to a pool, it uses the variables from the mappingsrules or poolRuleSettings etc ,for example:

function performUpdate(address _pool) public {
address rule = address(rules[_pool]);
require(rule != address(0), "Pool not registered");
PoolRuleSettings memory settings = poolRuleSettings[_pool];

Impact

When UpdateWeightRunner address is changed:

  • Pool becomes permanently unable to update weights since:

    • Rules cannot be set on new contract

    • All pool configurations are lost (rules, oracles, settings)

    • Only the pool itself can set its configurations (msg.sender mappings)

    • No post-initialization setting mechanism exists

  • Core pool functionality is broken

Tools Used

  • Manual code review

Recommendations

  1. Add a new function to allow setting rules after UpdateWeightRunner changes:

function migrateRules(
int256[] memory _initialWeights,
int256[] memory _ruleIntermediateValues,
int256[] memory _initialMovingAverages,
IQuantAMMWeightedPool.PoolSettings memory _poolSettings
) external {
require(msg.sender == quantammAdmin, "ONLYADMIN");
_setRule(_initialWeights, _ruleIntermediateValues, _initialMovingAverages, _poolSettings);
}
Updates

Lead Judging Commences

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

finding_setUpdateWeightRunnerAddress_will_DoS_rules

Likelihood: Low, when setting a new UpdateWeightRunner (for hotfixes) Impact: High, DoS performUpdate and force redeployment

Support

FAQs

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