Skip to content

Add gas efficiency comparison page with Uniswap v4/v3 benchmarks - #10

Merged
moodysalem merged 17 commits into
mainfrom
docs-gas-efficiency
Sep 18, 2026
Merged

moodysalem merged 17 commits into
mainfrom
docs-gas-efficiency

Conversation

@moodysalem

Copy link
Copy Markdown
Member

New Concepts page (/concepts/gas-efficiency/) measuring Ekubo EVM swaps against Uniswap v4 and v3 on like-for-like workloads.

What it contains:

  • Single-hop tables (0.3% concentrated pools, wide-range positions, identical tokens, cold access, both directions) with tx-level percentages
  • Per-hop scaling marginals (~24k Ekubo vs ~52k v4 vs ~76k v3) and transfer-count tables
  • Frame-level attribution with flamegraphs (pool core 20k vs 46k vs 77k)
  • Mainnet-fork validation at block 25991868 (98k / 175k / 142k) with tier and tick-crossing disclosures
  • The mint exception, tier-labeled (Ekubo bare 179k / NFT 213k vs v4 162k vs v3 121k)
  • Full harness sources, snapshots, flamegraphs, and reproduction notes under benchmarks/

Methodology notes: each protocol compiled under its own production settings; minimal routers on all sides (favoring Uniswap); two external advisor reviews; no-crossing, hookless/extensionless scope stated on-page.

Checks: bun run check, build, lint, check:legacy, check:links, check:a11y, check:overflow, check:theme, check:api all pass.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

Deploying ekubo-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 864d485
Status: ✅  Deploy successful!
Preview URL: https://cc220d28.ekubo-docs-966.pages.dev
Branch Preview URL: https://docs-gas-efficiency.ekubo-docs-966.pages.dev

View logs

moodysalem and others added 8 commits September 17, 2026 10:39
New Concepts page measuring Ekubo EVM swaps against Uniswap v4 and v3 on
like-for-like workloads (0.3% concentrated pools, full-range-equivalent
positions, identical tokens, cold access): single-hop tables, per-hop
scaling marginals (~24k vs ~52k vs ~76k), frame-level attribution with
flamegraphs, mainnet-fork validation at block 25991868, and the mint
exception where Ekubo is not cheapest. Includes full harness sources,
snapshots, and reproduction notes under benchmarks/.
Lab now measures warmed steady-state (identical unmeasured warm-up before
each snapshot) after finding cold-access overstated v4/v3 single-hop costs
by ~17k while Ekubo is warmth-invariant. Mint legs use economically matched
liquidity (v3 depth corrected 1000x). Fixed a test-router bug that stranded
output in the v4 multihop router instead of delivering to the user.

Fork legs now share one pair (1000 USDT->USDC), warmed, negligible tick
movement: live Ekubo pool via the production Yul router with SDK calldata,
deepest v3/v4 fee-100 pools via SwapRouter/minimal locker. USDT quirks
handled with low-level calls like production routers.
Investigating warm/cold behavior found: vm.cool is a no-op under isolate;
in-test warm-ups are what warm. Ekubo is warmth-invariant but v4/v3 carry
~17k of cold swap-path slots, so warmed headlines understated them.
Singles now report the cold path on capitalized pools (87/121/105k),
scaling keeps warmed marginals (correct for in-route hops) with a
first-hop-cold note, and flamegraphs capture single cold-path calls.
Also fixes a v4 multihop test router that retained output instead of
delivering to the user (numbers unchanged) and matches v3 mint depth to
the other harnesses.
Rebase the headline single-swap comparison on steady-state figures
(Ekubo 87,416 / v4 103,533 / v3 87,641) with the first-swap-in-fresh-pool
surcharge (+17,100 on v4 and v3) and v3's next-block oracle write (93,712)
noted alongside. Keep execution gas and transaction gas on separate,
labeled bases and recompute every percentage.

- Scaling table reports v3 net of refunds with gross and refund shown;
  marginals 24,429 / 34,411 / 58,696 (78,596 gross).
- Fork table carries both swap sizes, pool identifiers, hook confirmation,
  output amounts, and recipient/allowance conditions.
