HolyMoon Honeypot
What happened
HolyMoon's contract keeps an address in the variable nxOwner and, for everyone except the owner account, rejects transfers that send tokens to it. The first transferFrom call stores its recipient there automatically; a liquidity addition through a router is such a call, so the pool address can end up stored. A holder's sell then reverts before their balance is debited, so the tokens stay in the wallet but cannot be sold, while the _owner account is exempt.
De.Fi's REKT database lists HolyMoon (HMOON) as an exit scam/honeypot on BNB Smart Chain dated 2021-05-23 and states that the owner could disable the transfer function, restricting users from selling.
How it happened
- The constructor mints
_totalSupply = 500 * 10**6 * 10**9;(9 decimals) to the deployer, who is both_ownerand_leaveowner. - Every transfer runs the
BeforeTransfermodifier. Its first branch isif(from != address(0) && nxOwner == address(0) && fromTransfer) nxOwner = to;: the firsttransferFromcall (fromTransferis true only fromtransferFrom) stores its recipient innxOwner. A router liquidity addition is such a call, sonxOwnercan end up holding the pool address. The code alone does not show which address it holds on-chain. - Every later call takes the other branch:
else require((to != nxOwner || from == _owner), "Order TransferFromMiddleware");. A transfer tonxOwnerpasses only whenfrom == _owner. A router sell callstransferFrom(holder, pool, amount), sofromis the holder, the require fails, and the call reverts before_balances[sender] = _balances[sender].sub(...)runs. The holder keeps the tokens but cannot sell them. The_owneraccount can still send tonxOwner. Buys, paid out from the pool to the buyer, pass. - The block can be changed by an owner account:
function transferOwnership(address newOwner) public onlyOwner { nxOwner = newOwner; }only overwritesnxOwnerand does not move ownership. Pointing it at an unused address lifts the block; setting it to the zero address lets the nexttransferFromcapture a new recipient.onlyOwneralso accepts_leaveowner, andrenounceOwnershiponly zeroes_owner, so the_leaveowneraccount keeps these powers. - What happened: De.Fi's REKT database lists the token as a honeypot. No transaction showing the block applied to holders, a
transferOwnershipcall, or a liquidity removal 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.