Nemo Inu Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Nemo Inu (NEMO) is an ERC-20 whose transfer and transferFrom both run through a burnTokenCheck modifier. A holder who is not the owner, not the stored _safeOwner and not whitelisted can transfer only to the hard-coded Uniswap V2 router address (_unirouter) or to the owner, while _sellAmount is 0; once the owner sets _sellAmount, transfers below that amount pass to any recipient. Any other transfer reverts with "ERC20: transfer amount exceeds balance".

The owner can whitelist or blacklist individual addresses, repoint _safeOwner, and call a public _mint. De.Fi's REKT database lists the token as an Exit Scam/Honeypot on Ethereum and describes it as a contract whose owner could disable the transfer function, which restricted users in selling their tokens. No transaction hash, attacker address or loss figure is available for this record.

How it happened

What the code allows:

  1. The constructor mints twice, and each _mint call credits the owner's balance, not the account argument: _balances[_owner] = _balances[_owner].add(amount);. The _mint function is public and gated only by require(msg.sender == _owner, ...), so the owner can mint more at any time.
  2. Every holder transfer goes through _approveCheck(...) internal burnTokenCheck(sender,recipient,amount). The modifier's first branch is if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}: while _safeOwner equals the owner, the first transfer the owner makes sets _safeOwner to its recipient. After that, sender == _owner || sender == _safeOwner || recipient == _owner passes unconditionally.
  3. Any other sender is checked in this order: if (_whiteAddress[sender] == true){_;} lets whitelisted senders move tokens to any recipient; for a blacklisted sender the check is require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance").
  4. A sender on neither list reaches if (amount < _sellAmount). _sellAmount is initialised to 0, so amount < 0 is never true until it is set, and the else branch applies the same requirement: require((sender == _safeOwner)||(recipient == _unirouter), ...). While _sellAmount is 0, such a holder can send tokens only to _unirouter, or to the owner through the unconditional branch in step 2; a transfer to any other recipient reverts. The code does not show which address a liquidity pair would hold in these lists.
  5. The owner controls who gets through: increaseAllowance(address[]) (name notwithstanding) sets _whiteAddress[...] = true, addApprove(address[]) sets _blackAddress[...] = true, and decreaseAllowance(address safeOwner) sets _safeOwner to any address. multiTransfer also whitelists the first approvecount receivers and approves the router for them.
  6. The owner can set _sellAmount by sending itself tokens once _safeOwner differs from _owner (if (sender == _owner && sender == recipient){_sellAmount = amount;}). While _sellAmount is above zero, a non-listed holder's transfer of a smaller amount is allowed to any recipient, and if the recipient is _safeOwner the sender is added to _blackAddress in that same call: if(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}.

De.Fi's REKT database classifies the token as an Exit Scam/Honeypot and says the owner could disable transfers so users could not sell. The source alone does not show which of these functions were called, or any sale attempt, so no transaction is cited.

Protocol details

Classification Token
Protocol Type Exit Scam/Honeypot
Affected asset / contract NEMO

Build your security review skills

Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.