QuantAMM

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

Missing Oracle and Pool Existence Checks (Both Functions)

Summary

Both setWeightsManually and setIntermediateValuesManually, the contract assumes that the _poolAddress parameter corresponds to a valid and approved pool, and that the oracles associated with the pool are operational and up-to-date. However:

  • The existence and approval of the pool (_poolAddress) are not verified.

  • The oracles associated with the pool are not checked for staleness or validity.

Vulnerability Details

function setWeightsManually(
int256[] calldata _weights,
address _poolAddress,
uint40 _lastInterpolationTimePossible,
uint _numberOfAssets
) external {
uint256 poolRegistryEntry = QuantAMMWeightedPool(_poolAddress).poolRegistry();
if (poolRegistryEntry & MASK_POOL_OWNER_UPDATES > 0) {
require(msg.sender == poolRuleSettings[_poolAddress].poolManager, "ONLYMANAGER");
} else if (poolRegistryEntry & MASK_POOL_QUANTAMM_ADMIN_UPDATES > 0) {
require(msg.sender == quantammAdmin, "ONLYADMIN");
} else {
revert("No permission to set weight values");
}
//though we try to keep manual overrides as open as possible for unknown unknows
//given how the math library works weights it is easiest to define weights as 18dp
//even though technically G3M works of the ratio between them so it is not strictly necessary
//CYFRIN L-02
for (uint i; i < _weights.length; i++) {
if (i < _numberOfAssets) {
require(_weights[i] > 0, "Negative weight not allowed");
require(_weights[i] < 1e18, "greater than 1 weight not allowed");
}
}
IQuantAMMWeightedPool(_poolAddress).setWeights(_weights, _poolAddress, _lastInterpolationTimePossible);
emit SetWeightManual(msg.sender, _poolAddress, _weights, _lastInterpolationTimePossible);
}
/// @notice Breakglass function to allow the admin or the pool manager to set the intermediate values of the rule manually
/// @param _poolAddress the target pool
/// @param _newMovingAverages manual new moving averages
/// @param _newParameters manual new parameters
/// @param _numberOfAssets number of assets in the pool

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/UpdateWeightRunner.sol#L559-L594

function setIntermediateValuesManually(
address _poolAddress,
int256[] memory _newMovingAverages,
int256[] memory _newParameters,
uint _numberOfAssets
) external {
uint256 poolRegistryEntry = approvedPoolActions[_poolAddress];
//Who can trigger these very powerful breakglass features is under review
if (poolRegistryEntry & MASK_POOL_OWNER_UPDATES > 0) {
require(msg.sender == poolRuleSettings[_poolAddress].poolManager, "ONLYMANAGER");
} else if (poolRegistryEntry & MASK_POOL_QUANTAMM_ADMIN_UPDATES > 0) {
require(msg.sender == quantammAdmin, "ONLYADMIN");
} else {
revert("No permission to set intermediate values");
}
IUpdateRule rule = rules[_poolAddress];
// utilises the base function so that manual updates go through the standard process
rule.initialisePoolRuleIntermediateValues(_poolAddress, _newMovingAverages, _newParameters, _numberOfAssets);
emit SetIntermediateValuesManually(
msg.sender,
_poolAddress,
_newMovingAverages,
_newParameters,
_numberOfAssets
);
}
}

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/UpdateWeightRunner.sol#L595-L625

Impact

  • Malicious or unauthorized pool addresses could be passed to the functions, potentially allowing unauthorized updates.

  • Updates based on outdated or malfunctioning oracles could cause incorrect calculations, leading to pool instability and financial losses.

Tools Used

  • Manual Code Review

Recommendations

  • Validate Pool Existence: Introduce a registry of approved pools.

  • validate the _poolAddress before using it.

  • Add a function to check the staleness of oracles.

  • Call the validation function before using the oracle.

  • include pool and oracle checks:

require(approvedPools[_poolAddress], "Pool address not approved");
for (uint i = 0; i < poolOracles[_poolAddress].length; i++) {
validateOracle(poolOracles[_poolAddress][i]);
}
function setWeightsManually(
int256[] calldata _weights,
address _poolAddress,
uint40 _lastInterpolationTimePossible,
uint _numberOfAssets
) external {
// Validate pool address
require(approvedPools[_poolAddress], "Pool address not approved");
// Validate oracles
for (uint i = 0; i < poolOracles[_poolAddress].length; i++) {
validateOracle(poolOracles[_poolAddress][i]);
}
uint256 poolRegistryEntry = QuantAMMWeightedPool(_poolAddress).poolRegistry();
if (poolRegistryEntry & MASK_POOL_OWNER_UPDATES > 0) {
require(msg.sender == poolRuleSettings[_poolAddress].poolManager, "ONLYMANAGER");
} else if (poolRegistryEntry & MASK_POOL_QUANTAMM_ADMIN_UPDATES > 0) {
require(msg.sender == quantammAdmin, "ONLYADMIN");
} else {
revert("No permission to set weight values");
}
for (uint i; i < _weights.length; i++) {
if (i < _numberOfAssets) {
require(_weights[i] > 0, "Negative weight not allowed");
require(_weights[i] < 1e18, "Weight greater than 1 not allowed");
}
}
IQuantAMMWeightedPool(_poolAddress).setWeights(_weights, _poolAddress, _lastInterpolationTimePossible);
emit SetWeightManual(msg.sender, _poolAddress, _weights, _lastInterpolationTimePossible);
}
Updates

Lead Judging Commences

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

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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

Give us feedback!