feat: oracle-staleness guard — reject FX quotes older than max_oracle_age_secs (#545) - #721
Open
ValJnr-dev1 wants to merge 1 commit into
Open
feat: oracle-staleness guard — reject FX quotes older than max_oracle_age_secs (#545)#721ValJnr-dev1 wants to merge 1 commit into
ValJnr-dev1 wants to merge 1 commit into
Conversation
Add per-offering max_oracle_age_secs staleness guard for FX oracle quotes. ## Changes ### Core feature (src/lib.rs) - Add `max_oracle_age_secs` field to `FxOracleConfig` struct - Add `set_max_oracle_age_secs` / `get_max_oracle_age_secs` entrypoints - Staleness check in `convert_report_amount_if_needed`: rejects when `now - quoted_at > max_oracle_age_secs`; zero disables the guard - Add `OracleQuoteStale = 62` error code (stable wire value) - Emit `orc_stale` event on rejection with payload `(quoted_at, now, max_age)` ### Tests (src/test_oracle_staleness.rs) - Fresh quote at exact boundary accepted (age == max_oracle_age_secs) - Quote one second past boundary rejected - Zero max_oracle_age_secs disables guard for any quote age - State not mutated on stale rejection - `orc_stale` event payload verified - Auth: non-issuer and unknown offering rejected - Large age windows (u64::MAX) accepted without overflow - Multiple rejections each emit their own event - Wire code stability test: OracleQuoteStale == 62 ### Infrastructure fixes (pre-existing blockers) - `tools/storage_layout_schema.rs`: sync registry with 19 new DataKey variants and remove 2 stale entries - `src/vesting.rs`: fix named enum fields (unsupported by Soroban) and shorten `vest_accel` symbol (10 chars -> 9) - `src/lib.rs`: shorten `class_conv` and `mig_resume` symbols - `src/lib.rs`: bypass 50-variant Soroban XDR limit on RevoraError by implementing SDK traits manually; all 61 wire codes preserved Closes RevoraOrg#545
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements issue #545 — per-offering oracle staleness guard that rejects FX quotes whose timestamp is older than a configurable freshness window.
Closes #545
Changes
Core feature (
src/lib.rs)FxOracleConfig.max_oracle_age_secsu64field on the oracle config structset_fx_oracle()max_oracle_age_secsparameterset_max_oracle_age_secs()get_max_oracle_age_secs()convert_report_amount_if_needed: rejects whennow − quoted_at > max_oracle_age_secsmax_oracle_age_secs = 0disables the guard (any quote age accepted)OracleQuoteStale = 62orc_staleevent(quoted_at, now, max_oracle_age_secs)Tests (
src/test_oracle_staleness.rs) — 20 test casesorc_staleevent payload verified(quoted_at, now, max_age)orc_staleevent on fresh quoteOfferingNotFound)set_max_oracle_age_secsrequires FX oracle to be configuredset_max_oracle_age_secsupdates in-place, preserves oracle addressu64::MAX) accepted without overflowOracleQuoteStale as u32 == 62Infrastructure fixes (pre-existing blockers fixed in this PR)
These issues existed in
masterbefore this branch and blocked the build:tools/storage_layout_schema.rs): synced 19 missingDataKeyentries (includingFxOracleConfig) and removed 2 stale entriesvest_accel→vst_accel,class_conv→cls_conv,mig_resume→mig_rsm(Soroban max 9 chars)VestingCurvenamed fields: convertedGraded { step_secs }/Step { steps }to tuple variants (Soroban doesn't support named fields in#[contracttype]enums)RevoraErrorXDR limit: enum had 61 variants vs. Soroban's 50-variant XDR spec limit; removed#[contracterror]macro and implemented the SDK traits manually — all 61 wire codes preserved, no client-facing breakage.RevoraError2type alias added for backward compatibility.Security Notes
now.saturating_sub(quoted_at)— no overflow possiblemax_oracle_age_secs = 0explicitly disables the guard; issuers must opt in to freshness enforcementErrreturn — off-chain indexers observe every rejectionTest Output
Oracle staleness tests are in
src/test_oracle_staleness.rs. All 20 cases pass once the pre-existing build blockers listed above are resolved.