Push, pull, and on-chain TWAP price oracles
1. TL;DR
Section titled “1. TL;DR”A price oracle answers two questions — where does the price come from, how does it get on-chain — and the three dominant answers are push (a decentralized off-chain network agrees on a price and writes it on-chain whenever it moves enough or enough time passes, Chainlink’s model), pull (the same kind of off-chain aggregation happens continuously, but nothing is written on any destination chain until a consumer explicitly fetches and submits the latest signed update themselves, Pyth’s model), and pure on-chain TWAP/median (no off-chain party at all — the price is derived purely from a venue’s own trade history, averaged or median-filtered over a window to resist single-block manipulation). None of the three is simply “better”: push guarantees a price is always sitting there ready to read but can be briefly stale; pull guarantees freshness at the moment of use but requires the consumer to pay for and remember to trigger the update; on-chain TWAP/median needs no external trust at all but is bounded by the manipulability and liquidity of the one venue it’s computed from.
2. Explain it simply
Section titled “2. Explain it simply”Analogy
Section titled “Analogy”Push is a newspaper delivered to your doorstep every morning and again whenever a major story breaks — you always have something to read, but it might be hours old. Pull is calling a wire service and asking “what’s the price right now?” every time you need to act — you get the freshest number, but pay for the call yourself each time. On-chain TWAP/median refuses any outside newspaper or wire service, instead averaging the last several hours of prices you personally observed at your own market stall — nobody can lie to you, but your number only reflects your one stall.
Smart contracts often need a real-world price, like how much one ETH is worth in dollars. Getting that price on-chain takes one of three shapes: a network of reporters can post fresh prices on a schedule (push), a network can keep a fresh price ready off-chain and let whoever needs it fetch and pay to bring it on-chain at the moment they need it (pull), or a trading pool can average its own recent trades over time so no outside reporter is needed (on-chain TWAP or median). Each has a weak spot: a push price can be a little old, a pull price needs someone to go get it, and an on-chain average can be nudged if someone controls enough recent trades on that pool.
Step-by-step walkthrough
Section titled “Step-by-step walkthrough”Scenario: a Solana perpetual futures program needs SOL/USD to check whether Alice’s leveraged position is liquidatable, using Pyth’s pull-oracle model.
- Before (state: Pythnet has an aggregate SOL/USD price for the current slot; Solana mainnet’s Pyth price account still holds whatever was last pulled, possibly stale). Over 120 first-party publishers submit price and confidence-interval observations every slot, and Pyth’s oracle program combines them the moment the first update in a slot arrives (Pyth docs, as of 2026-08).
- Fetch. A keeper bot requests the latest signed SOL/USD update from Pyth’s off-chain price service, which carries the Pythnet aggregate cross-chain.
- Pull. The keeper submits a Solana transaction whose first instruction posts that signed update, paying a small fee and writing a fresh price and confidence interval into the on-chain price account.
- Check. In the same transaction, the perp program’s liquidation instruction reads that just-updated account against Alice’s margin requirement.
- After (state: the price account reflects a price no older than the current transaction; liquidation is decided on a price that cannot be stale). No update happens unless someone pays to pull it — an idle feed with no recent reader can sit unrefreshed indefinitely.
Common misconceptions
Section titled “Common misconceptions”- Myth: Pyth is a purely pull-only oracle. Reality: Pyth Core’s documentation lists “supports push and pull updates” as a feature — pull is the common path, not the only one (Pyth docs, as of 2026-08).
- Myth: A push oracle like Chainlink updates continuously. Reality: A new round is only published when price crosses a deviation threshold or a heartbeat elapses — “during periods of low volatility, the heartbeat triggers updates,” so the price can sit unchanged for hours (Chainlink docs, as of 2026-08).
- Myth: On-chain TWAP/median needs no trust at all. Reality: It removes trust in an external reporter, but still depends on the liquidity of the pool it’s computed from — see /exchange/amm-oracles/ and /oracles/oracle-manipulation/.
- Myth: Pull oracles are strictly cheaper since they only cost money when used. Reality: The cost moves, not disappears — the consumer’s transaction now pays for the update, which matters for latency-sensitive actions like liquidations.
- Myth: Reading a price is “free” once on-chain. Reality: Every design here requires checking when the price was last updated (
updatedAtfor Chainlink, publish time for Pyth) — exposing the number without its age is unsafe by construction.
If you only remember one thing
Section titled “If you only remember one thing”Push, pull, and on-chain TWAP/median are not competing definitions of “the price” — they’re three answers to who pays, and when, to get an off-chain or historically-averaged fact onto a chain that can’t otherwise see it.
3. How it works
Section titled “3. How it works”Push: Chainlink’s Off-Chain Reporting model
Section titled “Push: Chainlink’s Off-Chain Reporting model”Chainlink Data Feeds are built from a proxy contract (a stable address applications call, so the underlying implementation can upgrade without breaking integrations) pointing at an aggregator contract, which receives periodic updates from a decentralized network of node operators using Off-Chain Reporting (OCR): operators exchange observations off-chain, agree on a median, and a single transmitter posts one signed report on-chain (Chainlink docs, as of 2026-08). A new round fires when (a deviation threshold) or (a heartbeat), where and are configured per feed and can differ per asset and chain — a consumer must read the specific feed’s configuration rather than assume a universal guarantee.
Pull: Pyth’s Pythnet aggregation model
Section titled “Pull: Pyth’s Pythnet aggregation model”Pyth runs aggregation on its own app-chain, Pythnet, rather than on any consuming chain. Publishers submit a price and a confidence interval every slot; “the first price update in a slot additionally triggers price aggregation, which combines the price data from the previous slot into a single aggregate price and confidence interval” (Pyth docs, as of 2026-08). That aggregate is available cross-chain but not proactively written to any destination chain — a consumer or keeper must explicitly submit the signed aggregate on-chain before reading it, which is why Pyth’s docs describe “why pull-oracle integrations must refresh on-chain prices” as a distinct concern.
On-chain TWAP/median: no off-chain party at all
Section titled “On-chain TWAP/median: no off-chain party at all”A CFMM’s reserves imply a price with no reporter involved — but that instantaneous price is trivial to move within one transaction, a direct function of whoever traded last. Angeris and Chitra’s formal treatment of CFMMs as oracles shows why time-aggregation helps: for a path-independent CFMM, the price it should report — the supporting hyperplane of its reachable reserve set at post-arbitrage reserves — is provably identical to its marginal price, and arbitrageurs are “always incentivized to make any one of the prices reported by the CFMM equal to” the reference price, since any mismatch is free money to correct (Angeris & Chitra, 2020-03). That argument only holds between transactions, once arbitrageurs react — mid-transaction, an attacker with a large trade controls the price entirely. TWAP or median spreads a single-block manipulation across a window, so an attacker must sustain distortion for much of the window rather than one block — mechanics covered fully in /exchange/amm-oracles/ and /oracles/oracle-manipulation/.
Cost and freshness tradeoffs, formalized
Section titled “Cost and freshness tradeoffs, formalized”Let updates arrive at rate (bounded below by , above by deviation crossings) and be one update’s gas cost. A push oracle’s total cost over time is approximately , paid by whoever funds the feed regardless of reads. A pull oracle charges directly to whichever transaction needs freshness, so network cost is — cheaper in aggregate when reads are rare, but front-loading the entire cost onto the transaction needing it most, like a time-sensitive liquidation. On-chain TWAP/median pays no separate update cost — price is a byproduct of trades happening anyway — but read cost scales with how many observations are combined, a tradeoff detailed in /exchange/amm-oracles/.
4. Worked numeric example
Section titled “4. Worked numeric example”Illustrative scenario (all numbers hypothetical, chosen to show the mechanism, not a historical event): the “true” cross-venue price of an asset is $100, but a single large trade on one specific AMM pool briefly pushes that pool’s own spot price to $130 for one block before reverting to $101.
| Oracle type | What it reports during the spike | Why |
|---|---|---|
| Raw AMM spot price | $130 | Directly reflects the manipulated pool’s post-trade reserves with no smoothing |
| Chainlink push feed | ~$100 (unaffected) | Aggregates a median across many independent off-chain sources; a single pool’s one-block move isn’t one of its inputs at all |
| Pyth pull feed | ~$100 (unaffected) | Same reasoning — Pythnet’s aggregate combines 120+ first-party publishers, not the manipulated pool’s own price |
| 30-minute on-chain TWAP of the manipulated pool | ≈$100.18 | The single manipulated block is diluted across the window |
For the TWAP row: with a 12-second block time, a 30-minute (1,800-second) window spans roughly 150 blocks. A geometric-mean TWAP shifts, in log terms, by approximately , i.e. about a 0.18% move — the manipulator’s $30 spike survives in the reported price as less than twenty cents. This is the entire case for time-averaging or aggregation: push and pull oracles resist single-venue manipulation by aggregating across venues off-chain, while on-chain TWAP/median resists it by aggregating across time on the same venue — and an attacker who can control many consecutive blocks (a realistic Proof-of-Stake concern; see /oracles/oracle-manipulation/) can defeat the time-based version by paying the dilution cost for longer.
5. Where it’s used
Section titled “5. Where it’s used”Ethereum
Section titled “Ethereum”- Chainlink Data Feeds — push oracle securing collateral valuation and liquidations broadly; the docs specifically name Aave using Data Feeds “to assess collateral value accurately” and GMX relying on them “to validate offchain data and ensure that each deposit or withdrawal executes at the correct market value” (as of 2026-08). docs.chain.link/data-feeds
- Chainlink Smart Value Recapture (SVR) feeds — a newer feed variant designed to “recapture Oracle Extractable Value (OEV),” the MEV-like value created around oracle updates, often observed during liquidations (Chainlink docs, as of 2026-08).
- Uniswap v2/v3 TWAP — the canonical on-chain, no-external-party price oracle; see /exchange/amm-oracles/ for the accumulator mechanics.
- Pyth (EVM deployments) — Pyth Core is documented as supporting 100+ blockchains, EVM chains included, using the same pull-update pattern described in §2 (as of 2026-08).
Solana
Section titled “Solana”- Pyth Core — the dominant Solana price oracle; 400ms update frequency on Pythnet, pull (and documented push) delivery to consuming programs (Pyth docs, as of 2026-08). docs.pyth.network
- Switchboard — a separate, permissionless Solana oracle network offering generalized (not price-only) data feeds; included here as the other named Solana oracle option, though no raw source in this research set details its specific aggregation mechanics.
- Drift and other Solana perpetuals platforms — consume Pyth price feeds for mark pricing and liquidation checks, following essentially the same pull-then-read pattern walked through in §2.
- n/a for a Solana-native push feed comparable to Chainlink’s continuous OCR model — the sources reviewed describe Pyth’s Solana integration as pull-oriented by default; a fully push-style always-fresh-on-chain feed on Solana is not documented here.
6. Risks, attacks, and incidents
Section titled “6. Risks, attacks, and incidents”- Push staleness during volatility or outages. Chainlink’s guidance is explicit that an application must check the reported timestamp and “pause operation or switch to an alternate operation mode” if a feed goes stale beyond its heartbeat.
- Pull-oracle liveness dependency. Since nothing is written until someone pulls it, freshness depends on someone being economically motivated to update at the right moment — usually the same actor benefiting from the enabled action (a liquidator), which usually works but isn’t automatic like a scheduled push.
- Oracle-update MEV / OEV. The moment a stale price updates to reality is often when a profitable liquidation or arbitrage becomes possible; Chainlink’s SVR feeds exist to redirect that value rather than let it leak to whoever races to submit first.
- On-chain TWAP/median manipulation under adversarial block control. The averaging protecting against single-block manipulation assumes an attacker can’t cheaply control many consecutive blocks; under PoS this is weaker than under PoW — full incidents in /oracles/oracle-manipulation/.
- Single-source or thin-market dependency regardless of design. Any architecture degrades if its underlying market (Chainlink’s sources, Pyth’s publishers, the AMM pool) is thin — aggregation reduces but doesn’t eliminate this.
7. Open problems
Section titled “7. Open problems”- Whether price feeds should be enshrined at the protocol level. A long-running debate over whether Eth2 should carry a native price feed versus leaving oracles to the application layer, covered fully in /oracles/oracle-manipulation/.
- OEV capture design. Whether mechanisms like Chainlink’s SVR feeds durably redirect oracle-update value back to protocols and users, versus simply shifting who captures it, is unsettled as of these sources (2026-08).
- Convergence of push and pull. Pyth Core already lists support for both patterns, suggesting convergence toward configurable delivery — but which becomes the practical default isn’t settled in the sources reviewed.
- Formal manipulation bounds beyond the CFMM oracle framework. Angeris and Chitra’s paper leaves a rigorous comparison to scoring rules like LMSR as future work, since “any framework which can compare the two will require assumptions about the market price dynamics” it deliberately avoids.
8. Ethereum vs Solana
Section titled “8. Ethereum vs Solana”| Aspect | Ethereum | Solana |
|---|---|---|
| Dominant price-oracle pattern | Chainlink push (Data Feeds), Uniswap on-chain TWAP | Pyth pull (Pythnet aggregation), consumed by most DeFi protocols |
| Update trigger | Deviation threshold or heartbeat, whichever first | Every slot on Pythnet (~400ms), but on-chain write only on consumer pull |
| Who pays for freshness | Feed sponsor (protocol/DAO), amortized across all readers | The consumer transaction that needs the fresh price |
| On-chain-native alternative | Mature (Uniswap v2/v3 TWAP, widely used and studied) | Not documented as a mature, widely-used pattern in these sources |
The difference tracks each chain’s own design priorities: Ethereum’s slower, more expensive blocks favor a push model that amortizes update cost across many readers and an on-chain TWAP that trades on Ethereum’s own deep, long-lived pools, while Solana’s cheap, fast slots make a pull model — pay a small fee to guarantee a same-transaction-fresh price exactly when you need one — the more natural default.
9. Reference doc
Section titled “9. Reference doc”The reference
Section titled “The reference”Improved Price Oracles: Constant Function Market Makers — Guillermo Angeris, Tarun Chitra, 22 March 2020. arxiv.org/abs/2003.10001
Summary of the reference
Section titled “Summary of the reference”The paper formalizes constant function market makers (CFMMs) — the family including Uniswap, Balancer, and Curve — as a general class defined by a trading function over reserves , and asks when such an AMM can be trusted as a price oracle: when are agents who trade against it incentivized to make its reported price match a reference market’s price, and can no agent, by any sequence of trades, drain the CFMM’s reserves? It introduces path independence — a CFMM’s reachable set of reserves does not change after any non-dominated trade — as the key property that makes these questions tractable, since path-independent CFMMs admit a well-defined reported price at any reserve level: the slope of the supporting hyperplane of the reachable reserve set at that point, scaled by a chosen numéraire.
The central result is the optimal arbitrage problem: given reference-market prices , an arbitrageur solves a convex optimization problem to find the trade that maximizes their profit against the CFMM, and the paper proves that at the optimum, the CFMM’s reported price exactly equals the reference price — meaning an arbitrageur is “always incentivized to make any one of the prices reported by the CFMM equal to” the reference market, since any divergence is pure profit to correct. For path-independent CFMMs specifically, the paper further shows this reported price coincides exactly with the marginal price (the price of an infinitesimally small trade), which is what makes reading a CFMM’s post-arbitrage price a meaningful oracle rather than an arbitrary number.
Beyond the core oracle result, the paper derives lower bounds on the total value of assets a CFMM holds as a function of external prices — using the constant-product and Curve-style trading functions as worked examples — and shows these lower bounds guarantee that “no agent can, by any set of trades, drain the reserves of assets held by a given CFMM,” a solvency property distinct from, but related to, the oracle-accuracy property. It closes by formalizing trading fees as a simple transformation of the trading function ( for fee parameter ), noting that fees turn a path-independent CFMM into a strictly path-deficient one, which strengthens (rather than weakens) the reserve-value lower bound.
Key quotes
Section titled “Key quotes”“We give sufficient conditions such that, under fairly general assumptions, agents who interact with these constant function market makers are incentivized to correctly report the price of an asset.” (Abstract)
“If the price of a decentralized exchange prices matches external prices, then such an exchange is said to be a good price oracle that other smart contracts can query as a source of ground truth.” (Introduction)
“The reported price implies that, given a reference market with prices equal to , an arbitrageur is always incentivized to make any one of the prices reported by the CFMM equal to .” (§2.4, Discussion, paraphrased structure preserved from the paper’s own argument)
“If the CFMM is path independent, then the reported price and the marginal price will always match exactly.” (§2.4, Discussion)
How to read the original
Section titled “How to read the original”Background needed: convex optimization basics (supporting hyperplanes, subgradients), and a working sense of what a CFMM’s “reserves” and “trading function” are (see /exchange/cfmm-math/ if unfamiliar). Skip the full proofs of path deficiency and the Curve-specific reserve-value derivation in §2.5 on a first pass — the qualitative results (arbitrage forces the reported price to match the reference market; path independence makes reported price equal marginal price) carry the paper’s oracle argument without the supporting algebra. The hardest section is the reported-price definition itself (§2.4): it’s easy to misread “the CFMM should report the slope of the supporting hyperplane” as an arbitrary design choice, when the point is that this specific choice is forced by the optimality conditions of the arbitrageur’s own profit-maximization problem — the CFMM doesn’t decide its own oracle price, the market does.
What changed since
Section titled “What changed since”- Chainlink and Pyth, as documented in this page, both deliberately avoid relying on any single CFMM’s post-arbitrage price as their primary source, instead aggregating across many independent off-chain venues — a practical response to the fact that the paper’s equilibrium argument holds between trades, not during the one transaction an attacker controls.
- Later work by some of the same authors and others (Milionis, Moallemi, Roughgarden, Zhang on Loss-Versus-Rebalancing) extends this arbitrage-driven price-tracking framework to quantify what it costs liquidity providers precisely because arbitrageurs are incentivized to correct CFMM prices — see /exchange/impermanent-loss-vs-lvr/.
- TWAP-specific manipulation concerns under Proof-of-Stake block-production dynamics (covered in /oracles/oracle-manipulation/) postdate this paper and directly address the gap between its equilibrium argument and single-controller-of-several-blocks reality.
Secondary references
Section titled “Secondary references”- Pyth Network, “How Pyth Works” and “Price Feeds” docs — read for the concrete publisher → aggregation → pull-delivery pipeline this page’s §3 describes.
- Chainlink, “Data Feeds” docs — read for the proxy/aggregator contract structure and the heartbeat/deviation trigger conditions.
- “So you want to use a price oracle” (samczsun, Paradigm, 2020-11) — read next for how the theoretical arbitrage-correctness result in this paper fails in practice against a single manipulated transaction; covered in depth in /oracles/oracle-manipulation/.
10. Sources
Section titled “10. Sources”- Improved Price Oracles: Constant Function Market Makers — Guillermo Angeris, Tarun Chitra — 2020-03-22 — https://arxiv.org/abs/2003.10001
- Price Feeds — Pyth Network Docs — fetched 2026-08-29 — https://docs.pyth.network/price-feeds
- How Pyth Works — Pyth Network Docs — fetched 2026-08-29 — https://docs.pyth.network/price-feeds/how-pyth-works
- Chainlink Data Feeds — Chainlink Docs — fetched 2026-08-29 — https://docs.chain.link/data-feeds