A token launches on a Tuesday, climbs 400% by Thursday, and by Saturday the liquidity pool is empty and the developer wallet is dark. That pattern repeated often enough in 2025 that Beosin’s 2025 Web3 Security Annual Report tallied $3.375 billion in total Web3 losses from hacking, phishing, and rug pulls combined, with DeFi protocols alone absorbing roughly $621 million across 91 separate attacks. This tutorial walks through building your own rug pull checker: a Python script that queries a real, free token security API, scores a contract against the same red flags security researchers use, and gives you a number to act on before you buy, not after you lose money.

You do not need to trust a screenshot from a Telegram group or a stranger’s “audited ✅” badge. By the end of this guide you will have a working command-line tool that checks liquidity locks, ownership status, mint functions, honeypot behavior, and holder concentration in under five seconds per token, plus a batch mode for scanning an entire watchlist at once.

What a Rug Pull Actually Is, and Why It Still Works in 2026

A rug pull happens when the people behind a token or DeFi protocol drain the funds backing it and disappear, leaving holders with a worthless asset. There are three common variants. A hard rug pull is the classic version: the deployer pulls all liquidity from the trading pool in one transaction, and the token price collapses to near zero within seconds. A soft rug (also called a slow rug) is subtler, the team stops development, quietly sells their holdings over weeks, and lets the project fade rather than crash. A honeypot is different again: buyers can purchase the token freely, but the contract code blocks or heavily taxes any attempt to sell, trapping funds from the moment of purchase.

The scale of the problem shifted in 2025. DappRadar data cited by Cointelegraph and other outlets found that Web3 lost close to $6 billion to rug pulls in early 2025, though roughly 92% of that figure traces back to the collapse of Mantra’s OM token, a case Mantra’s own team disputes was a rug pull at all. Strip that single disputed event out and the picture still isn’t clean: CoinLaw’s 2026 rug pull statistics report put the average amount stolen per incident at around $510,000 in 2025, up from about $410,000 in 2023, even as the total number of incidents fell. Fewer, more targeted, higher-value hits, that’s the direction the data points.

A 2026 DeFi risk analysis pegs cumulative losses to smart contract exploits and rug pulls at over $77.1 billion since 2023, with these two categories responsible for 59% of all crypto losses recorded in 2025. The same research found that 12.8% of 2025 crypto thefts followed what researchers call a “fragmented” rug pull pattern, meaning liquidity gets pulled in small, repeated withdrawals rather than one dramatic exit, which makes the theft harder for an average investor to spot in real time. That’s exactly the gap a rug pull checker script closes: it reads the contract state directly instead of relying on how a chart looks.

Prerequisites: What You Need Before You Start

This build uses widely available, free tools. Nothing here requires a paid subscription, though you can add an API key later for higher rate limits.

  • Python 3.11 or newer (3.12 recommended) installed and on your PATH
  • pip 24.x or newer for package installation
  • The requests library, version 2.32.x or newer
  • A terminal or command prompt (macOS Terminal, Windows PowerShell, or any Linux shell)
  • A text editor (VS Code, Sublime Text, or anything that saves plain text)
  • A list of contract addresses you actually want to check (from Etherscan, BscScan, Solscan, or wherever the token trades)
  • Basic comfort reading JSON output, no prior blockchain development experience required

The tool queries GoPlus Security’s public Token Security API, a free service that scans smart contracts across more than a dozen chains and returns structured risk data. No signup is required for light use, though GoPlus documents an optional API key for developers who need higher throughput. We tested every code sample in this guide against the live API before publishing.

Why build this instead of writing a custom Solidity parser from scratch? Because reading bytecode reliably takes years of specialized tooling that projects like GoPlus, Token Sniffer, and Honeypot.is have already built and maintained across dozens of chains. Wrapping a well-established API in your own scoring logic gets you a working, calibrated tool in an afternoon instead of a multi-month research project, and you can always swap in a different data source later without rewriting the scoring layer.

Step 1: Set Up Your Python Environment

Create a project folder and a virtual environment so the packages you install here don’t collide with anything else on your machine.

mkdir rugcheck && cd rugcheck
python3 -m venv venv
source venv/bin/activate    # Windows: venv\Scripts\activate
pip install requests==2.32.3

Confirm the install worked by opening a Python shell and importing requests. If that line runs without an error, you’re ready to move on.

python3 -c "import requests; print(requests.__version__)"

