Reporting Team: BugBlow
Context: We are an independent team contributing to the security and stability of the PancakeSwap ecosystem.
Location: Predictions V2, _getPriceFromOracle()
Description of the bug
The contract enforces a strict requirement that the Chainlink roundId must always increase:
require(uint256(roundId) > oracleLatestRoundId,...);
However, Chainlink does NOT guarantee that roundId always increases Docs:
- If price did not change, roundId may stay the same
- Some feeds update sparsely or aggregate several on-chain pushes
- Certain feeds update internal aggregator phases, which may reuse roundId patterns
This creates a scenario where:
Chainlink updates the price
roundId remains the same
The contract rejects the update
And freezes the prediction market
Impact
Round DoS (Denial of Service):
- executeRound() stops working
- Rounds never close
- Rounds never lock
- Rewards are never calculated
- Users cannot claim
- Contract becomes stuck after the first occurrence of equal roundId
This is a failure mode.
Fix
Use a non-strict check::
- require(
- uint256(roundId) > oracleLatestRoundId,
- "Oracle update roundId must be larger than oracleLatestRoundId"
-);
+ require(
+ uint256(roundId) >= oracleLatestRoundId,
+ "RoundId must not decrease"
+);
Detailed Public Report Link: Report
Reporting Team: BugBlow
Context: We are an independent team contributing to the security and stability of the PancakeSwap ecosystem.
Location: Predictions V2, _getPriceFromOracle()
Description of the bug
The contract enforces a strict requirement that the Chainlink roundId must always increase:
require(uint256(roundId) > oracleLatestRoundId,...);However, Chainlink does NOT guarantee that roundId always increases Docs:
This creates a scenario where:
Chainlink updates the price
roundId remains the same
The contract rejects the update
And freezes the prediction market
Impact
Round DoS (Denial of Service):
This is a failure mode.
Fix
Use a non-strict check::
Detailed Public Report Link: Report