Skip to content

feat(blend): periodic SEP-40 oracle price snapshot with Comet BLND/LP leg#660

Open
aditya1702 wants to merge 8 commits into
blend/pr3-validator-processorfrom
blend/pr4-price-snapshot
Open

feat(blend): periodic SEP-40 oracle price snapshot with Comet BLND/LP leg#660
aditya1702 wants to merge 8 commits into
blend/pr3-validator-processorfrom
blend/pr4-price-snapshot

Conversation

@aditya1702

@aditya1702 aditya1702 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Blend oracle price snapshot task

Fourth of 5 stacked PRs adding Blend Capital v2 lending support (stacked on #659).

Adds a periodic price snapshot task under ingest (live mode only) that keeps blend_oracle_prices fresh for PR5's USD valuation:

  • OraclePriceModelGetPriceTargets derives the deduped (oracle, asset) set from blend_pools × blend_reserves (NULL-oracle pools excluded); BatchUpsert on (oracle, asset). Runs directly on the pool (no ingest tx — the task is on its own schedule).
  • SEP-40 helpersAsset::Stellar(Address) arg encoding + Option<PriceData> decoding. Verified against the SEP-40 spec, the deployed Reflector oracle interface, and a live mainnet lastprice simulation round-trip (encoding accepted, real PriceData returned).
  • Comet leg — BLND spot + backstop LP price derived from the Comet BLND:USDC weighted pool (getters get_tokens/get_balance/get_normalized_weight/get_total_supply, 7-dec weight scalar, pinned against the deployed WASM 8abc2891…). Convention (PR5 reads this): rows live under oracle_contract_id = <Comet address>; the LP row is self-priced (asset == oracle), the BLND row keys the real BLND token address. USDC ≡ $1 documented.
  • Snapshot service — immediate pass then per-interval ticks; decimals() once per oracle; Option::None prices skipped, as are prices the pool contract itself would reject (pool.rs::load_price): oracle-reported timestamps older than 24h (stale) and prices ≤ 0 (invalid); per-oracle failures isolated (errors.Join) and counted, never abort a pass; one BatchUpsert per pass. Metrics: snapshot duration histogram, fetch counter (success|error|none|stale|invalid), prices-tracked gauge, oldest-price-age gauge (covers prices skipped as stale — a dead oracle surfaces as unbounded growth).
  • ConfigBLEND_PRICE_INTERVAL (default 60s, 0 disables) and BLEND_BACKSTOP_LP_CONTRACT_ID (empty disables the Comet leg); wired in setupDeps behind live-mode + interval gates; documented in docker-compose.

Deviations register (reviewer sign-off):

# Item
6 SEP-40 Asset::Stellar ScVec encoding verified against a live Reflector oracle (spec + interface dump + mainnet simulation)
7 Comet getter names + 7-decimal weight scalar pinned from the deployed WASM (hash recorded in code comment); BLND leg identified by pool weight (80/20), address taken from get_tokens

🤖 Generated with Claude Code


Review fixes:

  • Run waits the full interval AFTER each snapshot pass (timer reset) instead of a ticker, so an overrunning pass never triggers an immediate back-to-back pass (Codex).
  • 23486c90 — skip stale and non-positive oracle prices at snapshot time: the pool contract itself rejects prices older than 24h or ≤ 0 (pool.rs::load_price), so persisting them only lets the API price positions the pool would refuse to. New stale/invalid fetch outcomes plus a wallet_blend_price_oldest_age_seconds gauge covering every decoded price (including skipped-as-stale ones — a dead oracle surfaces as unbounded gauge growth). This is the write-side half of the staleness guard; feat(graphql): Blend positions, pools, and earn discovery #661 adds the read-side half so already-stored rows also stop pricing once aged.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d86bb208a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/services/blend/prices.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1197eb096

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/ingest/ingest.go Outdated
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch from a1197eb to 5c7d419 Compare July 9, 2026 13:57
@aditya1702 aditya1702 force-pushed the blend/pr3-validator-processor branch 2 times, most recently from 9330867 to edaf72c Compare July 9, 2026 20:12
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch from 5c7d419 to 731499d Compare July 9, 2026 20:12
@aditya1702 aditya1702 force-pushed the blend/pr3-validator-processor branch from edaf72c to e00ce3f Compare July 9, 2026 20:34
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch 2 times, most recently from 10ccc0a to 9d078d4 Compare July 9, 2026 21:37
@aditya1702 aditya1702 force-pushed the blend/pr3-validator-processor branch from e00ce3f to 23307c6 Compare July 9, 2026 21:37
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch from 9d078d4 to 23486c9 Compare July 10, 2026 11:32
@aditya1702 aditya1702 force-pushed the blend/pr3-validator-processor branch from 23307c6 to 3995153 Compare July 10, 2026 11:32
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch from 23486c9 to 6cdb564 Compare July 15, 2026 20:52
@aditya1702 aditya1702 force-pushed the blend/pr3-validator-processor branch 2 times, most recently from 39d5745 to 8b68326 Compare July 16, 2026 16:56
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch from 6cdb564 to 97ab9f5 Compare July 16, 2026 16:56
…e live advisory lock

The blend price snapshot task started in setupDeps, so an instance that
never wins the advisory lock (rolling deploy, standby pod) still ran
snapshot passes, duplicating oracle RPC load and writes. Long-lived
background tasks now register as PostLockTasks and launch inside
startLiveIngestion after the lock is held.
The pool contract itself (pool.rs::load_price) rejects prices older than
24h or <= 0, so persisting them only lets the API price positions the
pool would refuse to. Skip both at snapshot time, counted as new
"stale"/"invalid" fetch outcomes, and add a
wallet_blend_price_oldest_age_seconds gauge covering every decoded price
including skipped-as-stale ones, so a dead oracle surfaces as unbounded
gauge growth.
@aditya1702 aditya1702 force-pushed the blend/pr3-validator-processor branch from 8b68326 to d6d740f Compare July 16, 2026 20:07
@aditya1702 aditya1702 force-pushed the blend/pr4-price-snapshot branch from 97ab9f5 to adec3b6 Compare July 16, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant