Skip to content

TWAMM: the time-weighted average market maker

A TWAMM lets a trader submit a long-term order—sell 100 ETH over the next 2,000 blocks—that an embedded constant-product pool executes as infinitely many infinitesimal “virtual” trades, with a closed-form formula so the cumulative effect of any number of blocks costs one computation. Arbitrageurs keep the embedded pool near the market price between blocks, so the order fills near the time-weighted average price instead of paying the full price impact of one large swap. The cost is that long-term orders are public, so the design trades sandwich resistance for information leakage and a dependence on arbitrage.

A pension fund that wants to buy $100 million of a stock does not send one market order; it hands the order to a broker’s algorithm that drips it into the market over eight hours, aiming to pay roughly the day’s average price. A TWAMM is that broker built into the exchange: you tell it how much to sell and over how many blocks, and it feeds tiny slices into its own pool continuously, while outside traders keep the pool’s price honest by arbitraging it against other markets.

If you try to sell a huge pile of apples at one stall in one go, the stall pays you less and less for each apple because it fears you know something. A time-weighted stall lets you say “sell my pile a little at a time over the whole afternoon.” It sells one apple at a time all afternoon, and whenever its price drifts below the other stalls, other shoppers buy from it and sell elsewhere, which pulls its price back. By the end you have sold the pile for close to the afternoon’s average price. The stall only has to do the maths once per visitor, no matter how many apples it sold in between.

Scenario: the embedded pool holds 10,000,000 USDC and 5,000 ETH (k=5×1010k = 5\times10^{10}, price 2,000). Alice submits a long-term order to buy ETH with 1,000,000 USDC over 100 blocks; arbitrageurs restore the pool price to 2,000 every block.

  1. Before: reserves (10,000,000 USDC, 5,000 ETH); Alice’s order is registered as a selling rate of 10,000 USDC per block, joining the USDC-selling pool.
  2. Block 1: the TWAMM’s virtual trades sell 10,000 USDC into the pool: it receives 5,000×10,000/10,010,000=4.9955{,}000 \times 10{,}000 / 10{,}010{,}000 = 4.995 ETH, and the pool’s price rises to about 2,004.
  3. Between blocks: an arbitrageur sees ETH at 2,004 on the pool versus 2,000 elsewhere, sells about 5 ETH to the pool and restores 2,000. After block 1: reserves are back near (10,000,000 USDC, 5,000 ETH), Alice has 4.995 ETH.
  4. Blocks 2–100: the same thing repeats. Nobody needs to touch the contract every block; when someone finally does, lazy evaluation computes all intervening virtual trades in one formula.
  5. After block 100: Alice holds about 499.5 ETH at an average price of 2,002 USDC. A single 1,000,000 USDC swap would have returned 454.5 ETH at 2,200. The difference, 45 ETH, is the price impact the TWAMM avoided by letting arbitrage do the work.
  • Myth: the TWAMM itself provides the better price. Reality: with no arbitrage in between, a one-sided long-term order returns exactly what a single swap would (constant product without fees is path-independent); the benefit comes from arbitrageurs resetting the price between blocks.
  • Myth: it splits orders into a few chunks like a bot. Reality: it splits them into “infinitely many infinitely small pieces” and integrates their effect analytically; that is what makes gas cost independent of the number of blocks.
  • Myth: public orders make it trivially front-runnable. Reality: virtual trades execute between blocks, so a sandwich needs the last transaction of one block and the first of the next—multi-block MEV—which the 2021 design treats as rare but growing.
  • Myth: it is a TWAP oracle. Reality: a TWAP oracle measures an average price; a TWAMM executes at one.
  • Myth: nobody built one. Reality: Fraxswap has run an embedded TWAMM on a Uniswap v2 fork since 2022, and Uniswap v4’s hooks were designed with TWAMM as a headline use case.

A TWAMM turns “split my order over time” into contract logic with a closed-form integral, so a large trader pays close to the average price while arbitrageurs, not the trader, absorb the work of keeping the pool honest.

