Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ci/critical-coverage-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"worker/src/api/health.ts": 100,
"worker/src/cron/sync-stablecoins.ts": 97.3,
"worker/src/cron/sync-stablecoins/enrich-prices.ts": 100,
"worker/src/cron/sync-stablecoins/price-corroboration-observations.ts": 100,
"worker/src/cron/sync-stablecoins/price-corroboration.ts": 72.9,
"worker/src/cron/sync-stablecoins/pricing.ts": 88.5,
"worker/src/cron/detect-depegs.ts": 100,
Expand Down
7 changes: 4 additions & 3 deletions docs/live-reserves.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ Warnings now carry both a display `severity` and an execution `effect`:
3. Resolves an adapter from `worker/src/cron/reserve-adapters/index.ts`.
4. Builds a breaker key as `live-reserves:${breakerScope ?? adapter}`.
5. Checks the per-source circuit breaker before each coin fetch.
Each primary or fallback adapter attempt receives its own start time as `nowSec`, so time spent earlier in the queue cannot make current chain heads appear to be in the future.
6. Persists either a fresh snapshot (`reserve_composition`) plus sync-state row, or an error/degraded/skipped sync-state row.

The `reserve-recovery` lane retains its five-minute trigger. In `recover` mode it fences any in-flight attempt, claims the checkpoint's ready pointer, and replays the suffix; a crash before terminal checkpoint finalization is therefore retried within one recovery tick. `off` keeps the sweep but skips recovery scans. The checkpoint pointer is the sole run-level resume mechanism; the cache table is not used for reserve cursor ownership.
Expand Down Expand Up @@ -526,15 +527,15 @@ the `re-metrics` adapter parses Re Protocol's official metrics page and now extr

`fx` now publishes f(x) protocol pool debt balances as conservative live proxy redemption capacity for `fxusd-f-x-protocol`; the configured score-grade path reads the reviewed Ethereum WBTC and wstETH pool collateral/debt totals directly on-chain. `fxsave-f-x-protocol` uses the generic `erc4626-single-asset` path to publish the vault's idle fxSP balance as live-direct capacity for its fxSP/router exit route. The same adapter can also attach reviewed ERC-4626 liquidity sidecars: Morpho V1/V2 vault configs use Morpho V2 `liquidity` or V1 `liquidity.underlying` as same-run API capacity after validating the vault address, chain id, listed status, and underlying asset; Yearn V3 configs use the vault's same-run default withdrawal queue, measuring `totalIdle()` plus each funded strategy's `min(currentDebt, convertToAssets(maxRedeem(vault)))`; `sbold-k3-capital` uses `sbold-sp-withdrawable` to read the BOLD amount returned by the vault's `calcFragments()` liquidity view, representing compounded Stability Pool deposits that the vault can withdraw; and `sfrxusd-frax` uses `fraxtal-hop-withdrawable` because Ethereum-local withdrawal is disabled. Two coin-specific paths override the generic idle-balance assumption: `eearn-ember` pins the vault, validator, and protocol-config proxy/implementation identities and reports zero immediate capacity for its operator-batched queue while exposing pause, queue, and current-fee diagnostics; `sdusd-dtrinity` pins the dSTAKE router and exact strategy/adapter set, then uses the current dLEND `maxWithdraw` cross-checked against dUSD available liquidity and the current unstaking fee. Required identity or state-read failures abort those snapshots rather than falling back to idle assets or full NAV. The sfrxUSD observer pins finalized Ethereum and Fraxtal blocks, all six proxy implementations, direct-contract code, peers, tokens, oracles, inventory, quote components, and return-message funding. It publishes the accepted packet for diagnostics and bounded capacity, but the V9 route remains non-scoreable while Ethereum transaction gas and a measured or primary-source settlement upper bound are missing. Morpho V2 `forceDeallocatableLiquidity` is persisted for context but not used as scoring capacity. Yearn V3 funded-strategy probe failures, sBOLD liquidity-read failures, and any sfrxUSD identity/state drift degrade instead of falling back to full NAV or the disabled local withdrawal path. `asymmetry` now publishes USDaf protocol supply from the timestamped stats API as live direct redemption capacity alongside branch collateral slices. `jupusd` consumes Jupiter's public transparency API and latest snapshot timestamp, grouping USDC/USDtb holdings into reserve slices while emitting whitelisted-primary live redemption capacity and route status from the public oracle endpoint.

