Skip to content

Spotting a Honeypot Token Before You Buy

💡
Before you start

Python 3 and a terminal. No wallet, no coins, no test network. macOS and Linux include Python; on Windows install it from python.org with “Add python.exe to PATH” ticked, then check with python3 --version.

You will build the trap, not just read about it. Forty lines of Python reproduce a honeypot token faithfully enough to be caught by exactly the technique real honeypot checkers use — and, more usefully, to show you the two variants that technique misses. Nothing here touches a blockchain, so there is no risk and no cost.

What a Honeypot Token Is

A honeypot is a token you are allowed to buy and not allowed to sell. The purchase goes through normally. The balance appears in your wallet. The price chart climbs. Then the sale fails — every time, for everyone except the people who built it.

This is a different trap from a project whose team drains the trading pool and disappears. Here nothing is withdrawn and nothing needs to be: the restriction is written into the token's own code, so the money never has to leave, because it was never able to.

The deception works because everything a buyer normally looks at behaves correctly. Buying works, so the token looks tradeable. The wallet shows a rising figure, so it looks profitable. The chart only ever goes up — for the arithmetic reason that a market with no sellers has no downward pressure. What looks like exceptional performance is the signature of the trap.

How the Trap Is Built

A token contract decides for itself what happens on every transfer, so it can treat a sale differently from a purchase. Selling on a decentralised exchange means transferring tokens to the pool contract, which the token can detect and refuse. The common mechanisms:

Reverting on sale The transfer function cancels the transaction whenever the destination is the trading pool. The sale simply fails, and the seller pays the network fee for nothing.
Blacklisting buyers Every address that buys is quietly added to a blocked list. Buying still works for the next person, so the trap keeps catching newcomers while existing holders are frozen.
A punitive sell tax The sale succeeds, which is worse, because it looks legitimate. A tax of ninety-nine percent returns almost nothing and the transaction is recorded as a success.
A permission list Only approved addresses may sell. The list holds the creator and nobody else, so the exit exists but is reserved.
Limits and cooldowns Maximum transaction sizes and enforced waiting periods, tuned so tiny sales pass and any meaningful exit does not. These are also legitimate anti-bot tools, which is what makes them useful cover.
Rewriting the balance The contract reduces a holder's balance immediately before the sale executes, so the amount sold is a fraction of what the wallet displayed a second earlier.

Test the Exit, Not the Entrance

The decisive question is never "can I buy this?" It is "can I get out?" — and that can be answered before spending anything.

Honeypot simulators execute a purchase and an immediate sale against the real trading pool on a throwaway copy of the blockchain, then report what happened. Because the copy is discarded, the test costs nothing and risks nothing. A useful report tells you whether the sale reverted, what the buy and sell taxes actually were, and whether any transfer restriction fired.

💡
Read the tax numbers, not just the verdict

A token can pass a pass-or-fail check while charging a forty percent tax on sales. That is not a honeypot by the strict definition, and it will still take most of your money on the way out. The numbers matter more than the label.

Run more than one simulator. They use different techniques and occasionally disagree, and a disagreement is itself information worth having before you commit funds.

What the Blockchain Already Shows You

A token's public transaction history answers the question without any tool at all. On a block explorer, open the token and read its transfers:

  • Count sales against purchases. Hundreds of buys and almost no sells is the shape of a honeypot. Healthy trading has both, continuously, from many different addresses.
  • Look at who does sell. If the only successful sales come from a small group of addresses, that group is the permission list.
  • Look for failed transactions. A cluster of failed transfers from ordinary holders is people discovering the trap in real time.
  • Check how many holders there are, and how recently the contract was created. A token minted days ago with a vertical chart has no history to judge it by.

Reading the Contract Yourself

If the source code is not published on the explorer, stop there. An unpublished contract cannot be reviewed by anyone, and choosing not to publish is a decision the creator made deliberately.

Where the code is available, you do not need to be a programmer to search it. Look for terms that control who may transfer and on what terms: blacklist, whitelist, trading enabled, maximum transaction, cooldown, and any function that changes a fee. Then ask who is permitted to call those functions, and whether the code puts any ceiling on what they can set. A fee that can be raised to any value at any time is a trap that has not been sprung yet.

⚠️
A clean result is a snapshot, not a promise

If the owner can change the tax or edit the blocked list, today's successful test says nothing about tomorrow. Many honeypots launch entirely harmless, collect buyers for a few days, and are switched on afterwards. Ask whether the dangerous powers still exist, not merely whether they have been used.

