ShinyDoge Honeypot

Reported loss Not disclosed
BNB Chain
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

  1. The constructor sets _owner = owner; _safeOwner = owner; and mints the initial supply to the owner.
  2. The first transfer the owner makes while _owner == _safeOwner runs if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, which hands the _safeOwner role to that recipient. The owner can also reassign it at any time with decreaseAllowance(address safeOwner).
  3. For any other sender, burnTokenCheck lets the transfer through only if the sender is _owner or _safeOwner, the recipient is _owner, or the sender is whitelisted. Everyone else reaches require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). A holder sending to any address other than _unirouter or the owner therefore reverts, and the holder's balance is not debited because _balances[sender].sub(...) runs after the modifier.
  4. The owner controls who is exempt: increaseAllowance(address[]) whitelists addresses, addApprove(address[]) blacklists them, and multiTransfer whitelists the first approvecount receivers. A blacklisted sender faces the same require as everyone else and never gets the _sellAmount exemption.
  5. _sellAmount starts at 0, so amount < _sellAmount is 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 _safeOwner also runs _blackAddress[sender] = true.
  6. _mint is public and gated by require(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

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

Build your security review skills

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