`solstice-attestation` and `river-protocol-info` are proof-class reserve-sync adapters. They make current issuer/protocol telemetry visible on reserve detail and status surfaces, but their registry evidence class is `weak-live-probe`, so they do not become V9 Backing reserve evidence. Solstice remains proof-class until its aggregate solvency feed exposes timestamped asset-category composition; River remains proof-class because its protocol-info endpoint exposes aggregate TVL/circulating-supply telemetry rather than asset-level collateral composition. River snapshots degrade when the aggregate TVL is below circulating satUSD, and timestampless protocol-info payloads remain freshness-unverified.
`solstice-attestation` and `river-protocol-info` are proof-class reserve-sync adapters. They make current issuer/protocol telemetry visible on reserve detail and status surfaces, but their registry evidence class is `weak-live-probe`, so they do not become V9 Backing reserve evidence. Solstice remains proof-class until its aggregate solvency feed exposes timestamped asset-category composition; River remains proof-class because its protocol-info endpoint exposes aggregate TVL/circulating-supply telemetry rather than asset-level collateral composition. River snapshots degrade when the aggregate TVL is below circulating satUSD, and timestampless protocol-info payloads remain freshness-unverified. River's bounded redemption probe tolerates reverts in speculative manager slots beyond the on-chain count; every manager inside that count and its branch reads remain mandatory.

`audx-independent-assurance` uses the reviewed July 31, 2026 report: AUD 3,231,371.79 in designated bank accounts against AUD 3,208,057.00 issued supply. Aura Partners signed its limited-assurance report on August 20, 2026; the posting date is unknown. The manifest retains the report's printed AEDT timestamp and exact PDF hash, with freshness measured from the examined period rather than the signature or fetch date.

`usdgo-transparency` is now independent: the Deloitte examination is the authoritative composition/liability source through the independent-assurance manifest (exact PDF SHA-256 binding), with the Avalanche BUIDL balance pinned on-chain and the issuer transparency API demoted to a cross-check that raises informational warnings on later-period drift.
`usdgo-transparency` uses the Deloitte examination as its authoritative composition/liability source through the independent-assurance manifest (exact PDF SHA-256 binding), with the issuer transparency API retained as a cross-check that raises informational warnings on later-period drift. The July 31, 2026 report supersedes June and locates BUIDL on Solana. Config version 3 retires the obsolete June Avalanche balance check; current report hash, latest-report detection, asset/liability reconciliation, and same-period issuer disagreement checks remain mandatory. Pharos does not claim an independent replay of the report-time Solana balance. The offline compiler verifies the report's zero Morph liabilities before omitting that empty chain from positive liability rows.

`anzen-usdz` is now independent: it reads USDz `totalPooledSPCT()` and actual SPCT holdings on-chain and reconciles them against bridge-adjusted USDz liabilities across the five issuance chains, failing closed on shortfall instead of trusting global SPCT supply.

`moc-v3-buckets` is a narrow Money-on-Chain V3 adapter (USDRIF): pinned Rootstock block/header and proxy implementation hashes, bucket-identity and sole-token revert checks, liability/supply reconciliation, wallet-accounting exclusions, and protocol-vs-market price divergence guards; it emits no redemption telemetry.
`moc-v3-buckets` is a narrow Money-on-Chain V3 adapter (USDRIF): pinned Rootstock block/header and proxy implementation hashes, bucket-identity and sole-token revert checks, liability/supply reconciliation, wallet-accounting exclusions, and protocol-vs-market price divergence guards; it emits no redemption telemetry. The September 5 review at Rootstock block 9214021 binds both upgraded buckets to the verified MocCARC20 implementation `0x5316384be99310fdea0da0b3cc0d0bb9e7f0887f` and rechecks the RIFUSD peg-container identity.

`zephyr-scanner` consumes Zephyr's reserve snapshot API for `zsd-zephyr-protocol`, preserving the snapshot capture timestamp, ZEPH reserve value, ZSD supply, reserve ratio, moving-average reserve ratio, and ZSD yield-reserve metadata. It is proof-class because the feed is protocol-published native-chain telemetry over volatile ZEPH collateral rather than independently verified asset-level reserve evidence.