The same caution applies to a contract that can be replaced. Where the code sits behind an upgradeable layer, what you reviewed today can be substituted for something else entirely, and every earlier check becomes void.

If You Are Already Holding One

There is no technique that forces a contract to let you sell. The restriction is enforced by the network exactly as written, and no service can override it. Treat any offer to recover trapped funds for a fee as a second attempt on your money by people who know you have already lost some.

What is worth doing costs nothing: review which contracts you have given permission to spend your other tokens, and withdraw any permission you no longer need. The site that sold you a honeypot frequently asked for more than a purchase, and that permission outlives the trade until you remove it.

Now Build a Honeypot and Then Catch It, in Five Steps

A honeypot token lets you buy and quietly refuses to let you sell. Reading that sentence does not prepare you to spot one; building it does. In the next twenty minutes you will write a normal token, turn it into a honeypot with a two-line change, run the standard test that detects it, and then meet the two versions that pass that test and still take your money. Every line of output below came from running these files.

1
Write a normal token and a honeypot side by side

Go: open a terminal in a folder you can write to, e.g. cd ~/Desktop (Windows: cd %USERPROFILE%\Desktop).

Do: save this as hp.py. Read the difference between the two classes before you run anything — it is three lines, and it is the entire scam.

class Token:
    """A normal token: anyone who holds it can move it."""
    def __init__(self):
        self.balances = {"pool": 1_000_000}

    def transfer(self, sender, to, amount):
        if self.balances.get(sender, 0) < amount:
            raise Exception("insufficient balance")
        self.balances[sender] -= amount
        self.balances[to] = self.balances.get(to, 0) + amount
        return amount


class Honeypot(Token):
    """Looks identical -- until you are the one selling."""
    def __init__(self):
        super().__init__()
        self.allowed_to_sell = {"owner"}

    def transfer(self, sender, to, amount):
        if to == "pool" and sender not in self.allowed_to_sell:
            raise Exception("execution reverted")
        return super().transfer(sender, to, amount)

You should see: nothing. Run python3 hp.py and it should return to the prompt silently — that means the file parses and both classes exist.

If not: IndentationError means the methods lost their indentation in copying; every def sits four spaces in from class. NameError: name 'super' is not defined cannot happen on Python 3 — check python3 --version.

2
Buy and sell the honest one, so you know what working looks like

Go: same folder.

Do: save this as normal.py and run python3 normal.py.

from hp import Token

t = Token()
t.transfer("pool", "you", 10_000)
print("you bought :", t.balances["you"], "tokens")
t.transfer("you", "pool", 10_000)
print("you sold   :", 10_000, "tokens, balance now", t.balances["you"])

You should see: a complete round trip:

you bought : 10000 tokens
you sold   : 10000 tokens, balance now 0

Money in, tokens out, tokens in, money out. Note that buying looked exactly the same in both classes — which is the reason honeypots work at all.

If not: ModuleNotFoundError: No module named 'hp' means the two files are not in the same folder — ls (Windows: dir) and confirm both names appear.

3
Now buy the honeypot, and try to get out

Go: same folder. This is the moment the victim experiences.

Do: save this as trapped.py and run it.

from hp import Honeypot

t = Honeypot()
t.transfer("pool", "you", 10_000)
print("you bought :", t.balances["you"], "tokens")

try:
    t.transfer("you", "pool", 10_000)
    print("you sold   : ok")
except Exception as e:
    print("you sell   :", e)
    print("balance    :", t.balances["you"], "tokens you can never sell")

t.transfer("pool", "owner", 5_000)
t.transfer("owner", "pool", 5_000)
print("the owner sells the same token: ok")

You should see: your sale refused while the owner’s goes through:

you bought : 10000 tokens
you sell   : execution reverted
balance    : 10000 tokens you can never sell
the owner sells the same token: ok

execution reverted is the real message a blockchain returns, and it is deliberately uninformative — your wallet will show it as a failed transaction with no explanation. Meanwhile your balance is intact, the chart looks healthy, and the price keeps rising, because everyone who buys is real and nobody can sell. The only seller is the owner.

If not: if your sale succeeds, the to == "pool" condition in hp.py is not being reached — check that Honeypot defines its own transfer and that it appears inside the class.

4
Write the check that catches it before you spend anything

