The StrataxOracle.getPrice() function retrieves price data from Chainlink via latestRoundData() but completely discards the updatedAt and answeredInRound return values. This means there is zero validation that the price data is current. Stale prices lead to incorrect position sizing during opens (risking immediate liquidation) and incorrect collateral withdrawal during unwinds.
At line 70 of StrataxOracle.sol, the getPrice() function destructures latestRoundData() as (, int256 answer,,,) — discarding roundId, startedAt, updatedAt, and answeredInRound. The only validation is require(answer > 0), which passes for prices that are hours or days old.
Ironically, the same contract has a getRoundData() function (L98-108) that DOES return all Chainlink fields — but getPrice(), the one actually called by Stratax.sol in 6 locations (L395, L402, L461, L462, L570, L571), ignores them.
Stale prices affect both critical paths: calculateOpenParams() (borrow amount computation) and _executeUnwindOperation() (collateral withdrawal calculation).
Likelihood:
Chainlink price feeds can become stale during network congestion, extreme gas prices, or oracle node issues. This has occurred historically: June 2020 (ETH flash crash), March 2023 (USDC depeg stress).
The getPrice() function is called in 6 locations across Stratax.sol (L395, L402, L461, L462, L570, L571), covering both open and unwind critical paths.
Impact:
During position creation: stale price leads to incorrect borrowAmount calculation. Aave evaluates position health using its own fresh oracle — if Stratax's stale price significantly diverges, the position may be created with a dangerously low health factor, risking immediate liquidation.
During position unwinding: stale price leads to incorrect collateralToWithdraw calculation. If calculated too high, Aave's withdraw() reverts (health factor violation). If too low, less collateral is recovered than expected.
The following scenario demonstrates how stale oracle data can lead to incorrect position health. When Chainlink's price feed hasn't been updated due to network congestion, getPrice() returns the old price without any warning. Since Aave uses its own oracle internally, the position can be created with parameters based on stale data while Aave evaluates with current prices — leading to an unexpectedly low health factor and immediate liquidation risk.
The fix captures all five return values from latestRoundData() and adds three standard Chainlink staleness checks: (1) verifying the round is complete via updatedAt > 0, (2) ensuring answeredInRound >= roundId to confirm the answer was finalized, and (3) enforcing a maximum age for the price data (1 hour threshold shown, configurable based on asset volatility). This is the industry-standard approach used by protocols like Aave and Compound.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.