DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk6 min

How to Check a DEX Pool’s Sandwich Attack Rate with Python and an API

A reproducible Python guide to querying hourly DEX pool bars, calculating a transaction-weighted sandwich rate, and interpreting missing data and risk fields.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To estimate a DEX pool’s recent sandwich-attack rate, request hourly bars for the pool from Codex’s GraphQL API, then calculate a transaction-weighted average of the returned sandwichRate values. Treat the result as an indexer-derived historical estimate—not a prediction that a particular swap will or will not be attacked.

What a pool’s sandwich rate tells you

A sandwich attack brackets a victim’s swap with an attacker’s front-run and back-run. The front-run changes pool reserves before the victim trades, potentially worsening the victim’s exchange rate; the back-run completes the attacker’s position afterward. A pool’s historical sandwich rate summarizes indexed activity over an observation period. It does not measure the risk of a specific future transaction.

As an Amazon Associate I earn from qualifying purchases.

Codex’s field definition, as reproduced in the how-to article, describes sandwichRate as sandwiched events divided by transactions and says it is null when there is no transaction data. A null observation therefore means the rate is unavailable, not zero. The underlying mechanism and the effect of slippage limits are discussed in the ETH Zurich study of sandwich attacks.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Query hourly pool bars with Python

You need a Codex API key, Python, and the requests package. The example below calls getBars at https://graph.codex.io/graphql, requests 60-minute bars, and uses a Unix-time start and end. Supply the pool’s address and network ID in the symbol value. Codex expects the API key in the Authorization header without a Bearer prefix.

import os
import time
import requests
from datetime import datetime, timedelta, timezone

API_URL = "https://graph.codex.io/graphql"
API_KEY = os.environ["CODEX_API_KEY"]
POOL_ADDRESS = "0xYourPoolAddress"
NETWORK_ID = 1  # Replace with the pool's network ID

# Example window: the previous seven days, ending now.
end_time = int(datetime.now(timezone.utc).timestamp())
start_time = int((datetime.now(timezone.utc) - timedelta(days=7)).timestamp())

query = """
query GetPoolBars($symbol: String!, $from: Int!, $to: Int!) {
  getBars(
    symbol: $symbol
    from: $from
    to: $to
    resolution: "60"
  ) {
    t
    transactions
    sandwichRate
    liquidityUsd
    volumeUsd
    pair {
      address
      networkId
      token0 { symbol }
      token1 { symbol }
      exchange { name }
    }
  }
}
"""

variables = {
    "symbol": f"{NETWORK_ID}:{POOL_ADDRESS}",
    "from": start_time,
    "to": end_time,
}

response = requests.post(
    API_URL,
    headers={"Authorization": API_KEY, "Content-Type": "application/json"},
    json={"query": query, "variables": variables},
    timeout=30,
)
response.raise_for_status()
payload = response.json()
if payload.get("errors"):
    raise RuntimeError(payload["errors"])

bars = payload["data"]["getBars"]
if not bars:
    raise RuntimeError("No bars returned for this request")

pair = bars[0].get("pair") or {}
if pair.get("address", "").lower() != POOL_ADDRESS.lower():
    raise RuntimeError(f"Returned a different pool: {pair.get('address')}")
if pair.get("networkId") != NETWORK_ID:
    raise RuntimeError(f"Returned a different network: {pair.get('networkId')}")

weighted_numerator = 0.0
weighted_denominator = 0
sandwiched_estimate = 0.0
usable_bars = 0
missing_rate_bars = 0
transaction_total = 0

for bar in bars:
    transactions = int(bar.get("transactions") or 0)
    transaction_total += transactions
    rate_value = bar.get("sandwichRate")

    if rate_value is None:
        missing_rate_bars += 1
        continue

    rate = float(rate_value)
    weighted_numerator += rate * transactions
    weighted_denominator += transactions
    sandwiched_estimate += rate * transactions
    usable_bars += 1

weighted_rate = (
    weighted_numerator / weighted_denominator
    if weighted_denominator else None
)

print({
    "pool": pair.get("address"),
    "network_id": pair.get("networkId"),
    "tokens": [
        (pair.get("token0") or {}).get("symbol"),
        (pair.get("token1") or {}).get("symbol"),
    ],
    "protocol": (pair.get("exchange") or {}).get("name"),
    "bars_returned": len(bars),
    "bars_with_rate": usable_bars,
    "bars_without_rate": missing_rate_bars,
    "transactions_in_all_bars": transaction_total,
    "transactions_in_rate_denominator": weighted_denominator,
    "weighted_sandwich_rate": weighted_rate,
    "estimated_sandwiched_transactions": sandwiched_estimate,
})

