Bulldoge Honeypot

Reported loss Not disclosed
BNB Chain
Honeypot

What happened

Bulldoge (BDG) is a BEP-20 token on BNB Smart Chain deployed on 2021-05-05 at 0x5dd713d7…4165d3. De.Fi's REKT database lists it as an exit scam/honeypot dated 2021-05-07 and says the contract owner could disable the transfer function, which restricted users in selling their tokens. In the verified source, every transfer passes through a burnTokenCheck modifier.

By default, a holder who is not on the owner's whitelist can only send tokens to the hard-coded _unirouter address or to the owner, so a sale to any other pair address reverts with "ERC20: transfer amount exceeds balance" even though the balance is sufficient. The owner can whitelist or blacklist addresses, change _safeOwner, set _sellAmount, and mint.

How it happened

  1. The constructor sets _owner = owner; _safeOwner = owner; and mints the supply to the owner. _sellAmount starts at 0 and _unirouter is hard-coded as 0x05fF2B0D…608C7F.
  2. Every transfer and transferFrom goes through _approveCheck(...) burnTokenCheck(sender,recipient,amount). While _owner == _safeOwner, the first transfer made by the owner runs _safeOwner = recipient;, so _safeOwner becomes whichever address the owner first sends to. The source does not say who that address is.
  3. After that, a sender that is the owner, the _safeOwner, or sends to the owner passes. A sender on _whiteAddress passes. Everyone else reaches the final checks.
  4. A sender on _blackAddress runs require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). Because _safeOwner already passed in step 3, this means the recipient must be _unirouter.
  5. A sender on neither list passes only when amount < _sellAmount. With _sellAmount at its initial 0 this is never true, so such a sender faces the same require and can only send to _unirouter or the owner. In that case a transfer to any other address, such as a liquidity pair that is not _unirouter, reverts, and the sender's balance is not debited. If _sellAmount is set above the amount, the transfer passes, and if recipient == _safeOwner the sender is added to _blackAddress and removed from _whiteAddress.
  6. The owner sets the state with owner-only functions: increaseAllowance(address[]) whitelists, addApprove(address[]) blacklists, decreaseAllowance(address safeOwner) replaces _safeOwner, a transfer from the owner to itself sets _sellAmount = amount, and multiTransfer whitelists the first approvecount receivers and approves _unirouter for the maximum amount for them. _mint is public but requires msg.sender == _owner, and it adds the amount to _balances[_owner].
  7. The source has no function to change _owner or renounce it. Whether the owner called any of these functions on this token is not shown by the code; no transaction was opened.

Protocol details

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

Build your security review skills

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