feat(contracts): add oracle staleness gate to lending_pool (#1379 Phase 1) - #1571
Open
david87131 wants to merge 3 commits into
Open
feat(contracts): add oracle staleness gate to lending_pool (#1379 Phase 1)#1571david87131 wants to merge 3 commits into
david87131 wants to merge 3 commits into
Conversation
Add require_fresh_price to contracts/lending_pool: an admin-pushed price cache stamped with the recording ledger, a configurable max-age (default 60 ledgers), and a PoolError::OracleStale revert when a cached price is older than that threshold. Includes an admin-gated set_oracle_price / set_oracle_max_age pair and unit tests covering fresh, stale, boundary, missing-price, and auth-gated cases. This is a scoped Phase 1 slice of LabsCrypt#1379: lending_pool has no live oracle integration today (rate logic lives in loan_manager, which only exposes a raw rate with no staleness metadata), so this establishes the reusable freshness-check primitive called out in the issue's file list without attempting the full cross-layer circuit breaker. Addresses LabsCrypt#1379
cargo fmt --check was failing on lending_pool/src/test.rs due to a double blank line before the new oracle staleness test section. Addresses LabsCrypt#1379
…le-staleness-check # Conflicts: # contracts/lending_pool/src/lib.rs # contracts/lending_pool/src/test.rs
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.
Scope
This is a scoped-down, contract-only first slice of #1379, which is a large cross-layer epic (contract circuit-breaker, backend monitor, frontend banner, CI/infra wiring, verification — the issue itself estimates 48-72 hours across 5 phases). This PR implements only the core, security-critical piece: an on-chain staleness check that reverts when a cached oracle price is too old.
Context / honest discrepancy from the issue text
The issue assumes
lending_poolandloan_managerboth read aRateOraclePriceData { rate, updated_ledger }with no staleness bound. In the actual current codebase:lending_poolhas no oracle integration at all today.loan_managerdoes read an oracle (RateOracleInterface::get_rate), but that interface returns a rawu32rate with noupdated_ledger/staleness metadata whatsoever — there's nothing to bound yet on that side without a larger interface change.Given that, this PR adds the reusable staleness-check primitive to
lending_poolexactly at the file path the issue calls out (contracts/lending_pool/src/oracle.rs), so it exists and is tested independently, ready to be wired into real call sites in follow-up phases.What's implemented
contracts/lending_pool/src/oracle.rs:PriceData { rate: i128, updated_ledger: u32 }set_oracle_price(admin, asset, rate)— admin-gated, stamps the current ledger asupdated_ledger(stands in for a live oracle feed until one is wired up)set_oracle_max_age(admin, max_age)— admin-gated setter for the staleness threshold (defaults toDEFAULT_ORACLE_MAX_AGE_LEDGERS = 60)require_fresh_price(asset) -> Result<PriceData, PoolError>— computesage = current_ledger - updated_ledger, reverts withPoolError::OracleStaleifage > max_agePoolError::OracleStaleadded to the existing error enum (matches existing style)DataKey::OraclePrice(Address)andDataKey::OracleMaxAgeadded to storage keysset_oracle_price,set_oracle_max_age,get_oracle_max_age,require_fresh_price, all following the contract's existingSelf::admin(&env).require_auth()patterncontracts/lending_pool/src/test.rs: fresh price passes, stale price reverts withOracleStale, exact-boundary age still passes,set_oracle_pricerequires admin auth, missing price returnsNotInitializedWhat's explicitly deferred (not in this PR)
loan_managerintegration — wiring an actual staleness bound intoRateOracleInterface::get_rate/borrow/liquidate(requires extending that interface with anupdated_ledger, a larger and separately-reviewable change)oracleHealthMonitor.ts/defaultChecker.tsdrift detectionOracleStatusBanner.tsx/useOracleStatus.tsdocker-compose.ymlresume()flowTest plan
cargo build --libpasses forlending_poolin isolation from this changecargo test— all 63 tests pass (58 pre-existing + 5 new oracle tests)contracts/lending_pool/src/lib.rsandsrc/test.rsonmainalready contain pre-existing dead/broken code appended aftermod test;(a duplicatedepositfree function referencing an undefinedErrortype, and a matching broken test using undefined helpers) that fails to compile as-is. This is pre-existing onmain, unrelated to this change, and out of scope here — flagging it separately rather than folding an unrelated fix into this PR. I verified this PR's own code builds and all its tests pass by temporarily excising that pre-existing dead code locally, confirming the failure is isolated to it and not to anything touched in this diff.Addresses #1379