Ethereum SHIBA Honeypot
What happened
Ethereum SHIBA (eSHIB) is an Ethereum token, contract 0x8372ede9…b4cc69, whose every transfer and transferFrom runs through a burnTokenCheck modifier. Unless the sender is the owner, the _safeOwner address or a whitelisted address, the transfer reverts unless its recipient is the Uniswap V2 router address 0x7a250d56…F2488D or the owner, and the revert message imitates a balance error. A sell through the router moves tokens to the liquidity pair, so it reverts for ordinary holders.
The owner controls the whitelist, a blacklist, _safeOwner and a public _mint. De.Fi's REKT database lists eSHIB as an exit scam/honeypot in which the contract owner could disable the transfer function, restricting users from selling their tokens. The sources opened here do not show which address _safeOwner held on-chain or any specific holder's failed sell.
How it happened
- The constructor sets
_owner = owner;and_safeOwner = owner;and mints the whole supply to the owner with_mint(_owner, initialSupply*(10**18));. - Every transfer path calls
_approveCheck, which carries theburnTokenCheckmodifier. Its first branch,if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, moves_safeOwnerto the recipient of the owner's first outgoing transfer. If that transfer is the liquidity deposit (transferFrom(owner, pair, ...)), the pair becomes_safeOwner; the code alone does not show what the on-chain value was. - The owner,
_safeOwner, and any transfer to the owner pass:if (sender == _owner || sender == _safeOwner || recipient == _owner). With the pair as_safeOwner, a buy (pair to buyer) passes. - A holder who is not whitelisted or blacklisted reaches the last branch.
_sellAmountdefaults to0, soamount < _sellAmountis false and the code runsrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");. A router sell istransferFrom(holder, pair, amount): the sender is not_safeOwnerand the recipient is the pair, not_unirouter, so it reverts and the holder's balance is not debited. Wallet-to-wallet transfers revert the same way; only transfers to_unirouteror the owner pass. - The owner can change who passes:
increaseAllowance(despite its name) sets_whiteAddressto true and_blackAddressto false,addApprovedoes the reverse,decreaseAllowance(address safeOwner)replaces_safeOwner, andmultiTransferwhitelists its firstapprovecountrecipients and gives each a maximum allowance to_unirouter. All arerequire(msg.sender == _owner, "!owner")._mintispublicand owner-only and credits_balances[_owner], so the owner can mint more at any time. - A transfer from the owner to the owner (when
_owner != _safeOwner) runs_sellAmount = amount;. With_sellAmountabove zero, a non-listed holder's transfer of a smaller amount passes, and if the recipient is_safeOwnerthe holder is added by_blackAddress[sender] = true;, after which only transfers to_unirouterpass. Transfers of_sellAmountor more still revert.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.