The selected metadata fields can help identify the returned pair and describe the sample. If you also request fee or MEV fields, convert decimal strings to numbers before arithmetic and keep nulls as missing values. Their interpretation and availability can vary by chain and indexing coverage.

Check the response before trusting the number

  • Call raise_for_status() before parsing the response, and check GraphQL’s errors array before reading data.getBars.
  • Verify the returned pair.address and network ID against the pool you intended to query. A syntactically valid request can resolve a token identifier to a pool; the echoed pool address is an important check.
  • EVM addresses are case-insensitive, but Solana base58 addresses are case-sensitive. Do not lowercase a Solana address for validation.
  • The how-to article reports a maximum of 1,500 datapoints per request and recommends paging longer, fine-grained windows. Because API limits can change, confirm the current limit in Codex documentation before relying on it.

Calculate the aggregate correctly

For each bar with a non-null rate, multiply the rate by that bar’s transaction count. Divide the sum of those products by the sum of transaction counts for those same bars:

weighted_rate = sum(rate_i * transactions_i) / sum(transactions_i)

This weights each hour according to its transaction volume. A simple average gives a quiet hour the same influence as a busy hour and answers a different question. The denominator must include only bars with a non-null rate; if it is zero, report the aggregate as unavailable rather than zero.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The corresponding estimated number of sandwiched transactions is the sum of rate_i × transactions_i across bars with rates. It is an estimate derived from indexed rates, not a separately verified count of individual attacks. Report the transaction denominator and how many bars lacked a rate alongside the aggregate so readers can judge its coverage.

Interpret and compare pool rates

There is no established “good” threshold

The consulted how-to does not provide an official benchmark for a good sandwich rate. Its author recommends comparing pools for the same token pair over several days; that is practical guidance, not an industry standard. For a useful comparison, use the same observation window, rate definition, chain, and similar data coverage. Include each pool’s transaction denominator and missing-rate-bar count.

Do not substitute MEV risk for sandwich incidence

mevRiskLevel and sandwichRate describe different things. The how-to article says the MEV risk field reflects builder-tip share, which can relate to arbitrage, back-runs, liquidations, and other MEV activity—not just sandwiches. It reports one author-tested Ethereum USDC/WETH example dated September 29, 2026, where the pool had a zero sandwich rate while most hourly bars showed medium MEV risk. That single example illustrates why the fields can diverge; it is not a general finding about pools.

Read fee fields and missing values cautiously

A null fee field should not be read as a zero fee or zero MEV. The how-to author reports null fee fields in sampled Solana pools and null builder-tip fields on Base and Arbitrum, while cautioning that field behavior may depend on indexing availability or chain fee structure. Confirm current field semantics and network coverage with Codex before drawing conclusions from those fields.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A historical pool rate cannot certify a future trade

A low rate over the period you measured does not establish that your next swap is safe. Pool-level history cannot resolve the details of an individual transaction, including its size, timing, slippage tolerance, or submission path. Slippage limits can make a swap fail if the exchange-rate change exceeds the permitted bound; they are not a guarantee against adverse execution.

Forensic alternative: inspect EVM attack legs with Dune

For trade-level investigation on supported EVM networks, Dune documents dex.sandwiches as a table of the outer front-run and back-run trades in sandwich attacks. Its documentation states: “The dex.sandwiches table captures detailed data on the outer trades of sandwich attacks in decentralized exchanges (DEXs), recording front-running and back-running trades across various EVM networks.” See Dune’s sandwiches table documentation.

This is a source for examining attack legs, not a ready-made per-pool hourly rate. To derive a rate, define the pool filter, time window, what counts in the numerator, and the transaction denominator explicitly. The how-to article also mentions a companion victim table, but the cited official documentation here covers dex.sandwiches; validate any other table name and schema before building a query around it.

How large studies fit—and do not fit—this check

Published attack counts provide context for the phenomenon, but they are not pool-specific benchmarks. A 2022 CHI study by Ye Wang, Patrick Zuest, Yaxing Yao, Zhicong Lu, and Roger Wattenhofer analyzed Uniswap and Sushiswap Ethereum data from May 4, 2020 through April 30, 2021, reporting 480,276 sandwich attacks across 5,728 pools in that historical period. That total cannot be used as a present-day pool rate.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A 2026 arXiv preprint by Lioba Heimbach, Ozan Solmaz, Burak Öz, and Christof Ferreira Torres studied protected-order-flow attacks across Ethereum, Solana, Tron, Base, Arbitrum, and Monad over three years. It reports 28.0 million attacks on Solana, 38,567 on Tron, 30,607 on Ethereum, and 1,889 on Base against transactions intended to be protected from front-running. Those counts are scoped to the study and its transaction set; they are neither current total chain counts nor comparable rates for the API method.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.