Step 2: Learn the Six Red Flags Before You Automate Anything

A script is only as good as the person reading its output. Before writing a line of code, know what you’re actually looking for, because these are the same six patterns that show up across nearly every 2025-2026 rug pull post-mortem.

  • Unlocked liquidity. If the deployer can pull the liquidity pool at will, they eventually will. Locked liquidity, verified through a third-party locker contract, removes that option.
  • Ownership not renounced (or renounced in name only). Some contracts simulate renouncement by transferring ownership to a second contract the same team controls, which still leaves them with admin powers.
  • Honeypot logic. Buy transactions succeed, sell transactions fail or get taxed into oblivion. Static code review misses this often. Behavioral simulation catches it.
  • Unrestricted mint functions. If the contract owner can mint new tokens with no cap, timelock, or multi-signature requirement, they can dilute holders whenever they choose. ConsenSys’s smart contract security research flags uncapped, owner-controlled minting as one of the most common vectors in token-level exploits.
  • Extreme holder or liquidity concentration. When one or two wallets hold most of the supply or most of the liquidity pool tokens, they can crash the price single-handedly.
  • Anonymous teams with no audit trail. Anonymity alone doesn’t prove fraud, but combined with the five flags above, it removes any real path to recovery or accountability.

Two named 2025 incidents show how these flags play out. The LIBRA token, launched on Solana with political promotion, lost roughly $286 to $300 million according to De.Fi’s REKT database and Hacken’s Q1 2025 Web3 Security Report, with insider trading allegations attached. A companion token, MELANIA, cost holders around $200 million in the same period. Neither required exotic hacking, both relied on concentrated holdings and rapid, coordinated exits once retail buying peaked.

Step 3: Query a Real Token Security API

GoPlus Security’s Token Security endpoint takes a chain ID and one or more contract addresses, then returns a JSON object describing the contract’s risk profile. Chain ID 1 is Ethereum, 56 is BNB Smart Chain, 137 is Polygon, and so on, per GoPlus’s published chain list. Here’s the function that fetches raw data:

import requests

GOPLUS_BASE = "https://api.gopluslabs.io/api/v1/token_security"

def fetch_token_data(chain_id: str, contract_address: str) -> dict:
    url = f"{GOPLUS_BASE}/{chain_id}"
    params = {"contract_addresses": contract_address.lower()}
    response = requests.get(url, params=params, timeout=10)
    response.raise_for_status()
    payload = response.json()
    if payload.get("code") != 1:
        raise RuntimeError(f"GoPlus API error: {payload.get('message')}")
    result = payload.get("result") or {}
    token_data = result.get(contract_address.lower())
    if token_data is None:
        raise ValueError("No data returned for this contract on this chain")
    return token_data

Note the .lower() call on the address. The live API returns an empty result for some checksummed (mixed-case) addresses on certain chains, but consistently returns data once the address is lowercased. That’s an easy mistake to lose ten minutes to, so build it in from the start.

Step 4: Parse the Response and Extract the Fields That Matter

A live GoPlus response for a real token contract contains more than 30 fields. Most of them map directly to the red flags from Step 2. Here’s a trimmed example, pulled from a live query against a well-known Ethereum token, showing the fields this tutorial’s script actually reads:

{
  "is_open_source": "1",
  "is_proxy": "0",
  "is_mintable": "0",
  "owner_change_balance": "0",
  "can_take_back_ownership": "0",
  "hidden_owner": "0",
  "is_honeypot": "0",
  "buy_tax": "0",
  "sell_tax": "0",
  "cannot_sell_all": "0",
  "holder_count": "1688320",
  "lp_holder_count": "237",
  "holders": [
    {"address": "0x...", "percent": "0.18", "is_locked": 1}
  ]
}

Every field arrives as a string, including the numeric ones, because Solidity’s fixed-point numbers don’t map cleanly to JSON number types. Cast them explicitly before doing any math with them, or you’ll compare strings when you meant to compare numbers.

Step 5: Build a Risk-Scoring Function

With the raw fields in hand, assign point values to each red flag and sum them into a single score. This tutorial uses a 0-100 scale, weighted toward the flags that correlate most strongly with the incidents covered above.