Each TWAMM instance pairs two assets and contains an embedded constant-product AMM that anyone can trade against normally. A long-term order sells a fixed amount of one asset over a fixed number of blocks—e.g. “sell 100 ETH over 2,000 blocks” is a rate of 0.05 ETH per block. All orders selling the same asset are pooled: if Bob sells 0.1 ETH/block and Charlie 0.05 ETH/block, the ETH-selling pool sells 0.15 ETH/block and Bob receives 2/3 of its proceeds, tracked with the same per-share accounting (“billion-dollar algorithm”) used for LP rewards in Compound and Uniswap. There are always two pools, one per direction, either of which may be empty.

Let xstart,ystartx_{\text{start}}, y_{\text{start}} be the embedded pool’s reserves at the last evaluation, k=xstartystartk = x_{\text{start}} y_{\text{start}}, and let the two order pools sell xinx_{\text{in}} of X and yiny_{\text{in}} of Y in total over the next tt blocks at constant rates fx=xin/tf_x = x_{\text{in}}/t and fy=yin/tf_y = y_{\text{in}}/t. Treating the alternating infinitesimal trades as continuous flows, the X reserve obeys

dxdt=fxfyxy=fxfykx2,\frac{dx}{dt} = f_x - f_y \cdot \frac{x}{y} = f_x - \frac{f_y}{k}\,x^2,

since each unit of Y sold buys x/yx/y units of X and y=k/xy = k/x throughout. This Riccati equation has equilibrium x=kfx/fyx_\infty = \sqrt{k f_x/f_y} (the reserve level at which the two flows exactly offset) and solution

$$x_{\text{end}} = \sqrt{\frac{k,x_{\text{in}}}{y_{\text{in}}}}\cdot\frac{E + c}{E - c}, \qquad E = e^{2\sqrt{x_{\text{in}} y_{\text{in}}/k}}, \qquad c = \frac{\sqrt{x_{\text{start}},y_{\text{in}}} - \sqrt{y_{\text{start}},x_{\text{in}}}}{\sqrt{x_{\text{start}},y_{\text{in}}} + \sqrt{y_{\text{start}},x_{\text{in}}}},$$

with yend=k/xendy_{\text{end}} = k / x_{\text{end}}. The X-selling pool receives all the Y that did not stay in the AMM, ystart+yinyendy_{\text{start}} + y_{\text{in}} - y_{\text{end}}, and the Y-selling pool receives xstart+xinxendx_{\text{start}} + x_{\text{in}} - x_{\text{end}}. (Paradigm’s post presents these formulas under “Virtual Trade Math”; the derivation above reproduces them from the constant-product rule.) If only one pool is active, fy=0f_y = 0 and the equation reduces to xend=xstart+xinx_{\text{end}} = x_{\text{start}} + x_{\text{in}}: exactly one big swap, which is why the design relies on arbitrage between evaluations. Note also that EE depends on tt only through xinyinx_{\text{in}} y_{\text{in}}, so the cost is one exponential regardless of how many blocks elapsed.

Virtual trades are deemed to happen between blocks. The contract does nothing until someone interacts—swaps, adds an order, cancels—and then retroactively applies all virtual trades since the last interaction using the closed form: “Even if the TWAMM goes one million blocks between external interactions, the next time somebody interacts with it, it will be able to accurately calculate the results.”

Expiries complicate laziness: if orders expire at arbitrary blocks, each expiry changes the rates and forces a separate evaluation segment—in the worst case one per block. The fix is to allow expiry only on block numbers that are multiples of some interval (e.g. every 250 blocks, roughly hourly in 2021). Fraxswap’s implementation aligns expiries to hourly intervals and uses an approximation of the exact formula for gas efficiency (Frax docs). Cancellation is allowed at any block because the canceller pays their own gas.

Long-term flow pushes the embedded pool away from the market price gradually; arbitrageurs trade against it and restore parity, so the order executes near the time-weighted average price. Because none of the long-term traders is in a hurry, the post argues their flow carries less adverse selection, so the embedded pool’s LPs see “a high volume of uninformed flow” and can charge low impact—the same logic that batch auctions uses at the batch level and that IL vs LVR formalises as fees versus arbitrage losses.

Embedded pool: 10,000,000 USDC (xx) and 5,000 ETH (yy), k=5×1010k = 5\times10^{10}, no fee.

