Skip to content

Rates Engine v0.5.0-rc.80

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 May 16:08
· 581 commits to main since this release

[v0.5.0-rc.80] — 2026-05-26

Fixed

  • sorobanevents.AsyncSink cursor-drop incoherence (ADR-0029,
    superseding the original buffer-full-drop design).
    The
    2026-05-26 fill walk dropped ~18.86M rows of ~4.66B (~0.40%)
    across all 12 parallel chunks because PushEvent dropped rows
    on a full channel while the backfill cursor advanced per
    produced ledger — so the dropped rows had no recovery path
    (-resume short-circuited at the "already complete" branch).
    The fix: PushEvent now blocks on a full channel (back-pressure
    into the dispatcher) so the cursor cannot outrun durable writes.
    Stop() closes a new stopping channel that unblocks any
    in-flight producers (counted as dropped — shutdown-race only).
    The backfill driver and live indexer both watch ctx and call
    Stop early on cancellation so a hung Postgres can't deadlock the
    hot path past SIGTERM. ADR-0029 updated with the post-mortem;
    runbook to reset the 12 soroban-events cursors and re-walk is
    in follow-up rc.80 ops. Regression-tested via
    internal/sources/sorobanevents/dispatcher_adapter_test.go (no
    drops under sustained back-pressure; Stop releases blocked
    producers; pending rows drain on shutdown without channel-close
    panic).