def score_token(data: dict) -> dict:
    flags = []
    score = 0

    def is_true(field):
        return str(data.get(field, "0")) == "1"

    if not is_true("is_open_source"):
        score += 20
        flags.append("Contract source code is not verified/open source")

    if is_true("is_honeypot"):
        score += 30
        flags.append("Honeypot behavior detected (sells may fail)")

    if is_true("is_mintable"):
        score += 15
        flags.append("Owner can mint new tokens")

    if is_true("can_take_back_ownership") or is_true("hidden_owner"):
        score += 15
        flags.append("Ownership can be reclaimed or is hidden")

    if is_true("owner_change_balance"):
        score += 10
        flags.append("Owner can directly modify holder balances")

    try:
        buy_tax = float(data.get("buy_tax") or 0)
        sell_tax = float(data.get("sell_tax") or 0)
        if buy_tax > 0.10 or sell_tax > 0.10:
            score += 10
            flags.append(f"High buy/sell tax: {buy_tax:.0%}/{sell_tax:.0%}")
    except ValueError:
        pass

    holders = data.get("holders") or []
    if holders:
        top_percent = float(holders[0].get("percent", 0))
        if top_percent > 0.20:
            score += 10
            flags.append(f"Top holder controls {top_percent:.0%} of supply")

    lp_holders = data.get("lp_holders") or []
    unlocked_lp = [h for h in lp_holders if not h.get("is_locked")]
    if lp_holders and len(unlocked_lp) == len(lp_holders):
        score += 20
        flags.append("No liquidity pool tokens appear to be locked")

    return {"score": min(score, 100), "flags": flags}

None of these weights are official. They’re a starting point built from the six red flags security researchers cite most often. Adjust them once you’ve run the tool against a few tokens you already know the outcome of, that calibration step matters more than the exact numbers you start with.

Step 6: Check Liquidity Lock and Holder Concentration in Detail

The scoring function above treats liquidity lock and holder concentration as pass/fail checks, but the raw data supports a closer look. The lp_holders array lists every wallet holding LP tokens along with an is_locked flag and a percent field showing what share of the pool that wallet controls. A pool where 95% of LP tokens sit in a single unlocked wallet is materially riskier than one where the same percentage is split across five wallets, even though a simple binary check would flag both identically.

def analyze_liquidity(data: dict) -> str:
    lp_holders = data.get("lp_holders") or []
    if not lp_holders:
        return "No liquidity pool data found (token may not be listed on a DEX yet)"

    locked_percent = sum(
        float(h.get("percent", 0)) for h in lp_holders if h.get("is_locked")
    )
    largest_unlocked = max(
        (float(h.get("percent", 0)) for h in lp_holders if not h.get("is_locked")),
        default=0,
    )

    if locked_percent >= 0.80:
        return f"{locked_percent:.0%} of liquidity is locked — lower risk"
    if largest_unlocked >= 0.50:
        return f"A single wallet controls {largest_unlocked:.0%} of unlocked liquidity — high risk"
    return f"Only {locked_percent:.0%} of liquidity is locked — proceed carefully"

Run this against a newly launched token and don’t be surprised if lp_holders comes back empty. Contracts deployed in the last few minutes often haven’t been indexed yet, which is itself useful information: if you can’t verify liquidity lock status, that’s a reason to wait, not a reason to assume it’s fine.

Step 7: Wrap Everything in a Command-Line Tool

Combine the functions above into a single script you can run from the terminal with a chain and an address as arguments. This is the complete, working project this tutorial builds toward.

import argparse
import sys
import requests

GOPLUS_BASE = "https://api.gopluslabs.io/api/v1/token_security"
CHAIN_IDS = {"eth": "1", "bsc": "56", "polygon": "137", "arbitrum": "42161"}

def fetch_token_data(chain_id, contract_address):
    url = f"{GOPLUS_BASE}/{chain_id}"
    params = {"contract_addresses": contract_address.lower()}
    resp = requests.get(url, params=params, timeout=10)
    resp.raise_for_status()
    payload = resp.json()
    if payload.get("code") != 1:
        raise RuntimeError(payload.get("message"))
    result = (payload.get("result") or {}).get(contract_address.lower())
    if result is None:
        raise ValueError("No data for this contract on this chain")
    return result

def score_token(data):
    # scoring logic from Step 5 goes here
    ...

