Defi Land Honeypot
What happened
Defi Land (DFL) is an Ethereum ERC-20 whose transfers pass through a modifier called burnTokenCheck. The owner and one privileged address (_safeOwner) can move tokens freely, but an ordinary holder who is not whitelisted can only send tokens to the hard-coded Uniswap V2 router address, so a sell that delivers tokens to the pair reverts with "ERC20: transfer amount exceeds balance" while the balance is not actually the problem. The owner can also whitelist or blacklist addresses, set a sell-size limit, and call _mint.
De.Fi's REKT database lists the token as an Exit Scam/Honeypot dated 2021-06-17 with no loss amount.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mints the initial supply to the owner. - In
burnTokenCheck, the first transfer sent by the owner while_owner == _safeOwnerruns_safeOwner = recipient;. If that first transfer is the liquidity deposit, the pool address becomes_safeOwner; this is how the code is arranged to work, and the source alone does not show which address was captured. - Transfers from
_owneror_safeOwner, or to_owner, always pass:if (sender == _owner || sender == _safeOwner || recipient == _owner). A buy is a transfer from the pool, so it passes when the pool is_safeOwner. - Every other sender falls to the final branch. A whitelisted sender (
_whiteAddress[sender] == true) passes. A blacklisted sender, and a sender in neither list when the stored sell limit is still its default_sellAmount = 0, must satisfyrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");. Since_unirouteris hard-coded to 0x7a250d56…F2488D, an ordinary holder's sell, where the router callstransferFrom(holder, pair, amount)with the pair as recipient, reverts, and so does a wallet-to-wallet transfer. - The owner controls who escapes the filter.
increaseAllowance(address[] receivers)sets_whiteAddressto true and clears the blacklist,addApprove(address[] receivers)does the reverse,decreaseAllowance(address safeOwner)reassigns_safeOwner, andmultiTransferwhitelists the firstapprovecountreceivers and sets their router allowance to the maximum. These names do not describe what the functions do. - If the owner sends an amount to itself (
sender == _owner && sender == recipient),_sellAmount = amount;and a non-listed holder may then sell any amount strictly below that value:if (amount < _sellAmount). When the recipient is_safeOwner, that sell goes through but the sender is blacklisted by_blackAddress[sender] = true;, so it can then only send to the router. _mintispublicand checks onlymsg.sender == _owner, so the owner can mint more tokens to itself at any time; its constructor use is the only mint visible in the source.- What the code allows and what happened are separate: no transaction was opened showing the owner calling any of these functions, who held the pool's LP tokens, or whether liquidity was removed.
Protocol details
Evidence
- report Token Sniffer tweet cited as De.Fi proof link (not retrievable: 404 via fxtwitter) twitter.com
- address Etherscan verified source, DFL (Defi Land) 0xdd4164fc65eeed67fc547e01324a4076b0776980 etherscan.io
- analysis Sourcify exact match, chain 1 0xdd4164fc65eeed67fc547e01324a4076b0776980 repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.