Go: same folder. This is what honeypot-checker websites do, reduced to its principle.

Do: save this as check.py and run it. It performs the whole round trip with a tiny amount and reports whether the exit worked.

from hp import Token, Honeypot

def can_i_sell(token_class):
    """Simulate the whole round trip BEFORE spending anything."""
    t = token_class()
    t.transfer("pool", "tester", 1_000)
    try:
        t.transfer("tester", "pool", 1_000)
        return "SAFE   -- a test sale went through"
    except Exception as e:
        return f"REFUSED -- {e}"

print("normal token :", can_i_sell(Token))
print("honeypot     :", can_i_sell(Honeypot))

You should see: the trap named before any money is at risk:

normal token : SAFE   -- a test sale went through
honeypot     : REFUSED -- execution reverted

On a real chain the same idea runs the buy and the sell against a copy of the current blockchain state, so nothing is actually spent. The principle worth remembering is that the only meaningful test of a token is a sale, not a purchase.

If not: if both lines say SAFE, can_i_sell is being handed an instance instead of the class — pass Token, not Token().

5
Meet the two versions that pass that check anyway

Go: same folder. A defence you trust blindly is worse than none.

Do: save this as variants.py and run it. The first half is a token that lets you sell and keeps almost everything; the second is a honeypot that behaves perfectly until the owner changes its mind.

from hp import Honeypot

class TaxedToken:
    def __init__(self, sell_tax):
        self.balances = {"pool": 1_000_000}
        self.sell_tax = sell_tax

    def sell(self, who, amount):
        kept = amount * (100 - self.sell_tax) // 100
        self.balances[who] -= amount
        return kept

t = TaxedToken(sell_tax=5)
t.balances["you"] = 10_000
print("sell 10,000 at the advertised 5% tax ->", t.sell("you", 10_000), "tokens back")

t = TaxedToken(sell_tax=99)         # the owner raised it after you bought
t.balances["you"] = 10_000
print("sell 10,000 after the owner sets 99% ->", t.sell("you", 10_000), "tokens back")

h = Honeypot()
h.allowed_to_sell.add("you")          # the token behaves perfectly at first
h.transfer("pool", "you", 10_000)
h.transfer("you", "pool", 4_000)
print("your first test sale         : ok")

h.allowed_to_sell.discard("you")      # one owner transaction, any time later
try:
    h.transfer("you", "pool", 6_000)
except Exception as e:
    print("your real sale, an hour later:", e)

You should see: both defeats:

sell 10,000 at the advertised 5% tax -> 9500 tokens back
sell 10,000 after the owner sets 99% -> 100 tokens back
your first test sale         : ok
your real sale, an hour later: execution reverted

The first is not a honeypot at all — every sale succeeds, so every checker reports SAFE — and you keep one per cent. The second passes any test you run today, because the trap is a switch the owner flips whenever they choose. This is why the contract scan matters more than the sell test: what you need to know is not “can I sell right now” but “can anybody change the answer later”.

If not: if the 99% line prints 9500 as well, the second TaxedToken was created before its tax was set — the constructor argument must be sell_tax=99. If the last line prints nothing, the discard call is missing, so the sale succeeded.

🎉
Check yourself before moving on

Without scrolling up: a token you are considering passes a well-known honeypot checker, and its chart has risen every day for a week with no sellers visible. Why is the steady rise evidence against it rather than for it, and what would you check next? Answer: a price that only ever rises, with no sell pressure at all, is the exact signature of a token nobody can sell — in a real market some holders always take profits. What to check next is the contract itself: whether an owner exists and what powers it kept (a tax it can raise, a list it can add you to, a transfer it can pause), because step 5 showed both defeats come from powers, not from today’s behaviour. If the source is not published at all, the question is already answered.

Now do it without the page: add a third variant to variants.py — a token that allows a sale only if the amount is under 100, so a small test sale succeeds and a real exit does not — then run your can_i_sell checker against it and watch it report SAFE. Now improve the checker so it catches this one too. You have just discovered why real detectors simulate a sale of the whole balance, not a token amount.

The Habit That Prevents This

Buying is not evidence of anything. Every honeypot on every chain permits buying, because a trap that refused deposits would catch nobody. Before any purchase, simulate the sale, read the actual tax figures, check that sales are happening for ordinary holders, and confirm that nobody retains the power to change the rules after you commit.

An asset you cannot sell is not an investment at any price, however impressive the number in your wallet.