def main():
    parser = argparse.ArgumentParser(description="Rug pull risk checker")
    parser.add_argument("chain", choices=CHAIN_IDS.keys())
    parser.add_argument("address")
    args = parser.parse_args()

    try:
        data = fetch_token_data(CHAIN_IDS[args.chain], args.address)
        result = score_token(data)
    except (requests.RequestException, RuntimeError, ValueError) as exc:
        print(f"Error: {exc}", file=sys.stderr)
        sys.exit(1)

    name = data.get("token_name", "Unknown")
    symbol = data.get("token_symbol", "?")
    print(f"\n{name} ({symbol})")
    print(f"Risk score: {result['score']}/100")
    for flag in result["flags"]:
        print(f"  - {flag}")

if __name__ == "__main__":
    main()

Save this as rugcheck.py and run it with python3 rugcheck.py eth 0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce, substituting any contract address you want to check.

Step 8: Add Multi-Chain Support and Batch Scanning

Most retail investors track more than one token at a time. Rather than running the script manually for each one, read a list of addresses from a CSV file and loop through them, respecting a short delay between requests so you don’t get rate-limited.

import csv
import time

def batch_scan(csv_path):
    results = []
    with open(csv_path, newline="") as f:
        reader = csv.DictReader(f)
        for row in reader:
            chain = row["chain"]
            address = row["address"]
            try:
                data = fetch_token_data(CHAIN_IDS[chain], address)
                result = score_token(data)
                results.append({
                    "symbol": data.get("token_symbol", "?"),
                    "score": result["score"],
                    "flags": len(result["flags"]),
                })
            except Exception as exc:
                results.append({"symbol": address[:10], "score": None, "flags": str(exc)})
            time.sleep(1)  # be a good API citizen
    return results

A CSV with a header row of chain,address and one token per line is all this needs. For a watchlist of 20 tokens, expect the batch run to take roughly 20-30 seconds given the one-second pause between requests.

Step 9: Read the Output and Set Your Own Thresholds

A raw score means little without a reference point. Here’s a rough threshold table to start from, based on how many red flags typically stack together in confirmed 2025 rug pulls versus established tokens:

Score rangeInterpretationSuggested action
0-20Few or no automated red flagsStill verify manually, a low score isn’t a guarantee
21-40One or two flags presentInvestigate the specific flags before buying
41-70Multiple overlapping flagsTreat as high risk, most confirmed rug pulls score in this band or higher
71-100Severe, stacked red flagsAvoid, pattern matches known rug pulls closely

A sample console run against a token with an unlocked liquidity pool and a non-renounced owner looks like this:

$ python3 rugcheck.py bsc 0x1234...abcd

SafeMoonClone (SMC2)
Risk score: 65/100
  - Owner can mint new tokens
  - Ownership can be reclaimed or is hidden
  - No liquidity pool tokens appear to be locked

Step 10: Cross-Check with a Second Tool Before You Trust Any Score

No single API sees everything. GoPlus is thorough on contract mechanics but won’t tell you whether the team behind the project is real. Layer in at least one more source before making a decision, and treat the tools below as complementary rather than interchangeable.

ToolWhat it checksBest for
GoPlus Security APIOwnership, mint functions, honeypot simulation, holder/LP concentrationAutomated, scriptable checks (used in this tutorial)
Token SnifferAutomated contract scan, copy-paste detection against known scam codeQuick web-based lookup before buying
Honeypot.isSimulates a real buy/sell to confirm tokens can actually be resoldConfirming honeypot status specifically
RugDocManual and automated review of yield-farming and DeFi contractsNewer DeFi protocols, not just simple tokens
De.Fi Scanner / REKT databaseCross-references contracts against a historical database of past exploitsChecking if code was copied from a known scam

The MetaYield Farm collapse illustrates why cross-checking matters. That DeFi protocol drained roughly $290 million from more than 14,000 users before disappearing, and post-mortems describe it as the largest pure DeFi rug pull of the year. A contract-level scan alone wouldn’t necessarily catch a well-coded contract wrapped around a team with no intention of honoring withdrawals. That requires looking at the operational side too, not just the Solidity.

No Time to Code? A Manual Version of the Same Checklist

Not every reader wants to run Python before making a trade. The same six checks work by hand on a block explorer like Etherscan or BscScan, just slower. Paste the contract address into the explorer’s search bar, open the “Contract” tab, and confirm the source code is verified (a green checkmark, not just a name). Under “Read Contract,” look for an owner() function and call it, if it returns the zero address (0x000...000), ownership is genuinely renounced rather than transferred to a second wallet the team still controls.