- Mint table tiered by new position vs top-up vs NFT (harness-only).
- New pool-init, calldata, and chain-capacity sections; fork transaction
  totals recomputed (133,750 / 151,515 / 155,960).
- Flamegraph captions state the router call frame and the SVG root.
- Methodology corrected: isolate gives each call its own EVM context and
  the snapshot is the call's execution gas net of refunds, not receipt gas.
- benchmarks/README.md matched to the current test names and numbers;
  reference calldata files added for the v4 minimal locker and the Ekubo
  Solidity Router; harness comments on isolate semantics corrected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add mainnet-fork mint benchmarks (block 25991868) through the deployed Ekubo
Positions contract, the Uniswap v4 PositionManager and the Uniswap v3
NonfungiblePositionManager on the same live USDC/USDT pools as the fork swap
legs, with cold-boundary-tick variants and state assertions proving each mint.

Measured (warm, boundary ticks initialized): Ekubo 244,513, v4 297,390,
v3 381,653. The gas page now presents mints at two tiers: the user-facing
production-manager tier, where Ekubo is cheapest (17.8% below v4, 35.9% below
v3), and the bare direct-to-core lab tier, which keeps its existing numbers and
remains the one place Ekubo is not cheapest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Split the lab bare mints into core state update, settlement and lock/router
  plumbing from -vvvv traces; label the v3 direct pool.mint as a lock-free tier
  and quantify the plumbing Ekubo and v4 carry (31,473 and 68,832).
- State the mint exception exactly: Ekubo's core frame (106,407) is not the
  cheapest in the committed never-swapped lab pool (v4 63,358, v3 108,185 net),
  and disclose the traded-pool probe (v4 +39,800, v3 +39,844, Ekubo unchanged)
  that explains why: Uniswap position fee-growth snapshots go zero-to-nonzero
  once a pool has traded, while Ekubo pre-initializes its accumulators.
- Remove one-time initialization costs from every comparison: delete the
  pool-creation section and the cold-boundary-tick mint rows; keep the
  first-swap accumulator note to one disclosed line; add the exclusion to the
  methodology.
- Rework chain capacity around routes: 1/2/3-pool route ceilings per 60M block
  from the lab route totals plus 21,000, and a pools-per-swap sensitivity blend
  (1.0/1.5/2.0) using the measured per-extra-pool marginals. No published
  pools-per-swap figure was found, stated as such.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o benchmarks/README

Rewrite concepts/gas-efficiency.md as a shorter, decision-oriented page:
headline numbers, why Ekubo is cheaper, and what it means for integrators.
The measurement-harness details (test names, frame attribution, EIP-7623
floor math, how to reproduce) now live in benchmarks/README.md so the
concept page no longer depends on forge internals.

Also picks up the regenerated OpenAPI documents from `bun run sync:openapi`
(quoter 3.4.1 -> 3.4.4 with a 503 response; ekubo adds volume0/volume1/
swap_count to the OHLC series). Both files were formatted with prettier.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
moodysalem and others added 9 commits September 17, 2026 10:52
…d on it

The chain-wide section previously blended per-transaction savings at
assumed 1.0/1.5/2.0 pools per swap because no measured figure existed.
This measures it: over 200 consecutive mainnet blocks (25997689-25997888,
2026-09-17 14:04-14:44 UTC) read through a public JSON-RPC endpoint,
5,341 successful transactions emitted at least one pool-level swap event
(Uniswap v2-family, v3, v4, Curve), averaging 1.66 pools per swap
(71.5% / 15.6% / 6.2% / 6.6% touch 1 / 2 / 3 / 4+ pools). A calldata
decode of the 470 transactions sent to the Uniswap and 1inch routers
(hop counts from Universal Router commands, SwapRouter paths, unoswapN)
averages 1.11 and matches the receipt event count on every transaction.

Dune was the intended source but no key or account was available, so
eth_getBlockReceipts + eth_getBlockByNumber were used instead; the script
verifies each router address by selector presence in on-chain bytecode.

Page: the measured 1.66 is now the headline blend (Ekubo 131,958 vs v4
150,974 / v3 153,652; 12.6% / 14.1% saving), with the router-only 1.11
and the 1.0/1.5/2.0 rows kept as context. Chain-wide freed-gas scenarios
are recomputed at three explicitly labeled block-space shares: the
measured 4.2% DEX-router burn lower bound, the 19.4% "defi" bracket, and
a stipulated 70% AMM-trading upside case marked as an assumption, not a
measurement. The window's own swap-transaction gas share (30.3%) is
reported as a check that 4.2% is a floor. Swaps-per-block ceilings are
unchanged.

