Real Madrid FC Honeypot
What happened
De.Fi's REKT database lists REALMADRID (Real Madrid FC) on Ethereum as an exit scam/honeypot, noting that the contract owner could disable the transfer function, which restricted users in selling their tokens. The verified source confirms an owner-controlled transfer gate: every transfer and transferFrom runs through the burnTokenCheck modifier. With the default _sellAmount of 0, a holder who is not the owner, the stored _safeOwner or on the owner's whitelist can only send tokens to the hard-coded _unirouter address or to the owner.
A normal swap sell pays the pair contract, which is neither, so it can revert. The gate is not fixed: the owner can raise _sellAmount with a self-transfer, which lets smaller transfers pass and blacklists any such sender who sends to _safeOwner. The owner can also whitelist, blacklist, replace _safeOwner and mint.
How it happened
- The constructor sets
_owner = owner;and_safeOwner = owner;._sellAmountstarts at0, and the router address is hard-coded asaddress private _unirouter = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;. - Every transfer goes through
_approveCheck(...) internal burnTokenCheck(sender,recipient,amount). The first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, so while the owner and the safe owner are the same address, the owner's first outgoing transfer can make its recipient the new_safeOwner. - The second branch is
if (sender == _owner || sender == _safeOwner || recipient == _owner). It can let through the owner, the_safeOwner, and any sender whose recipient is the owner. Inside it,if (sender == _owner && sender == recipient){_sellAmount = amount;}means that once_safeOwneris no longer the owner, the owner can set_sellAmountto any value by sending tokens to itself. - Every other sender falls to the third level. If
_whiteAddress[sender] == truethe transfer can pass with no further check. If_blackAddress[sender] == true, it must satisfyrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"), so a blacklisted holder can only send to_unirouter(or to the owner through the earlier branch). - A sender in neither list reaches
if (amount < _sellAmount). While_sellAmountis0, this is never true, so the code runs theelsebranch:require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");. A swap sell callstransferFrom(holder, pair, amount); the recipient is the pair, not_unirouteror the owner, so the call can revert and the holder's balance is not debited. - Once the owner has set
_sellAmountabove0, a transfer from an unlisted holder withamount < _sellAmountcan pass to any recipient. If that recipient is_safeOwner, the lineif(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}can blacklist the sender and clear any whitelist flag. Transfers withamountat or above_sellAmountstill hit theelserequire. - The owner keeps further switches:
increaseAllowance(address[])whitelists addresses and clears their blacklist flag,addApprove(address[])blacklists them,decreaseAllowance(address)replaces_safeOwner,multiTransfer(...)whitelists the firstapprovecountreceivers and sets their router allowance to the maximum, and_mint(owner only,public) adds_totalSupplywith no cap. The code shows these powers; it does not show which were used, and no sell transaction was opened for this record.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.