You bought the token. You see the chart pumping. You try to sell — and the transaction fails. Or it goes through, but the "sold" amount is zero. Or the sell goes through once, then never again.
You're in a honeypot.
Honeypot tokens are a specific breed of scam contract that lets anyone buy the token but blocks (or taxes at 99%) any attempt to sell. The contract looks like a normal ERC20 on the surface. The chart moves. Liquidity is real. But the exit door is locked.
This guide walks through the six most common on-chain patterns, shows you what the code looks like, and explains how to check any token in under 30 seconds.
Why honeypots work
Most retail buyers never look at the contract. They look at the chart, the Telegram, the influencer post, the momentum. The contract is the last thing they check — if at all. Honeypots are built to exploit that asymmetry.
A well-crafted honeypot:
- Passes basic "token scanner" checks because the malicious logic is hidden in
_transferoverrides or modifiers - Has real liquidity (the scammers provide it themselves)
- Looks like a standard OpenZeppelin ERC20 at a glance
- Only shows its true behavior when a non-whitelisted address tries to sell
By the time anyone notices the pattern, the scammers have drained the liquidity and moved on.
The 6 patterns to look for
1. The "canSell" whitelist
mapping(address => bool) public canSell;
function transfer(address to, uint256 amount) external returns (bool) {
if (to != owner) {
require(canSell[msg.sender], "Transfer not allowed");
}
// ...
}
Only whitelisted addresses — usually just the owner — can initiate transfers to non-owner addresses. Retail wallets are never whitelisted. You can buy from the liquidity pool, but you can never sell back into it.
2. The "maxSellAmount" trick
uint256 public maxSellAmount = 0;
function setMaxSell(uint256 _amount) external onlyOwner {
maxSellAmount = _amount;
}
maxSellAmount is set to zero at deployment. The owner can "unpause" selling at any time. Until they do — and they never will for you — every sell reverts. Variants of this include sellsEnabled, tradingEnabled, and paused flags that only the owner controls.
3. Hidden 99% sell tax
uint256 public sellTax = 99;
function _transfer(address from, address to, uint256 amount) internal {
if (to == liquidityPool) {
uint256 fee = (amount * sellTax) / 100;
_balances[taxWallet] += fee;
amount = amount - fee;
}
// ...
}
Sells to the liquidity pool get taxed at 99% (or 100%). On the block explorer, the transaction looks successful. In your wallet, you got back essentially nothing. The buy tax is often 0%, which is why scanners that only test buys miss this.
4. Blacklist-on-buy
mapping(address => bool) public blacklisted;
function transfer(...) {
require(!blacklisted[msg.sender], "blacklisted");
}
function blacklist(address user) external onlyOwner {
blacklisted[user] = true;
}
The owner can add any address to a blacklist. They watch their own contract, and the moment a whale (or any inconvenient holder) tries to sell, the scammer front-runs them by blacklisting their address. Your tokens are now frozen in your wallet.
5. Dynamic transfer function selector
function transfer(address to, uint256 amount) external returns (bool) {
return _dynamicTransfer(to, amount);
}
function setTransferLogic(address _logic) external onlyOwner {
transferLogic = _logic;
}
The transfer function delegates to an externally-set contract. Early on it works normally. After there's liquidity, the owner swaps the logic contract for one that blocks sells. Proxies and delegatecall patterns are the advanced version of this.
6. Fake approve / fake balance
function balanceOf(address account) external view returns (uint256) {
if (account == liquidityPool) return _balances[account];
return _fakeBalances[account];
}
The contract shows you a fake, inflated balance to make you feel rich, but the real tradeable balance is tracked in a separate mapping. When you try to sell your "10,000 tokens" you actually only have 10.
The fastest way to check
Three steps:
-
Read the contract on the block explorer. If it's not verified, that's the first red flag — don't trust unverified contracts. If verified, open the source.
-
Search for these keywords:
canSell,blacklist,maxSellAmount,tradingEnabled,onlyOwner,setFee,setTax. Every one of these deserves scrutiny. Not all uses are malicious, but every use needs to be understood. -
Run the contract through an AI auditor. A tool like Unrugify feeds the contract to Claude with prompts specifically tuned for rug-pull detection. The free preview shows the verdict and basic risks. The $1 full report flags every owner privilege function by name.
Final gut checks
Even if the code looks clean, ask yourself:
- Is the liquidity locked? If the LP tokens are in the deployer's wallet, they can pull liquidity at any time. That's a different kind of rug but equally fatal.
- Can you find a single organic holder who has sold? Etherscan's holder list + the token's trades list will tell you. If every sell came from the deployer, you're about to be the liquidity exit.
- Is the owner address a multisig or a single EOA? A single EOA with
onlyOwnerprivileges is a single point of failure — compromise, rug, or just greed.
Honeypots depend on you not looking. A 30-second contract read beats any amount of chart-watching.
Want an instant AI analysis of any contract? Try Unrugify free — 3 free previews a day, $1 for the full audit report.
