QuantAMM

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

Lack of Administrative Controls and Emergency Circuit Breakers in Immutable MultiHopOracle Implementation

Summary

The MultiHopOracle contract exhibits a critical architectural vulnerability in its immutable design structure. Upon inspection, the contract's core implementation reveals a complete absence of administrative capabilities or safety mechanisms:

https://github.com/Cyfrin/2024-12-quantamm/blob/main/pkg/pool-quantamm/contracts/MultiHopOracle.sol#L19

contract MultiHopOracle is OracleWrapper {
HopConfig[] public oracles;
constructor(HopConfig[] memory _oracles) {
for (uint i = 0; i < _oracles.length; i++) {
oracles.push(_oracles[i]);
}
}
}

The architectural design creates an inflexible system where oracle configurations become permanent upon deployment. This rigidity manifests in the contract's inability to adapt to security incidents or respond to market anomalies. The absence of administrative interfaces prevents any form of oracle management, while the lack of circuit breaker mechanisms leaves the system vulnerable during critical failures.

Within QuantAMM's TFMM framework, this vulnerability poses systemic risks as oracle reliability directly impacts pool operations. The immutable nature of the contract creates a scenario where compromised oracles remain active indefinitely, price validation remains static, and emergency situations cannot be addressed without complete system redeployment. This architectural limitation extends beyond mere operational constraints - it represents a fundamental security risk where the system must continue operating with known vulnerabilities until a full migration occurs.

The impact permeates through multiple layers of the QuantAMM ecosystem. A compromised oracle in a widely-used path could trigger cascading failures across interconnected pools, with no mechanism available for emergency intervention or graceful degradation. The absence of bounds checking on oracle prices compounds this risk, as there's no way to filter out obviously manipulated values, while the lack of pause functionality means the system must continue processing potentially harmful data even when issues are identified.

Proof of Concept

Consider this scenario:

  1. Alice notices that the Chainlink oracle for ETH/USD starts reporting obviously incorrect prices

  2. Bob, a protocol admin:

    • Identifies the compromised oracle

    • Wants to switch to a backup oracle source

    • Cannot modify the oracle path due to lack of admin functions

  3. Charlie, another admin:

    • Tries to pause affected pools to prevent losses

    • Discovers no emergency pause functionality exists

  4. Meanwhile:

    • Pools continue using corrupted price data

    • Users execute trades at incorrect prices

    • Strategy calculations use wrong inputs

  5. The protocol team:

    • Must rush to deploy new oracle contracts

    • Has to coordinate emergency migration of all affected pools

    • Faces significant operational risks during migration

  6. During the entire migration process:

    • The system continues operating with known bad data

    • No way to pause or halt operations

    • Users continue to be exposed to risk

  7. Several pools suffer losses before migration can be completed

  8. The incident highlights the critical need for administrative controls and circuit breakers

// Real-world example when oracle is compromised:
interface IChainlinkOracle {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
}
contract OracleFailureDemo {
MultiHopOracle public oracle;
IChainlinkOracle public chainlinkFeed;
function demonstrateNoFailsafe() public view returns (int256, bool) {
// Chainlink oracle starts returning bad data
int256 chainlinkPrice = chainlinkFeed.latestAnswer();
bool isObviouslyWrong = chainlinkPrice <= 0 ||
chainlinkPrice > 1000000 * 10**8; // $1M per ETH
// No way to switch oracle or pause:
// 1. Can't update oracle source
// 2. No circuit breaker
// 3. No admin functions
// 4. Must continue using bad data
// System forced to use potentially bad data
(int216 price,) = oracle.getData();
return (price, isObviouslyWrong);
}
}

Recommended mitigation steps

  1. Implement OpenZeppelin's AccessControl:

contract MultiHopOracle is OracleWrapper, AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
bool public paused;
constructor(HopConfig[] memory _oracles) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
_grantRole(EMERGENCY_ROLE, msg.sender);
for (uint i = 0; i < _oracles.length; i++) {
oracles.push(_oracles[i]);
}
}
modifier whenNotPaused() {
require(!paused, "Oracle paused");
_;
}
}
  1. Add emergency functions:

function togglePause() external onlyRole(EMERGENCY_ROLE) {
paused = !paused;
emit PauseToggled(paused);
}
function updateOracle(uint256 index, HopConfig calldata newOracle) external onlyRole(ADMIN_ROLE) {
require(index < oracles.length, "Invalid index");
emit OracleUpdated(index, oracles[index], newOracle);
oracles[index] = newOracle;
}
function addOracle(HopConfig calldata newOracle) external onlyRole(ADMIN_ROLE) {
oracles.push(newOracle);
emit OracleAdded(oracles.length - 1, newOracle);
}
  1. Add price validation bounds:

struct PriceBounds {
int216 minPrice;
int216 maxPrice;
}
mapping(uint256 => PriceBounds) public oracleBounds;
function setPriceBounds(uint256 index, int216 min, int216 max) external onlyRole(ADMIN_ROLE) {
require(min < max, "Invalid bounds");
oracleBounds[index] = PriceBounds(min, max);
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 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.