Diamond Hands Elon Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

Diamond Hands Elon (DHElon) is an Ethereum token whose transfers pass through a modifier, burnTokenCheck, that lets only privileged addresses move tokens freely. Any other holder can send tokens only to the hard-coded _unirouter address (or to the owner) unless the owner whitelists that holder, so a sale that sends tokens anywhere else reverts with the message ERC20: transfer amount exceeds balance. De.Fi's REKT database lists DHElon as an exit scam / honeypot in which the owner could disable the transfer function and restrict users from selling.

How it happened

  1. The constructor sets both control addresses to the deployer: _owner = _msgSender(); and _safeOwner = _msgSender();. _sellAmount is initialised to 0, and the owner can add or remove addresses from _whiteAddress and _blackAddress.
  2. transfer and transferFrom both call _approveCheck, which runs the modifier burnTokenCheck. While _owner == _safeOwner, the first transfer sent by the owner passes and moves _safeOwner to its recipient: if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}.
  3. After that, transfers from _owner or _safeOwner, and transfers whose recipient is _owner, pass. Whitelisted senders pass.
  4. Every other sender reaches require((sender == _safeOwner)||(recipient == _unirouter), ...). Because _sellAmount is 0, the test amount < _sellAmount is never true, so such a sender can only send to _unirouter; a transfer to any other recipient reverts.
  5. The owner decides who is exempt: increaseAllowance(address[] receivers) sets _whiteAddress to true and _blackAddress to false, addApprove does the reverse, and decreaseAllowance(address safeOwner) reassigns _safeOwner. These names do not change any ERC-20 allowance.
  6. A self-transfer by the owner, once _safeOwner differs from _owner, sets _sellAmount = amount. From then on non-listed senders can send amounts below that value, and doing so with _safeOwner as the recipient marks the sender as blacklisted.
  7. _mint is public, requires msg.sender == _owner and always credits _balances[_owner], so the owner can also mint more supply. In the constructor, _mint(0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B, initialSupply*(10**18)); therefore credits the deployer's balance, while the emitted Transfer event names 0xAb5801a7…9aeC9B as the recipient.

The code allows this; the sources opened for this entry do not include transactions showing which addresses were whitelisted or blacklisted, or what _safeOwner pointed to. The code has no function that changes or renounces _owner.

Protocol details

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

Build your security review skills

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