Added

  • Comet Balancer-v1 liquidity events end-to-end (#26). The
    decoder previously claimed only (POOL, swap) and silently
    dropped every other Comet event under the shared POOL
    namespace. It now decodes all five events the Soroban port of
    Balancer-v1 emits — swap continues to land in trades; the
    four liquidity-mutating kinds (join_pool, exit_pool,
    deposit, withdraw) land in a new comet_liquidity
    hypertable (migration 0042; PK includes token so multi-token
    joins from the same op don't collide). Each row carries the
    add/remove direction explicitly so dashboards SUM(amount) WHERE direction = 'add' without re-encoding the kind mapping.
    withdraw rows also carry pool_amount_in — the BPT (pool-
    share) token count burned in exchange for the underlying.
    Documented in internal/sources/comet/README.md. Verified
    2026-05-26 against upstream comet-contracts-v1 main: the
    EVM-Balancer-v1 admin events (bind / rebind / unbind /
    finalize / gulp / set_swap_fee / set_controller /
    set_public_swap) are NOT in the Stellar port — either the
    function doesn't exist or it's storage-only with no event
    publication. BPT transfer events go through the SEP-41
    standard token-event surface and are already claimed by
    internal/sources/sep41_supply when the pool is in scope.
    Historical fill plan: walk soroban_events (migration 0041)
    for the pre-rc back-window — a ratesengine-ops comet-backfill
    subcommand wrapping decodeLiquidityEvent is the cleanest path
    and is tracked as a follow-up. Updated wasm audit at
    docs/operations/wasm-audits/comet.md.

  • Soroswap skim event handler + soroswap_skim_events hypertable
    (#28).
    Closes the "every emitted Soroswap pair-contract topic
    gets classified" gap. TopicSymbolSkim had been declared in
    internal/sources/soroswap/events.go since the package was first
    written but was unreachable through classify() — the 5th
    pair-contract event (alongside swap/sync/deposit/withdraw) was
    silently dropped by the dispatcher. The Decoder now decodes
    SkimEvent { skimmed_0, skimmed_1 } (tolerant of the
    amount_0/amount_1 Uniswap-v2-derivative aliases per
    contract-schema-evolution.md), pulls an optional to Address
    field when a future WASM upgrade adds it, and emits a new
    soroswap.SkimEvent consumer.Event the pipeline sink lands as a
    row in a new soroswap_skim_events hypertable (migration 0043;
    PK leads with ledger_close_time per TS103; amounts NUMERIC per
    ADR-0003; compression after 7 days segmented by contract_id).
    Skim is not a trade — never feeds VWAP, never lands in the
    trades hypertable. Historical fill is a INSERT … SELECT FROM soroban_events WHERE topic_0_sym = 'skim' AND contract_id IN (<pair set>) query (ADR-0029 raw landing zone) — operator
    runbook follow-up after the initial backfill window lands.

  • Phoenix liquidity + stake event decoders (#27). Phoenix's pool
    contract (volatile contracts/pool/ + stableswap
    contracts/pool_stable/) and per-pool stake contract emit four
    N-events-per-action shapes the indexer previously silently dropped:
    provide_liquidity (5 events: sender, token_a, token_a-amount,
    token_b, token_b-amount), withdraw_liquidity (4 events: sender,
    shares_amount, return_amount_a, return_amount_b, plus an optional
    5th auto unbonded), bond (3 events: user, token, amount), and
    unbond (3 events: same shape as bond). The existing 8-event swap
    reassembly is extended to a per-action correlation-buffer fleet —
    one map per action so a same-(ledger,tx,op) bond+unbond pair can't
    collide on shared field names. Two new TimescaleDB hypertables
    back the reads: phoenix_liquidity (provide + withdraw rows,
    per-pool / per-sender / per-action indexes) and
    phoenix_stake_events (bond + unbond rows, per-contract / per-user
    / per-action indexes; migration 0044). Both partition daily on
    ledger_close_time, compress segment-by (pool, action) /
    (stake_contract, action) after 7 days. Per ADR-0003, all i128
    amounts ride NUMERIC; PKs include ledger_close_time per
    TimescaleDB TS103 (the lesson from migration 0041). Historical
    fill follow-up: once soroban_events (ADR-0029) covers the
    Soroban era, populate both tables via INSERT … SELECT FROM soroban_events WHERE topic_0_sym IN ('provide_liquidity', 'withdraw_liquidity','bond','unbond') fed through the same
    per-action correlation buffer — pending the per-WASM-hash decoder
    audit log being extended to enumerate the new field strings.

  • Blend money-market decoder (#25, per [[project_every_event_principle]]).
    Extended internal/sources/blend/decode.go::classify() to handle
    the 18 event topics that were silently dropped: supply,
    withdraw, supply_collateral, withdraw_collateral, borrow, repay,
    flash_loan, gulp, claim, bad_debt, defaulted_debt,
    reserve_emission_update, gulp_emissions, set_admin, update_pool,
    queue_set_reserve, cancel_set_reserve, set_reserve, set_status,
    deploy. New hypertables blend_positions, blend_emissions,
    blend_admin via migration 0045. Live ingest captures every
    event going forward; historical fill via INSERT … SELECT FROM soroban_events WHERE contract_id IN (<blend pool contracts>) AND topic_0_sym IN (…) once the soroban_events fill walk lands.

Changed

  • CCTP + Rozo flipped to BackfillSafe = true after WASM-history
    audit (#21).
    Walk on 2026-05-26: ratesengine-ops wasm-history -from 60000000 -to 62642779 -parallel 4 across all 6 mainnet
    contracts (3 CCTP + 3 Rozo) — 5h02m wall, 2,642,780 ledgers
    scanned, ZERO WASM upgrades observed (output JSON ranges=null
    per contract). CCTP's three contracts each have their own WASM
    (one per role: token messenger / message transmitter / token
    minter); Rozo's three contracts share a single WASM hash
    b56aedeaf80c3d4b… (per stellar.expert + RozoAI's
    internal/sources/rozo/events.go confirmation that all three
    emit identical PaymentEvent / FlushEvent schemas). Decoder
    coverage was already complete; with single-WASM-per-contract
    confirmed for the audit range, no decoder drift risk for
    historical replay. internal/sources/external/registry.go's
    BackfillSafe flag flipped false → true for both. Historical
    replay now unblocked via INSERT … SELECT FROM soroban_events
    per the canonical query shape in
    docs/operations/wasm-audits/cctp.md + rozo.md. Walk evidence
    archived to /tmp/wasm-history-bridges.json on r1.