benchmarks/README.md documents the method, window, event signatures,
router addresses, per-family and per-router tables, undecoded selectors,
and the reproduction command; benchmarks/pools-per-swap/ holds the script
and raw results.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…indow

The receipt-based measurement previously counted only Uniswap v2-family,
v3, v4 and Curve events over 200 blocks. It now covers PancakeSwap v3,
Curve's crypto/tricrypto events, Balancer v2 and v3, Maverick v1 and v2,
Fluid DEX, DODO v1/v2, Bancor v2.1/v3/Carbon, Solidly-style pairs and
Ekubo itself. Every signature was read from the protocol's source and
hashed with cast keccak. Ekubo Core writes its swap record with log0 and
no topics, so it is matched as a topic-less 116-byte log from the Core
address (Core.sol `log0(o, 116)`), which counts every Ekubo swap
regardless of caller; the Yul router is verified by the embedded Core
address and received one transaction in the window.

Over blocks 25997046-25998045 (2026-09-17 11:55-15:16 UTC): 32,417 swap
transactions, 54,407 pool swap events, 1.678 pools per swap
(72.1% / 14.8% / 6.3% / 6.9% touch 1 / 2 / 3 / 4+ pools), swap-containing
transactions used 32.67% of window gas. This confirms the earlier 1.66;
the page's blended rows and scenario cells are recomputed from the new
average (Ekubo 132,475 vs v4 151,703 / v3 154,894, 12.7% / 14.5%) and the
router-only row from 4,432 decoded router transactions at 1.283 pools.
The calldata cross-check now reports per router; the 25 mismatches are
v4 hook pools performing nested swaps and tax tokens selling their fee
through the same pair, all with more events than decoded hops.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…omponent

Add fork harnesses for Base (block 51439900) and Arbitrum One (block
506178800): 100 USDC to WETH through the deployed Yul router on a fresh
Ekubo pool mirroring the deepest v3 pool, SwapRouter02/SwapRouter, and the
v4 PoolManager with a minimal locker. Record execution gas, exact calldata
and the L1 data charge from each chain's fee oracle (GasPriceOracle on Base,
NodeInterface/ArbGasInfo on Arbitrum). Add a page section and the full
methodology, deployments, endpoints and formulas to benchmarks/README.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
New benchmarks/prod: production Ekubo (Core, Positions, Yul router), Uniswap v3
(factory, SwapRouter) and v4 (PoolManager, Universal Router + Permit2) on a fork
of the latest mainnet block with four fresh ERC20 tokens etched at fixed
addresses, 1/2/3-pool routes and native-ETH legs through production routers
and like-for-like minimal single-lock lockers, isolated and warmed, exact
calldata bytes recorded per call. Replaces the USDC/USDT pair as the headline.

pools-per-swap/measure.mjs gains --stride sampling across a month, endpoint
rotation, receipt/block consistency checks and per-day buckets.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… pools-per-swap sample

Headline is now a fresh ERC20 pair through each protocol's production router on
a latest-block fork (Ekubo 110,875 vs v4 Universal Router 144,390 vs v3
SwapRouter 123,587 transaction gas), with minimal-router and native-ETH rows and
USDC/USDT kept as the expensive-token bound. Pools per swap is measured over
every 10th block of a month (21,600 blocks, 664,726 swap txs, 1.75 avg, 32.7%
of gas), all AMM families, per-family and per-day breakdowns in the README.
Blend, routes-per-block and chain-wide scenario tables recomputed from the raw
files by benchmarks/page-numbers.mjs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…coder script

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The catalogue of swap events cannot be complete, so uncatalogued AMMs add
uncounted transactions, pools and gas; the chain-wide capacity gains inherit
that bias and are underestimates.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…figured

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@moodysalem
moodysalem merged commit 32a51a5 into main Sep 18, 2026
2 checks passed
@moodysalem
moodysalem deleted the docs-gas-efficiency branch September 18, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant