diff --git a/README.md b/README.md index f8594f7..17e18c2 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ Click an RFP to view details. Use the Submit Proposal button to apply. | RFP-015 | [Token Launchpad: Bonding Curve](RFPs/RFP-015-bonding-curve-launchpad.md) | L | $XXXXX | open | Applications & Integrations | [Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml) | | RFP-016 | [Token Launchpad: LBP](RFPs/RFP-016-lbp-launchpad.md) | XL | $XXXXX | open | Applications & Integrations | [Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml) | | RFP-017 | [Privacy-Preserving Token Vesting](RFPs/RFP-017-token-vesting.md) | L | $XXXXX | open | Applications & Integrations | [Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml) | +| RFP-019 | [On-Chain TWAP Oracle](RFPs/RFP-019-twap-oracle.md) | L | $XXXXX | open | Developer Tooling & Infrastructure | [Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml) | +| RFP-020 | [RedStone Off-Chain Oracle Adaptor for LEZ](RFPs/RFP-020-redstone-oracle-adaptor.md) | M | $XXXXX | open | Developer Tooling & Infrastructure | [Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml) | ## Terms & Conditions diff --git a/RFPs/RFP-019-twap-oracle.md b/RFPs/RFP-019-twap-oracle.md new file mode 100644 index 0000000..10f5186 --- /dev/null +++ b/RFPs/RFP-019-twap-oracle.md @@ -0,0 +1,540 @@ +--- +id: RFP-019 +title: "On-Chain TWAP Oracle" +tier: L +funding: $XXXXX +status: open +dependencies: See Platform Dependencies section +category: Developer Tooling & Infrastructure +--- +# RFP-019 — On-Chain TWAP Oracle + +## 🧭 Overview + +Build an on-chain TWAP (time-weighted average price) oracle program +for LEZ that reads pool accumulators from a LEZ DEX (RFP-004) and +exposes geometric-mean prices through a canonical oracle price +account standard. The on-chain TWAP serves two roles: it is the +**only** pricing path available for LEZ-native assets (LGS, the +reflexive stablecoin) +because no off-chain publisher has data to sign for pairs that +exist only on the LEZ DEX, and it is a **defence-in-depth layer** +for wrapped external assets (wXMR, wZEC, wBTC, wETH) that are +priced primarily by external oracles. This RFP covers the TWAP +program and the canonical price account standard only. The standard +allows multiple sources to publish prices for the same pair without +merging them; cross-source validation policy is the consumer +protocol's responsibility (see Design Rationale, "Multi-source +coexistence"). External oracle adaptors (RedStone in RFP-020, Pyth +in a future RFP) populate the same standard. The applying team +should have experience with AMM mathematics, oracle manipulation +analysis, and SVM program development. + +## 🔥 Why This Matters + +LEZ DeFi has two distinct pricing needs, and external oracles only +solve one of them. + +**LEZ-native assets have no off-chain price.** LGS (the Logos +token) and the reflexive stablecoin trade on a LEZ DEX (RFP-004) +and nowhere else at launch. No off-chain publisher (Chainlink, +Pyth, RedStone) has data to sign for these pairs because there is +no underlying CEX or institutional market to source from. The only +honest source is the LEZ DEX itself, read through an on-chain TWAP. +This is not a defence-in-depth nicety; it is the only pricing path +available for LEZ-native assets. + +The reflexive stablecoin +([RFP-013](./RFP-013-reflexive-stablecoin-protocol.md)) makes this +concrete. Its feedback controller computes a redemption rate from +the deviation between *market price* and *redemption price*, both +denominated in the reference collateral (following the RAI design, +which uses ETH-denominated prices throughout the controller). The +market price input is therefore the reflexive stablecoin priced in +its reference collateral (a LEZ-native pair, e.g. against LGS or +wBTC) that only the LEZ DEX can price. Without an on-chain TWAP +tier, RFP-013 +has no price feed to read. + +**Wrapped assets need manipulation-resistant pricing.** Wrapped +external assets (wXMR, wZEC, wBTC, wETH, potentially wSOL) used as +collateral by the lending protocol +([RFP-008](./RFP-008-lending-borrowing-protocol.md)) and others are +priced primarily by external oracles (RedStone in +[RFP-020](./RFP-020-redstone-oracle-adaptor.md), Pyth in a future +RFP). These also benefit from an on-chain TWAP cross-check where a +LEZ DEX pair exists with sufficient liquidity, since 36 documented +flash-loan oracle attacks have caused over $418M in cumulative +losses [5] and a single off-chain source remains the dominant DeFi +attack vector. The canonical price account standard supports +multi-source coexistence: when both an on-chain TWAP and an +external feed exist for the same pair, each publishes its own +price account and consumer protocols apply their own cross-source +policy (which is primary, which is fallback, how to handle +divergence). This RFP intentionally does not bundle a generic +divergence policy in the oracle program; the production record +shows that policy belongs in the consumer (see Design Rationale, +"Multi-source coexistence"). + +**The thin-liquidity caveat applies to both paths.** On new chains, +on-chain TWAP is itself vulnerable: with thin liquidity, a PoS +validator controlling two consecutive blocks can manipulate the +TWAP accumulator at a cost roughly equal to the round-trip swap +fees and price impact, with no competition for the back-run [6]. +The attack cost scales linearly with pool depth, so pools with $1M +in liquidity offer far less protection than pools with $100M. This +RFP mitigates the thin-pool case in two ways: per-block tick-delta +truncation (Uniswap v4 style; see Design Rationale below) raises the +single-block manipulation floor, and minimum-window guidance with +explicit manipulation-cost analysis tells consumer protocols how +long a window they need at LEZ launch liquidity levels. + +## 🏗 Design Rationale + +### Public oracle execution + +Oracle programs run as public LEZ executions with no confidential +state. Accumulator updates, TWAP computation (including the +geometric mean), and price queries are all visible to any caller. +This is intentional: oracles are a shared public good on LEZ, and +every dapp must be able to read the same canonical price. +Confidential execution is reserved for application-layer protocols +that consume oracle prices (for example, private DEX swaps in +RFP-004); the price feed itself stays public. + +### Geometric mean over arithmetic mean + +Uniswap v3 moved from arithmetic-mean TWAP (v2) to geometric-mean +TWAP (v3) for good reason. The geometric mean, computed via +tick-based accumulators (log-price space), is more +manipulation-resistant for multiplicative price processes: an +attacker who moves the price up by 10x in one block and back by 10x +in the next leaves no net impact on the geometric mean, whereas an +arithmetic mean would be skewed upward [9]. LEZ's TWAP oracle +should adopt the v3 approach. + +### Per-block tick-delta truncation + +Raw v3 accumulators record whatever tick the pool reaches at the end +of each block, which leaves the oracle exposed on thin pools at +chain launch: a single PoS multi-block validator or flash-loan +operator can move the pool by an arbitrary amount and have the full +excursion written into the accumulator. Uniswap v4's truncated +oracle hook addresses this by clamping the per-block tick delta +written to the accumulator to a fixed maximum (the v4 reference +value is 9,116 ticks per block, roughly a 2.39x price move). An +attacker therefore cannot inject more than `MAX_TICK_DELTA * +blockTime` of distortion per block regardless of how far they push +the pool, and must sustain manipulation across many blocks while +arbitrage erodes their position. See the appendix +([Uniswap v4 truncated oracle hook](../appendix/oracle-ecosystem.md#uniswap-v4-truncated-oracle-hook), +[Mitigation: tick-delta truncation](../appendix/oracle-ecosystem.md#mitigation-tick-delta-truncation-uniswap-v4)) +for the full mechanism. LEZ's TWAP oracle adopts this truncation as +a hard requirement: the cost is one tick-delta comparison and clamp +per accumulator update, and it materially raises the manipulation +floor on the thin pools that LEZ will have at launch. + +### Configurable cardinality + +Uniswap v3 pools default to storing a single observation +(cardinality 1). Expanding the observation ring buffer to N slots +costs a one-time storage payment and enables TWAP lookback of up to +N blocks. At 12s blocks, the maximum cardinality of 65,535 provides +approximately 9 days of history [9]. Protocols can trade storage +cost for lookback depth depending on their needs: a lending +protocol may need 1 to 2 hours of history, while a governance +oracle may need 7 days. + +### LEZ oracle data standard + +On EVM, Chainlink's `AggregatorV3Interface` (`latestRoundData()`) +became the de facto oracle standard because Chainlink was the first +mover; Pyth, RedStone, Switchboard, and DIA all ship compatible +wrapper contracts so that consuming protocols need no code changes. +The interface has known limitations: no confidence interval, no +source identifier, confusing `answeredInRound` semantics, and +variable `decimals()` per feed. + +On SVM (Solana, LEZ), no equivalent standard exists. Each oracle +provider defines its own account data layout (Pyth's `PriceAccount`, +Switchboard's `AggregatorAccountData`), so consuming programs write +per-provider integration code. This fragmentation is not an +architectural necessity; a shared account struct is feasible on SVM. + +LEZ can define a canonical oracle price account structure now, +before ecosystem fragmentation sets in. The struct should include +fields that `AggregatorV3Interface` lacks: explicit base and quote +asset identifiers, confidence interval, and source identifier. +Because +account data structures on SVM are append-friendly (a program can +add new fields at the end of the struct without breaking consumers +that read only the existing fields), the standard can evolve over +time without requiring coordinated upgrades across consuming +protocols. + +The standard is defined in this RFP. External oracle adaptors +(RFP-020 RedStone, future Pyth RFP) populate the same struct so +that consuming protocols integrate once and remain agnostic to the +underlying data source. If a new oracle provider becomes available +on LEZ, it populates the same struct without requiring any change +to consuming protocols. + +### Multi-source coexistence + +When the same pair has both an on-chain TWAP and one or more +external feeds, each source publishes its own price account under +the canonical struct. The oracle program does not merge or compare +them. Cross-source policy (which feed is primary, which is +fallback, what to do when sources disagree) is the consumer +protocol's responsibility, because risk tolerance and acceptable failure +modes vary by consumer: a lending protocol pausing liquidations is not +the same decision as a stablecoin pausing rate updates. + +The production record supports this split. The strongest +documented saves come from **source diversification** combined +with **consumer-owned policy**, not from generic divergence-flag +modules: + +- **Curve / Vyper exploit, 30 July 2023.** During the + reentrancy attack, on-chain CRV/USD on Curve pools collapsed + to roughly $0.08; Chainlink's aggregated CRV/USD bottomed at + approximately $0.59. Aave and other lending markets consuming + the Chainlink feed avoided cascade liquidation on a position + reported in coverage at roughly $200M. +- **USDe Binance flash, 11 October 2025.** On-chain consumers + of robust USDe pricing stayed within roughly 30 basis points + of $1 despite a Binance wick. +- **MakerDAO OSM delay, 31 March 2025.** The mandatory one-hour + delay absorbed roughly $84.4M of whale positions during an + ETH wick. Passive save: the delay window itself was the + protection. +- **Base sequencer outage, 5 August 2025.** Aave and Moonwell + on Base used the generic Chainlink Sequencer Uptime Feed to + pause borrowing and liquidations during a 33-minute handoff. + +By contrast, generic TWAP-anchor + divergence-flag modules have a +notably negative record: Compound V2's `UniswapAnchoredView` did +not prevent approximately $89M of liquidations during the +November 2020 DAI spike (Compound V3 then dropped it); Aave +removed `PriceOracleSentinel` in v3.7 after years with no +documented saves and repeated false positives; Aave's CAPO wstETH +safety wrapper itself caused roughly $27M of false-positive +liquidations on 10 March 2026. + +The load-bearing layers in production are source diversification, +time delay (OSM-style), and consumer-specific policy, all of which +are owned by the consumer. RFP-019's job is to deliver the +on-chain TWAP feed and the canonical struct that lets multiple +feeds coexist. Bundling a generic divergence policy in the oracle +program would also introduce a **liveness griefing surface**: an +attacker manipulating a thin LEZ DEX pool (cheap at chain launch, +per Oracle Security #2) could trigger a global halt for every +consumer through a shared gate. Implementing protocols (RFP-008, +RFP-013, RFP-004) own their multi-source policy in their own +scope of work. The Recommended Consumer Pattern in the SDK doc +packet (Supportability #5) provides a canonical example that +consumers can adopt or replace. + +### Economic model + +A pull-based TWAP oracle has a different cost structure to a +push-based feed: observation history is written as a side effect of +swaps (paid by swappers via gas), `observe()` is a view call (no +metering possible without a paywall contract), and the main explicit +cost is cardinality expansion (rent for additional observation +slots). Proposals must specify the economic model for oracle +operation: who bears the cost of maintaining observation history +(swappers via gas, pool deployers via cardinality rent, or protocol +subsidy), and whether any explicit fees are charged for pool +registration or cardinality expansion. The model should be +sustainable without ongoing subsidies once LEZ reaches moderate TVL. + +## ✅ Scope of Work + +### Hard Requirements + +#### Functionality + +1. Implement an on-chain TWAP oracle program that reads pool + accumulators from a LEZ DEX (RFP-004) and computes the geometric + mean TWAP over a configurable observation window. +2. Implement tick-based accumulator storage with configurable + cardinality: default 1, expandable up to 65,535 observations + per pool. +3. Provide a query interface: given a pool address and a window + length, return the TWAP price and the observation timestamps + used. +4. Define and implement the canonical LEZ oracle price account + structure as a reusable standard for the ecosystem (see Design + Rationale, "LEZ oracle data standard"). The struct must include + at minimum: `base_asset`, `quote_asset`, price, timestamp, source + identifier, and confidence interval (where the source provides + one; zero otherwise). `base_asset` and `quote_asset` are + canonical asset identifiers (token mint addresses for + LEZ-resident tokens; agreed canonical IDs for off-chain assets + such as `USD`) and together specify the denomination of `price` + (i.e. the value is *base per quote*, or equivalently, how much + of `quote_asset` one unit of `base_asset` is worth). Every price + account must populate these fields, and consuming protocols must + verify them before reading the price. The TWAP source must + populate this struct. The struct must be specified as a SPEL IDL + and published as a standalone artefact that other programs + (including external oracle adaptors in RFP-020 and any future + Pyth RFP) can import without depending on the TWAP program + itself. The interface must reject any price that is zero, + negative, or otherwise invalid before writing it to the account. + Multiple sources may publish price accounts for the same + `(base_asset, quote_asset)` pair; the standard does not merge + them, and cross-source policy is owned by consuming protocols + (see Design Rationale, "Multi-source coexistence"). +5. The oracle program owner can register new TWAP price feed + sources (add a pool) for which this RFP's program is responsible + for accumulator reads and price-account writes. External price + sources (RedStone in RFP-020, future Pyth RFP) publish their own + price accounts directly under the canonical standard and are not + registered with this program. +6. Every price account includes a timestamp. The query interface + accepts a `maxAge` parameter; reads older than `maxAge` return + an error rather than a stale value, leaving the consumer free + to decide what to do (revert, fall back to another source, log + and continue). + +#### Usability + +1. Provide an SDK that can be used to build Logos modules for + interacting with the oracle program (querying prices, expanding + cardinality, registering feed sources). +2. Provide a Logos mini-app GUI (price feed dashboard) with local + build instructions, downloadable assets, and loadable in Logos + app (Basecamp) via git repo. The dashboard must display: live + TWAP prices for each registered pool, side-by-side comparison + against any other price account published for the same + `(base_asset, quote_asset)` pair (e.g. RedStone), and observation + history. +3. Provide a CLI that covers core functionality: query price, + expand cardinality, register and deregister feed sources. +4. Provide an IDL for the oracle program and the oracle price + account standard, using the + [SPEL framework](https://github.com/logos-co/spel). The price + account IDL must be published as a standalone artefact that + other programs can import without depending on the oracle + program itself. +5. Return clear, actionable error messages for all failure modes: + stale price, no observation history for the requested window, + cardinality too low for the requested window, zero or negative + price from source, and `(base_asset, quote_asset)` mismatch + between the consumer's expected pair and the price account + read. +6. Provide a **reference consumer program**: a minimal LEZ program + (or equivalently a documented program-side code snippet plus + tests) that demonstrates the recommended consumer-side + integration pattern for reading the canonical price account. + The reference must show: verifying the `(base_asset, + quote_asset)` pair matches the consumer's expectation; reading + price, timestamp, and confidence interval from the account; + rejecting prices older than the consumer's chosen `maxAge`; and + the recommended response when a price is unavailable (typically: + refuse the action, do not fall back to an unsafe default). The + reference must also include a worked **multi-source pattern**: a + consumer that reads two price accounts for the same pair (e.g. + on-chain TWAP and RedStone) and applies an example consumer + policy (primary feed with fallback on staleness, plus a + divergence cross-check that logs but does not gate). The + reference makes clear that this policy is illustrative; each + downstream protocol owns its own choice. This is a guidance + artefact for downstream consumer protocols (RFP-008, RFP-013, + RFP-004), not a production product on its own. + +#### Reliability + +1. A price query is read-only and never modifies oracle state. +2. Cardinality expansion is atomic: partial failure leaves + existing observations intact. +3. Failure of one registered pool (e.g. accumulator unavailable, + cardinality exhausted) does not affect price queries against + other registered pools. + +#### Performance + +1. A TWAP query completes within a single LEZ transaction. +2. Document the compute unit (CU) cost of each operation: TWAP + query, accumulator update, and cardinality expansion. LEZ's + per-transaction compute budget may change during testnet. + +#### Supportability + +1. The oracle program is deployed and tested on LEZ devnet/testnet. +2. End-to-end integration tests run against a LEZ sequencer + (standalone mode) and are included in CI; CI must be green on + the default branch. +3. Every hard requirement in Functionality, Usability, Reliability, + and Performance has at least one corresponding test. The test + suite must include: TWAP computation correctness (known + accumulator values produce expected prices), tick-delta + truncation (a synthetic price excursion exceeding + `MAX_TICK_DELTA` is clamped in the accumulator and the + resulting TWAP matches the truncated trajectory, not the raw + one), staleness rejection (prices older than `maxAge` are + rejected), `(base_asset, quote_asset)` mismatch rejection, and + pool registration / deregistration state transitions. +4. A README documents end-to-end usage: deployment steps, program + addresses, and step-by-step instructions for querying prices, + expanding cardinality, and registering feed sources via CLI and + mini-app. +5. Submit a [doc packet](https://github.com/logos-co/logos-docs/issues/new?template=doc-packet.yml) + for the SDK, covering the developer integration journey for + querying prices, expanding cardinality, and registering feed + sources, **plus a "Recommended Consumer Pattern" section** that + walks a downstream protocol developer through the reference + consumer program from Usability #6: `(base_asset, quote_asset)` + verification, staleness handling, behaviour when a price is + unavailable, and an example multi-source policy (primary feed + plus fallback, with a divergence cross-check that logs but does + not gate). The pattern is illustrative; the doc must state + explicitly that cross-source policy is owned by the consumer + protocol, not by this oracle program. +6. Submit a [doc packet](https://github.com/logos-co/logos-docs/issues/new?template=doc-packet.yml) + for the CLI, covering the core operator/user journey. +7. Provide Figma designs or equivalent for the mini-app GUI (price + feed dashboard). + +#### + Oracle Security + +1. The TWAP computation must sample the accumulator at block + boundaries (before any same-block trades execute), not + mid-block, to resist within-block manipulation. +2. The minimum recommended observation window for lending protocol + use is documented, with a manipulation-cost analysis for + representative LEZ liquidity levels ($1M, $10M, $50M, and $100M + pool depth). +3. Implement per-block tick-delta truncation on accumulator updates, + following the Uniswap v4 truncated-oracle-hook design (see + Design Rationale, "Per-block tick-delta truncation"). Each + accumulator update must clamp the recorded tick delta against + the previous block's recorded tick to a configurable + `MAX_TICK_DELTA` (default: 9,116 ticks per block, matching the + v4 reference). The clamp must be applied before the + `tickCumulative` update, and `MAX_TICK_DELTA` must be governable + per pool by the oracle program owner so it can be tuned to LEZ + block time and per-pair volatility. The manipulation-cost + analysis required by item 2 must report costs both with and + without truncation, so the tradeoff is explicit. + +### Soft Requirements + +1. Multi-source consumer-pattern helper SDK: a library implementing + the example multi-source policy from the SDK doc packet + (primary feed plus fallback on staleness, with a divergence + cross-check that logs but does not gate). The helper reads two + or more price accounts for the same `(base_asset, quote_asset)` + pair and returns a single result plus diagnostic flags + (divergence detected, fallback in use). Consumer protocols are + free to use this helper as-is, configure it differently, or + replace it with their own policy: cross-source policy is owned + by the consumer, and this helper is one canonical implementation + among possible others. Reduces duplicated boilerplate across + consumer protocols (RFP-008, RFP-013, RFP-004) without changing + the on-chain program surface. + +### Out of Scope + +The following are explicitly excluded from this RFP and addressed +elsewhere: + +- External oracle adaptors. RedStone is delivered in + [RFP-020](./RFP-020-redstone-oracle-adaptor.md). A Pyth adaptor + (which depends on Wormhole on LEZ) is deferred to a future RFP. +- Confidential or shielded oracle execution. Oracle programs run + as public LEZ executions (see Design Rationale, "Public oracle + execution"). +- The reflexive stablecoin design. RFP-013 owns the reflexive + stablecoin and is a consumer of this oracle. RFP-013's controller + reads the stablecoin priced in its reference collateral (a + LEZ-native pair, e.g. against LGS or wBTC), which this RFP + delivers via on-chain TWAP. RFP-013's choice of reference + collateral, controller parameters, and any auxiliary + USD-denominated reporting are owned by that RFP, not this one. +- Price feed composition (combining two or more price accounts + whose denominations chain together, e.g. + `LGS/USD = LGS/wBTC × wBTC/USD`). This RFP exposes the + `base_asset` and `quote_asset` fields that make composition + *checkable*, but does not specify or implement the composition + itself. Composition becomes relevant only once token wrapping is + defined on LEZ. A future RFP, likely an evolution of + [RFP-020](./RFP-020-redstone-oracle-adaptor.md) (or a dedicated + token-wrapping RFP), is expected to specify a canonical + composition pattern including confidence-interval and staleness + rules across legs. Until then, consumer protocols that need a + price in a denomination not directly published are responsible + for their own composition logic. + +## ⚠ Platform Dependencies + +### Hard blockers + +These must be available on LEZ before the corresponding features +can be developed. + +#### RFP-004 (Privacy-Preserving DEX) + +The TWAP oracle reads pool accumulators from the DEX. Without +RFP-004, the on-chain TWAP tier cannot be exercised. The canonical +price account standard can be designed and prototyped in parallel. + +### Soft blockers + +Desirable but the RFP can open without them. + +None + +## 👤 Recommended Team Profile + +Team experienced with: + +- Oracle or DeFi protocol infrastructure development +- AMM mechanics and TWAP mathematics (accumulator design, + geometric-mean computation, window selection) +- Solana or SVM program development (Anchor or native) +- Smart-contract security auditing (oracle manipulation, flash-loan + attack vectors) + +## ⏱ Timeline Expectations + +Estimated duration: **8 to 12 weeks**. + +The canonical price account standard can be designed and shipped +early; the TWAP program itself depends on RFP-004 (DEX) and is the +longer pole. + +## 🌍 Open Source Requirement + +All code must be released under the **MIT+Apache2.0 dual License**. + + +## Resources + +- [RFP-004 — Privacy-Preserving DEX](./RFP-004-privacy-preserving-dex.md) + (pool accumulators, TWAP data source) +- [RFP-008 — Lending & Borrowing Protocol](./RFP-008-lending-borrowing-protocol.md) + (primary consumer of oracle price feeds) +- [RFP-012 — Advanced Lending Features](./RFP-012-advanced-lending-features.md) + (eMode and multi-collateral require reliable oracles) +- [RFP-013 — Reflexive Stablecoin Protocol](./RFP-013-reflexive-stablecoin-protocol.md) + (consumer of price feeds; the RAI-style controller reads the + reflexive stablecoin priced in its reference collateral, a + LEZ-native pair only the on-chain TWAP can price) +- [RFP-020 — RedStone Off-Chain Oracle Adaptor](./RFP-020-redstone-oracle-adaptor.md) + (first external adaptor to the canonical price account standard) +- [Appendix: Oracle Ecosystem](../appendix/oracle-ecosystem.md) +- [Uniswap v3 Oracle Documentation](https://docs.uniswap.org/concepts/protocol/oracle) +- [Uniswap v3 TWAP Oracles in PoS](https://blog.uniswap.org/uniswap-v3-oracles) + + +## ✏️ How to Apply + +👉 Submit a proposal using the Issue form: + +**[Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml)** + +We typically respond within **14 days**. For clarification questions, +please use **Discussions**. diff --git a/RFPs/RFP-020-redstone-oracle-adaptor.md b/RFPs/RFP-020-redstone-oracle-adaptor.md new file mode 100644 index 0000000..a0667ea --- /dev/null +++ b/RFPs/RFP-020-redstone-oracle-adaptor.md @@ -0,0 +1,761 @@ +--- +id: RFP-020 +title: "RedStone Off-Chain Oracle Adaptor for LEZ" +tier: M +funding: $XXXXX +status: open +dependencies: See Platform Dependencies section +category: Developer Tooling & Infrastructure +--- + + +# RFP-020 — RedStone Off-Chain Oracle Adaptor for LEZ + +## 🧭 Overview + +Build a RedStone off-chain oracle adaptor for LEZ: a public-mode +LEZ program that verifies RedStone-signed data packages, exposes +the resulting prices through the canonical oracle price account +standard defined in [RFP-019](./RFP-019-twap-oracle.md), and +supports day-one delivery of BTC/USD, ETH/USD, SOL/USD, XMR/USD, +and ZEC/USD feeds. RedStone's +data packages are signed with secp256k1 + keccak256 by its data +nodes; verification on LEZ runs as in-program code inside the +RISC-V zkVM (no cross-chain bridge, no Wormhole dependency). The +adaptor uses a push-mode aggregator pattern: a public-mode program +verifies signatures on the write side, stores the result in a +public price account, and consumers (including private-execution +programs) read the slot. + +LEZ is RISC0-based, so any signature scheme can be implemented in +program code. Early prototype work on in-program secp256k1 ECDSA +verification inside RISC0 ([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)) shows the +verification is slow enough that **pull-mode reads from inside a +private transaction are not feasible on consumer hardware** (a +private consumer would spend several minutes generating the proof +for each read), absent a RISC0-specific signature-verification +accelerator. The push-mode aggregator pattern is therefore the +working assumption: the verifier runs once per update on the write +side in public execution; consumers (public or private) read the +resulting public price account without doing any signature work. +Cost measurement remains a primary deliverable for the public-mode +write side, where amortisation across all downstream reads can +make in-program verification workable; if the measured public-mode +cost is unacceptable the measurement becomes the input to a +follow-on RFP that proposes adding a secp256k1 ECDSA + keccak256 +precompile to LEZ. + +### Scope + +In scope: + +- The RedStone off-chain oracle adaptor as a public-mode push aggregator on LEZ. +- Day-one BTC/USD, ETH/USD, SOL/USD, XMR/USD, and ZEC/USD feeds, registered and exercised on LEZ devnet/testnet. +- Cost measurement of the in-program RISC-V verification path as a primary deliverable. + +Out of scope at the Overview level (full list under Out of Scope below): + +- The on-chain TWAP tier and the canonical oracle price account standard, owned by [RFP-019](./RFP-019-twap-oracle.md). +- A Pyth adaptor: depends on Wormhole on LEZ, deferred to a future RFP. +- Pull-mode reads from inside private execution: blocked on either a RISC0 zkVM circuit-level accelerator (e.g. a future `risc0-ecdsa` extension that lowers in-circuit verification cost) or a different upstream signature scheme that admits acceptable in-circuit cost on RISC0; neither exists today. A LEZ secp256k1 + keccak256 *precompile* (a runtime host function) is the subject of a possible cost-conditional public-mode follow-on RFP; that precompile lives outside the ZK proof boundary, so it lowers public-mode write-side cost but does *not* unblock private-execution pull (a host function cannot be called from inside the privacy circuit). An alternative private-mode-friendly signature scheme (with the corresponding upstream publisher work) is the subject of a possible separate follow-on RFP. Whether either follow-on is warranted depends on consumer-protocol demand for private-execution pull, which is not yet established: some consumer protocols (notably the reflexive stablecoin in [RFP-013](./RFP-013-reflexive-stablecoin-protocol.md)) already constrain specific actions to public transactions for their own design reasons, so the capability is worth reaching for only if a downstream consumer actually needs it. + +## 🔥 Why This Matters + +Private DeFi is what LEZ is positioned to support, and reliable +USD reference prices for privacy collateral, in particular Monero +(XMR) and Zcash (ZEC), are a necessary step. The reflexive +stablecoin +([RFP-013](./RFP-013-reflexive-stablecoin-protocol.md)), the +privacy-preserving DEX +([RFP-004](./RFP-004-privacy-preserving-dex.md)), wrapped privacy +assets, and other cross-chain primitives all need those reference +prices to function. + +The on-chain TWAP tier in +[RFP-019](./RFP-019-twap-oracle.md) is not sufficient on its own +for the day-one asset list. TWAP security scales linearly with +pool depth: on a new chain where liquidity is thin, a validator +controlling two consecutive blocks can manipulate the accumulator +at a cost roughly equal to the round-trip swap fees and price +impact, which on a $1M pool is cheap (see +[Appendix: TWAP Manipulation Vectors](../appendix/oracle-ecosystem.md)). +This applies even to majors like BTC/USD, ETH/USD, and SOL/USD: +those pairs will exist as pools on LEZ, but at chain launch their +pool depth will not yet be sufficient for TWAP to stand alone. +More structurally, TWAP only produces a price for pairs that +exist as pools on LEZ; XMR/USD and ZEC/USD don't, because XMR and +ZEC aren't natively on LEZ. An off-chain feed is the only way to +get those prices on chain at all, and pairing it with TWAP for +the pairs where TWAP does work is the production norm for layered +oracle defence. + +Across the surveyed off-chain oracle providers, RedStone is the +only one that combines: support for both XMR and ZEC in its public +token registry, a portable connector pattern (single secp256k1 +ECDSA + keccak256 verification path that works the same on every +host chain), no cross-chain bridge requirement, and a self-serve +deployment path that does not require an oracle-team business +engagement. Pyth covers both feeds and adds higher publisher +counts and confidence intervals, but is gated on Wormhole +integration on LEZ; it should land as a fast-follow in a future +RFP. Chainlink is permissioned and not self-serve. DIA Lumina is +permissionless but requires bespoke per-chain deployment. See +[Appendix: Oracle Ecosystem, Privacy-Asset Feed Availability](../appendix/oracle-ecosystem.md) +for the full coverage matrix. + +The combination of "private DeFi needs XMR and ZEC" and "RedStone +is the only path that is self-serve on LEZ today" makes this the +priority off-chain oracle integration for LEZ. + +### A building block in a layered oracle stack + +Neither an off-chain feed nor an on-chain TWAP is a complete +oracle on its own; both have known failure modes and the +production norm in DeFi is to layer them. This RFP delivers the +off-chain adaptor as a swappable building block in that layered +stack: production-grade code on its own terms, paired with the +TWAP tier from [RFP-019](./RFP-019-twap-oracle.md) on the +consumer side. Consuming protocols (the reflexive stablecoin in +[RFP-013](./RFP-013-reflexive-stablecoin-protocol.md), the +lending market in +[RFP-008](./RFP-008-lending-borrowing-protocol.md), the DEX in +[RFP-004](./RFP-004-privacy-preserving-dex.md)) compose these +pieces according to their own production-security choices, with +the canonical price account standard from RFP-019 keeping +swap-out cheap if those choices change later. + +## 🏗 Design Rationale + +### Public-mode aggregator with private-account composability + +The adaptor runs as a public-mode LEZ program with no confidential +state. Signature verification, data-package decoding, and price +publication are all visible to any caller. Any LEZ dapp can read +the same canonical price. + +This shape is determined by where signature verification can run +on LEZ. LEZ is a RISC-V zkVM built on RISC0; any code that runs +inside a private transaction has to be expressible inside the +RISC-V zkVM circuit, so a private transaction that wants to verify +a secp256k1 ECDSA signature has two options, both unappealing: +verify the signature inside the privacy circuit (forfeits the +batching benefits that make ZK proof amortisation work; RISC0 +elliptic-curve performance for this primitive is currently +unmeasured), or place the signature in the transaction journal +where it is publicly disclosed (breaks the privacy of the +transaction). Neither option preserves both efficiency and +privacy. + +The adaptor therefore runs the verifier in a public-mode +aggregator: signatures are recovered once per update on the write +side, and the verified price plus timestamp are stored in a public +price account. Private-execution programs compose with the price +by reading the public account, not by carrying signed payloads +inline. Cost is paid once per update and amortises across all +downstream reads, public and private. Confidential execution is +reserved for application-layer protocols that consume oracle +prices (for example, private DEX swaps in +[RFP-004](./RFP-004-privacy-preserving-dex.md)); the price feed +itself stays public. + +Pull-mode reads (where a public consumer transaction carries a +signed payload and verifies inline) remain technically possible on +LEZ inside public execution, but are out of scope for this RFP +because they don't extend to private execution and because the +push-mode aggregator gives strictly better cost amortisation for +the LEZ DeFi consumer set. They can be revisited in a follow-on +once measured cost data is in. + +See [Appendix: Oracle Ecosystem, Implications for LEZ](../appendix/oracle-ecosystem.md#implications-for-lez) +for the full four-shape analysis (trusted re-signer, FROST-BIP340 +federation, DLC-oracle extension, and the cost-conditional +precompile path) that this section condenses. + +A LEZ-specific freshness pattern follows from the public / private +execution split. A user who needs a price fresher than the +heartbeat's last update can submit a public transaction that +pushes a fresh signed payload to the aggregator account, then +submit a private transaction immediately after that reads the +just-updated public price. Verification cost is paid in the public +path (cheaper, especially under the precompile follow-on); the +private transaction does no signature work. This recovers pull +mode's "fresh at transaction time" property for private consumers +without paying the in-circuit cost in the privacy proof. The +adaptor program already accommodates this: any caller can submit +a valid signed payload and the program writes if signatures and +timestamps check out. + +The same mechanism enables a **consumer-pays push variant** that +does not require a dedicated relayer at all. Users push when they +need a fresh price; idle periods incur zero update cost; the +aggregator only advances when someone needs it. This is +operationally pull (consumer-pays, on-demand) but structurally +push (the program owns the public price account that downstream +private consumers read from). Whether to run a heartbeat relayer +in addition (RedStone's own pusher, a sovereign relayer, or +neither) is a deployment-time choice: a heartbeat keeps the slot[]() +warm for read-only consumers; consumer-pays push keeps the cost +model strictly proportional to demand. Both can coexist; the +program logic does not distinguish between them. + +The two-transaction split (public push, then private read) is +distinct from the rejected "put the signature in the journal" +option. The signature is carried only in the public push; the +private transaction reads the resulting public price account by +address with no upstream signature in its calldata or journal, +so the private transaction's contents (assets, counterparty, +amount) stay private. This fits the adaptor's existing write +path: the program already accepts signed payloads from any +caller and writes a public price account, regardless of whether +the caller is a relayer or an end user. There is a residual +linkability risk that the consumer needs to handle on its side, +not the adaptor's: an observer can correlate a public push from +wallet X at time T with a private transaction at time T plus +epsilon and infer that the same actor is consuming the +just-pushed price. Mitigations (separate funding wallet for the +push, timing decorrelation, reliance on a heartbeat to mask +single-purpose pushes) are consumer-side production-security +choices. The privacy story is strictly better than +journal-disclosed signatures (the private transaction's body +stays private) but not equivalent to a heartbeat-only push +model. + +### RISC-V verification path and the precompile question + +This RFP implements signature verification in RISC-V program code, +running inside RISC0. There is no host primitive to call: the +recovery is an in-program ECDSA + keccak256 path written against +existing Rust crates (k256 / sha3 / equivalents) and proved by +RISC0 along with the rest of the program. + +This is the central technical bet of the RFP. Early prototype +work on in-program secp256k1 ECDSA verification inside RISC0 +([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)) is already enough to flag that the +naive in-circuit path is slow on consumer hardware: a private +consumer attempting pull-mode verification would spend several +minutes generating the proof for each read. That rules out +private-execution pull mode in any practical sense for the +in-program path, absent a RISC0-specific signature-verification +accelerator (e.g. a future `risc0-ecdsa` extension or a secp256k1 +precompile wired into the zkVM proving system itself). The first concrete +deliverable of this RFP refines this picture for the public-mode +write side: implement the verifier in RISC-V, run it on LEZ, +document the cost (compute units, proof time, proof size, +per-update bytes) for both the per-signature recovery and the +full 3-of-N aggregator write, and characterise where the +public-mode cost lands relative to the production-cadence budget. +Public-mode cost is the cost that matters for shipping the +adaptor: it amortises across all downstream reads. + +Two outcomes are possible from that measurement: + +1. **Measured cost is acceptable for the push-mode aggregator.** + The adaptor ships on the runtime as it stands. The aggregator's + update cadence amortises the per-update cost across all + downstream reads. No runtime change required. +2. **Measured cost is unacceptable.** The measurement becomes the + input to a follow-on RFP that proposes adding a secp256k1 ECDSA + + keccak256 precompile to LEZ for use by public-execution + programs. A precompile lives outside the ZK proof boundary and + is invoked as native validator code, so the cost goes from + "ZK-proven elliptic-curve operations" to "native ECDSA recovery + + keccak", which is the cost profile RedStone's existing + connectors assume on every other chain. The precompile is an + optimisation path conditional on the measurement, not a + precondition for this RFP. + +The applicant should therefore design the verification path so +that swapping in a precompile in a later release is a localised +change (a single trait implementation or syscall wrapper), not a +restructuring of the program. + +The precompile path addresses public-mode write-side cost only; +private-execution pull mode is foreclosed under it for the same +structural reason it is foreclosed under the in-program path +(a precompile lives outside the ZK proof boundary, so it is not +callable from inside a private transaction). If a signature +scheme exists, or can be selected, that yields acceptable +in-circuit cost on RISC0 (a RISC0-friendly hash and curve +combination, or a different signature primitive that admits +cheaper in-circuit verification), pull-mode reads from inside +private execution become reachable and the public-mode +aggregator becomes one option among several rather than the only +viable shape. Identifying or building such a scheme, and either +modifying an existing oracle network to publish in it or +standing up a new publisher set that does, is the subject of a +possible separate follow-on RFP. It is independent of the +public-mode precompile question and out of scope for this RFP. +Whether such a follow-on is worth pursuing depends on whether +any consumer protocol actually needs private-execution pull, +which is not yet confirmed: consumer protocols may already +have design reasons to keep specific actions in public +transactions, with the reflexive stablecoin in +[RFP-013](./RFP-013-reflexive-stablecoin-protocol.md) as one +concrete example. + +### Why RedStone first + +Three reasons specific to LEZ's constraints: + +1. **Privacy-asset coverage with no bridge.** Both XMR and ZEC are + in RedStone's public token registry, and the RedStone connector + pattern is fully self-serve: deployment does not require an + oracle-team engagement, a bridge, or a per-chain registration + step. LEZ can deploy and exercise these feeds without touching + any external infrastructure. Pyth and DIA both cover the same + assets but require either Wormhole (Pyth) or bespoke per-chain + deployment (DIA Lumina) before they work on a new chain. +2. **Single verification primitive, no bridge.** RedStone's + signature scheme is plain m-of-N secp256k1 ECDSA over keccak256 + (typically 3-of-N). Verification on LEZ is in-program ECDSA + recovery and keccak256 hashing inside RISC0; the cost profile + is the open variable this RFP measures (see "RISC-V verification + path and the precompile question"). Pyth's full 13-of-19 + Wormhole VAA verification is heavier in two ways: it adds a + Merkle proof on top of more signatures, and it presupposes a + Wormhole guardian-set tracking program on LEZ that does not yet + exist. RedStone has neither cost. +3. **Independent of LEZ's external integration timeline.** + Choosing RedStone first decouples the oracle layer from when + Wormhole on LEZ is decided. Pyth then fast-follows in a future + RFP, contributing higher publisher counts (especially the + roughly 80+ on XMR/USD versus RedStone's smaller per-feed + roster) and confidence intervals that RedStone does not + natively expose. + +See +[Appendix: Oracle Ecosystem, Signature Verification Schemes](../appendix/oracle-ecosystem.md) +for the full per-scheme analysis and citations. + +### Conformance to the canonical price account standard + +The canonical oracle price account standard is owned by RFP-019 +(see "LEZ oracle data standard" in that RFP's Design Rationale). +The RedStone adaptor populates the same struct as the on-chain +TWAP source: `base_asset`, `quote_asset`, price, timestamp, source +identifier, and confidence interval (zero, since RedStone does not +publish one). Consuming protocols query a single data layout and +remain agnostic to whether the price came from TWAP, RedStone, or +any future provider; cross-source policy lives in the consumer per +RFP-019, Design Rationale ("Multi-source coexistence"). + +If RFP-019 has not yet shipped the canonical struct when this RFP +is delivered, the team must define a forward-compatible minimal +struct using append-friendly account-data conventions, so that a +later RFP-019 release can extend the struct without breaking +consumers. + +### HTTPS data path: centralisation and censorship + +Signed RedStone data packages are fetched from the RedStone Data +Distribution Layer (DDL) over **HTTPS, not P2P**. The default +gateway URLs are DNS-resolved endpoints under +`*.redstone.finance` and `*.redstone.vip` (see the SDK source at +`packages/sdk/src/data-services-urls.ts` and the appendix section +"Infrastructure Requirements for External Oracles on LEZ"). This +applies whether the data reaches LEZ via the relayer (push) or +inline as transaction calldata (pull). Two consequences follow: + +- **Censorship surface.** A gateway operator (and its upstream + network) can withhold responses to specific clients, + geographies, or asset IDs. On-chain signature verification + protects against falsified data, not against withheld data: a + censored consumer cannot obtain a signed payload, and any + transaction depending on it reverts. +- **Liveness dependency.** DNS, TLS validity, and HTTPS + availability at RedStone's hosts (AWS, GCP) all become LEZ + oracle liveness dependencies. Regional outages at these + providers can take the feed offline. + +Implementers must document, as part of the relayer operator +journey, the mitigations the operator chooses: multiple parallel +gateway queries (SDK default), the use of RedStone private +gateways via the `OVERRIDE_DIRECT_CACHE_SERVICE_URLS` mechanism +where available, and recent-price fallback policy if no gateway +responds within the operator's tolerance. None of these +mitigations eliminate the structural centralisation; they reduce +specific failure modes. + +This caveat is inherent to RedStone's design and to every oracle +in the survey that uses an HTTPS portal (Pyth Hermes has the same +property). It is not an objection to RedStone; it is the trade-off +LEZ accepts by adopting any HTTPS-served signed-data oracle, and +must be communicated to consumer protocols so they can size their +liveness assumptions accordingly. + +### Fee structure + +In the push-aggregator shape this RFP commits to, the on-chain +verification cost is paid once per update by whoever submits the +signed data package to the aggregator, and is amortised across all +downstream reads (public and private). RedStone itself does not +publish prices on-chain; a relayer fetches the signed packages from +the RedStone gateway and pushes them, so "whoever pays for an +update" in practice means whoever runs (or pays for) the relayer. +The adaptor does not need to fund a dedicated node operator pool. + +Beyond that structural point, this RFP does not prescribe a fee +model. Downstream users of the adaptor (consuming protocols, +relayer operators, deployers) are free to handle fees in whatever +way fits their product: subsidised by the consuming protocol, +charged per read, charged per update, routed to a treasury, burned, +or left at zero. The adaptor program itself should not bake in +policy that forecloses these choices. + +## ✅ Scope of Work + +### Hard Requirements + +#### Functionality + +1. Implement a public-mode LEZ program (push-mode aggregator) that + accepts signed RedStone data packages, recovers each signer's + public key via in-program secp256k1 ECDSA recovery (with + keccak256 hashing) running inside the RISC-V zkVM, and verifies + that the recovered public keys match the configured set of + authorised RedStone data nodes for the requested feed. + Structure the verification path so that swapping the in-program + recovery for a future host primitive (precompile or syscall) is + a localised change. +2. Verify the M-of-N signer threshold for each feed (configurable + at registration; default 3-of-N consistent with RedStone's + reference parameters) and reject any data package that does + not meet the threshold. +3. Decode the RedStone data package format (asset identifier, + value, timestamp, signer set) and reject any package whose + timestamp is older than a configurable `maxAge`, whose value is + zero, negative, or otherwise invalid, or whose asset identifier + does not match the registered feed. +4. Publish the verified price into a canonical oracle price + account conforming to the standard defined in RFP-019. The + adaptor must populate `base_asset`, `quote_asset`, price, + timestamp, source identifier (a constant identifying RedStone), + and confidence interval (zero; RedStone does not publish + confidence intervals in its standard data packages). +5. The adaptor program owner can register new RedStone feeds (by + asset identifier, M-of-N threshold, and authorised signer set), + update an existing feed's signer set on RedStone roster + changes, and deregister feeds. +6. BTC/USD, ETH/USD, SOL/USD, XMR/USD, and ZEC/USD feeds must be + registered and exercised on LEZ devnet/testnet as part of the + deliverable. +7. **Relayer module.** Provide a relayer service that fetches signed + RedStone data packages from the RedStone Data Distribution Layer + gateways (see Appendix, "Infrastructure Requirements for External + Oracles on LEZ") and submits them to the LEZ adaptor. The + relayer must be implemented as a **Logos module accompanied by a + Logos Core headless CLI/daemon** (same packaging model as the + liquidator bot in RFP-008 Functionality #13), so that operators + (RedStone, the Logos ecosystem, or consuming protocols) can run + it as a standalone long-running process without requiring a + user-facing app. The daemon must support: configurable + `dataServiceId` (default `redstone-primary-prod`), configurable + feed list and update triggers per feed (heartbeat interval and + deviation threshold), parallel querying of multiple DDL gateways + with first-success selection, retry and back-off on transient + gateway or LEZ errors, structured logging of submitted updates + and rejections (with the on-chain rejection reason where + available), wallet-balance monitoring, and a clean shutdown + path. Document the operator journey end-to-end: install, + configure, run, monitor. The operator documentation must + explicitly cover the HTTPS data-path centralisation discussed + in Design Rationale ("HTTPS data path: centralisation and + censorship"): which gateways are queried, what the operator's + policy is when none respond, and how the operator detects + selective censorship. + +#### Usability + +1. Provide an SDK that can be used to build Logos modules for + submitting RedStone data packages and reading verified prices + from the canonical price account. +2. Provide a Logos mini-app GUI (off-chain feed dashboard) with + local build instructions, downloadable assets, and loadable in + Logos app (Basecamp) via git repo. The dashboard must display: + live prices for each registered feed, the configured signer + set, the current M-of-N threshold, the latest data-package + timestamp, and the staleness of each feed. +3. Provide a CLI that covers core functionality: submit a data + package, query the verified price, register and deregister + feeds, update signer sets. +4. Provide an IDL for the adaptor program and the canonical + oracle price account standard (re-exported from RFP-019, not + forked), using the + [SPEL framework](https://github.com/logos-co/spel). +5. Return clear, actionable error messages for all failure modes: + stale data package, signer-threshold not met, signer not in + authorised set, asset identifier mismatch (`base_asset` or + `quote_asset` does not match the registered feed), malformed + package, invalid signature, zero or negative price. +6. Provide a **reference consumer program**: a minimal LEZ program + (or equivalently a documented program-side code snippet plus + tests) that demonstrates the recommended consumer-side + integration pattern for reading the canonical price account + populated by this adaptor. The reference must show: verifying + the `(base_asset, quote_asset)` pair matches the consumer's + expectation, reading price and timestamp from the account, + rejecting prices older than the consumer's chosen `maxAge`, and + the recommended response when a price is unavailable + (typically: refuse the action, do not fall back to an unsafe + default). Cross-source policy (combining the RedStone feed with + an on-chain TWAP or another external source) is the consumer + protocol's responsibility per RFP-019, Design Rationale + ("Multi-source coexistence"); this reference must not bundle a + divergence policy. This is a guidance artefact for downstream + consumer protocols (RFP-008, RFP-013, RFP-004), not a + production product on its own. + +#### Reliability + +1. A price read is read-only and never modifies adaptor state. +2. Feed registration is atomic: partial failure leaves existing + registrations intact. +3. Signature verification is deterministic: given the same data + package and signer set, the verification result is the same. + +#### Performance + +1. End-to-end signature verification and price publication for a + single 3-of-N RedStone data package must complete within a + single LEZ public transaction at the per-transaction compute and + proof budget in force on LEZ at delivery time. +2. Cost measurement is a primary deliverable, not a side report. + The applicant must measure and document, for the RISC-V + in-program verification path: per-signer ECDSA recovery cost + (compute units, RISC0 proof time, RISC0 proof size), keccak256 + hashing cost, package decoding cost, signer-set membership + check, canonical price account write, and feed registration. + Numbers must be reproducible from the test suite. +3. Document the cost delta between the in-program path and a + hypothetical native ECDSA + keccak256 precompile, using existing + per-chain reference points (for example, the RedStone EVM + end-to-end gas range of 50K to 100K, and the per-recovery cost + profile on chains that expose a native primitive). The delta + informs whether a follow-on precompile RFP is warranted. + +#### Supportability + +1. The adaptor program is deployed and tested on LEZ + devnet/testnet. +2. End-to-end integration tests run against a LEZ sequencer + (standalone mode) and are included in CI; CI must be green on + the default branch. +3. Every hard requirement in Functionality, Usability, Reliability, + and Performance has at least one corresponding test. The test + suite must include: valid signature acceptance, invalid + signature rejection, signer-threshold enforcement (M-of-N, + including boundary cases), stale-package rejection (`maxAge`), + asset-identifier mismatch rejection, zero or negative price + rejection, and feed registration / signer-set update transitions. +4. A README documents end-to-end usage: deployment steps, program + addresses, initial BTC/USD, ETH/USD, SOL/USD, XMR/USD, and + ZEC/USD feed registrations, and step-by-step instructions for + submitting data packages and querying prices via CLI and + mini-app. +5. Submit a [doc packet](https://github.com/logos-co/logos-docs/issues/new?template=doc-packet.yml) + for the SDK, covering the developer integration journey for + submitting RedStone data packages and reading verified prices, + **plus a "Recommended Consumer Pattern" section** that walks a + downstream protocol developer through the reference consumer + program from Usability #6: `(base_asset, quote_asset)` + verification, staleness handling, behaviour when a price is + unavailable, and an example multi-source policy pairing the + RedStone feed with the on-chain TWAP tier from RFP-019. The + doc must state explicitly that cross-source policy is owned by + the consumer protocol, not by this adaptor. +6. Submit a [doc packet](https://github.com/logos-co/logos-docs/issues/new?template=doc-packet.yml) + for the CLI, covering the core operator/user journey. +7. Provide Figma designs or equivalent for the mini-app GUI + (off-chain feed dashboard). + +#### + Adaptor Security + +1. The adaptor must reject any data package whose recovered + signer is not in the configured authorised signer set for the + requested feed. +2. The signer set must be updatable only by the program owner; + the update path itself must be tested. +3. The minimum recommended `maxAge` for production use is + documented, with a manipulation analysis covering signer + compromise, replay of stale packages, and signer-set update + delays. + +### Soft Requirements + +1. Multi-feed batched verification: amortise calldata and + signature recovery overhead across multiple feeds in a single + instruction (analogous to Pyth's Perseus amortisation). +2. Multi-source integration test against the on-chain TWAP tier + from RFP-019 once the TWAP program is available: confirm that + a consumer reading both the RedStone price account and the + TWAP price account for the same `(base_asset, quote_asset)` + pair can apply an example cross-source policy (primary plus + fallback, divergence cross-check) without the adaptor + participating in that policy. + +### Out of Scope + +The following are explicitly excluded from this RFP and addressed +elsewhere: + +- The on-chain TWAP tier and the canonical oracle price account + standard are owned by [RFP-019](./RFP-019-twap-oracle.md). This + RFP populates the standard, it does not define it. +- A Pyth adaptor. Pyth depends on Wormhole on LEZ and is deferred + to a future RFP. Higher publisher counts and confidence + intervals (which RedStone does not natively expose) come with + that adaptor. +- Adaptors for other off-chain oracles (Chainlink, DIA, Chronicle, + Switchboard, Supra). None of these match the combination of + privacy-asset coverage, single-primitive verification, and + bridge independence that motivates this RFP. Future RFPs may + add them. +- Pull-mode reads from inside private execution. A private + transaction that wants to verify a secp256k1 signature inline + cannot do so without forfeiting batching benefits or breaking + privacy (see Design Rationale). Private composability is via + reading the public price account that the push-mode aggregator + writes to. +- Adding a secp256k1 ECDSA + keccak256 precompile to LEZ. The + RISC-V in-program path is the deliverable here. A precompile + becomes a candidate for a follow-on RFP if and only if the cost + measurement in this RFP shows the in-program path is too + expensive for production cadence. +- Switching the upstream signature scheme to one that yields + acceptable in-circuit cost for private execution on RISC0 + (RISC0-friendly hash and curve, or a different signature + primitive entirely). If such a scheme exists or can be selected, + modifying an existing oracle network to publish in it, or + standing up a new publisher set that does, would unlock + pull-mode reads from inside private transactions and is the + subject of a possible separate follow-on RFP. It is independent + of the public-mode precompile question above and is not a + deliverable of this RFP. The follow-on is itself contingent on + consumer-protocol demand for private-execution pull mode, which + is not yet confirmed: parts of the reflexive stablecoin design + in [RFP-013](./RFP-013-reflexive-stablecoin-protocol.md), for + instance, already constrain specific actions to public + transactions, so the capability is worth pursuing only if a + downstream consumer actually requires it. +- Price feed composition (combining two or more price accounts + whose denominations chain together, e.g. computing + `LGS/USD = LGS/wBTC × wBTC/USD`). RFP-019's canonical standard + exposes `base_asset` and `quote_asset` to make composition + checkable, but neither RFP-019 nor this adaptor specifies or + implements the composition itself. Composition becomes relevant + only once token wrapping is defined on LEZ; a future RFP, likely + an evolution of this one or a dedicated token-wrapping RFP, is + expected to specify a canonical composition pattern (confidence- + interval and staleness rules across legs). Until then, + consumer protocols that cross denominations are responsible for + their own composition logic. + +## ⚠ Platform Dependencies + +### Hard blockers + +None at the runtime level. The adaptor builds on the LEZ runtime +as it stands today (RISC-V zkVM on RISC0, public-execution mode, +public account storage). Signature verification runs as in-program +code; no new precompile or syscall is required to deliver the +adaptor. + +### Cost-conditional follow-on (not a blocker for this RFP) + +#### secp256k1 ECDSA + keccak256 precompile in public-execution mode + +If the cost measurement deliverable shows that in-program ECDSA +recovery and keccak256 hashing in RISC0 are too expensive for the +push-mode aggregator's production cadence, a follow-on RFP can +propose adding a precompile (or accelerated host function) to LEZ +for use by public-execution programs. That RFP would substitute +for the in-program verification path in this adaptor via the +localised swap-out described in the Functionality requirements. +The precompile would be public-mode only; private execution paths +are unaffected because they do not call this primitive. + +The LEZ runtime team has noted that supporting a secp256k1 +primitive raises a broader set of design questions (nullifier +tracking for replay, privacy-circuit branching to support +Ethereum-signed private accounts, identifier-flow / wallet +implications) that are not blockers for the narrow oracle use of +the precompile but should be acknowledged. Those questions can be +scoped out of the follow-on or addressed in a separate runtime +RFP, depending on appetite. + +### Soft blockers + +#### RFP-019 (canonical oracle price account standard) + +This RFP populates the canonical price account standard defined in +[RFP-019](./RFP-019-twap-oracle.md). If RFP-019 has not landed +when this RFP is delivered, the applicant defines a +forward-compatible minimal struct (see Design Rationale). + +#### Event emission (LP-0012) + +Analytics and monitoring benefit from structured on-chain events +for price updates, feed registrations, and signer-set changes. +[LP-0012](https://github.com/logos-co/lambda-prize/blob/main/prizes/LP-0012.md) +(Structured events for LEZ program execution) is currently +**open**. + +## 👤 Recommended Team Profile + +Team experienced with: + +- Oracle or DeFi protocol infrastructure development +- Cryptographic verification (secp256k1 ECDSA recovery, keccak256 + hashing, calldata parsing, signer-set management) +- LEZ / RISC0 program development; in particular, comfort writing + and measuring elliptic-curve and hash-function code in RISC-V + programs proved by RISC0 (cost characterisation experience is a + strong signal, since cost measurement is a primary deliverable) +- RedStone's data-package format, EVM connector, or Solana + connector (any prior integration is a strong signal) +- Smart-contract security auditing (signer compromise, replay + attacks, signer-set update races) + +## ⏱ Timeline Expectations + +Estimated duration: **6 to 10 weeks**. + +The adaptor has no hard runtime dependencies; it builds on LEZ as +it stands today. The canonical price account standard is a soft +dependency on RFP-019 with a documented fallback. The cost +measurement deliverable resolves the open question of whether +in-program ECDSA + keccak256 in RISC0 is fast enough for the +push-mode aggregator at production cadence; if not, a follow-on +RFP for a secp256k1 precompile becomes the optimisation path, +with this adaptor as the immediate consumer. + +## 🌍 Open Source Requirement + +All code must be released under the **MIT+Apache2.0 dual License**. + + +## Resources + +- [RFP-004 — Privacy-Preserving DEX](./RFP-004-privacy-preserving-dex.md) + (consumer of price feeds; private swaps consume the + RedStone-published prices) +- [RFP-008 — Lending & Borrowing Protocol](./RFP-008-lending-borrowing-protocol.md) + (primary consumer of price feeds) +- [RFP-013 — Reflexive Stablecoin Protocol](./RFP-013-reflexive-stablecoin-protocol.md) + (reflexive stablecoin; consumer of external-price feeds for + any wrapped-asset collateral path) +- [RFP-019 — On-Chain TWAP Oracle](./RFP-019-twap-oracle.md) + (defines the canonical oracle price account standard) +- [Appendix: Oracle Ecosystem](../appendix/oracle-ecosystem.md) +- [RedStone Documentation](https://docs.redstone.finance/) +- [RedStone token registry](https://github.com/redstone-finance/redstone-api/blob/main/docs/ALL_SUPPORTED_TOKENS.md) + + +## ✏️ How to Apply + +👉 Submit a proposal using the Issue form: + +**[Submit Proposal](https://github.com/logos-co/rfp/issues/new?template=proposal.yml)** + +We typically respond within **14 days**. For clarification questions, +please use **Discussions**. diff --git a/appendix/oracle-ecosystem.md b/appendix/oracle-ecosystem.md new file mode 100644 index 0000000..8fd59ff --- /dev/null +++ b/appendix/oracle-ecosystem.md @@ -0,0 +1,1706 @@ +# Appendix: Oracle Ecosystem + +This appendix surveys oracle protocols, TWAP mechanics, manipulation +vectors, and external oracle models relevant to +[RFP-019](../RFPs/RFP-019-twap-oracle.md). It provides the technical +and market context for the two-tier oracle architecture proposed for +LEZ. + +## Oracles Surveyed + +DeFi-style oracles are ordered by Total Value Secured (TVS), +largest first; this order is maintained throughout the document. +The DLC-oracle row is appended at the end because the DLC +attestation model does not have a TVS metric comparable to +push/pull DeFi oracles (DLC oracles secure individual Bitcoin DLC +contracts at maturity rather than continuously-running DeFi +positions). DLC oracles are included because the BIP-340 +attestation format they publish is the LEZ-native signature +primitive, which makes them relevant to the verification-cost +analysis later in this document; their structural fit is +prediction markets, not streaming price feeds. + +| Protocol | TVS | Chains | Model | Feed Count | Key Feature | +|----------|-----|--------|-------|------------|-------------| +| Chainlink | $66B-$75B (May 2025) | 27 push / 60+ via CCIP | Push (OCR/DON) | 1,000+ | Decentralised Oracle Network with VWAP from premium data aggregators | +| Chronicle | $10.2B+ (per [2]) | 13 | Push | Limited | MakerDAO-native; concentrated TVS from Sky's $10B+ TVL | +| Pyth | $8.6B+ | 50+ via Wormhole | Pull (Wormhole) | 2,800+ | First-party data from 120+ institutional publishers; confidence intervals | +| RedStone | $10B+ | 50+ push / 120+ pull | Pull (calldata) | 1,000+ | No bridge dependency; modular push+pull; fastest-growing oracle | +| Switchboard | $3B+ [1] | 9 | Pull (TEE) | Permissionless | TEE (SGX/SEV) security; permissionless custom feed creation | +| Supra | $650M+ [1]; Supra positioning cites 50+ networks | 45 | Push+Pull | N/A | Newer entrant; DORA (Distributed Oracle Agreement) consensus | +| DLC oracles (Pythia live; Sibyls operator wound down and repo deleted; P2PDerivatives dormant; Ernest on hiatus; Magnolia closed source) | N/A (not DeFi-TVS measured) | Bitcoin native; BIP-340 attestations portable to any verifying chain | Event-driven attestation (pre-announced R-points, signed at maturity) | Limited (BTC/USD; some chain metrics) | Native BIP-340 Schnorr; live ecosystem split between plain SHA-256 (Pythia, P2PDerivatives, rust-dlc) and tagged SHA-256 (Kormir, Ernest, Sibyls dlc_v0 mode); structural fit is prediction markets, not streaming price feeds | + +## Scale and Traction + +Total Value Secured measures the aggregate DeFi TVL in protocols that +depend on a given oracle. An oracle with higher TVS has withstood +more economic scrutiny, though TVS is a trailing indicator: new chains +start at $0 regardless of oracle choice. + +### Market share + +Chainlink dominates with approximately 68% of global oracle TVS and +over 80% on Ethereum specifically [1]. Chronicle's high TVS +(approximately 17%) is concentrated in a single protocol +(MakerDAO/Sky) and does not reflect general-purpose adoption [2]. +Pyth leads on data quality through first-party institutional +publishers; per Pyth's own April 2026 positioning, the network reaches +"100+ blockchains" via Wormhole, with cross-chain support +established on roughly 50+ chains in production. RedStone has the +fastest growth trajectory, driven by explicit support for L2s, +appchains, and rollups. Per RedStone's own reporting [3][17], +no oracle-induced mispricing has occurred on its flagship integrations +(Ethena, Gearbox) through early 2026; no independent post-incident +review corroborates this absence claim. + +### Per-protocol adoption + +**Chainlink.** Deployed on 27 chains with push model and 60+ public +and private blockchains via CCIP. Network integration requirements +include high-availability RPC providers, valid SSL, Ethereum +JSON-RPC compatibility, and 30-day historical RPC performance +metrics, making it inaccessible for new chains at launch [4]. Uses +Off-Chain Reporting (OCR) where nodes aggregate prices from premium +data vendors (Kaiko, CoinMetrics) and submit a single signed +transaction per round. Update triggers are deviation threshold (e.g. +0.5% price change) or heartbeat (e.g. 1 hour maximum staleness). + +**Pyth.** Originated on Solana and now cross-chain via Wormhole. +Aggregates first-party data from 120+ institutional publishers +(April 2026), including Jane Street, Coinbase, and Binance, across +2,800+ price feeds (December 2025). Architecture: publishers post +prices on Pythnet (a Solana appchain) every 400ms; Wormhole guardians +sign a Merkle root; the Hermes off-chain cache stores latest proofs; +users fetch and submit proofs in their transactions. Every price +includes a confidence interval, enabling protocols to reject +high-uncertainty updates. Known incidents include the September 2021 +BTC/USD mispricing, where the feed reported approximately $5,402 +against an actual price near $43,500 (an approximately 87% drop) +[37], and the March 2025 Morpho cbETH wrongful liquidation on Base, +where a roughly 7-minute cbETH/ETH staleness window distorted the +collateral price and liquidated a user for approximately $33,000 on +a Re7 Labs vault [38]. + +**RedStone.** Modular oracle with both push and pull delivery. Pull +model attaches signed data to EVM calldata; the on-chain contract +verifies node signatures without requiring a bridge or dedicated +relay infrastructure [3]. Fastest-growing oracle in 2024 to 2025, +with deployments on Monad, Hyperliquid (HyperStone), and 120+ pull +chains. Per RedStone's own reporting [3][17], zero mispricing +incidents through early 2026; no independent post-incident review +corroborates this. +Expanding into RWA feeds (BlackRock BUIDL, VanEck VBILL) and risk +ratings via Credora acquisition. + +**Switchboard.** Permissionless feed creation via TEE (SGX/SEV) +oracle nodes [13]. Any developer can create custom feeds for assets +not covered by Pyth or RedStone. Can aggregate from multiple upstream +oracles (Pyth + Chainlink + custom APIs) in a single feed. The core +protocol contract is a single-deployment artefact per chain +(deployed by the Switchboard team), but feed creation on top of it +is permissionless; TEE hardware requirements limit the operator pool. + +**DIA Lumina.** Fully permissionless: both data sourcing (Feeder +nodes) and feed deployment (Aggregator contracts) require no team +permission [7]. ZK proof verification aligns with privacy-focused +chains. Smaller feed catalogue (200+) and newer ZK architecture +(Lumina V2) make it less battle-tested than Pyth or RedStone. + +## TWAP Mechanics + +### Uniswap v2 accumulator + +Each Uniswap v2 pool stores `price0CumulativeLast` and +`price1CumulativeLast` variables. These accumulators are updated at +the beginning of each block (before any same-block trades execute) +using the price set by the last trade of the previous block [14]. The +formula: `cumulativePrice += price * timeElapsed`. To compute a TWAP, +an external contract reads the accumulator at two timestamps (T1 and +T2) and divides: + +``` +TWAP = (accumulator[T2] - accumulator[T1]) / (T2 - T1) +``` + +This yields an arithmetic mean price. No off-chain components are +required. + +### Uniswap v3 accumulator + +Uniswap v3 replaced the raw price accumulator with a tick-based +accumulator (`tickCumulative`), which stores the running sum of +`currentTick * secondsElapsed` [9]. The TWAP is: + +``` +averageTick = (tickCumulative[T2] - tickCumulative[T1]) / (T2 - T1) +price = 1.0001^averageTick +``` + +This yields a geometric mean price, which is more appropriate for +multiplicative price processes. The observation buffer is a circular +array of up to 65,535 slots, expandable via +`increaseObservationCardinalityNext()` at a one-time gas cost [9]. + +### Uniswap v4 truncated oracle hook + +Uniswap v4 removed the oracle from core pool state and moved it to +an optional hook, so pools that do not need an oracle no longer pay +the per-swap accumulator-update gas. The v3 design described above +remains the production reference for on-chain TWAP (v3 is still the +dominant AMM by deployed volume), and the v4 hook builds on the same +tick-accumulator pattern rather than replacing it. + +The notable evolution in v4 is the **truncated oracle hook**, which +caps the per-block tick movement that the accumulator records [61]. +Before each swap, the hook compares the pool's current tick against +the previous-block tick stored by the hook. If the absolute +difference exceeds a threshold (the Uniswap reference implementation +uses 9,116 ticks, corresponding to roughly a 2.49x price move per +block: `1.0001^9116 ≈ 2.49`), the value written to the accumulator is clamped to +±threshold rather than the raw observed tick. The geometric-mean +TWAP formula is otherwise identical to v3. + +Concretely: + +``` +observedTick = pool.currentTick +previousTick = hook.lastObservedTick +delta = observedTick - previousTick +clampedDelta = clamp(delta, -MAX_TICK_DELTA, +MAX_TICK_DELTA) +recordedTick = previousTick + clampedDelta +tickCumulative += recordedTick * timeElapsed +``` + +The effect is that a single-block manipulation can shift the +accumulator by at most `MAX_TICK_DELTA * timeElapsed`, regardless of +how far the attacker actually moved the pool. To produce the same +oracle distortion that an unbounded v3 accumulator would record from +one manipulated block, an attacker must sustain a manipulated price +across many consecutive blocks (Uniswap's reference scenario cites +roughly 15 blocks for the oracle to "catch up" to a large move), +during which arbitrage bots compete on the unclamped pool price and +erode the attacker's position [61]. The truncated hook does not +eliminate the cost-vs-window tradeoff (long sustained manipulation +on a thin pool is still feasible), but it raises the per-block cost +floor and is currently the strongest in-AMM mitigation against +single-block and PoS multi-block oracle attacks (see "TWAP +Manipulation Vectors" below). + +For LEZ, this is directly relevant: an LEZ-side on-chain TWAP that +emulates v3's raw accumulator inherits v3's vulnerability to thin +pools at chain launch. Porting the truncation logic is a low-cost +addition (one tick-delta comparison and clamp per accumulator +update) that materially raises the manipulation floor without +requiring an external feed. + +### Geometric vs arithmetic mean + +The arithmetic mean (v2) is sensitive to outliers: an attacker who +moves the price up by 10x in one block and back by 10x in the next +leaves a net upward bias in the arithmetic mean. The geometric mean +(v3) is invariant to such symmetric multiplicative manipulation, +because `log(10x) + log(1/10x) = 0` [9]. For this reason, the v3 +approach is strictly preferred for price oracle use. + +### Example computation (v3) + +``` +tickCumulatives = [70,000, 1,070,000] over 10 seconds +averageTick = (1,070,000 - 70,000) / 10 = 100,000 +price = 1.0001^100,000 = 22,015.5 USDC/WETH +``` + +Minor imprecision arises because ticks are integers and fractional +ticks are truncated, but this is negligible for most use cases [9]. + +## TWAP Manipulation Vectors + +### Flash loan attacks (within-block) + +An attacker borrows massive capital via a flash loan, moves the pool +price heavily, and profits from a protocol that reads the manipulated +price in the same or next block. Under Uniswap v2/v3, the accumulator +is updated at block start (before same-block trades), so within-block +manipulation does not affect the current block's accumulator sample. +However, the attacker can manipulate price at the end of block N, +which contaminates the accumulator sample in block N+1 [6][10]. + +### PoS multi-block validator attacks + +Under Proof of Stake, validators know one epoch ahead (32 blocks on +Ethereum, approximately 6.4 minutes) whether they control consecutive +blocks. A validator controlling two consecutive blocks can move the +price in block N and reverse it in block N+1, at a cost approximately +equal to the round-trip swap fees and price impact, with no back-run +competition [6]. This contaminates one accumulator data point per +attack. On high-liquidity pools (e.g. +USDC/WETH 5bps on Ethereum), the attack is economically infeasible; +on low-liquidity pools, it is trivially cheap. + +### Low-liquidity vulnerability + +Manipulation cost scales approximately linearly with pool liquidity +depth [6][10]. On the deep USDC/WETH 5bps pool, adding $1M of +wide-range liquidity raises the marginal cost of a two-block oracle +attack by approximately $360B above the already-large baseline, +demonstrating extreme sensitivity [6]. On a new chain like LEZ with +$1M pools, the same attack that costs trillions on Ethereum mainnet +costs only thousands. + +### Short observation window attacks + +An attacker sustains a manipulated price across multiple blocks for +the duration of a short TWAP window (e.g. 5 minutes). This is more +expensive than single-block manipulation but feasible on low-liquidity +pools [10]. The cost scales with both window length and pool depth. + +### Mitigation: tick-delta truncation (Uniswap v4) + +The Uniswap v4 truncated oracle hook (described above under +"Uniswap v4 truncated oracle hook") clamps per-block tick movement +written to the accumulator [61]. This directly raises the cost of +flash-loan and PoS multi-block attacks: a single manipulated block +contributes at most `MAX_TICK_DELTA * blockTime` to the accumulator +regardless of the actual price excursion, forcing an attacker to +sustain manipulation across many blocks and pay arbitrage costs each +block. It does not address the short-window-on-thin-pool case, where +the attacker is willing to sustain price across the full window; +defending that case still requires either deeper liquidity or a +divergence check against an external feed. + +### Historical losses + +According to the Rekt Database (cited in the Ormer paper), 36 flash +loan oracle attacks alone caused over $418M in cumulative losses [5]. +Oracle manipulation is the primary attack vector in DeFi exploits. + +## Window Selection Tradeoffs + +### The core tradeoff + +Short TWAP windows (e.g. 5 minutes) provide fresh prices but are +cheap to manipulate. Long windows (e.g. 24 hours) are expensive to +manipulate but lag the market severely during genuine volatility. +Unlike external oracle networks, AMM TWAP cannot simultaneously +optimise both security and freshness [10]. + +### Production standards + +The majority of TWAP oracles in production DeFi use windows between +30 minutes and 12 hours [11]. + +| Use case | Typical window | Rationale | +|----------|---------------|-----------| +| Lending collateral valuation | 30 min to 2 h | Resist short-term manipulation; liquidation timing tolerable | +| DEX AMM internal pricing | 5 to 30 min | Requires responsiveness for arbitrage | +| Governance and voting | 24 h to 7 days | Resist flash attacks on governance weight | + +### Cardinality math + +At 12-second blocks, the maximum observation cardinality of 65,535 +provides approximately 218 hours (roughly 9 days) of lookback [9]. +Protocols trading off storage cost vs lookback depth should expand +cardinality to at least `(desired_window_seconds / block_time) + buffer`. +For a 2-hour window at 12s blocks, minimum cardinality is 600 + buffer. + +### Manipulation cost scaling + +Moving the price by 5% on a 1-hour TWAP requires sustaining that 5% +deviation every block for 1 hour, at a cost approximately equal to +the arbitrage losses and fees incurred per block, multiplied by the +number of blocks [10]. Doubling pool liquidity approximately doubles +the cost; doubling the window length approximately doubles the cost. + +## External Oracle Models + +### Push vs pull + +Push oracles (Chainlink) submit price updates to an on-chain contract +on a heartbeat (e.g. every hour) or deviation trigger (e.g. 0.5% +price change). Gas cost per update ranges from 300K to 2.4M gas +depending on the aggregation method [4]. Pull oracles (Pyth, RedStone) +sign data off-chain; the consumer fetches the signed data and submits +it as part of their own transaction, paying the verification gas cost +(approximately 50K to 100K gas per update) [3][5]. + +For new chains, pull is strongly preferred: no dedicated per-chain +node operators, no ongoing gas subsidies, and immediate availability +once the verification contract is deployed. + +### DON vs single-source + +Chainlink's Decentralised Oracle Network (DON) uses Off-Chain +Reporting (OCR) where multiple independent nodes each fetch prices +from premium data aggregators, communicate via P2P, elect a leader +who produces a signed report containing all observations, and submit +the median on-chain [12]. This is technically VWAP (volume-weighted +from multi-exchange aggregation), not a strict TWAP from a single +AMM [12]. + +Single-source oracles (a single AMM TWAP) offer maximum +trustlessness but depend entirely on that source's liquidity and +availability. DON-style oracles trade some trustlessness (off-chain +node operators) for dramatically better manipulation resistance and +market coverage. + +### Comparison table + +| Dimension | AMM TWAP | Pyth | RedStone | Chainlink DON | +|-----------|---------|------|----------|---------------| +| Trust model | Trustless (on-chain) | Semi-trusted (publishers + Wormhole) | Semi-trusted (node signatures) | Semi-trusted (node operators + staking) | +| Data source | Single DEX pool | 70+ first-party publishers | CEX + DEX + aggregators | Premium aggregators (Kaiko, CoinMetrics) | +| Market coverage | On-chain pairs only | 2,800+ feeds (Dec 2025; crypto, FX, equities) | 1,000+ feeds | 1,000+ feeds | +| New-chain deployability | Requires AMM with liquidity | Requires Wormhole | No bridge needed | Requires multiple high-availability RPC providers, valid SSL, JSON-RPC compatibility, 30-day historical RPC performance metrics | +| Manipulation resistance | Scales with pool depth | Independent of on-chain liquidity | Independent of on-chain liquidity | Independent of on-chain liquidity | +| Gas per query | Very low (read accumulator) | 50K to 100K (VAA verification) | 50K to 100K (signature verification) | N/A (push: consumer reads storage) | +| Confidence interval | No | Yes | No | No | +| Real-world assets | No | Yes | Yes (RWA feeds) | Yes | + +## Infrastructure Requirements for External Oracles on LEZ + +The architectural choice (push vs pull, bridge vs direct signature) +determines what Logos has to deploy, host, or coordinate to make +each external oracle available on LEZ. This section is operational: +it answers "who runs what, where does the data come from, and what +happens if it breaks." It complements the higher-level model +comparison above. + +The summary up front: **RedStone is a self-deploy task** (port a +verifier program, optionally run a relayer); **Pyth is a +multi-party governance task** gated on Wormhole guardian-set support +for LEZ; **Chainlink is impractical at launch** (DON onboarding has +no public path for new chains without months of integration work +and high-availability RPC providers in place). + +### Side-by-side: bringing an external oracle live on LEZ + +| Dimension | RedStone (Pull) | RedStone (Push) | Pyth | Chainlink | +| --------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| Relayer service required? | No (user attaches signed payload to their tx) | Yes (a service writes prices on-chain on a schedule) | No scheduled relayer (Hermes is a read-only cache) | Yes (DON node operators write on-chain) | +| Off-chain data endpoint | RedStone DDL HTTPS gateways | Same | Hermes HTTPS REST/SSE | DON gossip + private aggregator data | +| Bridge / cross-chain trust layer | None: signatures verified directly | None | Wormhole (19 guardians, 13/19 threshold) | None for the price flow itself, but DON nodes coordinate via Wormhole-free P2P | +| New-chain onboarding type | Self-deploy: any team ports the verifier | Self-deploy: same plus a relayer | Multi-party: Wormhole governance proposal, Core Contract port, guardian observation, Pyth Receiver port | Multi-party: Chainlink integration program, DON spin-up, RPC provider qualification [4] | +| Contracts to deploy on LEZ | One verifier module per consumer (or one shared `ConsumerBase`-equivalent) | Same plus `PriceFeedsAdapter`-equivalent | Wormhole Core port + Pyth Receiver port | DON aggregator contract per feed | +| Who runs the off-chain infra | RedStone (default DDL gateways) | RedStone, Logos ecosystem, or a consumer protocol can run relayer instances | Pyth Data Association (default Hermes) or third-party node providers (Triton, P2P, extrnode, Liquify) [62] | Chainlink + node operator coalition | +| Gas paid by | Consumer on every read (calldata + verification) | Relayer wallet, per update | Consumer on every update (VAA verification + Merkle proof) | Effectively the consumer (heartbeat cost socialised across all readers) | +| Logos ongoing operational burden | None on LEZ side | Relayer instances + signing wallet gas + monitoring | Optional: self-hosted Hermes mirror for low latency; otherwise none on LEZ side | Continuous: DON nodes, RPC infrastructure, integration support | +| Time-to-live for a new chain | Weeks (verifier port + audit) | Same | Months (Wormhole governance + cross-runtime port) | Months to quarters, gated on Chainlink integration program | +| Trust assumptions added | RedStone authorised signer set (~3-of-N per `dataServiceId`); RedStone DDL HTTPS gateways for liveness (censorship/outage; signatures still protect against falsified data — see "HTTPS portals are a centralisation risk") | Same plus the relayer (only for liveness; data is still signature-verified on-chain); DDL gateway liveness as above | Pythnet validators + 13-of-19 Wormhole guardians + publisher set; Hermes HTTPS gateway for liveness (same caveat as RedStone DDL) | Chainlink node operator set + premium aggregator licensing chain | +| Documented LEZ-relevant precedent | None for LEZ-native SVM runtime; EVM port pattern is mature | Same | No SVM-non-Solana port of the Pyth receiver is documented as of May 2026 | No new-chain integration without Chainlink-side prioritisation | + +### Where the signed data comes from + +#### RedStone + +The signed data lives in RedStone's **Data Distribution Layer +(DDL)**, a set of public HTTPS gateways operated by RedStone. +The SDK and any relayer fetch from URLs hardcoded in +[`packages/sdk/src/data-services-urls.ts`](https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/sdk/src/data-services-urls.ts) +[63]: + +- `https://oracle-gateway-1.a.redstone.finance` (AWS, production, metadata, no historical) +- `https://oracle-gateway-2.a.redstone.finance` (AWS, production, metadata, historical) +- `https://oracle-gateway-1.a.redstone.vip` (GCP, production, no metadata, no historical) + +A request specifies a `dataServiceId` (e.g. `redstone-primary-prod`), +the feed IDs to fetch (e.g. `BTC`, `ETH`), and the minimum number of +unique signers required (typically 3). The response is a signed +data package: per signer, a payload over `(feedId, value, +timestamp)` plus an ECDSA signature, with packages concatenated. No +authentication on the read paths. + +#### Pyth + +The signed data is exposed via **Hermes**, an HTTPS REST + SSE +service that mirrors Wormhole-signed Pyth Merkle roots [62]: + +- `https://hermes.pyth.network` (public, operated by Pyth Data Association, 20 req / 10 s per IP) +- Third-party node providers for production: Triton, P2P, extrnode, Liquify [62] + +The v2 API exposes `/v2/updates/price/latest`, +`/v2/updates/price/{publish_time}`, and an SSE stream at +`/v2/updates/price/stream`. The payload is a binary VAA (base64 or +hex), submittable directly as calldata to the on-chain Pyth Receiver +contract. + +### HTTPS portals are a centralisation risk + +Both RedStone DDL and Pyth Hermes are **HTTPS gateways**, not P2P +networks. There is no gossip layer, no DHT, no decentralised +fan-out: every consumer of signed data fetches from a small set of +DNS-resolved endpoints controlled by the oracle provider or one of +its named third-party hosts. This has three direct consequences: + +- **Censorship**. The operator (and the network operator + upstream) can withhold responses to specific clients, geographies, + or asset IDs. Signature verification still protects against + *falsified* data, but does not protect against *withheld* + data: a censored consumer simply cannot fetch the latest update + and their transaction will revert. +- **Outage**. DNS resolution, TLS certificate validity, and + HTTP availability all become liveness dependencies. A regional + cloud outage at AWS (most RedStone gateways) or at the Pyth Data + Association's Hermes hosting takes the oracle offline for + affected users. +- **Observability**. The gateway sees who is reading what. + Even though Logos's confidential execution model keeps the + on-chain *use* of a price private, the off-chain *fetch* of a + signed payload is fully observable to the gateway operator. + +These are inherent properties of the HTTPS-portal design, not +implementation bugs. They are present on every chain that uses +RedStone or Pyth today; LEZ inherits them by adopting either +oracle. Mitigations available to a consumer: + +- Run a local mirror of the gateway (RedStone supports + `OVERRIDE_DIRECT_CACHE_SERVICE_URLS`; Pyth supports running a + private Hermes instance against Pythnet + Wormhole feeds). +- Query multiple gateway hosts in parallel (the RedStone SDK + default; Pyth recommends third-party node providers). +- Maintain a recent-price fallback on-chain (last verified update + served until a new one arrives), accepting staleness risk for + liveness. + +None of these mitigations eliminate the centralisation; they +reduce specific failure modes at the cost of additional +infrastructure or risk acceptance. + +### RedStone relayer setup (Push mode), end to end + +The reference relayer is open source in +[`redstone-finance/redstone-oracles-monorepo`](https://github.com/redstone-finance/redstone-oracles-monorepo), +Node.js/TypeScript. Per cycle it: + +1. Polls a DDL gateway via the SDK for signed packages + matching the configured `dataServiceId` and feed IDs. +2. Compares against the last on-chain value. Writes a new + transaction when either trigger fires: heartbeat + (`UPDATE_PRICE_INTERVAL`, e.g. 5 min) or deviation + (`MIN_DEVIATION_PERCENTAGE`, e.g. 0.5%). +3. Packs the concatenated signed packages as transaction data + targeting the on-chain adapter; signs with the relayer's hot + wallet (`PRIVATE_KEY` env var). +4. Submits, monitors, repeats. + +The on-chain adapter, on receipt, verifies each signer's signature +against the known signer set, checks the package timestamp is fresh +(within a configurable window), takes the median across signers, +and writes the result. + +For LEZ specifically, three artefacts are needed beyond the +RedStone reference code: + +- A SPEL port of the `PriceFeedsAdapter` writing to the canonical + price account from RFP-019 (populating `base_asset`, + `quote_asset`, price, timestamp, source, confidence). +- A SPEL port of the consumer-base library if Pull mode is offered + alongside Push. +- LEZ-specific transaction-building and signing bindings in the + relayer (most likely via the same SDK that consumer programs use). + +Operational footprint per Push deployment: + +- 1+ relayer process (a few hundred MB RAM each; cloud or + bare metal). RedStone recommends 2+ independent instances for + redundancy. +- 1 hot wallet on LEZ per instance, funded with gas. +- Monitoring: feed freshness on-chain, wallet balance, gateway + reachability, transaction failure rate. + +Typical per-update verification cost on EVM is 100-200k gas; the +LEZ-side equivalent under SVM CU pricing should fall in the same +range as the pull-mode verification cost documented in the +[Signature Verification Schemes](#signature-verification-schemes) +section, since the verification work is identical and only the cost +allocation differs (relayer vs consumer). + +### Who runs the relayer + +RedStone's documentation says the relayer is permissionless: "anyone +could run the service as the data is eventually validated on-chain" +[64]. In practice on a new chain, the operating party is usually +one of: + +1. **RedStone itself**, as part of an integration package. + Monad mainnet (24 Nov 2025) is the recent precedent: RedStone + shipped 50+ feeds and ran the infrastructure from day one [65]. +2. **The chain ecosystem**, funding and running the relayer as + shared infrastructure. +3. **A consuming protocol**, if it wants exclusive control over + its oracle update cadence. + +For LEZ, the realistic at-launch posture is (1) for primary, with +(2) as redundancy for liveness insurance. RFP-020 covers the SVM +adapter port; running additional relayer instances is a separate +operational commitment that is **not** required to use RedStone on +LEZ in Pull mode. + +### Pull vs Push: when does Push become worth the cost + +Push trades persistent ecosystem-paid gas for cheaper per-consumer +reads. The break-even depends on read volume on each pair: if a +feed is read N times per heartbeat interval and the per-update gas +is roughly equal to per-read calldata gas, the crossover is around +N=1 reads per heartbeat. In practice, dedicated feeds for a single +high-throughput lending protocol can justify Push at LEZ scale; +shared feeds consumed by occasional dapps typically cannot. + +At chain launch with no TVL, Pull is the right default. Push +becomes worth revisiting once a specific feed sees concentrated, +sustained read demand that exceeds the gas budget of a typical +relayer cadence. + +## Signature Verification Schemes + +The cost of verifying oracle signatures on-chain dictates whether +LEZ can host an oracle adaptor at all. LEZ is a RISC-V zkVM +execution environment built on RISC0. The on-chain signature +primitive currently wired into the runtime is single-key secp256k1 +Schnorr (BIP-340) over SHA-256, validated as a witness on the +transaction (the runtime checks the signature when it admits the +transaction). This primitive is **not exposed to guest programs**: +a program running inside the RISC-V zkVM cannot invoke it as a +host function. No threshold or aggregate scheme (BLS, Schnorr +multisig, t-Schnorr) is exposed to guest programs either, and no +other signing scheme has a host primitive at all. Any signature +that a program needs to verify (whether BIP-340 Schnorr from a +DLC or FROST publisher, secp256k1 ECDSA from RedStone or Pyth, +ed25519 from Switchboard) has to run as program code inside the +RISC-V zkVM, where verification cost is dominated by the ZK +proving overhead of the underlying primitive. ECDSA recovery and +keccak256 are both expensive to prove; in-circuit Schnorr/SHA-256 +performance on RISC0 is currently unmeasured. The cost question +is identical in shape across signature schemes: how much does +in-circuit verification cost, and is that acceptable for the +adaptor's update cadence. + +This matters because every general-purpose price oracle in +production today (RedStone, Pyth via Wormhole, Chainlink Data +Streams, Chronicle's per-signer leg) signs with secp256k1 ECDSA +over keccak256, and Switchboard signs with ed25519. None of these +match the LEZ-native primitive. Verifying their payloads on chain +therefore requires either (a) adding a secp256k1 ECDSA + keccak256 +precompile to LEZ, or (b) running a trusted relayer that re-signs +upstream payloads in BIP-340 Schnorr over SHA-256, which collapses +the trust set from N publishers to one re-signer. This section walks through what schemes Pyth and +RedStone actually use, and what they cost on chains that do expose +the matching primitive, so the gap between the upstream cost +profile and the LEZ-side cost is visible to the reader. + +### Wormhole VAA verification (Pyth dependency) + +A Verifiable Action Approval (VAA) is the canonical Wormhole +attestation. The guardian set is a fixed roster of 19 nodes; a +super-majority of 13 signatures is required for a VAA to be +considered valid [19][20]. Each guardian signs the +double-keccak256 hash of the VAA body (single keccak256 on Solana, +because the Solana secp256k1 program hashes the message itself) +[19]. The signature scheme is plain m-of-n ECDSA over secp256k1, +with no aggregation: the VAA carries 13 independent (v, r, s) +tuples plus a guardian index per signature [19][21]. Wormhole's +own protocol documentation explains the choice: BLS aggregation +would cost roughly 130K gas to verify on Ethereum, whereas plain +ECDSA via the ecrecover precompile costs about 5K gas per +signature, so the simpler scheme wins on cost despite the linear +verification work [21][22]. + +On EVM chains, the core bridge contract calls verifyVM, which +invokes verifySignatures and loops over the 13 signatures one by +one, calling ecrecover for each [21][22]. The ecrecover +precompile has a fixed base cost of 3,000 gas [23]; combined with +calldata costs, the documented per-signature cost is +approximately 5K + 5K (recovery + calldata), giving roughly 130K +gas for the signature step alone before Merkle proof verification +and storage writes [22]. On Solana, Wormhole calls the native +secp256k1 precompile via verify_signatures, but Solana's per-call +compute-unit budget forces the verification to be split across +multiple instructions, each verifying six or seven signatures at +a time [22][24]. The Solana secp256k1 precompile costs +approximately 6,690 compute units per signature verified [24][25]. +For Pyth specifically, the Perseus upgrade amortises the VAA +verification step across multiple price updates: a single set of +Wormhole signatures is verified once per transaction regardless +of how many feeds are updated, yielding a 50 to 80 per cent gas +reduction when updating five feeds at once [26]. + +Alternative verification paths exist but are not in production +for Pyth. Wormhole has shipped a Boundless ZK verifier (RISC Zero +Groth16 proofs of Ethereum consensus) deployed on Ethereum, Base, +Optimism, Arbitrum, Linea, and Avalanche, with a two-of-two +policy that requires both a valid guardian signature set and a +valid ZK proof before a transfer executes [27]. The +wormhole-foundation/example-zk-light-clients repository contains +ZK light client templates for various source chains [27]. None of +these supersede the 13-of-19 ECDSA path for Pyth price-feed +delivery; they augment it. + +### RedStone per-chain signatures + +RedStone signs every data package with one scheme everywhere it +operates: ECDSA over secp256k1 with a keccak256 message hash, +matching Ethereum's signing convention [28][29]. The reference +implementation lives in the redstone-finance/rust-sdk crate; its +Cargo.toml depends on either the secp256k1 crate (with the +recovery feature) or the k256 ECDSA crate, plus sha3 for keccak +[29]. The crypto module exposes recover_public_key and +recover_address functions that validate signature malleability +against the secp256k1 curve order and accept Ethereum-style +recovery bytes (0, 1, 27, 28) [29]. The on-chain EVM consumer +contract calls SignatureLib.recoverSignerAddress on +keccak256(signedMessage), then enforces a per-feed unique-signer +threshold via getUniqueSignersThreshold(); RedStone's +documentation recommends at least three unique signers as a +balance between security and gas cost [28][30]. + +The signing scheme does not change per chain; only the +verification primitive does. Each chain-specific connector +recovers the same secp256k1 ECDSA signatures using whatever +host-chain primitive is available: + +| Chain | Verification primitive | Source | +|-------|-----------------------|--------| +| EVM | ECRECOVER precompile (secp256k1, keccak256) | [28][30] | +| Solana | secp256k1_recover syscall / secp256k1 program | [25][29] | +| Sui | sui::ecdsa_k1::secp256k1_ecrecover Move builtin | [31] | +| Stellar (Soroban) | recover_key_ecdsa_secp256k1 host function | [32][33] | +| Fuel | Sway contract using secp256k1 recovery | [34] | +| Radix (Scrypto) | Rust SDK with secp256k1 / k256 crate | [29][35] | +| Casper | Rust SDK with secp256k1 / k256 crate | [29] | + +Note: although Stellar's native account model uses ed25519 +(referenced in RedStone's Stellar connector deployment +documentation [36]), RedStone's data-package signing and +verification on Stellar use the same secp256k1 ECDSA over +keccak256 as on every other chain, via Soroban's +`recover_key_ecdsa_secp256k1` host function [32][33]. + +Per-chain verification cost (single signature): + +| Chain | Cost per ECDSA recovery | Source | +|-------|------------------------|--------| +| Ethereum / EVM | 3,000 gas (precompile) plus calldata | [23] | +| Solana | approximately 6,690 compute units | [24][25] | +| Stellar (Soroban) | approximately 2.3M CPU instructions (2,315,295) | [32] | + +For an M-of-N RedStone payload with the recommended threshold +of three unique signers [30], total verification cost on EVM is +approximately 9,000 gas for the precompile calls plus calldata +and signer-bitmap accounting; the documented end-to-end gas cost +of a RedStone update on EVM falls in the 50K to 100K range [3] +(consistent with the table in External Oracle Models above). + +### Implications for LEZ + +The discussion below applies only to off-chain price oracles +(external publishers signing data that has to be verified on +chain). The on-chain TWAP tier is structurally separate: it reads +LEZ-native AMM pool state, accumulates price observations, and +exposes them through a program account. No external signature is +involved, so the LEZ-native single-sig BIP-340 Schnorr primitive +is sufficient (it covers transaction authentication, not data +attestation). RFP-019 sits entirely on the on-chain side and is +unaffected by what follows. + +For the off-chain side, the gap is real: every general-purpose +price oracle in production today signs with secp256k1 ECDSA over +keccak256 (RedStone, Pyth via Wormhole, Chainlink, Chronicle's +per-signer leg) or ed25519 (Switchboard). None match the +LEZ-native primitive. The candidates that *do* sign in BIP-340 +Schnorr over tagged SHA-256 are concentrated in the Bitcoin DLC +ecosystem (Pythia from DLC Markets, Sibyls, Suredbits, Ernest +Oracle on Nostr), all of which are single-operator BTC/USD +publishers built around discrete-event attestation rather than +continuous price streams. None today publish ZEC/USD or XMR/USD, +and none are decentralised in the way a DeFi-grade feed needs. + +Four realistic adaptor shapes exist for closing this gap. They +are independent of RFP-019. A constraint that runs across C and +D: no signature-verification primitive is currently exposed to +guest programs on LEZ, so any in-program signature check (whether +ECDSA-keccak for shape D's adaptor or BIP-340 for shape C's DLC +attestations) runs as RISC-V code inside the RISC0 zkVM. The +cost question is the same shape across both; only the upstream +supply differs. Shapes A and B avoid the question because the +signature being checked authenticates the LEZ transaction itself, +not data carried inside calldata: the transaction sender is a +regular LEZ user (a single re-signer in A, a t-of-n FROST +federation emitting one aggregated BIP-340 signature in B), the +runtime validates the BIP-340 transaction witness at admission +time as part of the standard transaction-admission flow, and the +price-aggregator program does only an equality check on the +authenticated caller against a registered pubkey. There is no +in-program signature verification under either shape, so the +in-circuit cost question never arises in public push mode. The +remaining variable is trust: collapse to one re-signer (A) or to +t honest signers in a federation (B). Crucially, neither shape +unlocks private-execution pull: both are public push-mode +designs, with private consumers reading the public price account +written by the relayer or federation. + +The structural test that distinguishes the shapes is **whose +signature authenticates the LEZ transaction**. If it is the +transaction sender's (a single re-signer in A, a FROST federation +emitting one aggregated BIP-340 signature in B), the runtime +handles verification at admission and the guest program does an +authorisation check on the caller. If the LEZ transaction carries +an upstream publisher's signature inside calldata, distinct from +the transaction sender, the guest program has to verify it +in-circuit (shapes C and D). + +**Shape A — Trusted re-signer relayer.** A LEZ-side process +fetches RedStone or Pyth payloads, verifies them off chain, and +submits a regular LEZ transaction that calls the price-aggregator +program with the resulting price. The relayer's BIP-340 Schnorr +signature is on the transaction itself; the runtime validates it +at admission time. The aggregator program checks the authenticated +caller against a registered relayer pubkey (an equality check, not +a signature verification) and writes the price to a public price +account. The trust set collapses from N upstream publishers to one +re-signer; the chain has no cryptographic evidence that the relayer +reported what the publishers actually signed. + +**Shape B — FROST-BIP340 federation, transaction-signing.** A +t-of-n federation jointly signs the LEZ transaction itself (not +the data inside calldata) using FROST, emitting a single +BIP-340-verifiable Schnorr signature as the transaction witness. +Each federation member fetches upstream RedStone or Pyth payloads +independently, verifies the upstream signatures off chain in +native code, and proposes a `(price, timestamp, source_metadata)` +tuple. When t members agree on the tuple within a tolerance +window, they run FROST signing rounds (commit + sign) over the +LEZ transaction hash and the coordinator submits the resulting +tx. The aggregator program checks the authenticated caller against +a registered federation aggregate pubkey `P_fed` (an equality +check, not a signature verification) and writes the price to a +public price account. The signing infrastructure exists as +libraries (Zcash Foundation FROST [45], Blockstream `bip-frost-dkg` +[46], Frostsnap [47]; jesseposner FROST-BIP340 [48] is the +reference implementation), and ZF is actively building FROST +tooling for Zcash, which aligns with the privacy-asset focus. + +**Assumption to validate by PoC: the runtime accepts the** +**federation's FROST-aggregated BIP-340 signature as a normal LEZ** +**transaction witness.** FROST output is byte-identical to a single +BIP-340 signature under an aggregate public key, so the runtime's +existing tx-admission BIP-340 primitive should validate it without +changes. If that assumption holds, the federation's write tx pays +only the standard tx-admission verification cost (host-program +BIP-340 verification, runs outside the RISC-V zkVM circuit), and +the price-aggregator program does no in-program signature +verification on the write side. The compute-unit cost of pushing +a price update is therefore lower than under shape D, where the +aggregator program verifies an upstream data signature in RISC-V +code at in-circuit cost. If the assumption fails (the runtime +rejects the FROST-aggregated witness for some reason, or +operationally the federation cannot be set up to sign LEZ +transactions directly), the federation would have to fall back to +verifying a data signature in program code, raising the +public-mode push CU cost to the in-circuit Schnorr cost the bench +measures (5:22 E2E private TX vs 7:26 ECDSA at 3-of-N on consumer +CPU, +[`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)). +The reasons such a fallback might be forced are an open question +that the PoC has to surface. + +**Either way, shape B is push-only mode. It does not unlock** +**private-execution pull.** Pull mode for a private consumer means +the consumer's own private transaction authenticates the upstream +data inside its own ZK circuit. Shape B authenticates a *write* +transaction submitted by the federation; the data the private +transaction reads is the public price account written by the +federation. Private-mode reads under shape B are identical to +push-mode reads under shape D: read the slot, no signature work +in the read path. Private pull (the consumer's private tx +verifies an upstream signature inline) remains foreclosed under +shape B for the same reason it is under shape D: the upstream +signature still has to be verified somewhere, and putting it in +the consumer's privacy circuit is what the bench rules out. + +No price-oracle product is deployed in this shape today. Public +framing of FROST by its implementers and grant funders is +exclusively wallet and custody (Blockstream `bip-frost-dkg` README, +ZF FROST documentation, OpenSats and Brink grants for +jesseposner/FROST-BIP340 and Frostsnap, Blockchain Commons HRF 2025 +FROST grant for shared-custody multisig). The closest production +precedent is iBTC Network (formerly dlcBTC; operator rebranded +DLC.Link to BitSafe in 2025), which runs a t-of-n attestor +federation at sizes 10-of-15 (iBTC on EVM) and 7-of-10 (CBTC on +Canton, mainnet October 2025). The federation runs two parallel +signing modes [51]: per-attestor secp256k1 ECDSA over keccak256 +for EVM-bridge attestations (verified on chain by +`ECDSAUpgradeable.recover` per signature, not aggregated), and a +single FROST-aggregated BIP-340 Schnorr signature inside the +Taproot spend path on Bitcoin. The FROST-BIP-340 path is therefore +live but only inside a Bitcoin script; there is no off-chain wire +format that a downstream LEZ verifier could subscribe to as a +single BIP-340 stream. The attestation content is also contract +outcomes (was a burn observed on the counterparty chain) rather +than continuous price data, and the FROST library used is the +project's own `DLC-link/conduition-frost` (a fork-of-fork of ZF +FROST) rather than Blockstream's `bip-frost-dkg` or jesseposner's +implementation. Chainflip +runs FROST in production at 100-of-150 for cross-chain vault signing +[52], showing FROST scales operationally, but its use is internal +transaction signing rather than external attestation. Babylon EOTS +[53] uses BIP-340 Schnorr but is per-validator (not threshold) and +signs consensus votes, not external data. The only academic proposal +specifically for FROST-as-oracle is *FrostOracle* (Chen et al., IEEE +iThings 2023, [54]), which describes the construction but has no +known implementation. + +A consequence of FROST's round-stateful design is that +nonce-management discipline for repeated signing differs from the +one-shot wallet-ceremony model the existing libraries are scoped to. +Public reference deployments of FROST for high-frequency repeated +signing (such as a heartbeat-driven price update) do not exist, and +the existing audits of ZF FROST and `bip-frost-dkg` cover the +wallet-custody threat model rather than an oracle-shaped one. + +**Shape C — DLC-oracle extension.** A handful of DLC oracle +publishers emit BIP-340 attestations natively. + +Two disqualifiers apply, either of which is sufficient on its own. +First, shape C carries the same in-circuit cost question as shape +D: verifying a DLC attestation requires the guest program to +verify BIP-340 Schnorr in-circuit at unmeasured cost, multiplied +by N (the bit-precision of the numeric DLC encoding). Pursuing +shape C is therefore not the right call unless LEZ later exposes +Schnorr verification to guest programs at acceptable cost. Second, even +with cheap Schnorr verification, the structural fit of the DLC +attestation model is prediction markets and discrete-outcome +contracts (which is what the format was designed for), not +streaming price feeds for DeFi protocols. Either condition alone +moves shape C out of scope for the current oracle work; the +description below documents the ecosystem state for reference and +for a future prediction-market RFP. + +A DLC oracle pre-announces nonce points (R-values) for a future +event with a known maturity time, then at maturity publishes the +s-values that, combined with the pre-committed R-points, yield +BIP-340 Schnorr signatures over a hash of the outcome. The native +cadence is "one attestation per scheduled event," which matches +"did BTC settle above $X on date D" but does not match "what is +BTC/USD right now, updated every 30 seconds." For a continuous +price feed, every update has to be modelled as a scheduled event +in advance, which is an unusual usage pattern relative to what +existing publishers operate. + +#### Two signing conventions in the live ecosystem + +The dlcspecs `Oracle.md` text mandates a tagged SHA-256 +construction with domain `DLC/oracle/announcement/v0` for the +announcement signature and `DLC/oracle/attestation/v0` for the +attestation signature. The live ecosystem does not implement this +uniformly. Two distinct conventions exist, both calling themselves +dlcspecs-compatible: + +- **Plain SHA-256 lineage.** Pythia (DLC Markets) [49], the + P2PDerivatives reference oracle [56], and the rust-dlc reference + verifier all use plain `SHA256(message)` with no tag. Pythia + inherited this from sibyls but removed sibyls' dual-mode support; + rust-dlc's `OracleAnnouncement::validate` and + `OracleAttestation::validate` follow the same plain-SHA-256 path. + Anything verified against this lineage will not verify under a + strict reading of `Oracle.md`. +- **Tagged SHA-256 lineage.** Kormir [57] (active reference + library), Ernest Oracle [58] (which delegates to Kormir), and + Sibyls in `dlc_v0` mode (the `SigningVersion` selected by Lava's + shipped `config/oracle.json` before the operator wound down) use + the tagged construction byte-for-byte per the spec. + +The two lineages produce different signed bytes for the same +underlying message. A LEZ-side verifier consuming attestations +from this ecosystem must either pick a lineage and reject the +other, or maintain both code paths. Choosing the rust-dlc / +plain-SHA-256 path captures the more numerous and more +historically-deployed publishers (Pythia is the only one of those +currently live); choosing the spec-correct tagged path captures +Kormir, Ernest, and any future deployments that follow Kormir's +canonical reference. + +#### State of the live publishers (May 2026) + +- **Pythia (DLC Markets) [49]:** live mainnet, `https://pythia.dlcmarkets.com`, + cron every minute, BTC/USD only, single oracle pubkey, no + rotation, no public attestation index (consumers must already + know the maturity timestamp). Plain SHA-256 lineage. +- **Sibyls (Lava) [50]:** operator dead. `oracle.lava.xyz` returns + 404 (Wayback last-alive 2025-04-14, dead by 2025-11-12). The + `lava-xyz/sibyls` GitHub repo has been deleted; the codebase + exists only on a third-party mirror (`briefgaming/sibyls`) + whose owner is unaffiliated with Lava. Lava itself abandoned + DLCs in late 2025 and went custodial. No surviving Sibyls + operator. +- **P2PDerivatives oracle (Crypto Garage) [56]:** repo dormant + since 2022-05-24. Last historical operator URLs verified dead + (`oracle.10101.finance`, `oracle.lava.xyz`). Library code in + `rust-dlc` continues; the application code is frozen. The only + multi-asset DLC oracle in the survey (BTC/USD plus BTC/JPY) + but not currently published. +- **Kormir [57]:** active library, monthly releases continuing + through March 2026. Live reference deployment at + `kormir.dlcdevkit.com` is dev/test data only. Operator runbook + is minimal (Postgres plus a Nostr nsec key); no bundled price + feed or scheduler. +- **Ernest Oracle [58]:** on hiatus since 2025-06-02. The OpenSats + blog characterises Ernest as a Nostr publisher; the daemon does + not import Nostr in-tree and exposes only an HTTP API on port + 3001 (the Nostr publication path lives in `kormir-server` which + Ernest does not deploy). Implements four Bitcoin chain-metric + attestations (hashrate, fee rate, block fees, difficulty); the + UTXO-size metric mentioned in the announcement post is not in + the source. No public deployment located. Repo is unlicensed + (no LICENSE file, no `license` field in `Cargo.toml`). +- **Magnolia Financial price oracle [59]:** live commercial, + powers Lygos institutional Bitcoin lending. Attestations are + dlcspecs-shaped BIP-340 (per the operator's public statements) + but not publicly retrievable: the documented endpoint + `GET /oracle/events/{eventId}` requires an API key, and there + is no public attestation explorer or relay. Closed source. +- **v0l on Nostr (kind 1009) [60]:** live single-publisher feed. + The signature is BIP-340 native (Nostr's signature scheme) but + the message is `serialised_event_json` per NIP-01 with plain + SHA-256, not the dlcspecs construction. Cannot be reused as a + DLC attestation without the publisher dual-signing. The + successor proposal NIP-1658 defines kinds 31892 / 1892 / 10041, + not kind 1009; kind 1009 is informal and not in the official + NIPs registry. + +#### Numeric DLC verification cost on LEZ + +The numeric DLC encoding signs the outcome bit-by-bit: a price +attested with N-bit precision requires N nonce-point announcements +up front and N independent BIP-340 signatures at maturity, which +the consumer chain verifies in sequence. For 18-bit base-2 +precision (covering integer dollar amounts up to roughly +$262,000; cent granularity for prices in that range would require +27+ binary digits, which is what Pythia's production config uses +at 30 digits), that is 18 single-sig Schnorr verifications per +update on LEZ. As +noted in the Signature Verification Schemes section, BIP-340 +verification is not exposed to guest programs on LEZ, so each of +those 18 verifications runs in-circuit; the per-update cost is +therefore 18× whatever in-circuit BIP-340 + SHA-256 verification +costs in RISC0 (currently unmeasured). If LEZ later exposes +Schnorr verification as a host primitive at low cost, the +multiplier becomes a constant overhead instead of dominating; until +then, shape C inherits the same in-circuit cost question that +shape D's ECDSA path does. + +#### Trust and decentralisation + +Trust is single operator per oracle. DLC's multi-oracle pattern +combines independent attestations via t-of-t adaptor signatures on +the Bitcoin spend path [55]; the LEZ analogue is an aggregator +program that registers K independent BIP-340 publishers and +requires M-of-K agreement within a tolerance window. The +publishers do not coordinate, no DKG is involved, and each +publisher remains a single-key DLC oracle. With Sibyls dead, +P2PDerivatives dormant, Magnolia closed, and Ernest in hiatus, +the realistic candidate set for an LEZ M-of-K federation today is +one (Pythia) plus whatever forks an external builder stands up. + +#### Privacy-asset coverage + +None of the live BIP-340 publishers attest XMR/USD or ZEC/USD. +Pythia's roadmap covers BTC options, not non-BTC pairs. Forking +Pythia or Kormir for additional asset pairs is a few hundred lines +of code (per the deep-research notes for both projects); the +harder constraint is operator obligations (key custody, rotation, +uptime) and pricefeed selection (LN Markets and BitcoinAverage are +BTC-only; Kraken delisted XMR/USD for US users; coverage on +Gate.io and Bitstamp is patchy). + +The cleaner long-term home for shape C is a future prediction- +market RFP, where the discrete-event attestation model is the +native fit and the operational pattern matches what DLC publishers +already run. + +**Shape D — secp256k1 ECDSA on LEZ.** Verify RedStone (or Pyth) +secp256k1 ECDSA + keccak256 signatures on the LEZ side. Two +implementation paths share the same adaptor program shape; only +the verification call site differs. + +**Path D1 (day one): RISC-V in-program verification.** Implement +ECDSA recovery and keccak256 hashing as program code running +inside the RISC0 zkVM, using existing Rust crates (k256 / sha3 / +equivalents) proved by RISC0 along with the rest of the program. +This is what RFP-020 commits to for the public-mode write side. +No runtime change required. The cross-scheme bench +[`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench) +establishes naive in-circuit ECDSA is slow on consumer CPU: +end-to-end private TX time (privacy wrap plus sequencer +roundtrip) for ECDSA secp256k1 at 3-of-N is **7:26** on a +CPU-only AMD Ryzen 9 7940HS (16 threads, no CUDA, no Bonsai), +and no scheme in the four-way matrix (ECDSA secp256k1, Schnorr +secp256k1, ECDSA P-256, Ed25519) lands under 30 s. That rules +out private-execution pull mode under D1 absent a RISC0-specific +signature-verification accelerator or GPU / Bonsai proving. +Public-mode cost remains the open variable RFP-020 measures. +The bench above is a proving-cost benchmark (private-execution +path); the public-mode aggregator does no proving, so its +write-side cost is in LEZ runtime compute units rather than +proof time and is not captured by these numbers. Real LEZ +devnet measurement of the aggregator's compute-unit cost is +what RFP-020 commits to. Public-mode cost amortises across all +downstream reads, so a write-side cost that would be unworkable +per-private-transaction may still be acceptable per heartbeat. + +For reference, the bench's per-signature user-cycle deltas +(N=1, sub-noop) and end-to-end private-TX rankings at 3-of-N: + +| Scheme | user cycles / sig (N=1) | E2E private TX (3-of-N) | +|---|---:|---:| +| ECDSA P-256 | 198 K | 4:58 | +| Schnorr secp256k1 | 271 K | 5:22 | +| ECDSA secp256k1 | 303 K | 7:26 | +| Ed25519 | 803 K | 11:09 | + +P-256 is roughly 32% cheaper per-sig than secp256k1 ECDSA in +this stack (sha256 prehash vs keccak256 dominates the gap). +Schnorr secp256k1 is roughly 9% cheaper than ECDSA secp256k1 on +the same precompile path. Ed25519 is the most expensive of the +four, despite curve25519-dalek's accelerated RISC0 backend, +because Edwards arithmetic plus the in-algorithm sha512 (no +zkVM precompile) dominates. These per-sig deltas matter for any +future "private-mode-friendly upstream" follow-on; they do not +change the day-one D1 picture, which is gated by +private-execution pull being infeasible at every scheme on CPU. + +Caveats: synthetic same-message fixtures, no batch-verify +shortcuts, and the bench is an AI-assisted research repository +explicitly not intended for mainnet. The numbers are +order-of-magnitude indicators; production LEZ measurement is +RFP-020 Deliverable D1. + +**Path D2 (cost-conditional follow-on): an accelerated precompile +or host function in public-execution mode.** Triggered only if D1 +is too expensive at the push-mode aggregator's production cadence. +A precompile lives outside the ZK proof boundary, so a public-mode +program calls it as native code. The upstream cost reference +points are approximately 6,690 CU per recovery on Solana +[24][25] and an end-to-end RedStone EVM update in the 50K to 100K +gas range [3]; LEZ public-mode cost via a precompile would track +the lower of these two on a constant-overhead basis [22][29]. D2 +is the optimisation path, not a precondition. + +#### Public-mode aggregator design (applies to both D1 and D2) + +The adaptor runs in public execution: the verifier executes once +per update on the write side, and the verified price plus +timestamp land in a public price account. Private-execution +programs compose by reading the public account, not by carrying +signed payloads inline. This is push mode. The reasoning for +preferring it differs slightly between D1 and D2, but the +end-state design is identical. + +Under D1, in-program verification is technically reachable from +private execution (the same RISC-V code can run inside a user's +private proof), but bench data +([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)) +puts end-to-end private TX time at 7:26 for ECDSA secp256k1 at +3-of-N on a CPU-only Ryzen 9 7940HS, with no scheme in the +four-way matrix landing under 30 s. That makes private-execution +pull mode infeasible in practice on consumer CPU, not merely +expensive, absent a RISC0-specific signature-verification +accelerator or GPU / Bonsai proving. Push mode amortises the +cost once across all downstream reads on the public-mode write +side instead. + +Under D2, the asymmetry becomes structural rather than economic. +A precompile is unreachable from private execution: anything in a +private transaction has to be expressible inside the RISC-V zkVM +circuit, and a host function lives outside it. Private execution +that wants to verify a secp256k1 signature would have to either +(a) verify in the privacy circuit (forfeits batching, pays +unmeasured RISC0 EC cost, defeats the precompile's purpose), or +(b) place the signature in the transaction's journal and break +privacy. Neither option preserves both efficiency and privacy. So +under D2 push mode is not a preference but the only design that +works. + +In both cases, push mode is the right choice. Under D1 the +amortisation argument carries it; under D2 the structural +argument forces it. The aggregator program is the same either +way, which is what makes D2 a localised swap-in for D1 if cost +forces the upgrade. + +Pull-mode reads are therefore deliberately out of scope: + +- **Pull mode from public execution under D1.** Technically + possible (the in-program verifier can be called from a public + consumer's transaction), but it pays full proving cost per + consumer transaction with no amortisation, which is strictly + worse than reading the push-mode aggregator's public price + account. Excluded by design. +- **Pull mode from private execution under D1.** Possible at + a heavy proving-cost penalty for every private transaction. + Excluded by design. +- **Pull mode from public execution under D2.** Available (a + public consumer can carry a signed payload and call the + precompile inline), but offers no benefit over reading the + push-mode aggregator's public price account. Out of scope. +- **Pull mode from private execution under D2.** Structurally + unavailable (precompile cannot be called from inside the + privacy circuit). Out of scope. + +A clarification on the demand side. The framing above treats +private-execution pull mode as a desirable capability that the +current paths foreclose; whether any consumer protocol on LEZ +actually needs it is a separate question, and not one that has +been settled. Some consuming protocols already have design +reasons to keep specific actions in public transactions: the +LSC stablecoin in +[RFP-013](../RFPs/RFP-013-reflexive-stablecoin-protocol.md), for +example, places parts of its flow in public execution for +constraints unrelated to oracle access, so a private-execution +pull path would not change how the stablecoin reads prices for +those actions. A future follow-on RFP that proposes either a +RISC0-friendly upstream signature scheme or any other route to +private-execution pull should therefore start by establishing +that some downstream consumer genuinely needs the capability, +not just by selecting a primitive that admits cheaper in-circuit +verification. + +#### Broader open issues with adding a secp256k1 primitive (path D2 only) + +Beyond the oracle adaptor, the broader question of "what does a +secp256k1 primitive in LEZ unlock" has open design issues that +LEZ runtime developers have flagged but not resolved. The Solana +precompile's main published use case is letting Ethereum users +authorise transactions on Solana with their existing Ethereum +keys; mapping that flow to LEZ raises additional questions: + +- **Nullifier tracking.** Replay protection for secp256k1 + signatures used in either public or privacy execution requires + tracking nullifiers so the same signature cannot be reused. +- **Privacy-circuit branching.** Supporting private accounts + authorised by an Ethereum signature (rather than the LEZ-native + `nsk`) requires branching logic in the privacy circuit. +- **Account-identifier flow.** A recent LEZ change introduces + identifiers that let one private-key set support multiple + private accounts, with maintenance and recovery encrypted under + the viewing public key. Identifiers are not currently supported + for public accounts (each public account requires a fresh key + set), so an Ethereum-signed public-account flow would imply + fresh Ethereum accounts per use, and Ethereum-signed private + accounts would require LEZ-specific wallet support to handle the + identifier flow. + +These issues are not blockers for the narrow oracle-adaptor use of +the precompile (push-mode aggregator writing a public price +account), but they are part of why the LEZ runtime team is not +currently championing a precompile addition: the cost is real, the +in-circuit elliptic-curve performance is unmeasured, and the +compelling-use-case story beyond oracle adaptors is not yet +established. If RFP-020's cost measurement triggers a follow-on +RFP for path D2, that follow-on should be scoped on the assumption +that the precompile is bespoke runtime work that has to be argued +for, not a small extension that is already on the LEZ roadmap. + +For private-account composability with off-chain price data, push +mode is therefore the structural design under both D1 and D2. +The pull-vs-push analysis below frames the same point in terms of +the upstream RedStone / Pyth dichotomy. + +#### Push mode is preferable to pull mode on LEZ + +RedStone supports both pull (signed payload attached to consumer +calldata) and push (a relayer submits signed updates to an +aggregator contract on a heartbeat or deviation trigger). On LEZ +the push model is the better fit: + +- **Verification cost is paid once per update, not once per + read.** The aggregator program recovers signatures and checks + the unique-signer threshold on write, then stores the latest + price and timestamp in a public account. Consumers just read + the slot. The single write-side cost amortises across all + downstream reads instead of being paid by every consuming + transaction. +- **Composes cleanly with private accounts.** A private account + reads a public price-feed account's slot the same way it reads + any other shared public state. Pull mode is the awkward case: + the consumer's transaction must carry the signed payload in + calldata, coupling oracle data into the private execution path + and making both signature recovery and payload handling part of + the private workload. Under D1 this is technically reachable + but pays the full in-circuit ECDSA cost in every private + consumer's proof; under D2 it is structurally unavailable + because the precompile cannot be called from inside the privacy + circuit. Either way push mode is strictly better for private + consumers. +- **Update cadence is a tunable parameter.** Heartbeat plus + deviation threshold trade cost against freshness. For a TWAP + oracle this is acceptable because the consumer is already + smoothing; pull mode's "fresh at transaction time" guarantee + is not required. + +Tradeoffs: push mode requires someone to operate the relayer +(RedStone runs the pusher for their existing push deployments; a +sovereign LEZ deployment would rely on RedStone's relayer or run +its own), and the aggregator program still has to perform +secp256k1 recovery and keccak256 hashing on the write side. Under +D1 that path is RISC-V program code; under D2 it is a precompile +call. The write-side cost per update differs between the two but +the design shape does not. + +There is one freshness pattern that is unusual to LEZ and worth +calling out: a user who needs a price fresher than the +heartbeat's last update can submit a **public transaction that +pushes a fresh signed payload to the aggregator account**, and +then submit a **private transaction immediately afterwards that +reads the just-updated public price**. The verification cost is +paid in the public transaction (where it is cheaper, especially +under D2 where the precompile is callable), and the private +transaction does no signature work at all, just reads a slot. +This pattern is uninteresting on chains without a public / private +execution split because it collapses to ordinary pull mode, but on +LEZ it captures pull mode's "fresh at transaction time" property +without paying the in-circuit cost in the privacy proof. Cost is +borne by the consumer, in the public path, once per private +action that needs a guaranteed-fresh price. The aggregator program +already accommodates this: any caller can submit a valid signed +payload and the program writes if signatures and timestamps check +out. + +A useful corollary: this enables a **consumer-pays push variant** +that does not require a dedicated relayer at all. Users push when +they need a fresh price, paying the verification cost themselves +in the public path; idle periods incur zero update cost; the +aggregator only advances when someone actually needs it. This is +operationally pull (consumer-pays, on-demand) but structurally +push (the program owns the public price account that downstream +private consumers read from). Whether to run a heartbeat relayer +in addition is a deployment-time choice: a heartbeat keeps the +slot warm for protocols that read it without first pushing +themselves; consumer-pays push keeps the cost model strictly +proportional to demand. Both can coexist; the program logic does +not distinguish between them. + +#### How this differs from "put the signature in the journal" + +The two-transaction split (public push, then private read) is +not the same as embedding the upstream signature in the +private transaction's journal. The differences matter: + +- **Two distinct transactions, not one.** The signature is + carried only in the public push transaction. The private + transaction reads the resulting public price account by + address, with no upstream signature in its calldata or + journal. The private transaction's *contents* (which assets, + which counterparty, which amount) remain private; only the + fact that some price update happened is observable, and + that fact is observable for any push regardless of who + submitted it. +- **Fits the existing aggregator design.** The aggregator + program already accepts signed payloads from any caller and + writes a public price account; that is its normal write + path. Consumer-pays push exercises this path from an + end-user wallet rather than from a dedicated relayer. No + new program logic. +- **Linkability risk to clarify, not to wave away.** An + observer can correlate "wallet X pushes a price update at + time T" with "private transaction at time T plus epsilon" + and infer that the same actor is consuming the just-pushed + price. Strength of the inference depends on push frequency + and the consumer's wallet hygiene. Mitigations are + consumer-side, not adaptor-side: push from a separate + funding wallet from the one used in the private + transaction, time-shift the push and consume across enough + blocks that timing correlation weakens, or rely on a + heartbeat relayer so that single-purpose pushes are not the + observable pattern. None of these are guaranteed by the + aggregator program; they are choices the consumer protocol + or end user makes. + +The privacy story is therefore strictly better than +journal-disclosed signatures (the private transaction's body +stays private) but not equivalent to a heartbeat-only push +model (timing-correlation linkability remains). Whether the +residual linkability is acceptable is a consumer-side +production-security decision, the same way any DEX-routing or +liquidity-management decision is. + +RedStone is the simpler day-one option for the upstream-source +side because it carries no bridge dependency. Pyth depends on the +full 13-of-19 VAA verification plus Merkle proof verification, +though it amortises across many feeds per transaction after the +Perseus upgrade [26]. Neither requires threshold or aggregate +schemes (BLS, Schnorr) on the *upstream* side, so the crypto +surface required by shape D is limited to secp256k1 ECDSA +recovery with keccak256 hashing — implemented in-program under D1 +(no runtime change) and exposed as a precompile under D2 (cost- +conditional follow-on). + +## Production Oracle Architectures + +Major lending and borrowing protocols have converged on multi-source +oracle designs with fallback mechanisms. These production patterns +inform the requirements and design rationale of RFP-019. + +### Aave V3 + +Aave V3's `AaveOracle` contract uses Chainlink aggregators as the +primary price source via `getAssetPrice()`. Each asset is mapped to a +Chainlink feed through `setAssetSources()`. If the Chainlink feed +returns a price <= 0, the call is forwarded to a configurable fallback +oracle via `getFallbackOracle()` [15]. On Layer 2 deployments, the +`PriceOracleSentinel` contract monitors sequencer uptime: if the L2 +sequencer goes down, borrowing is disabled and liquidations are paused +for a configurable grace period (`setGracePeriod()`), giving users +time to restore position health after an outage [15]. Aave does not +use TWAP as a primary or secondary price source; it relies entirely +on Chainlink feeds with governance-managed fallback. + +### Compound V2 and V3 + +Compound V2's `UniswapAnchoredView` contract implemented a two-source +design: Coinbase as the primary reporter, anchored against a Uniswap +V2 TWAP. If the Coinbase price diverged beyond 20% of the TWAP +anchor, the price was rejected and the system retained the last valid +price [16]. This is the closest production precedent to RFP-019's +circuit breaker design. On 26 November 2020, a DAI price spike to +$1.30 on Coinbase triggered approximately $89M in liquidations; +the TWAP anchor limited the damage by rejecting the most extreme +prices, but the 20% tolerance was too wide to prevent all +mispricing [16]. Compound V3 (Comet) dropped the TWAP anchor entirely +and uses Chainlink feeds directly via `AggregatorV3Interface`, with +only zero-value validation; some markets use derived-asset price +wrappers (e.g. wstETH/ETH multiplied by ETH/USD) but these are +conversion adaptors, not bounds-checking circuit breakers [16]. + +### MakerDAO / Sky + +MakerDAO's oracle pipeline has two layers: the Median contract +(aggregates prices from multiple whitelisted feed providers) and +the Oracle Security Module (OSM), which imposes a mandatory one-hour +delay before new prices take effect in the system [15a]. The delay +is a circuit breaker by design: it gives governance one hour to +detect and respond to oracle manipulation before the system acts on +a compromised price. Emergency responses include calling `stop()` +to freeze the OSM or triggering Emergency Shutdown. MakerDAO does +not use Uniswap TWAP. Chronicle Protocol evolved from MakerDAO's +internal oracle infrastructure, using Schnorr signature aggregation +to consolidate validator signatures into a single "super signature," +achieving constant-time verification at approximately 52K gas +regardless of the number of validators [15b]. + +### Liquity V2 + +Liquity V2 explicitly rejected Uniswap V3 TWAP as a primary or +fallback source due to liquidity migration risk (uncertainty about +whether v3 liquidity would persist after the Uniswap v4 launch) +[18]. Instead, Liquity V2 uses Chainlink as the primary oracle (composing multiple +Chainlink feeds for LST collateral, e.g. ETH/USD combined with an +LST market-rate feed) with a simple fallback: if the primary feed +is frozen for more than 12 hours or returns bad data, the system +falls back to a secondary oracle (once, with no cascading). Liquity V2 explicitly prefers +this simple fallback over complex circuit breaker designs (e.g. +Gyroscope's pause-on-divergence model), reasoning that pausing +operations requires human intervention to set a new oracle and +unpause, which conflicts with their immutability goals [18]. The design prioritises automation: simple +trigger conditions, single fallback, no manual intervention required. + +### Common patterns + +| Protocol | Primary | Secondary / fallback | Circuit breaker | TWAP role | +|----------|---------|---------------------|-----------------|-----------| +| Aave V3 | Chainlink | Governance-set fallback | PriceOracleSentinel (L2 sequencer) | None | +| Compound V2 | Coinbase reporter | Last valid price | 20% TWAP anchor tolerance | Anchor / sanity check | +| Compound V3 | Chainlink | None (governance pauses) | Zero-value check only | None | +| MakerDAO | Median (multi-feed) | Emergency Shutdown | 1-hour OSM delay | None | +| Liquity V2 | Chainlink | Simple fallback (one hop) | None (by design) | Rejected | + +Two patterns emerge. First, most major lending protocols use at +least two tiers of price validation (Aave, MakerDAO, Liquity V2, +Compound V2): cross-check, delay, or fallback. Compound V3 is the +notable exception, relying on Chainlink with only zero-value +validation and governance-managed pause as its safety net. Second, +TWAP serves as an anchor or sanity check in the protocols that use +it (Compound V2), never as the sole price source for lending. These +patterns motivate RFP-019's two-tier architecture (on-chain TWAP + +external feeds) and circuit breaker design as a defence-in-depth +choice rather than a universal industry default. + +## Privacy-Asset Feed Availability + +LEZ's privacy focus likely makes XMR/USD and ZEC/USD first-class +pricing requirements. On-chain TWAP cannot supply these prices: no +wrapped XMR or ZEC token has sufficient DEX liquidity (low five to +six figures across all surveyed pools on Ethereum and Solana) for a +manipulation-resistant TWAP, so an off-chain feed is the only viable +path on day one. Coverage across the surveyed oracles is summarised +below. + +| Oracle | XMR/USD | ZEC/USD | Self-serve on LEZ? | +|--------|---------|---------|--------------------| +| Chainlink (push) | Active on Optimism (1,200s heartbeat, 0.2% deviation) and Polygon (24h, 1%) [39] | Active on Ethereum (24h, 2%) and Polygon (24h, 1%) [40] | No: permissioned onboarding | +| Chainlink Data Streams | 43+ chains, subscription-gated [39] | 35+ chains, subscription-gated [40] | No: paid product | +| Pyth (pull) | `crypto-xmr-usd`, multiple publishers across both Pyth clusters; live count at [41] | `crypto-zec-usd`, multiple publishers; live count at [41] | Yes, once Wormhole endpoint and the Pyth receiver are deployed | +| RedStone (pull) | Listed; data feed ID `XMR` [42] | Listed; data feed ID `ZEC` [42] | Yes once shape D1 or D2 lands per RFP-020 (LEZ-side ECDSA + keccak verification path); no bridge dependency on the upstream side, no per-chain RedStone team engagement | +| DIA / Lumina | Production-ready (MAIR aggregation, 120s, announced January 2026) [43] | Available (MAIR, 120s) [43] | Yes via Lumina; bespoke deployment per chain | +| Supra | XMR_USDT, 195 sources (Standard tier) [44] | ZEC_USDT, 60 sources (Premium tier) [44] | No: requires Supra team engagement | +| Chronicle | Not in public feed catalogue | Not in public feed catalogue | N/A | +| API3 | Not found | Not found | N/A | +| Switchboard | Not found | Not found | Permissionless feed creation supported but no XMR or ZEC feed currently exists | + +## LEZ Bootstrap Strategy + +### Phase 1: Genesis (no TVL) + +Deploy RedStone pull oracle contract (no bridge dependency) and, if +Wormhole is available, the Pyth EVM receiver contract. This provides +400 to 1,500+ price feeds immediately with zero per-chain oracle node +infrastructure [3][5]. RedStone is the practical day-one oracle +because it requires no cross-chain bridge; Pyth is conditional on +Wormhole integration [8]. + +### Phase 2: Early growth (first DEX, some TVL) + +Once RFP-004 (DEX) is live, deploy the on-chain TWAP oracle as a +supplementary data source. At this stage, TWAP should be used only +as a sanity check (circuit breaker comparison against external feeds), +not as a primary price source, because pool liquidity will be +insufficient for manipulation resistance [10]. + +Engage Switchboard for core EVM contract deployment (TEE security, +permissionless custom feeds). Consider DIA Lumina as a permissionless +fallback for assets not covered by Pyth or RedStone [7]. + +### Phase 3: Maturity (significant TVL) + +As DEX pools grow beyond $50M to $100M in depth, on-chain TWAP +becomes a viable secondary price source for lending and liquidation +use cases. At this stage, multi-source aggregation (median of TWAP + +Pyth + RedStone) provides the highest reliability [6]. + +Engage Chainlink for official DON deployment once LEZ meets +infrastructure requirements (3+ independent RPC providers, sufficient +TVL, dedicated node operators). Treat Chainlink as a 12 to 24 month +post-launch milestone [4][8]. + +### Graduation path + +The TWAP tier's role evolves with liquidity: + +| Pool depth | TWAP role | Recommended window | +|------------|-----------|-------------------| +| < $1M | Not usable (manipulation trivially cheap) | N/A | +| $1M to $10M | Sanity check only (circuit breaker) | 2 to 12 h | +| $10M to $50M | Secondary source (median with external) | 30 min to 2 h | +| > $50M | Co-primary source alongside external feeds | 30 min to 1 h | + +## References + +1. DefiLlama, "Oracles" dashboard, accessed Q1 2026. + https://defillama.com/oracles +2. Mitosis University, "Which Oracle Powers What," 2025. + https://university.mitosis.org/chainlink-pyth-redstone-chronicle-supra-switchboard-which-oracle-powers-what/ +3. RedStone, "Blockchain Oracles Comparison: Chainlink vs Pyth vs + RedStone 2025," Jan 2025. + https://blog.redstone.finance/2025/01/16/blockchain-oracles-comparison-chainlink-vs-pyth-vs-redstone-2025/ +4. Chainlink, "Network Integration Requirements." + https://docs.chain.link/resources/network-integration +5. Bai et al., "Ormer: A Manipulation-Resistant and Gas-Efficient + Blockchain Oracle Scheme," arXiv:2410.07893v2, Oct 2024. + https://arxiv.org/html/2410.07893v2 +6. ChainSecurity, "Oracle Manipulation After The Merge," 2022. + https://www.chainsecurity.com/blog/oracle-manipulation-after-merge +7. DIA, "Lumina" documentation, accessed 2026. + https://www.diadata.org/lumina/ +8. Pyth Network, "Cross-Chain Delivery" documentation. + https://docs.pyth.network/price-feeds/core/how-pyth-works/cross-chain +9. Uniswap, "Oracle" (v3 protocol concepts). + https://docs.uniswap.org/concepts/protocol/oracle +10. Uniswap Labs, "Uniswap v3 Oracles" (PoS analysis), 2022. + https://blog.uniswap.org/uniswap-v3-oracles +11. SmartContent, "TWAP Oracles vs Chainlink Price Feeds: A + Comparative Analysis." + https://smartcontentpublication.medium.com/twap-oracles-vs-chainlink-price-feeds-a-comparative-analysis-8155a3483cbd +12. Chainlink, "Off-Chain Reporting" documentation. + https://docs.chain.link/architecture-overview/off-chain-reporting +13. Switchboard, "Protocol" documentation. + https://docs.switchboard.xyz/how-it-works/switchboard-protocol +14. Uniswap, "Oracles" (v2 protocol concepts). + https://docs.uniswap.org/contracts/v2/concepts/core-concepts/oracles +15. Aave, "Oracles" (v3 smart contracts documentation). + https://aave.com/docs/aave-v3/smart-contracts/oracles +15a. MakerDAO, "Oracle Security Module (OSM)" documentation. + https://docs.makerdao.com/smart-contract-modules/oracle-module/oracle-security-module-osm-detailed-documentation +15b. Chronicle Labs, "Understanding Chronicle" documentation. + https://docs.chroniclelabs.org/understandingChronicle +16. Compound Finance, "Price Feed" documentation. + https://compound.finance/docs/prices +17. RedStone, "Blockchain Oracles Comparison: Chainlink vs Pyth vs + RedStone 2026," Mar 2026. + https://blog.redstone.finance/2026/03/30/blockchain-oracles-comparison-chainlink-vs-pyth-vs-redstone-2026/ +18. Liquity, "The Oracle Conundrum," 2023. + https://www.liquity.org/blog/the-oracle-conundrum +19. Wormhole, "VAAs (Verifiable Action Approvals)" documentation, + accessed Apr 2026. + https://wormhole.com/docs/protocol/infrastructure/vaas/ +20. Wormhole, "Guardians" documentation, accessed Apr 2026. + https://wormhole.com/docs/protocol/infrastructure/guardians/ +21. Wormhole, "Security" documentation, accessed Apr 2026. + https://wormhole.com/docs/protocol/security/ +22. Sec3, "How Do Cross-Chain Bridges Work? A Case on Wormhole + (Part 2)," 2022. + https://www.sec3.dev/blog/bridges2 +23. Ethereum, "Precompiled Contracts" (ECRECOVER at address 0x01, + base cost 3,000 gas). + https://www.evm.codes/precompiled +24. Solana Labs, "block_cost_limits.rs" (secp256k1 verification + compute units). + https://github.com/solana-labs/solana/blob/master/cost-model/src/block_cost_limits.rs +25. Solana Foundation, "Fee Structure" (Ed25519, Secp256k1, + Secp256r1 precompile programs). + https://solana.com/docs/core/fees/fee-structure +26. Pyth Network, "Perseus Network Upgrade" blog post, 2025. + https://www.pyth.network/blog/perseus-network-upgrade +27. Wormhole, "Boundless Partners with Wormhole to Launch ZK + Network Powered by RISC Zero," 2025. + https://wormhole.com/blog/boundless-partners-with-wormhole-to-launch-zk-network-powered-by-risc-zero +28. RedStone, "How Data Flows to the Blockchain" architecture + documentation, accessed Apr 2026. + https://docs.redstone.finance/docs/architecture/ +29. RedStone, "rust-sdk" repository (crates/redstone, including + crypto/mod.rs and Cargo.toml dependencies on secp256k1 and + k256). + https://github.com/redstone-finance/rust-sdk +30. RedStone, "redstone-oracles-monorepo" EVM connector + (RedstoneConsumerBase.sol, getUniqueSignersThreshold, + SignatureLib.recoverSignerAddress). + https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/evm-connector/contracts/core/RedstoneConsumerBase.sol +31. Sui Documentation, "Module sui::ecdsa_k1" + (secp256k1_ecrecover Move builtin). + https://docs.sui.io/references/framework/sui_sui/ecdsa_k1 +32. Stellar, `rs-soroban-env` budget metering calibration table + (`RecoverEcdsaSecp256k1Key` const cost 2,315,295 CPU + instructions). CAP-0051 ("Smart Contract Host Functionality") + defines the host function; the calibrated cost is in the + `rs-soroban-env` test fixture below. + https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/test/budget_metering.rs + https://github.com/stellar/stellar-protocol/blob/master/core/cap-0051.md +33. Veridise, "RedStone Stellar Connector" security assessment, + Oct 2025. + https://veridise.com/wp-content/uploads/2025/10/VAR-Redstone-251006-Oracles-SDK-V2.pdf +34. RedStone, "redstone-oracles-monorepo" Fuel connector + (Sway contract adapter). + https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/fuel-connector/README.md +35. RedStone, "RedStone Brings Secure, Gas-Efficient Oracle + Solutions to Radix DeFi Ecosystem," Jun 2025. + https://blog.redstone.finance/2025/06/12/redstone-brings-secure-gas-efficient-oracle-solutions-to-radix-defi-ecosystem/ +36. RedStone, "redstone-oracles-monorepo" Stellar connector + DeployingFeed.md (Stellar account key uses Ed25519-curve; + refers to deployer key, not RedStone signing scheme). + https://github.com/redstone-finance/redstone-oracles-monorepo/blob/570006fccf0f919ad9722d11914dd0bc1c5b136d/packages/stellar-connector/DeployingFeed.md +37. CoinDesk, "Bitcoin Flash Crashed to $5K on Pyth Network's Data + Feed," Sep 2021. + https://www.coindesk.com/markets/2021/09/22/bitcoin-flash-crashes-to-5k-on-pyth-networks-data-feed +38. Morpho governance forum, "PYTH CBETH price feed is easily + manipulated, resulted in me losing $33,000," Mar 2025. + https://forum.morpho.org/t/pyth-cbeth-price-feed-is-easily-manipulated-resulted-in-me-losing-33000/1577 +39. Chainlink, XMR/USD price feeds: Optimism Mainnet + (`0x2a8D91686A048E98e6CCF1A89E82f40D14312672`) and Polygon + Mainnet (`0xBE6FB0AB6302B693368D0E9001fAF77ecc6571db`); Data + Streams XMR/USD-RefPrice product on 43+ chains. + https://data.chain.link/feeds/optimism/mainnet/xmr-usd + https://data.chain.link/feeds/polygon/mainnet/xmr-usd + https://data.chain.link/streams/xmr-usd-cexprice-streams +40. Chainlink, ZEC/USD price feeds: Ethereum Mainnet + (`0x3f929667bdf783b99274F10465a89d6aF772736E`) and Polygon + Mainnet (`0xBC08c639e579a391C4228F20d0C29d0690092DF0`); Data + Streams ZEC/USD-RefPrice product on 35+ chains. + https://data.chain.link/ethereum/mainnet/crypto-usd/zec-usd + https://data.chain.link/feeds/polygon/mainnet/zec-usd + https://data.chain.link/streams/zec-usd-cexprice-streams +41. Pyth Network, legacy price feeds dashboard + (`crypto-xmr-usd`, `crypto-zec-usd`). + https://insights.pyth.network/legacy-price-feeds/crypto-xmr-usd + https://insights.pyth.network/legacy-price-feeds/crypto-zec-usd +42. RedStone, "ALL_SUPPORTED_TOKENS" registry (XMR and ZEC listed). + https://github.com/redstone-finance/redstone-api/blob/main/docs/ALL_SUPPORTED_TOKENS.md +43. DIA, asset price index (XMR and ZEC). + https://www.diadata.org/app/price/asset/Monero/0x0000000000000000000000000000000000000000/ + https://www.diadata.org/app/price/asset/Zcash/0x0000000000000000000000000000000000000000/ +44. Supra, "Data Feeds Index" (XMR_USDT, ZEC_USDT). + https://docs.supra.com/oracles/data-feeds/data-feeds-index +45. Zcash Foundation, FROST (Flexible Round-Optimised Schnorr + Threshold) reference implementation and documentation. + https://frost.zfnd.org/ +46. Blockstream Research, `bip-frost-dkg` (FROST distributed key + generation, BIP-340 compatible). + https://github.com/BlockstreamResearch/bip-frost-dkg +47. Frostsnap, hardware-wallet stack using secp256kfun for FROST + threshold Schnorr. + https://github.com/frostsnap/frostsnap +48. Jesse Posner, `FROST-BIP340` (reference implementation of + FROST emitting BIP-340-verifiable signatures). + https://github.com/jesseposner/FROST-BIP340 +49. DLC Markets, "DLC Markets open-sources its oracle Pythia," + May 2025; Pythia source. + https://blog.dlcmarkets.com/dlc-markets-open-sources-its-oracle-pythia/ + https://github.com/dlc-markets/pythia +50. Lava, `sibyls` (DLC oracle implementing BIP-340 attestation + over numeric outcomes). URL no longer resolves as of 2026-05; + see body discussion at "State of the live publishers" for + operator and repo status. Third-party mirror at + `briefgaming/sibyls` (unaffiliated). + https://github.com/lava-xyz/sibyls +51. iBTC Network (formerly DLC.Link / dlcBTC), technical stack + documentation describing the attestor federation (10-of-15 on + EVM, 7-of-10 on Canton). Companion FROST blog post URL no + longer resolves as of 2026-05; tech-stack page remains live. + https://docs.dlc.link/tech-stack + https://www.ibtc.network/blog/frost-at-dlc-link-pioneering-advanced-security-for-dlcs +52. Chainflip, "FROST Signature Scheme" protocol documentation + (100-of-150 threshold for cross-chain vault signing). + https://docs.chainflip.io/protocol/frost-signature-scheme +53. Babylon Labs, "EOTS Manager" architecture documentation + (per-validator BIP-340 Schnorr finality voting; not threshold). + https://docs.babylonlabs.io/guides/architecture/btc_staking_program/eots_manager/ +54. Chen et al., "FrostOracle: A Novel and Efficient Blockchain + Oracle Scheme Based on Threshold Signature," IEEE iThings/ + CPSCom 2023. + https://ieeexplore.ieee.org/document/10501857/ +55. Discreet Log Contracts specifications, "MultiOracle.md" + (combining independent oracle attestations via t-of-t + adaptor signatures). + https://github.com/discreetlogcontracts/dlcspecs/blob/master/MultiOracle.md +56. P2PDerivatives / Crypto Garage, `p2pderivatives-oracle` + reference DLC oracle (Go; signs BTC/USD and BTC/JPY; repo + last commit 2022-05-24). + https://github.com/p2pderivatives/p2pderivatives-oracle +57. Kormir, reference Rust DLC oracle library + (`bennyhodl/dlcdevkit/kormir`; tagged SHA-256 per dlcspecs; + monthly releases through March 2026). + https://github.com/bennyhodl/dlcdevkit +58. Ernest Oracle (`ernest-money/ernest-oracle`); Bitcoin + chain-metric DLC oracle delegating to Kormir; HTTP-only, + no Nostr publication in-tree; on hiatus since 2025-06-02. + https://github.com/ernest-money/ernest-oracle +59. Magnolia Financial Services, "Oracles" product page; + commercial DLC oracle powering Lygos, attestations gated + behind API key. + https://magnolia.financial/oracles/ +60. NIP-1658, asset price publishing on Nostr (proposed kinds + 31892 / 1892 / 10041); kind 1009 is informal and not in + the official NIPs registry. + https://github.com/nostr-protocol/nips/pull/1658 +61. Uniswap, "v4 Truncated Oracle Hook" blog post. + https://blog.uniswap.org/uniswap-v4-truncated-oracle-hook +62. Pyth Network Documentation, "Hermes API Instances and + Providers" (public endpoint at hermes.pyth.network, 20 req / + 10 s rate limit, third-party node providers Triton, P2P, + extrnode, Liquify). + https://docs.pyth.network/price-feeds/core/api-instances-and-providers/hermes +63. RedStone SDK, hardcoded DDL gateway URLs (`oracle-gateway-1.a. + redstone.finance`, `oracle-gateway-2.a.redstone.finance`, + `.vip` GCP mirror). + https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/sdk/src/data-services-urls.ts +64. RedStone Documentation, "Standardized Access for DeFi + Interoperability" (Push model; permissionless relayer service). + https://docs.redstone.finance/docs/dapps/redstone-push/ +65. RedStone blog, "RedStone on Monad: The Real-Time Data Layer + for High-Speed DeFi," 27 Nov 2025. + https://blog.redstone.finance/2025/11/27/redstone-on-monad-the-real-time-data-layer-for-high-speed-defi/ diff --git a/appendix/oracle-ift-research-slides.md b/appendix/oracle-ift-research-slides.md new file mode 100644 index 0000000..df7aabf --- /dev/null +++ b/appendix/oracle-ift-research-slides.md @@ -0,0 +1,515 @@ +--- +title: "Oracles on LEZ — TWAP and Off-Chain Adaptors" +description: "Talk-track for RFP-019 + RFP-020" +tags: [presentation, oracles, lez, rfp] +slideOptions: + theme: white + transition: fade + slideNumber: true +--- + +# Oracles on LEZ +### TWAP and Off-Chain Adaptors + +RFP-019 + RFP-020 + +Note: +Open with: oracles are the missing infrastructure piece for DeFi on LEZ. Lending is specced (RFP-008) and the stablecoin is specced (RFP-013); neither works without a price feed. The DEX is specced (RFP-004) and does its own price discovery from pool state, so it doesn't consume an external feed for swaps, but the on-chain TWAP tier in RFP-019 reads its pool accumulators, so the DEX is upstream of part of the oracle work rather than a consumer of it. We're filling the price-feed gap with two RFPs. + +--- + +# What is an oracle? + +A program that brings off-chain data on-chain. + +For DeFi, that almost always means a **price feed**. + +Note: +Plain definition first. Smart contracts can't reach out to coingecko or a CEX themselves; they can only read state that's already on-chain. An oracle is the bridge: someone off-chain looks up the price, signs it, posts it on-chain, and the contract reads it. + +Concrete example: Aave needs to know what 1 ETH is worth in USD to decide if a borrower's position is underwater. That number doesn't exist on-chain natively — it has to be fed in. + +There are non-price oracles too (weather, sports scores, randomness) but ~99% of production oracle infrastructure today is price feeds. + +--- + +# Why DeFi needs them + +- **Lending** — collateral valuation, liquidation triggers +- **Stablecoins** — peg maintenance, redemption pricing +- **Derivatives** — settlement, mark-to-market +- **Liquidations** — when to act + +Note: +Walk through each one. The constant: every protocol that has to know "what is this thing worth in dollars" needs an oracle. DEXes are the exception — AMMs do their own price discovery from pool state — but every protocol that *consumes* that price for solvency or settlement decisions needs an oracle. + +For LEZ specifically: RFP-008 (lending) and RFP-013 (stablecoin) cannot ship without a price oracle. That's why this is the priority infra unlock. + +Anchor stat: 36 documented flash-loan oracle attacks have caused $418M in cumulative DeFi losses. Bad oracles aren't just an inconvenience — they are the single biggest historical attack surface. + +--- + +# Two kinds of oracle + +| | **On-chain** | **Off-chain** | +| -------------- | ------------------- | ----------------------------- | +| Source | DEX pool state | external publishers | +| Trust | math + liquidity | signer set | +| Day-one viable | needs deep pools | needs only verifier program | +| Coverage | only on-chain pairs | any asset (other chain) or event | + +Note: +This is the core dichotomy. Not strict — there are hybrids — but useful for explaining tradeoffs. + +On-chain: the canonical example is Uniswap V3's TWAP. The DEX itself stores a running price accumulator; any contract can read it and compute a time-weighted average. No external publisher, no signature, no bridge. + +Off-chain: someone outside the chain (Chainlink, Pyth, RedStone) signs a price and gets it on-chain via either push or pull mechanics. We'll come back to push vs pull. + +--- + +# On-chain TWAP: how it works + +**TWAP = Time-Weighted Average Price** (i.e., not a spot price) + +- Pool stores running accumulator: `price × elapsed_time` +- Reader takes accumulator at T1 and T2 +- TWAP = (acc[T2] − acc[T1]) / (T2 − T1) +- Uniswap V3: geometric mean over log-tick accumulators +- Cardinality up to 65,535 observations (~9 days at Ethereum's 12s blocks) + +Note: +Whiteboard moment if needed. Two values stored in the pool, both monotonically increasing. To get a **mean price** over an interval, you read the accumulator at two points in time and divide. The result is the time-weighted **average** of all prices in that period. + +Geometric mean is what Uniswap V3 switched to (V2 was arithmetic). The reason: an attacker who pushes the price 10x up in one block and 10x back in the next leaves zero impact on the geometric mean, but pushes the arithmetic mean way up. **Geometric mean is the right shape for computing averages on multiplicative price processes.** + +Cardinality: how many past observations the pool stores. Default is 1; can be expanded up to 65,535 at a one-time storage cost. At 12-second blocks that's ~9 days of history. + +--- + +# On-chain TWAP: the catch + +- Security scales **linearly with pool depth** +- Two-block validator attack costs ≈ round-trip swap fees + price impact +- $1M pool offers far less protection than $100M pool +- **Doesn't work for off-chain assets** (no on-chain pool for USD, XMR, ZEC) + +Note: +This is the load-bearing slide for "why we still need off-chain". TWAP's security comes from the cost of moving the pool price and holding it. On a $100M pool, that's expensive. On a $1M pool, it's cheaper. + +The PoS multi-block attack is the cleanest example: under PoS, validators know one epoch ahead whether they control consecutive blocks. A validator with two consecutive blocks can move the price in block N, accumulator records it, then move it back in block N+1. Cost ≈ round-trip swap fees + price impact + the foregone arbitrage. Cheaper than people think. + +And the killer: TWAP only works for pairs that exist as pools on the chain. If you want USD/XMR pricing on LEZ, there's no LEZ pool that produces it (XMR isn't natively on LEZ). You need an off-chain feed. + +--- + +# Off-chain oracles: push vs pull + +**Push:** oracles write prices on-chain regularly (Chainlink classic, Chronicle). +**Pull:** consumer submits signed price data at txn time (Pyth; RedStone in pull mode). + +RedStone runs in both modes natively (50+ push deployments, 120+ pull deployments per the appendix survey). + + +Note: +Push is the chicken-and-egg model for new chains: push oracles need node operators, operators need TVL, TVL needs DeFi, DeFi needs oracles. Pull flips it — the consumer pays per update, no permanent infrastructure layer required, works on day one. + +Regular write can be on heartbeat or threshold + + +--- + +# Off-chain oracle: verification + +Signers sign data packages, an on-chain verifier recovers M-of-N signatures, verified price is published. + +--- + +# Off-chain oracle: verification + +| | **Pyth** | **RedStone** | +|---------------|-------------------------------------------------------------------------------|---------------------------------------| +| Mode | Pull (Wormhole) | Push + Pull | +| Quorum | 13-of-19 | 3-of-N\* | +| Scheme | secp256k1 ECDSA + 2*keccak256\*\*, Wormhole VAA | secp256k1 ECDSA + keccak256, calldata | +| Bridge needed | Wormhole | none | + +\*typically +\*\*single keccak256 on Solana + +Note: +LEZ-specific wrinkle: classical pull mode (verify-inside-the-consumer-tx) doesn't transfer cleanly because of the zkVM's in-circuit cost profile. We end up with a push-mode aggregator that consumers (including private accounts) read, regardless of whether the upstream is delivered as push or pull on its native chain. + +Both Pyth and RedStone sign with secp256k1 ECDSA over keccak256 — same primitive, different wrapping. Pyth wraps in Wormhole VAAs (13 ECDSA recoveries + Merkle proof per update + guardian-set tracking on-chain). RedStone is calldata-only: the signed package is just bytes, the verifier recovers signers and checks against a registered allowlist. No bridge. + +The next slide covers what LEZ has wired into its runtime, what guest programs can actually call, and what that means for the in-program cost of verifying these schemes. + +VAA = Verified Action Approval - Wormhole's standard cross-chain message format, signed by the guardians. +calldata: the signed price packages are just appended to the consmer tx's calldata. + +--- + +# Privacy needs + +| | | | +| --- | ------ |---| +|Push | Public | Make price available to everyone| +|Push | Private | (!) Doesn't make sense| +|Pull | Public | For stablecoin needs and other public pools| +|Pull | Private | (?) Private program that uses oracle| + +Note: +Pull private might be interesting for prediction markets, where one could claim an outcome privately? + +Private pull can always re-use pushed data. + +--- + +# LEZ verification primitives (1) + +- LEZ is a RISC-V zkVM (built on RISC0) +- One signature primitive wired into the runtime: **single-key BIP-340 Schnorr over SHA-256** +- That primitive validates **transaction witnesses only**; it is **not exposed to guest programs** +- No threshold / aggregate primitives, no ECDSA, no ed25519 callable from program code + +--- + +# LEZ verification primitives (2) + +Any signature a program needs to verify (BIP-340 from a DLC publisher, ECDSA-keccak from RedStone or Pyth, ed25519 from Switchboard) runs in RISC0: in-circuit (private), CU (public). + +The bench [`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench) covers four schemes on a CPU-only Ryzen 9 7940HS (16 threads): private TX for the RedStone scheme (ECDSA secp256k1, 3-of-N) lands at **7:26**, and no scheme in the matrix hits sub-30s interactive UX. + +Note: +This is the slide that reframes the rest of the deck. + +LEZ is a RISC-V zkVM built on RISC0. The runtime has one signature primitive wired in: single-key BIP-340 Schnorr over SHA-256, used to validate the witness on each transaction at admission time. Crucially, this primitive is not exposed to guest programs — a program running inside the RISC-V zkVM cannot call it as a host function. There is also no callable ECDSA, no callable ed25519, no keccak256 host function, no threshold/aggregate primitive. + +Every general-purpose price oracle in production today (RedStone, Pyth via Wormhole, Chainlink Data Streams, Chronicle's per-signer leg) signs with secp256k1 ECDSA over keccak256. Switchboard signs with ed25519. The DLC oracle ecosystem signs with BIP-340 Schnorr over SHA-256 — same scheme as LEZ's transaction primitive but, again, not callable from a guest program. (Of the DLC publishers, only Pythia is currently live; Sibyls is dead, Ernest is on hiatus, Suredbits is dormant.) + +The cost question is therefore the same shape across signature schemes: any in-program verification has to run as RISC-V code inside the RISC0 zkVM. Some primitives are more expensive to prove than others (ECDSA recovery and keccak256 in particular), but none get the "free precompile" treatment. + +The next slide gives the bench numbers, then we walk the four adaptor shapes. + +--- + +Local prove (no privacy wrap), N = signatures verified: + +| Scheme | N=1 prove | N=3 prove | user cycles / sig | +|-------------------------------------------|-----------|-----------|-------------------------| +| ECDSA secp256k1: RedStone, Pyth | 2:26 | 4:20 | 303 K | +| Schnorr secp256k1: BIP-340, FROST | 1:12 | 2:26 | 271 K | +| ECDSA P-256 | 1:09 | 2:22 | 198 K | +| Ed25519 (Switchboard) | 2:40 | 7:40 | 803 K | + +--- + +End-to-end private TX (privacy wrap + sequencer roundtrip), 3-of-N: + +| Scheme | E2E (3-of-N) | +|-------------------|--------------| +| ECDSA P-256 | 4:58 | +| Schnorr secp256k1 | 5:22 | +| ECDSA secp256k1 | **7:26** | +| Ed25519 | 11:09 | + +**No scheme fits sub-30s interactive UX on CPU.** P-256 is ~32% cheaper per-sig than secp256k1 ECDSA; Schnorr secp256k1 is ~9% cheaper. CUDA / Bonsai would compress these meaningfully. + +Note: +This is the data that pins down the design choice on the next four slides. Three takeaways: + +1. **Private-execution pull is off the table on CPU for every scheme in scope.** RedStone's ECDSA secp256k1 at 3-of-N is 7:26 end-to-end on a 16-thread Ryzen. The cheapest scheme (P-256) is still 4:58. Sub-30s interactive UX needs CUDA / Bonsai or a precompile, both of which are out of scope for RFP-020 day one. + +2. **The bench measures proving cost; the public-mode aggregator does no proving.** Public-mode pushes are validator-executed; their cost is in LEZ compute units, not proof time, and this bench doesn't cover that path. Both the local-prove and E2E columns above are private-execution costs (E2E adds the outer privacy-preserving circuit and sequencer roundtrip; local-prove is the inner kernel alone). RFP-020's first deliverable measures the public-mode aggregator's compute-unit cost on real LEZ infrastructure; the bench numbers establish the private-execution ceiling, which is what makes private pull infeasible. + +3. **Cross-scheme ranking is meaningful for any future "private-mode-friendly upstream" follow-on.** If consumer demand for private-execution pull is established later (the LSC stablecoin in RFP-013 currently constrains parts of its flow to public execution for unrelated reasons, so demand is unconfirmed), the bench data identifies the candidate primitives to consider on the upstream side: P-256 first, Schnorr secp256k1 second. Ed25519 is the most expensive of the four in this RISC0 stack despite curve25519-dalek's accelerated backend, because Edwards arithmetic plus in-algorithm sha512 (no precompile) dominates. + +Caveats: synthetic same-message fixtures, no batch-verify shortcuts, AI-assisted research bench (must not ship to mainnet). Real LEZ devnet numbers are part of RFP-020's Deliverable D1. + +--- + +# Options + +1. ECDSA Verification: RedStone, Pyth +2. Centralised Relayer Re-Signs +3. t-of-n federation (off-chain threshold) using FROST-signs +4. Bitcoin DLC Oracles + +--- + +# 1. ECDSA Verification + +1. Push and pull are the same +2. Potentially high cost for push and pull +3. Private pull very costly/slow +4. Precompile can help reduce cost (public only) +5. Re-use existing Oracle networks + +--- + +# 2. Relay re-signs (Schnorr) + +1. Push: valid tx sig = valid data, cheapest transactions +2. Pull, private: slightly cheaper than ECDSA +3. Highly trusted centralised party +4. Re-use existing Oracle networks + +--- + +# 3. t-of-n federation Schnorr threshold + +1. Push: valid tx sig = valid data, cheapest transactions +2. Pull, private: slightly cheaper than ECDSA (if using normal signal, not witness sig) +3. New Oracle Network +4. Would need to confirm feasible (use FROST/Schnorr threshold for LEZ transactions) + +--- + +# 4. Bitcoin DLC Oracles + +1. Push: BIP-340 tx sig = valid data, cheapest transactions (needs adaptor) +2. Discrete-outcome (prediction markets), not regular price feed +3. Need to confirm feasibility + + +Note: +Quick walk-through of the four: + +A — A LEZ-side process pulls RedStone/Pyth payloads, verifies them off-chain, then submits a regular LEZ transaction calling the price-aggregator program with the resulting price. The relayer's BIP-340 signature authenticates the transaction itself; the runtime validates it at admission time as part of the standard transaction-admission flow, and the program does an equality check on the caller against a registered relayer pubkey. No in-program signature verification, so no in-circuit cost. Trust collapses to one re-signer. Rejected. + +The structural test that distinguishes the shapes: **whose signature authenticates the LEZ transaction**. In A and B, the transaction sender's signature does (a single re-signer in A, a FROST federation emitting one aggregated BIP-340 sig in B); the runtime handles verification at admission. In C and D, the transaction carries an upstream publisher's signature inside calldata, distinct from the transaction sender, and the guest program has to verify it in-circuit. + +B — A t-of-n federation jointly FROST-signs the LEZ transaction itself (not the data inside calldata), emitting a single BIP-340 signature as the tx witness. Each member fetches upstream RedStone/Pyth payloads independently, verifies them off-chain in native code, and proposes a `(price, timestamp, source_metadata)` tuple; when t members agree within a tolerance window, they run FROST signing rounds over the LEZ tx hash and the coordinator submits. The aggregator program checks `caller == P_fed` and writes the slot. Libraries exist (ZF FROST, Blockstream bip-frost-dkg, jesseposner FROST-BIP340) but no oracle is using FROST in production today; FrostOracle (Chen et al., IEEE iThings 2023) is the lone academic proposal, and the closest production precedent is iBTC/DLC.Link's federation for *contract-outcome* attestation, not price feeds. **PoC assumption to validate:** the runtime accepts the FROST-aggregated BIP-340 witness as a normal LEZ tx-admission signature (it should — FROST output is byte-identical to single BIP-340 under the aggregate pubkey, which is what the runtime's existing primitive verifies). If it does, the federation's write tx pays only standard tx-admission verification (host program, runs outside the RISC-V zkVM circuit), with no in-program signature verification, so public-mode push CU is lower than D. If the assumption fails for any reason the PoC surfaces, the federation falls back to in-program data-sig verification and push CU rises to the bench's in-circuit Schnorr cost (~9% cheaper than D's ECDSA, 5:22 vs 7:26 E2E at 3-of-N on CPU). **Either way it is push-only mode**: shape B does not unlock private-execution pull. Private consumers read the public price account written by the federation; private pull (consumer's private tx verifies an upstream sig inline) remains foreclosed for the same reason as in shape D. + +C — Bitcoin DLC oracles (Pythia, Sibyls, Suredbits, Ernest Oracle) publish BIP-340 attestations. Two disqualifiers, either sufficient on its own. First, same in-circuit cost question as D: each verification runs in-circuit at unmeasured cost, and the numeric DLC encoding multiplies that by N (bit-precision of the price), so shape C is not the right call unless LEZ later exposes Schnorr verification to guest programs at acceptable cost. Second, even with cheap Schnorr verification the structural fit is prediction markets and discrete-outcome contracts, not streaming price feeds. Better positioned for a future prediction-market RFP than for the current oracle work. The DLC info is in the appendix for reference. + +--- + +# Push mode on LEZ + +- Public-mode aggregator does the verify **once** per update +- Stores price + timestamp in a public price account +- Private accounts **read** the slot — no signature work in the private path + +``` +Public-mode aggregator: + in-program ECDSA + keccak verify (RISC-V on RISC0) + writes price to public account + +Private account: + reads public price account + → no signature work in the private path +``` + +Note: +The push-mode aggregator pattern is the right design under both implementation paths. The reasoning differs. + +**Under D1 (RISC-V in-program ECDSA, day-1 path):** in-program verification is reachable from private execution (the same RISC-V code can run inside a user's private proof), but prototype data ([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)) puts end-to-end private TX time at **7:26 for ECDSA secp256k1 at 3-of-N** on a CPU-only Ryzen 9 7940HS, with no scheme in the four-way matrix landing under 30 s. That rules out private-execution pull mode in practice, absent a RISC0-specific signature-verification accelerator or GPU / Bonsai proving. Push mode amortises the public-mode write-side cost across all downstream reads. Pull mode from public execution is technically possible but pays full proving cost per consumer transaction with no amortisation, strictly worse than reading the public price account. + +**Under D2 (precompile follow-on, only if D1's measurement forces it):** the asymmetry becomes structural rather than economic. A precompile is unreachable from private execution because anything in a private transaction has to be expressible inside the RISC-V zkVM circuit, and a host function lives outside it. Private execution would have to either (a) verify in the privacy circuit (forfeits batching, defeats the precompile's purpose) or (b) place the signature in the transaction journal and break privacy. Neither option preserves both efficiency and privacy. So under D2, push mode is not a preference — it's the only design that works. + +In both cases, the aggregator program is the same. That's what makes D2 a localised swap-in for D1 if the cost measurement forces the upgrade. + +A LEZ-specific freshness pattern: a user who needs a price fresher than the heartbeat can submit a public transaction that pushes a fresh signed payload to the aggregator, then submit a private transaction immediately after that reads the just-updated price. Verification is paid in the public path (cheaper); the private path does no signature work. This recovers pull mode's "fresh at transaction time" property for private consumers without paying in-circuit cost. + +The same mechanism enables a **consumer-pays push variant** with no dedicated relayer at all: users push when they need it, idle periods incur zero update cost. Operationally pull, structurally push. Whether to run a heartbeat relayer in addition is a deployment-time choice. Both can coexist; the program logic does not distinguish between them. + +RedStone supports both push and pull natively (50+ push deployments, 120+ pull deployments per the appendix survey). RFP-020's push-mode aggregator on LEZ can consume RedStone's own pusher, run its own, or rely on consumer-pays push, in any combination. + +A note on demand: the framing here treats private-execution pull as a capability that current paths foreclose, but whether any consumer protocol on LEZ actually needs it is a separate, unsettled question. Some consuming protocols already have design reasons to keep specific actions in public transactions; the LSC stablecoin in RFP-013 is one example. A follow-on RFP that proposes a private-pull path should start by establishing that some downstream consumer genuinely needs it, not just by selecting a friendlier primitive. + +--- + +# TWAP vs off-chain + +| | **TWAP** | **Off-chain** | +|---------------------------|----------------------|-----------------------| +| Trust assumption | DEX liquidity | signer set honesty | +| Day-one viable on LEZ | risky (liquidity) | yes | +| Privacy assets (XMR, ZEC) | no | yes | +| Cost per query | cheap | data + sig verify | +| Manipulation defence | depth-dependent | M-of-N signers | + +**Best practice: use both.** Production protocols cross-check. + +Note: +Walk through the row by row. They're complementary, not competing. The production norm in EVM DeFi is multi-tier: +- Aave V3: Chainlink primary + configurable fallback +- Compound V2: Coinbase reporter anchored against Uni V2 TWAP (20% divergence triggers a circuit breaker) +- MakerDAO: median feed + 1-hour OSM delay as a manipulation circuit breaker +- Liquity V2: Chainlink + simple secondary fallback + +That's what the circuit-breaker interface in RFP-019 is for: when both sources are present, divergence above threshold flags the price as disputed. + +--- + +# What RFPs are for? + +Funding models: + +| | What? | When? | Funding | +|-----------|------------------|------------|-------------| +| RFP Infra | Building Blocks | Now | Full-funded | +| RFP Apps | User Facing Apps | Next Phase | Win-win | + +--- + +# The two oracle RFPs + +- **RFP-019**: On-chain TWAP +- **RFP-020**: RedStone off-chain adaptor (RISC-V in-program verify) + +Both needed for RFP-008 (lending) and RFP-013 (stablecoin) + +Note: +Why two RFPs and not one: different dependency profiles, different timelines. + +- RFP-019 reads on-chain AMM pool state, so it's gated on the DEX (RFP-004) landing. No external publisher signature is involved, so the LEZ-native single-sig primitive is sufficient. + +- RFP-020 picks shape D: implement RedStone's secp256k1 ECDSA + keccak256 verification as RISC-V program code inside RISC0, push-mode aggregator pattern. Cost measurement is a primary deliverable. If the measured cost is acceptable, the adaptor ships on the runtime as it stands. If not, a follow-on RFP proposes adding a secp256k1 ECDSA + keccak256 precompile to LEZ (public-execution mode only). The precompile is therefore an optimisation path, not a precondition for RFP-020. + +The push-mode design is structural, not stylistic — see the next slide. + +Awarding them as one combined RFP would have forced a single team to wait on the DEX before delivering anything. Splitting lets the off-chain tier ship in parallel with DEX work. + +--- + +## RFP-019: On-Chain TWAP Oracle + +**What it ships** +- Reads DEX pool accumulators; computes geometric-mean TWAP +- Defines **canonical oracle price account standard** (SVM IDL) + +**Why it matters** +- Single-source feeds = single point of failure +- Layered defence = on-chain + off-chain cross-check (production norm) +- Unlocks **LSC composite oracle path** (RFP-013 Path B) + +Note: +RFP-019 is structurally separate from the off-chain primitive question covered in earlier slides. It reads LEZ-native AMM pool state, accumulates price observations, and exposes them through a program account. No external publisher signature is involved; the LEZ-native single-sig primitive (used for transaction authentication, not data attestation) is sufficient. + +The deliverable splits into two halves with different timelines: +1. The **standard + circuit-breaker interface** — pure design work, can be specced, IDLed and prototyped in parallel with RFP-004. SVM-style account-data structures are append-friendly so the standard can evolve later without breaking consumers. +2. The **TWAP program itself** — reads pool accumulators, so it's gated on the DEX landing. This is the longer pole. + +The "why" pitch in three beats: +1. Every consuming protocol on LEZ inherits the oracle's risk profile. Ship only off-chain feeds, you're trusting one publisher set. +2. Cross-checking on-chain vs off-chain is the production norm. The circuit breaker (5% divergence threshold) is how every major lending protocol limits oracle damage. +3. On-chain TWAP unlocks designs that don't trust an external publisher for the pair — specifically the LGS/USD + LGS/LSC composite path that RFP-013 may pick. + +Soft blocker: LP-0012 (event emission) for dashboard / monitoring; not critical. + +--- + +## RFP-020: RedStone Off-Chain Adaptor + +- **Day 1**: implement secp256k1 ECDSA + keccak256 verification as RISC-V program code inside RISC0 +- **Push-mode aggregator** → public price account → private accounts read +- **Cost measurement is a primary deliverable** (compute units) +- Precompile is a **cost-conditional follow-on**, not a hard blocker +- **Day-one delivery: XMR/USD, ZEC/USD, BTC/USD, ETH/USD (TBC)** + + +Note: +LEZ is a RISC-V zkVM built on RISC0. The runtime's existing BIP-340 signature primitive validates transaction witnesses only; it is not exposed to guest programs, and there is no callable ECDSA / keccak host function either. So any signature a program needs to verify runs in-circuit. The cross-scheme bench ([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench), CPU-only Ryzen 9 7940HS, no CUDA, no Bonsai) measures four schemes; ECDSA secp256k1 at 3-of-N (the RedStone shape) is **7:26 end-to-end private TX**, with no scheme in scope landing under 30 s. Private-execution pull mode is therefore not on the table on consumer CPU, and the adaptor design has to be push-mode aggregator with the verification cost amortised across reads. + +RedStone's data nodes sign price packages with secp256k1 ECDSA over keccak256. RFP-020 implements that verification path in RISC-V program code using existing Rust crates (k256 / sha3 / equivalents) and proves it via RISC0 alongside the rest of the program. The structural choice is push-mode aggregator: the verifier runs once per update on the write side, prices land in a public price account, and private accounts compose by reading the slot. Pull mode for private accounts is not on the menu — verifying a signature inside the privacy circuit forfeits batching benefits, and putting it in the transaction journal breaks privacy. + +Bench data ([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)) already establishes that naive in-circuit ECDSA in RISC0 is slow enough to rule out private-execution pull mode on consumer CPU (7:26 end-to-end at 3-of-N for ECDSA secp256k1 on a Ryzen 9 7940HS, with no scheme in the four-way matrix landing under 30 s). The bench measures proving cost (private-execution path); the public-mode aggregator does no proving, so its write-side cost is in LEZ runtime compute units rather than proof time and is not captured here. That public-mode cost is the open variable RFP-020 measures on real LEZ infrastructure, and amortisation across all downstream reads is what makes a per-update cost workable that would be unworkable per-private-transaction. Measurement of the public-mode cost is the first deliverable. Two outcomes: + +1. **Cost is acceptable.** The adaptor ships on the runtime as it stands. +2. **Cost is unacceptable.** The measurement becomes the input to a follow-on RFP that proposes adding a secp256k1 ECDSA + keccak256 precompile to LEZ for public-execution mode. The applicant should design the verification path so that swapping in a precompile later is a localised change. + +Separately, if a signature scheme exists that yields acceptable in-circuit cost for **private** execution (RISC0-friendly hash + curve choices, or a different signature primitive entirely), a future RFP could propose either building or modifying an existing oracle network to publish in that scheme; that would unlock pull-mode reads from inside private transactions, which the current ECDSA-on-RISC0 path forecloses. Whether such a follow-on is worth pursuing depends on consumer demand for private-execution pull, which is not yet confirmed: parts of RFP-013's LSC stablecoin design already constrain specific actions to public transactions, so the capability is only worth chasing if a downstream consumer actually needs it. + +XMR and ZEC are mandatory deliverables. RedStone was chosen because both feeds are in its public token registry, it has no bridge dependency, and it natively supports both push and pull modes (RedStone runs its own pusher for existing push deployments, so the LEZ side can either consume that or operate its own relayer). + +--- + +## RFP-020: Why RedStone? + +XMR/USD + ZEC/USD feeds: + +| Provider | Both feeds? | Self-serve? | Bridge needed? | +| ------------ | ----------- | --------------------- | -------------- | +| Chainlink | partial | **no** (permissioned) | n/a | +| Pyth | yes | yes | **Wormhole** | +| DIA Lumina | yes | yes (bespoke) | n/a | +| **RedStone** | **yes** | **yes** | **none** | + +→ RedStone is the simplest upstream source. The LEZ-side verification path is the same regardless of which one we pick. + +Note: +This is a process-of-elimination on the *upstream* side, holding the LEZ-side decision (shape D — RISC-V in-program ECDSA + keccak verification, push-mode aggregator) constant. + +- Chainlink: needs business engagement; no self-serve onboarding for a new chain. Out for day one. +- Pyth: technically the strongest (120+ publishers, confidence intervals) but requires Wormhole on LEZ in addition to the ECDSA+keccak primitive. Two dependencies, not one. Future RFP. +- DIA Lumina: permissionless, but each new chain needs a bespoke deployment. +- RedStone: connector format is portable, no bridge, no team engagement, both feeds in the public registry. + +The adaptor framework is upstream-agnostic. Swapping in another upstream is a matter of replacing the data-package decoder and the signer-set registration; the verification path stays the same. + +Reviewer note: seugu (anon-comms) reviewed PR #37 and pushed back on the oracle technical claims. We verified the signature schemes against primary sources — the appendix has all the citations. + +--- + +# Next Steps + +- **RFP-019**: open immediately; build deferred until RFP-004 lands +- **RFP-020**: builds on LEZ as it stands today (no runtime change required up front) +- Cost measurement is a primary deliverable; if measured cost is unacceptable, a follow-on RFP proposes the precompile +- Canonical price account standard (RFP-019) and adaptor (RFP-020) can be designed in parallel + +Note: +TODO: get from user — actual timelines, funding numbers, go-live dates. $XXXXX placeholders still in both RFPs. Also confirm whether these RFPs need approval from a specific committee. + +The split-and-parallel story: + +- RFP-019's standard + circuit-breaker interface is pure design work and can ship ahead of the DEX. The TWAP program itself waits on RFP-004. +- RFP-020's verification path is RISC-V in-program code from the start. No runtime work is on the critical path. If the cost measurement deliverable shows the in-program path is too expensive at production cadence, a follow-on RFP for a public-mode precompile becomes the optimisation path, with this adaptor as the immediate consumer. + +Decision pending from user: keep RFP-020 as one combined RFP or split. + +--- + +# Q & A + +Note: +Anticipated questions and the short answer: + +**Q: Why does the adaptor implement ECDSA verification in program code rather than relying on a precompile?** Because LEZ doesn't currently expose any signature primitive to guest programs (the runtime's BIP-340 primitive validates transaction witnesses, not program-callable). LEZ is RISC0-based, so any signature scheme can be implemented in program code; the open question is whether the resulting cost is acceptable. RFP-020's first deliverable is to measure that cost. If it's acceptable for the push-mode aggregator's update cadence, the adaptor ships. If it's not, a follow-on RFP proposes adding a secp256k1 ECDSA + keccak256 precompile for public-execution mode. + +**Q: What about private execution? Can a private transaction verify a RedStone payload inline (pull mode)?** No. Bench data ([`fryorcraken/lez-signature-bench`](https://github.com/fryorcraken/lez-signature-bench)) puts end-to-end private TX time for ECDSA secp256k1 at 3-of-N at **7:26** on a CPU-only Ryzen 9 7940HS, with no scheme in the four-way matrix landing under 30 s, which rules pull mode out in practice on consumer CPU. Putting the signature in the transaction journal would break privacy. Even if a precompile is added later, it would live outside the ZK proof boundary and remain callable only from public execution. Private accounts compose by reading the public price account that the push-mode aggregator writes to. + +**Q: Why not just sign in BIP-340 Schnorr+SHA-256 at the oracle, since that matches LEZ's transaction-witness primitive?** This question is about an *upstream publisher* signing in BIP-340 (i.e. data-signing, equivalent to shape D but with Schnorr in place of ECDSA). Two reasons against. First, the runtime's BIP-340 primitive validates *transaction witnesses*, not arbitrary data signatures from inside calldata; a program verifying an upstream BIP-340 data signature still pays in-circuit cost (the bench measures ~9% cheaper than ECDSA at 3-of-N, neither under 30 s on consumer CPU). Second, no production price oracle signs data in BIP-340 today; the candidates that did or do (Pythia is the only live publisher; Sibyls operator is dead, Ernest on hiatus, Suredbits dormant) are single-operator BTC/USD publishers built around discrete-event attestation, and none publish XMR/USD or ZEC/USD. The shape that *does* exploit the runtime's tx-witness BIP-340 primitive is shape B (FROST tx-signing) — see the four-shapes section. + +**Q: What about FROST? Threshold Schnorr that emits one BIP-340 signature?** Shape B in the appendix. The right framing is *tx-signing*, not data-signing: a t-of-n federation FROST-signs the LEZ transaction itself, emitting a single BIP-340 sig as the tx witness, which the runtime's existing tx-admission BIP-340 primitive should validate without changes (FROST output is byte-identical to single BIP-340 under the aggregate pubkey). PoC assumption: that runtime acceptance holds. If it does, the federation's write tx pays only standard tx-admission verification (host program, no in-circuit cost), so public-mode push CU is lower than D. If the assumption fails, the federation falls back to in-program data-sig verification (bench: ~9% cheaper than D's ECDSA at 3-of-N, neither under 30 s on consumer CPU). **Either way it is push-only mode and does not unlock private-execution pull**: private consumers read the public price account the federation writes; private pull stays foreclosed for the same reason as in D. No oracle is using FROST in production today (closest precedent: iBTC/DLC.Link for *contract-outcome* attestation, not price feeds), and FROST library audit/threat-model coverage is wallet-custody, not oracle-shaped repeated signing — those are the open R&D risks the PoC has to surface. + +**Q: What about DLC oracles (shape C)?** Documented in the appendix for reference. Structurally a fit for prediction markets and discrete-outcome contracts, not streaming price feeds. Same in-circuit cost question multiplied by N bits of precision (numeric DLC encoding signs the outcome bit-by-bit). Better positioned for a future prediction-market RFP. + +**Q: Why isn't the secp256k1 precompile on the LEZ roadmap?** The LEZ runtime team has flagged genuine open questions beyond the oracle use case: nullifier tracking for replay protection, privacy-circuit branching to support Ethereum-signed private accounts, and identifier-flow / wallet implications around the recent multiple-private-accounts-per-keyset work. None blocks the narrow oracle use of the precompile, but they explain why it needs its own argument. Making the precompile a cost-conditional follow-on rather than a precondition lets RFP-020 ship without that argument having to land first. + +**Q: How does LSC (RFP-013) consume these feeds?** Two production-security paths, both viable on top of RFP-019 + RFP-020. Path A: LSC/USD direct via off-chain oracle — simple, but exposed to thin LSC CEX liquidity early. Path B: LGS/USD external + on-chain LGS/LSC TWAP — deeper LGS liquidity, but the TWAP becomes the manipulation surface. We deliberately leave this open; RFP-013's implementer ships production economics and picks A or B as a business decision. The canonical price account standard keeps the choice swappable later. + +**Q: Why not Pyth first?** Same in-circuit ECDSA + keccak verification path as RedStone, plus a Wormhole dependency on the LEZ side (guardian-set tracking, 13-of-19 VAA verification, Merkle proof). RedStone has only the verification; no bridge. Pyth becomes a future RFP once Wormhole-on-LEZ is decided. + +**Q: Why not Chainlink?** Permissioned onboarding. We can't self-deploy; we'd need a business engagement. + +**Q: What about TWAP manipulation on shallow LEZ pools at launch?** That is exactly why we need the off-chain tier as a cross-check. The circuit breaker in RFP-019 catches divergence between TWAP and the external feed. + +**Q: Why M-of-N for RedStone? What's the failure model?** Signer compromise. If 3-of-N signers collude, they can sign arbitrary prices. The mitigation is the circuit breaker (cross-check against on-chain TWAP) plus signer-set rotation by the program owner. + +**Q: Does this preclude future hybrid designs (TEE-attested, ZK-verified)?** No. The canonical price account standard is append-friendly. Future adaptors populate the same struct. Switchboard (TEE) and DIA Lumina (ZK) could be added without re-doing the consumer side, once their respective verification primitives are available on LEZ. + +TODO: any other questions the audience is likely to ask that I haven't anticipated. + +--- + +# Appendix: citations and detail + +- `appendix/oracle-ecosystem.md` — full ecosystem survey +- RFP-019 — `RFPs/RFP-019-twap-oracle.md` +- RFP-020 — `RFPs/RFP-020-redstone-oracle-adaptor.md` +- PR #37 — review thread + +Note: +For deep dives, point at the appendix. The full coverage matrix, signature scheme analysis (Wormhole VAA + RedStone), TWAP manipulation cost analysis, and citations all live there. The two RFPs themselves are tight; the appendix is the long-form reference.