(a) One swap. Alice sends 1,000,000 USDC at once: Δy=5,000×106/(1.1×107)=454.55\Delta y = 5{,}000 \times 10^6 / (1.1\times10^7) = 454.55 ETH, average 2,200 (10% impact; Hasu’s rule of thumb gives 2×1/20=10%2 \times 1/20 = 10\%).

(b) TWAMM, one-sided, arbitrage every block. 10,000 USDC per block for 100 blocks. Each block returns 5,000×10,000/10,010,000=4.9955{,}000 \times 10{,}000 / 10{,}010{,}000 = 4.995 ETH before the arbitrageur resets the pool. Total 499.5499.5 ETH, average 2,002—an improvement of 45 ETH (≈$90,000) over (a).

(c) TWAMM, two-sided, no arbitrage. Alice’s USDC order runs against Bob’s order to sell 200 ETH over the same 100 blocks (xin=106x_{\text{in}} = 10^6, yin=200y_{\text{in}} = 200):

  • E=e2106200/5×1010=e0.1265=1.1348E = e^{2\sqrt{10^6 \cdot 200 / 5\times10^{10}}} = e^{0.1265} = 1.1348;
  • c=(1072005000106)/(107200+5000106)=(44,72170,711)/(44,721+70,711)=0.2251c = (\sqrt{10^7\cdot 200} - \sqrt{5000\cdot 10^6})/(\sqrt{10^7\cdot 200} + \sqrt{5000\cdot 10^6}) = (44{,}721 - 70{,}711)/(44{,}721 + 70{,}711) = -0.2251;
  • xend=5×1010106/200(1.13480.2251)/(1.1348+0.2251)=15,811,388×0.6690=10,576,185x_{\text{end}} = \sqrt{5\times10^{10}\cdot 10^6/200}\cdot(1.1348 - 0.2251)/(1.1348 + 0.2251) = 15{,}811{,}388 \times 0.6690 = 10{,}576{,}185 USDC; yend=4,727.6y_{\text{end}} = 4{,}727.6 ETH.
  • Alice receives 5,000+2004,727.6=472.45{,}000 + 200 - 4{,}727.6 = 472.4 ETH (average 2,116.9); Bob receives 10,000,000+1,000,00010,576,185=423,81510{,}000{,}000 + 1{,}000{,}000 - 10{,}576{,}185 = 423{,}815 USDC (average 2,119.1). Net, the pool absorbed 576,185 USDC and released 272.4 ETH, ending at a price of 2,237.