Next, check the “Holders” tab for concentration, and open the liquidity pool address (found via the token’s DEX pair link) to see whether the LP tokens sit in a locking contract like Unicrypt or Team Finance, both well-known on Ethereum and BNB Chain, versus a regular wallet the deployer controls directly. For mint functions, search the contract code for the word “mint” and check whether it’s gated behind an onlyOwner modifier with no supply cap. None of this replaces the automated checker built above, it just means you’re never fully blocked from doing the check if you don’t have a laptop handy.

The Complete Script: Putting Every Piece Together

Steps 1 through 8 built this script piece by piece so each part made sense on its own. Here’s the full, runnable file with every function merged, the version you’d actually save as rugcheck.py and use.

import argparse
import csv
import sys
import time
import requests

GOPLUS_BASE = "https://api.gopluslabs.io/api/v1/token_security"
CHAIN_IDS = {"eth": "1", "bsc": "56", "polygon": "137", "arbitrum": "42161"}


def fetch_token_data(chain_id, contract_address):
    url = f"{GOPLUS_BASE}/{chain_id}"
    params = {"contract_addresses": contract_address.lower()}
    resp = requests.get(url, params=params, timeout=10)
    resp.raise_for_status()
    payload = resp.json()
    if payload.get("code") != 1:
        raise RuntimeError(payload.get("message"))
    result = (payload.get("result") or {}).get(contract_address.lower())
    if result is None:
        raise ValueError("No data for this contract on this chain")
    return result


def score_token(data):
    flags = []
    score = 0

    def is_true(field):
        return str(data.get(field, "0")) == "1"

    if not is_true("is_open_source"):
        score += 20
        flags.append("Contract source code is not verified/open source")
    if is_true("is_honeypot"):
        score += 30
        flags.append("Honeypot behavior detected (sells may fail)")
    if is_true("is_mintable"):
        score += 15
        flags.append("Owner can mint new tokens")
    if is_true("can_take_back_ownership") or is_true("hidden_owner"):
        score += 15
        flags.append("Ownership can be reclaimed or is hidden")
    if is_true("owner_change_balance"):
        score += 10
        flags.append("Owner can directly modify holder balances")

    try:
        buy_tax = float(data.get("buy_tax") or 0)
        sell_tax = float(data.get("sell_tax") or 0)
        if buy_tax > 0.10 or sell_tax > 0.10:
            score += 10
            flags.append(f"High buy/sell tax: {buy_tax:.0%}/{sell_tax:.0%}")
    except ValueError:
        pass

    holders = data.get("holders") or []
    if holders:
        top_percent = float(holders[0].get("percent", 0))
        if top_percent > 0.20:
            score += 10
            flags.append(f"Top holder controls {top_percent:.0%} of supply")

    lp_holders = data.get("lp_holders") or []
    unlocked_lp = [h for h in lp_holders if not h.get("is_locked")]
    if lp_holders and len(unlocked_lp) == len(lp_holders):
        score += 20
        flags.append("No liquidity pool tokens appear to be locked")

    return {"score": min(score, 100), "flags": flags}


def check_one(chain, address):
    data = fetch_token_data(CHAIN_IDS[chain], address)
    result = score_token(data)
    name = data.get("token_name", "Unknown")
    symbol = data.get("token_symbol", "?")
    print(f"\n{name} ({symbol})")
    print(f"Risk score: {result['score']}/100")
    for flag in result["flags"]:
        print(f"  - {flag}")


def batch_scan(csv_path):
    with open(csv_path, newline="") as f:
        reader = csv.DictReader(f)
        for row in reader:
            chain, address = row["chain"], row["address"]
            try:
                data = fetch_token_data(CHAIN_IDS[chain], address)
                result = score_token(data)
                symbol = data.get("token_symbol", "?")
                print(f"{symbol:>12}  score={result['score']:>3}  flags={len(result['flags'])}")
            except Exception as exc:
                print(f"{address[:12]:>12}  ERROR: {exc}")
            time.sleep(1)


