LuckyDoge Honeypot
What happened
LuckyDoge (LDE) is a BNB Smart Chain token whose transfer modifier, burnTokenCheck, lets only the owner, one owner-chosen address _safeOwner, and whitelisted addresses move tokens freely. With the default _sellAmount of 0, any other holder can send only to the hard-coded _unirouter address or to the owner; a transfer to any other address, such as a liquidity pair, reverts with "ERC20: transfer amount exceeds balance" even though the balance is untouched. The owner can whitelist or blacklist addresses, replace _safeOwner, and mint more tokens.
De.Fi's REKT database lists the token as an exit scam/honeypot and says the owner could disable the transfer function.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mints the initial supply to the owner. No function in the contract changes_ownerafterwards. - Every
transferandtransferFromrunsburnTokenCheck. Its first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}. The first time the owner sends tokens,_safeOwnerbecomes that recipient, and the transfer passes. - Next branch:
if (sender == _owner || sender == _safeOwner || recipient == _owner)passes. Owner,_safeOwnerand anyone sending to the owner are never blocked. Whitelisted senders (_whiteAddress[sender] == true) also pass. - Blacklisted senders must satisfy
require((sender == _safeOwner)||(recipient == _unirouter), ...), so they can send only to_unirouter. - Every other holder falls to
if (amount < _sellAmount){ ... _; }else{require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}._sellAmountstarts at 0, soamount < _sellAmountis never true and therequireruns. A sell sends tokens from the holder to a pair, which is neither the owner nor_unirouter, so it reverts. Wallet-to-wallet transfers revert the same way. The revert comes before the balance lines, so the holder keeps the tokens. Transfers whose sender is_safeOwnerpass, so if_safeOwneris the pair, buys are not stopped; the code does not say which address_safeOwnerholds. - The owner controls who is in each class:
increaseAllowance(address[])whitelists,addApprove(address[])blacklists,decreaseAllowance(address)replaces_safeOwner, andmultiTransfercan send tokens and whitelist the firstapprovecountreceivers while giving_unirouteran unlimited allowance over them. Once_safeOwner != _owner, an owner self-transfer sets_sellAmount = amount. Below that amount other holders can send anywhere, and a send to_safeOwneralso blacklists the sender. _mint(address account, uint256 amount)ispublicbut requiresmsg.sender == _owner, and it credits_balances[_owner](notaccount) while emitting aTransferevent toaccount, so the owner can increase the supply. No opened transaction shows any of these functions being called or sells failing, so these are what the code allows.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.