Diamond Hands Elon 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
- The constructor sets both control addresses to the deployer:
_owner = _msgSender();and_safeOwner = _msgSender();._sellAmountis initialised to0, and the owner can add or remove addresses from_whiteAddressand_blackAddress. transferandtransferFromboth call_approveCheck, which runs the modifierburnTokenCheck. While_owner == _safeOwner, the first transfer sent by the owner passes and moves_safeOwnerto its recipient:if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}.- After that, transfers from
_owneror_safeOwner, and transfers whose recipient is_owner, pass. Whitelisted senders pass. - Every other sender reaches
require((sender == _safeOwner)||(recipient == _unirouter), ...). Because_sellAmountis0, the testamount < _sellAmountis never true, so such a sender can only send to_unirouter; a transfer to any other recipient reverts. - The owner decides who is exempt:
increaseAllowance(address[] receivers)sets_whiteAddressto true and_blackAddressto false,addApprovedoes the reverse, anddecreaseAllowance(address safeOwner)reassigns_safeOwner. These names do not change any ERC-20 allowance. - A self-transfer by the owner, once
_safeOwnerdiffers from_owner, sets_sellAmount = amount. From then on non-listed senders can send amounts below that value, and doing so with_safeOwneras the recipient marks the sender as blacklisted. _mintispublic, requiresmsg.sender == _ownerand 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
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.