ShinyDoge Honeypot
What happened
ShinyDoge (SYD) is a BEP-20 token on BNB Smart Chain whose transfer logic lets the contract owner decide who can move tokens to which address. Every transfer and transferFrom runs through a burnTokenCheck modifier. A holder who is not the owner, not the _safeOwner address and not whitelisted can only send tokens to the hard-coded _unirouter address or to the owner, unless the amount is below an owner-set _sellAmount, which is zero by default.
All other transfers revert with "ERC20: transfer amount exceeds balance" even when the holder's balance is sufficient. De.Fi's REKT database lists SYD as an exit scam / honeypot dated 2021-05-14 and describes the owner as able to disable transfers so holders cannot sell; it gives no loss figure.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mints the initial supply to the owner. - The first transfer the owner makes while
_owner == _safeOwnerrunsif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, which hands the_safeOwnerrole to that recipient. The owner can also reassign it at any time withdecreaseAllowance(address safeOwner). - For any other sender,
burnTokenChecklets the transfer through only if the sender is_owneror_safeOwner, the recipient is_owner, or the sender is whitelisted. Everyone else reachesrequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). A holder sending to any address other than_unirouteror the owner therefore reverts, and the holder's balance is not debited because_balances[sender].sub(...)runs after the modifier. - The owner controls who is exempt:
increaseAllowance(address[])whitelists addresses,addApprove(address[])blacklists them, andmultiTransferwhitelists the firstapprovecountreceivers. A blacklisted sender faces the samerequireas everyone else and never gets the_sellAmountexemption. _sellAmountstarts at 0, soamount < _sellAmountis false for every amount. The owner can raise it by sending tokens to itself (if (sender == _owner && sender == recipient){_sellAmount = amount;}). Below that amount a non-whitelisted holder can transfer, but a transfer to_safeOwneralso runs_blackAddress[sender] = true._mintispublicand gated byrequire(msg.sender == _owner, ...); it adds to_balances[_owner]and_totalSupply, so the owner can mint more at any time. The code shows these powers; the source alone does not show which of them were used on-chain.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.