QuantAMM

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

Invalid Token Path Configuration and Missing Token Relationship Validation in MultiHopOracle Deployment

Summary

The MultiHopOracle contract contains a fundamental architectural weakness in its oracle path validation system. The contract's constructor accepts and implements any sequence of oracle configurations without performing essential validation checks:

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

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

The architectural flaw lies in the contract's assumption of path validity during deployment. The constructor's implementation blindly accepts oracle configurations without verifying the logical connection between consecutive price feeds. This creates a system where oracle paths can be deployed with broken price relationships, unconnected token pairs, or circular references that invalidate the entire price computation chain.

In QuantAMM's TFMM architecture, this vulnerability becomes particularly problematic as it permits the deployment of fundamentally broken price discovery mechanisms. Once deployed, these invalid oracle paths become permanent fixtures in the system, as the contract offers no post-deployment correction capabilities. The immutable nature of these configurations means that any logical inconsistencies, token mismatches, or circular dependencies become permanently embedded in the protocol's price discovery mechanism.

The severity of this issue extends beyond deployment mistakes. Invalid oracle paths can pass basic testing scenarios but fail in complex market conditions or specific edge cases. When such failures occur, they affect not just individual transactions but potentially compromise all pools and strategies relying on the corrupted price feed path. The requirement to redeploy and migrate affected components creates significant operational risks and potential disruptions to the protocol's functionality.

Proof of Concept

Consider this scenario:

  1. Alice is a protocol deployer at QuantAMM wanting to set up a new ETH/USDT price feed

  2. Direct price feeds aren't available, so Alice plans to use ETH -> WBTC -> USDT path

  3. During deployment setup, Alice accidentally misconfigures the second hop:

    • First hop correctly set as ETH/WBTC

    • Second hop mistakenly set as BNB/USDT instead of WBTC/USDT

  4. The deployment proceeds successfully as the contract lacks path validation

  5. The protocol accepts this oracle for ETH/USDT pricing

  6. Later, Bob, a liquidity provider:

    • Deposits funds into a pool using this oracle

    • The pool tries to calculate optimal weights using the broken price feed

    • Receives incorrect share calculations due to meaningless price derivations

  7. The issue is only discovered after multiple users experience unexpected losses

  8. Due to the immutable design, the entire oracle must be redeployed and all dependent pools must migrate

Intended Path:
ETH -> WBTC -> USDT
Expected Calculation: price_ETH_USDT = price_ETH_WBTC * price_WBTC_USDT
Actual (Broken) Path:
ETH -> WBTC -> [Disconnected] -> BNB -> USDT
Example Values:
ETH/WBTC = 0.0625 (16 WBTC per ETH)
BNB/USDT = 300 (1 BNB = $300)
Result: Meaningless calculation as there's no relationship between WBTC and BNB
price_ETH_USDT = 0.0625 * 300 = 18.75 (completely incorrect ETH price)

Recommended mitigation steps

  1. Implement comprehensive path validation in constructor:

struct HopConfig {
OracleWrapper oracle;
bool invert;
address inputToken;
address outputToken;
}
constructor(HopConfig[] memory _oracles) {
require(_oracles.length > 0, "Empty oracle path");
// Validate path connectivity
for (uint i = 0; i < _oracles.length - 1; i++) {
address currentOutput = _oracles[i].invert ?
_oracles[i].inputToken :
_oracles[i].outputToken;
address nextInput = _oracles[i + 1].invert ?
_oracles[i + 1].outputToken :
_oracles[i + 1].inputToken;
require(currentOutput == nextInput,
"Disconnected oracle path");
}
// Check for circular references
if(_oracles.length > 2) {
address startToken = _oracles[0].invert ?
_oracles[0].outputToken :
_oracles[0].inputToken;
address endToken = _oracles[_oracles.length - 1].invert ?
_oracles[_oracles.length - 1].inputToken :
_oracles[_oracles.length - 1].outputToken;
require(startToken != endToken, "Circular oracle path");
}
// Validate token addresses
for (uint i = 0; i < _oracles.length; i++) {
require(_oracles[i].inputToken != address(0), "Invalid input token");
require(_oracles[i].outputToken != address(0), "Invalid output token");
require(_oracles[i].oracle != OracleWrapper(address(0)),
"Invalid oracle address");
oracles.push(_oracles[i]);
}
}
  1. Add path visualization helper:

function getOraclePath() external view returns (
address[] memory tokens,
address[] memory oracleAddresses
) {
tokens = new address[](oracles.length + 1);
oracleAddresses = new address[](oracles.length);
// Build path representation for verification
for (uint i = 0; i < oracles.length; i++) {
tokens[i] = oracles[i].invert ?
oracles[i].outputToken :
oracles[i].inputToken;
oracleAddresses[i] = address(oracles[i].oracle);
}
// Add final token
tokens[tokens.length - 1] = oracles[oracles.length - 1].invert ?
oracles[oracles.length - 1].inputToken :
oracles[oracles.length - 1].outputToken;
}
  1. Add deployment script validations:

function validateDeployment(
address deployedOracle,
address[] calldata expectedPath
) external view returns (bool) {
MultiHopOracle oracle = MultiHopOracle(deployedOracle);
(address[] memory tokens,) = oracle.getOraclePath();
// Validate deployed path matches expected
if (tokens.length != expectedPath.length) return false;
for (uint i = 0; i < tokens.length; i++) {
if (tokens[i] != expectedPath[i]) return false;
}
return true;
}

These mitigations would:

  • Prevent deployment of invalid oracle paths

  • Ensure token pair compatibility

  • Provide tools for path verification

  • Make deployments more reliable and secure

The validation should be implemented in both the contract and deployment scripts for maximum security.

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.