Expand Down
4 changes: 3 additions & 1 deletion docs/pricing-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Supply fallback behavior is owned by [Supply Snapshot: Supply Pipeline](./supply
Pharos separates critical publication from best-effort corroboration:

1. **15-minute publication** runs the full primary consensus: DefiLlama and CoinGecko, the curated CoinGecko ticker and CEX lanes, RedStone, Curve on-chain/oracle, reserve NAV telemetry, promoted DEX observations, and the post-consensus pool challenge. Registered authoritative overrides then run before publication.
2. **Hourly corroboration** runs `enrichMissingPrices()` and the explicitly enabled exact-address provider against only the latest missing or low-depth rows, then stages provenance in `price_cache` for a later publication to revalidate.
2. **Hourly corroboration** runs `enrichMissingPrices()` and the explicitly enabled exact-address provider against only the latest missing or low-depth rows. It stages actual fetched observations in `price:corroboration-observations:v1` for a later publication to revalidate, separately from ordinary `price_cache` replay provenance.

The output is the cached `price`, `priceSource`, `priceConfidence`, `priceObservedAt`, `priceObservedAtMode`, `priceSyncedAt`, optional `priceSourceConfidenceProfile`, and compatibility `priceUpdatedAt` fields served through `/api/stablecoins`.

Expand Down Expand Up @@ -351,6 +351,8 @@ The same registry also supports historical replay for backfills where a provider

## Fallback Enrichment

The hourly observation handoff expires after one hour plus one 15-minute publication interval, allowing the next hourly primary to consume it before replacement corroboration runs. It independently enforces each source's existing observation-age limit, including the reviewed seven-day CoinGecko low-volume window. Only freshly collected provider observations enter it; published references and cached replays never do. A missing-price consumer revalidates candidates with the normal fallback and severe-downside corroboration guards, preserves their source and observation time, and publishes only `fallback` confidence. The existing `cachedFallbackCount` includes this D1 handoff and ordinary replay recovery. Empty successful collections clear the handoff; older writers cannot replace newer snapshots. Ordinary replay lifetime and trust rules are unchanged.

Fallbacks are detached from the critical publication. On the existing quarter-hour trigger's top-of-hour invocation, `runPriceCorroboration()` reads the just-published `stablecoins` cache, selects only rows that are missing a price or have fewer than three consensus sources, and runs `enrichMissingPrices()` against isolated probe copies. A fallback error cannot change the completed `sync-stablecoins` result or block its canonical cache write. Successful probes update `price_cache`; the next 15-minute publication revalidates those entries before using them as continuity. The hourly pass order is:

1. **Pass 1:** DefiLlama `coins.llama.fi` by canonical tracked contract identity, using the upstream row address when present and falling back to curated tracked `contracts` metadata when the upstream row is addressless. Accepted quotes must carry a fresh upstream timestamp, confidence, and matching symbol, then pass shared peg-aware bounds before they can resolve the asset. Schema-invalid OK responses record `dl-coins` breaker failures instead of being treated as healthy empty coverage.
Expand Down
2 changes: 1 addition & 1 deletion docs/yield-intelligence.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ The methodology above is the durable public contract. Runtime topology, storage
- `yield_publication_generations` and `yield_source_decisions` record publication state and bounded source-selection evidence. Repeated unchanged anomaly evidence is 30-day audit data; source switches and anomaly-episode boundaries remain durable.
- Public rankings expose only a validated published generation. Failed validation, stale-writer, or publication attempts leave the previous public snapshot intact.
- The final resolve-stage eligibility pass removes null, non-finite, or thin measured venue-TVL candidates in the three deposit-venue classes before evaluation and arbitration, across tracked, explicit, auto-discovered, supplemental, and linked-variant paths. Only eligible candidates can reach a validated published generation.
- History retention is enforced by the producer. Legacy rows remain explicitly partial rather than receiving invented evidence.
- History retention is enforced by the producer. Idempotent cleanup retries transient D1 overloads with the shared bounded, abort-aware retry policy; exhausted retries and schema errors still fail visibly without replaying publication. Legacy rows remain explicitly partial rather than receiving invented evidence.

### Producers And Consumers

Expand Down
33 changes: 15 additions & 18 deletions scripts/maintenance/refresh-independent-assurance-reports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ function profile(product: IndependentAssuranceProduct): CompilerProfile {
product,
profile: "usdgo-v1",
officialIndexUrl: "https://www.anchorage.com/platform/usdgo-reserve-attestations",
reportUrl: "https://learn.anchorage.com/06.30.26_USDGO-Stablecoin-Attestation-Report.pdf",
reportDate: "2026-06-30",
reportAsOf: "2026-06-30T23:59:59Z",
reportUrl: "https://learn.anchorage.com/07.31.26_USDGO-Stablecoin-Attestation-Report-signed.pdf",
reportDate: "2026-07-31",
reportAsOf: "2026-07-31T23:59:59Z",
reportTimeZone: "UTC",
reportIssuedAt: "2026-07-28T23:59:00Z",
reportIssuedAt: "2026-08-28T23:59:00Z",
attestor: "Deloitte & Touche LLP",
engagement: "Independent accountant's examination under AICPA attestation standards",
conclusion: "unmodified",
Expand All @@ -165,18 +165,12 @@ function profile(product: IndependentAssuranceProduct): CompilerProfile {
code: "solana",
label: "Solana USDGO redeemable tokens",
// eslint-disable-next-line security/detect-unsafe-regex -- anchored per-line pattern over an offline reviewed PDF text dump; bounded digit runs, no nested quantifier ambiguity.
pattern: /^\s*a\.\s+Total USDGO natively minted tokens\s+([0-9][0-9,]*(?:\.[0-9]+)?)\s+[0-9][0-9,]*(?:\.[0-9]+)?\s+[0-9][0-9,]*(?:\.[0-9]+)?\s*$/im,
},
{
code: "morph",
label: "Morph USDGO redeemable tokens",
// eslint-disable-next-line security/detect-unsafe-regex -- anchored per-line pattern over an offline reviewed PDF text dump; bounded digit runs, no nested quantifier ambiguity.
pattern: /^\s*a\.\s+Total USDGO natively minted tokens\s+[0-9][0-9,]*(?:\.[0-9]+)?\s+([0-9][0-9,]*(?:\.[0-9]+)?)\s+[0-9][0-9,]*(?:\.[0-9]+)?\s*$/im,
pattern: /^\s*a\.\s+Total USDGO natively minted tokens\s+([0-9][0-9,]*(?:\.[0-9]+)?)\s+(?:[0-9][0-9,]*(?:\.[0-9]+)?|-)\s+[0-9][0-9,]*(?:\.[0-9]+)?\s*$/im,
},
],
requiredText: [
{ label: "AICPA attestation standards", pattern: /American Institute of Certi(?:f|fi)ied Public Accountants[\s\S]*AICPA/i },
{ label: "USDGO June 2026 report date", pattern: /June 30, 2026[\s\S]*11:59:59 PM Coordinated Universal Time/i },
{ label: "USDGO July 2026 report date", pattern: /July 31, 2026[\s\S]*11:59:59 PM Coordinated Universal Time/i },
{ label: "favorable examination conclusion", pattern: /fairly stated, in all material respects/i },
{ label: "USDGO Schedule I", pattern: /Schedule I: Total USDGO Natively Minted Tokens/i },
{ label: "USDGO Schedule II", pattern: /Schedule II: Composition of Reserve Assets/i },
Expand All @@ -186,13 +180,16 @@ function profile(product: IndependentAssuranceProduct): CompilerProfile {
{ label: "qualified/adverse/disclaimed conclusion", pattern: /qualified opinion|adverse opinion|disclaimer of opinion|except for/i },
],
reportedTotals: [
// The reviewed dash is zero; omit the empty chain from positive liability rows.
// eslint-disable-next-line security/detect-unsafe-regex -- anchored per-line pattern over the reviewed offline report.
{ label: "USDGO Morph liabilities", expected: "0", pattern: /^\s*a\.\s+Total USDGO natively minted tokens\s+[0-9][0-9,]*(?:\.[0-9]+)?\s+([0-9][0-9,]*(?:\.[0-9]+)?|-)\s+[0-9][0-9,]*(?:\.[0-9]+)?\s*$/im, },
// eslint-disable-next-line security/detect-unsafe-regex -- anchored per-line pattern over an offline reviewed PDF text dump; bounded digit runs, no nested quantifier ambiguity.
{ label: "USDGO redeemable token total", expected: "859224943", pattern: /^\s*Total USDGO redeemable tokens outstanding\s+\$?([0-9][0-9,]*(?:\.[0-9]+)?)(?:\s+\(Schedule I\))?\s*$/im },
{ label: "USDGO reserve asset total", expected: "861072523", pattern: usdgoScheduleAmountPattern("Schedule II:", "Total") },
{ label: "USDGO redeemable token total", expected: "1112640495", pattern: /^\s*Total USDGO redeemable tokens outstanding\s+\$?([0-9][0-9,]*(?:\.[0-9]+)?)(?:\s+\(Schedule I\))?\s*$/im },
{ label: "USDGO reserve asset total", expected: "1116301304", pattern: usdgoScheduleAmountPattern("Schedule II:", "Total") },
],
reportedAssetTotal: "861072523",
computedAssetTotal: "861072523",
reportedLiabilityTotal: "859224943",
reportedAssetTotal: "1116301304",
computedAssetTotal: "1116301304",
reportedLiabilityTotal: "1112640495",
};
case "XSGD":
return straitsxProfile(product, "SGD", "23,674,708", "23,661,169");
Expand Down Expand Up @@ -276,7 +273,7 @@ function straitsxProfile(
function amountFromMatch(match: RegExpMatchArray | null, label: string): string {
const raw = match?.[1];
if (!raw) throw new Error(`offline assurance compiler: could not extract ${label}`);
return raw.replace(/[$,]/g, "");
return raw === "-" ? "0" : raw.replace(/[$,]/g, "");
}

function assertProfileText(text: string, config: CompilerProfile): void {
Expand Down
Loading