Mechadog Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Mechadog (MDOG) is an Ethereum token whose transfer and transferFrom both run through a burnTokenCheck modifier that decides, per sender, whether a transfer may proceed. Ordinary holders can only send tokens to the hard-coded _unirouter address or to _owner, unless the owner has whitelisted them or has set _sellAmount above the size of their transfer; the owner can also blacklist addresses and change _safeOwner. De.Fi's REKT database lists the token as an Exit Scam/Honeypot, stating that the contract owner could disable the transfer function and so restrict users from selling.

The code shows the controls that allow this; the sources opened here do not show any holder losses or the amount involved.

How it happened

  1. The constructor stores the owner and sets _safeOwner to the same address (_owner = owner; and _safeOwner = owner;) and mints the initial supply to the owner.
  2. Every transfer and transferFrom calls _approveCheck, which carries the burnTokenCheck(sender,recipient,amount) modifier. When _owner == _safeOwner and the sender is the owner, the first branch runs: _safeOwner = recipient; and the transfer proceeds, so the recipient of the owner's first transfer becomes _safeOwner.
  3. After that, a sender that is _owner or _safeOwner, or any transfer whose recipient is _owner, passes. For any other sender the code looks up the lists: a whitelisted sender passes. A blacklisted sender, and an unlisted sender whose amount is not below _sellAmount, hit require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). Because such a sender is never _owner or _safeOwner at that point, the transfer only succeeds when the recipient is _unirouter (the hard-coded address 0x05fF2B0D…608C7F).
  4. _sellAmount starts at 0 (uint256 private _sellAmount = 0;), so amount < _sellAmount is false for every transfer until the owner sets it by transferring to themselves (if (sender == _owner && sender == recipient){_sellAmount = amount;}). Once it is set, an unlisted holder can move amounts below it, and if the recipient of such a transfer is _safeOwner the sender is added to _blackAddress.
  5. The owner can adjust these lists at will: multiTransfer whitelists recipients and gives them an unlimited allowance to _unirouter, increaseAllowance whitelists and un-blacklists addresses, addApprove blacklists and un-whitelists them, and decreaseAllowance replaces _safeOwner. All are restricted with require(msg.sender == _owner, "!owner"). The function names do not match what they do.
  6. A sale to a pool address that is neither _unirouter nor _owner therefore reverts in the modifier, and because the revert undoes the whole call, the holder's balance is not debited. De.Fi's REKT database lists the token as an Exit Scam/Honeypot on this basis; the transactions behind any actual loss were not opened.

Protocol details

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

Build your security review skills

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