Bob’s opposite flow gave Alice a better fill than (a) even without arbitrage; adding arbitrage between blocks would pull both toward (b).

  • Fraxswap — “the first constant product automated market maker with an embedded time-weighted average market maker (TWAMM),” built on Uniswap v2, launched in June 2022 (IQ.wiki, secondary); long-term orders execute “before each AMM interaction, once per block,” expiries align to hourly intervals, and the formula is an approximation of Paradigm’s for gas. Frax uses it for FXS buybacks with AMO profits, peg stabilisation for FRAX and FPI, and protocol-owned liquidity. Frax docs
  • Uniswap v4 hooks — Uniswap’s v4 announcement lists pools that “act as a time-weighted average market maker (TWAMM) to spread out large orders over time” as a launch example of hooks, and the v4 whitepaper cites Paradigm’s post as reference [8]; an example TWAMM hook lived in the v4-periphery repository, which warns its examples are not production-ready. See v4 hooks and am-AMM.
  • n/a as an embedded TWAMM — none of the Solana sources reviewed (Raydium, Orca, Meteora, Jupiter docs; Helius) describes an AMM with on-chain long-term orders and lazy virtual execution (as of 2026-08). The function is served differently:
  • Jupiter Recurring (DCA) — “set up regular token swaps that execute automatically at specified time intervals”; each round is routed “through Metis Routing Engine to get the best possible price across all DEXes,” the Recurring API “takes 0.1% as fees,” and failed rounds “automatically retry at the next scheduled interval” (Jupiter docs and support, accessed 2026-08). This is off-chain scheduling of ordinary swaps, not virtual orders against one pool. docs
  • Meteora DLMM limit orders — pools in Limit Order mode support on-chain buy/sell orders as single-bin positions (Meteora docs).
  • Proprietary AMMs and cheap transactions — with typical fees of $0.001–0.01 (Raydium docs, as of 2026-04) and ~400 ms slots, manually splitting an order into hundreds of small swaps is cheap, and oracle-quoted market makers (Helius, 2025-08) absorb large flow without the gas problem that motivated the TWAMM on Ethereum.
  • Information leakage. Long-term orders must be public because any validator may process them; a large visible order invites front-running on the embedded pool and elsewhere. The post’s mitigation is that cancellation is free, so a spoofer can post a fake order, wait for front-runners to push the price, sell into them and cancel—keeping front-runners cautious (the “Sally the spoofer” example).
  • Multi-block MEV. Sandwiching virtual orders requires the last slot in one block and the first in the next; the 2021 post says “there is no way for an attacker to guarantee” that, but flags that “when such multi-block MEV becomes more common … this may become more of an issue.” Under proposer–builder separation a builder who wins consecutive blocks has exactly that power; see PBS and ePBS.
  • Arbitrage dependence. Without arbitrageurs (thin markets, congestion), a long-term order simply walks the pool’s curve and gets the single-swap price.
  • Incidents. No exploit of a TWAMM (Fraxswap or a v4 hook) appears in the sources reviewed (as of 2026-08). The relevant failure modes are economic (leakage, stale arbitrage) rather than code exploits.
  • Exact versus approximate math. Fraxswap uses an approximation of the closed form for gas reasons (Frax docs); how much execution quality the approximation gives up, and whether v4’s cheaper accounting makes the exact formula affordable, is unquantified in the sources.
  • Private long-term orders. Leakage is intrinsic to public orders; encrypted mempools or threshold decryption could hide them but do not exist for this use case (the post lists leakage as “the biggest tradeoff”). See encrypted mempools.
  • Multi-block MEV under PBS. The 2021 assumption that consecutive-block control is rare has weakened; whether TWAMMs need explicit protections (e.g. randomised virtual-trade timing) is open.
  • Is long-term flow really uninformed? The post argues patient orders carry less adverse selection; the LVR framework would still charge the embedded pool’s LPs for the drift the orders cause (see IL vs LVR).
AspectEthereumSolana
Live TWAMMFraxswap (since 2022-06); v4 hook examplesnone in sources (as of 2026-08)
Motivationgas per sub-order ($5–50 typical swap, Raydium docs 2026-04)weak: swaps cost $0.001–0.01
Block cadence for virtual trades~12 s; ≈250 blocks ≈ 1 hour in 2021 (post)~400 ms slots
Sandwich modelpublic mempool; between-block execution defeats single-block sandwichesno public mempool; leader ordering and Jito bundles
Time-sliced alternativemanual splitting, CoW batches, UniswapXJupiter Recurring (0.1% fee, Metis routing), DLMM limit orders
Who absorbs large ordersarbitrageurs against the embedded pooloracle-quoted proprietary AMMs (>60% of SOL/USDC, 2025-07)

The TWAMM answers two Ethereum constraints—expensive transactions and a public mempool with single-block sandwiches—and both are weaker on Solana. Fraxswap and the v4 hook model show the design works where gas amortisation matters; on Solana the same trader drips orders through Jupiter’s scheduler for a 0.1% fee or trades against market makers who refresh quotes every few hundred milliseconds. What does not transfer is the fairness anchor: a TWAMM’s fill is tied to arbitrage against an on-chain pool, whereas a scheduled DCA inherits whatever prices the aggregator finds each round.

TWAMM — Dave White, Dan Robinson, Hayden Adams (Paradigm; the page byline also credits Dan McCarthy), 2021-07-28. https://www.paradigm.xyz/writing/twamm

