Hex-Mex Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Hex-Mex (MEX) was an Ethereum token (0x53f86430…c01dde, deployed on 17 June 2021) whose transfer code let anyone buy from the pool but blocked ordinary holders from selling. A modifier on every transfer and transferFrom only lets a holder move tokens if they are the owner, the _safeOwner address, on an owner-controlled whitelist, or sending to the Uniswap router address itself; a sale to the pool fails with the misleading error "ERC20: transfer amount exceeds balance". The owner can whitelist or blacklist any address through functions disguised as increaseAllowance and addApprove, and the contract has no function to transfer or renounce ownership.

De.Fi's REKT database lists the token as a honeypot exit scam on 18 June 2021 in which the owner restricted users from selling; no loss figure is recorded.

How it happened

  1. The constructor stores the owner argument as _owner and _safeOwner. On the owner's first outgoing transfer, if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;} makes that recipient the new _safeOwner. If that first transfer is the liquidity deposit, the pool becomes _safeOwner and can send tokens freely, so buys go through.
  2. For any other sender, the burnTokenCheck modifier allows the transfer only if sender == _owner || sender == _safeOwner || recipient == _owner, or if _whiteAddress[sender] == true.
  3. A holder who is not whitelisted falls through to require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). A Uniswap sale moves tokens from the holder to the pool, not to the router, so it reverts with an error that looks like a balance problem.
  4. The only exception is if (amount < _sellAmount). _sellAmount starts at 0 and is set only by an owner transfer to itself (if (sender == _owner && sender == recipient){_sellAmount = amount;}). Below that threshold a transfer succeeds, but if the recipient is _safeOwner the sender is then blacklisted: if(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}.
  5. Owner-only functions with standard-looking names manage the lists: increaseAllowance(address[]) whitelists addresses, addApprove(address[]) blacklists them, decreaseAllowance(address) sets _safeOwner, and multiTransfer sends tokens and whitelists the first approvecount receivers.
  6. _mint is a public owner-only function that credits _balances[_owner] while emitting a Transfer event to a different account. The constructor calls it ten times with 0x896f2337…dD98CC as account, so the explorer shows that address receiving the supply while the balance sits with the owner.

Protocol details

Classification Exchange (DEX)
Protocol Type Exit Scam/Honeypot
Affected asset / contract MEX

Build your security review skills

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