fix(oracle): restore Chainlink staleness check dropped by an unrelated commit - #343
fix(oracle): restore Chainlink staleness check dropped by an unrelated commit#343Morenikeoa wants to merge 1 commit into
Conversation
…d commit parseChainlinkPrice validated buffer size, decimals, and price positivity, but had no staleness protection — the public API's own module docstring claims "These utilities validate oracle data BEFORE parsing to prevent silent propagation of stale or malformed Chainlink data as price," which was no longer true. This protection existed once: commit fb9083e ("fix(oracle): add staleness check to parseChainlinkPrice", 2026-04-04) added CHAINLINK_TIMESTAMP_OFFSET, OraclePrice.updatedAt, and an opt-in maxStalenessSeconds parameter that throws on stale data. It was silently dropped in commit af46df6 (2026-04-16, "v12.17 SDK update + SBF account parsing offset fix + V1M2 discovery") — a commit whose stated purpose is unrelated slab-layout work, indicating this was an incidental regression rather than an intentional removal. Any caller using the public parseChainlinkPrice/isValidChainlinkOracle API to source a price for trading/liquidation decisions got zero protection against a frozen/stale oracle account, with no way to even opt into a staleness bound. Fix: restore fb9083e's implementation verbatim (CHAINLINK_TIMESTAMP_OFFSET, ParseChainlinkOptions.maxStalenessSeconds, OraclePrice.updatedAt, and the age-check throw), adapted into the current file. Backward compatible: omitting maxStalenessSeconds preserves prior behavior exactly, just with updatedAt additionally populated. Added regression tests in test/oracle.test.ts: a fresh oracle within the staleness bound doesn't throw, a 30-day-old oracle with a 60s bound throws, and updatedAt is populated even when maxStalenessSeconds is omitted. Confirmed the new tests fail against the current regressed code (import error — CHAINLINK_TIMESTAMP_OFFSET doesn't exist) and pass against this fix. Full suite (pnpm test): exit 0, all green, including "All oracle tests passed!". Vitest portion: 851 passed | 31 skipped (882 total, unchanged — oracle.test.ts runs via tsx outside the vitest-counted suite).
|
Warning Review limit reached
More reviews will be available in 29 minutes and 6 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
parseChainlinkPricevalidated buffer size, decimals, and price positivity, but had no staleness protection — the public API's own module docstring claims "These utilities validate oracle data BEFORE parsing to prevent silent propagation of stale or malformed Chainlink data as price," which was no longer true.This protection existed once: commit
fb9083e("fix(oracle): add staleness check to parseChainlinkPrice") addedCHAINLINK_TIMESTAMP_OFFSET,OraclePrice.updatedAt, and an opt-inmaxStalenessSecondsparameter that throws on stale data. It was silently dropped in a later, unrelated commit (af46df6, "v12.17 SDK update + SBF account parsing offset fix + V1M2 discovery") — a commit whose stated purpose is unrelated slab-layout work, indicating this was an incidental regression rather than an intentional removal.Any caller using the public
parseChainlinkPrice/isValidChainlinkOracleAPI to source a price for trading/liquidation decisions got zero protection against a frozen/stale oracle account, with no way to even opt into a staleness bound.Fix
Restore
fb9083e's implementation (CHAINLINK_TIMESTAMP_OFFSET,ParseChainlinkOptions.maxStalenessSeconds,OraclePrice.updatedAt, and the age-check throw), adapted into the current file. Backward compatible: omittingmaxStalenessSecondspreserves prior behavior exactly, just withupdatedAtadditionally populated.Test plan
test/oracle.test.ts: a fresh oracle within the staleness bound doesn't throw, a 30-day-old oracle with a 60s bound throws, andupdatedAtis populated even whenmaxStalenessSecondsis omitted.CHAINLINK_TIMESTAMP_OFFSETdoesn't exist) and pass against this fix.pnpm testexit 0, including "All oracle tests passed!"); vitest portion unchanged at 851 passed / 31 skipped sinceoracle.test.tsruns viatsxoutside the vitest-counted suite.