Introduction and Summary define the time-weighted average market maker as an AMM that “breaks long-term orders into infinitely many infinitely small pieces” executed against an embedded constant-product pool, motivated by Alice’s problem of buying 100 million USDC of ETH on-chain without paying for the market’s fear that she is informed, and without the operational burden and gas of manual splitting. Market Making Basics explains adverse selection and “fading” orders. Automated Market Makers recaps the constant product formula with a 2,000 USDC / 1 ETH example in which buying 2,000 USDC of ETH returns 0.5 ETH at an average of 4,000—price impact as automated fading. Executing Large Orders on Current AMMs covers manual splitting and the sub-order size trade-off (operational risk versus fixed transaction costs). Analogy to Traditional Finance introduces the TWAP order a broker executes over hours. The Time-Weighted Average Market Maker gives the design: an embedded AMM, long-term orders as per-block rates, pooled orders (Bob 0.1 ETH/block and Charlie 0.05 ETH/block share proceeds 2:1), virtual orders executed alternately, arbitrageurs who “bring its prices back in line with the market average,” expiry, and the economic claim that patient flow is less toxic so LPs earn fees with less adverse selection. Infinitesimal Virtual Orders justifies the limit for smoothness and efficiency. Implementation describes lazy evaluation between blocks, gas optimisations (order pooling with the billion-dollar algorithm; expiries restricted to fixed intervals such as every 250 blocks; free cancellation), and the Virtual Trade Math giving xendx_{\text{end}} in closed form (the formulas are stripped in the scraped copy but reproduced in §3 above). Potential Attack Vectors analyses sandwich attacks (defeated by between-block execution, except under multi-block MEV) and information leakage (mitigated by free cancellation and spoofing). A Python reference implementation and Jupyter demo are linked; the conclusion invites collaboration with Paradigm and Uniswap Labs.

  • “It works by breaking long-term orders into infinitely many infinitely small pieces and executing them against an embedded constant-product AMM smoothly over time.” (Introduction)
  • “Because it processes trades in between blocks, it is also less susceptible to sandwich attacks.” (Summary)
  • “Even if the TWAMM goes one million blocks between external interactions, the next time somebody interacts with it, it will be able to accurately calculate the results of all of the intervening virtual trades.” (Implementation, Lazy Evaluation)
  • “The biggest tradeoff long-term traders are likely to encounter with the TWAMM is the information leakage they are exposed to when placing publicly visible orders” (Potential Attack Vectors, Information Leakage)
  • “When such multi-block MEV becomes more common, allowing traders to sandwich across multiple blocks, this may become more of an issue.” (Sandwiching and Virtual Orders)

Background: the constant-product formula (CFMM math) and a first-year ODE. Read Summary, Overview, Basic Design and Lazy Evaluation; skip the traditional-finance analogy and the Ethereum refresher if you know them. The hardest part is the virtual trade math, and the scraped page loses it: re-derive it by writing the two flows as dx/dt=fxfyx2/kdx/dt = f_x - f_y x^2/k, recognising a Riccati equation with equilibrium kfx/fy\sqrt{k f_x / f_y}, and checking that the constant cc is just the normalised distance of the starting reserve from that equilibrium. The Python reference implementation on GitHub is the ground truth for the formulas.

  • 2022-06: Fraxswap ships the first live TWAMM on a Uniswap v2 fork, with hourly expiry alignment and an approximated formula.
  • 2023-06: Uniswap v4 whitepaper and announcement name TWAMM as a canonical hook; an example hook appears in v4-periphery.
  • 2022–2024: proposer–builder separation makes consecutive-block control by one builder more plausible, weakening the multi-block MEV assumption.
  • 2023–2025: research on batch auctions, intents and LVR (CoW, UniswapX, am-AMM) offers alternative answers to the same large-order problem.
  • Solana: Jupiter’s DCA/Recurring product (0.1% fee) became the practical time-sliced execution tool; no embedded TWAMM appeared in the sources.
  1. Frax Finance, Fraxswap Overview and Technical Specifications — read if you want a production implementation’s choices (expiry alignment, approximation).
  2. Uniswap Labs, Our Vision for Uniswap v4 (2023) — read if you want the hook framing.
  3. Hasu, Understanding AMMs Part 1: Price Impact (2021-04) — read if you want the manual order-splitting advice the TWAMM automates.
  4. Angeris et al., An analysis of Uniswap markets (2019) — read if you want the proof that splitting within a block cannot help.
  5. Jupiter, Recurring API docs — read if you want the Solana-side alternative.