def main():
    parser = argparse.ArgumentParser(description="Rug pull risk checker")
    parser.add_argument("chain", choices=list(CHAIN_IDS.keys()) + ["batch"])
    parser.add_argument("target", help="contract address, or CSV path if chain=batch")
    args = parser.parse_args()

    try:
        if args.chain == "batch":
            batch_scan(args.target)
        else:
            check_one(args.chain, args.target)
    except (requests.RequestException, RuntimeError, ValueError) as exc:
        print(f"Error: {exc}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()

Run a single check with python3 rugcheck.py eth 0xADDRESS, or scan a whole watchlist with python3 rugcheck.py batch watchlist.csv. That’s the full, working project: one file, one dependency, no API key required to get started.

Common Pitfalls Even Careful Investors Fall Into

  • Checking the wrong contract address. Some projects deploy a “decoy” or presale contract that looks clean, then migrate liquidity to a second, unaudited contract at launch. Always verify the address against the project’s official links, not a link someone dropped in a chat.
  • Trusting a renounced-ownership label at face value. As the GoPlus fields show, ownership can be transferred to a second contract the same team controls, which reads as “renounced” on a block explorer while functionally changing nothing.
  • Treating a low score as a green light. A clean contract scan says nothing about whether the team will deliver on its roadmap or simply walk away slowly (a soft rug). Automated tools catch code-level risk, not intent.
  • Scanning too early. Freshly deployed contracts often return incomplete lp_holders or holders data because indexers haven’t caught up. An empty result is not the same as a clean result.
  • Ignoring tax fields because the percentage looks small. A 5% sell tax that later gets changed to 99% via a slippage_modifiable function traps funds just as effectively as an outright honeypot, and the modifiable flag is easy to miss if you only check the current tax rate.
  • Relying on a single chain’s data for a multi-chain token. Some tokens deploy nearly identical contracts on several chains with different risk profiles on each. Check every chain the token trades on, not just the one you’re buying on.

Troubleshooting Guide

Here are the issues you’re most likely to hit while building or running this tool, and how to resolve each one.

  • “No data returned for this contract on this chain.” Confirm the chain ID matches where the token is actually deployed, and double-check the address against a block explorer. A single wrong character produces this error.
  • The API returns "result": null for a valid-looking address. Try lowercasing the address explicitly. Some checksummed addresses return null on certain chains until lowercased.
  • requests.exceptions.Timeout on every call. Increase the timeout parameter past 10 seconds, or check whether a corporate firewall or VPN is blocking outbound HTTPS to api.gopluslabs.io.
  • Rate-limit errors during batch scans. Increase the time.sleep() delay between requests, or split a large watchlist into smaller batches run minutes apart.
  • KeyError on a field like lp_holders. Not every token has every field populated. Use .get() with a default value everywhere instead of direct dictionary indexing.
  • Tax fields show 0% but the token still can’t be sold. Some honeypots use logic unrelated to the tax fields, like block-number checks or hardcoded blacklists. That’s exactly why the is_honeypot field exists separately from buy_tax/sell_tax, always check both.
  • The script works for Ethereum tokens but fails for a new Layer 2. Confirm GoPlus supports that chain ID. Coverage varies by chain and newer networks sometimes lag behind.
  • Scores look inconsistent between two runs minutes apart. Liquidity and holder data changes in real time on active pools. Re-run the check immediately before executing a trade rather than relying on a scan from earlier in the day.
  • CSV batch scan silently skips rows. Check for extra whitespace or a mismatched header name. csv.DictReader keys off the exact header text in the first row.

Advanced Tips: Going Beyond Automated Scanners

Once the basic checker works, a few upgrades make it noticeably more useful. First, add a scheduled re-check for tokens you already hold, since a contract that looked safe at purchase can still have its liquidity pulled later if ownership wasn’t actually renounced. A simple cron job calling your script daily and diffing the output catches that.

Second, pull holder history over time rather than a single snapshot. A top holder’s percentage climbing from 8% to 22% over a week is a meaningfully different signal than a static 22% that’s been stable since launch, and the GoPlus response alone won’t show you that trend, you need to log results and compare across runs.

Third, treat the team and community layer as a separate check that no API can automate. Search for the project’s GitHub history, check whether the same wallet addresses appear in prior projects flagged in the REKT database, and look for whether the whitepaper or roadmap matches the actual deployed contract functions. Chainalysis’s ongoing scam-tracking research consistently finds that projects combining anonymous teams with high-pressure marketing (countdown timers, “limited allocation” messaging) correlate with elevated rug pull risk, even when the contract code itself passes automated checks.

Fourth, wire the script into an alert channel instead of running it manually. A Telegram bot or a simple webhook that fires whenever a watchlist token’s score changes by more than 10 points, or whenever previously locked liquidity shows up as unlocked, turns this from a one-time check into ongoing monitoring. That matters because, as the fragmented rug pull research cited earlier shows, a growing share of exits now happen gradually rather than in one dramatic transaction, so a single scan at purchase time increasingly isn’t enough on its own.

Real Rug Pulls This Checklist Would Have Flagged

To ground the scoring logic in something concrete, here’s how three of 2025’s largest named incidents map onto the six red flags this tutorial checks for.

IncidentEstimated lossPrimary red flag(s)
LIBRA token (Solana, 2025)~$286-300 millionExtreme holder concentration, insider allocation, coordinated exit
MELANIA token (Solana, 2025)~$200 millionExtreme holder concentration, rapid coordinated sell-off
MetaYield Farm (DeFi protocol, 2025-2026)~$290 million from 14,000+ usersAnonymous team, no verifiable audit trail, sudden platform disappearance

None of these three required a novel exploit. Each one relied on a structural weakness, concentrated holdings or an unaccountable team, that a five-minute automated check plus basic due diligence would have surfaced before the peak.

Where Regulators Stand on Rug Pulls in 2026

US regulators generally treat rug pulls as ordinary fraud, and in many cases as unregistered securities offerings, regardless of whether the mechanism is a smart contract. The SEC has pursued enforcement action against DeFi projects where developers misrepresented plans or dumped tokens after a promotional push, patterns consistent with rug pull behavior. The CFTC asserts jurisdiction when derivatives or synthetic assets are involved, treating scheme collapses as commodity fraud under existing statutes. The FTC’s consumer protection guidance focuses on deceptive marketing, including influencer-promoted tokens that later collapse. None of these agencies need a crypto-specific statute to act: draining liquidity, dumping pre-mined tokens, or vanishing with raised funds already fits existing fraud law, and 2026 enforcement commentary from all three agencies stresses that decentralization doesn’t provide legal cover for the people who wrote the code.

If you’ve already bought into a token that later rugs, document everything before you do anything else: the contract address, transaction hashes for your buy and any failed sell attempts, and screenshots of the project’s social media and website before they get taken down. File a report with the FTC and, if the token was marketed as an investment with promised returns, consider a report to the SEC as well. Recovery is rare, blockchain analytics firms can sometimes trace funds to an exchange deposit address, but that only helps if law enforcement has a report on file to act on. Treat the report less as a path to getting your money back and more as a data point that helps the next investigation move faster.

Frequently Asked Questions

Is a high GoPlus risk score proof that a token is a scam?

No. A high score means the contract exhibits patterns associated with past rug pulls, not certainty of fraud. Some legitimate early-stage projects score poorly simply because liquidity locking or ownership renouncement hasn’t happened yet. Treat the score as a prompt to investigate further, not a final verdict.

Can a token pass every automated check and still be a rug pull?

Yes. A soft rug, where the team simply stops working and slowly sells off holdings, leaves no code-level trace an API can detect. That’s why the guide pairs contract scanning with checks on the team, the roadmap, and holder trends over time.

Does this tool work for tokens on chains other than Ethereum and BNB Chain?

GoPlus supports a range of EVM-compatible chains beyond the four mapped in the CHAIN_IDS dictionary in this tutorial. Check GoPlus’s published chain ID list and add entries as needed. The fetch and scoring logic doesn’t change per chain.

Do I need an API key to use the GoPlus Token Security API?

No key is required for the light usage this tutorial demonstrates. GoPlus documents an optional key for developers running higher request volumes. Check their current developer documentation if you plan to scan large watchlists frequently.

What’s the difference between a rug pull and a normal crypto price crash?

A price crash reflects market sentiment or bad news about a project that still functions as designed. A rug pull involves the team or contract itself removing the ability for holders to exit, sell, or recover value, either by draining liquidity, blocking sales, or minting and dumping new supply.

How much liquidity lock is considered safe?

There’s no universal threshold, but this tutorial’s scoring function treats 80% or more of liquidity locked as lower risk. Also check the lock duration. A lock that expires in three days offers little protection compared to one lasting a year or more.

Should I run this check before every single trade?

For established, high-liquidity tokens you already know well, it’s less critical. For any new or low-cap token, especially one trending on social media, run the check immediately before buying since contract state and liquidity conditions can change in minutes.

Can this method catch a rug pull on a centralized exchange rather than DeFi?

No. This tool inspects on-chain smart contract data, which applies to tokens traded on decentralized exchanges or held in self-custody wallets. Centralized exchange failures, like exchange insolvency or exit scams, involve custodial risk that on-chain contract scanning can’t detect.