YellowRoad Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

YellowRoad (ROAD) on Ethereum routes every transfer through a burnTokenCheck modifier that lets the owner, a _safeOwner address and owner-whitelisted addresses move tokens freely, while any other holder can only send to _owner or to the hard-coded _unirouter address. A normal sell moves tokens from the holder to the trading pair, which is neither of those, so it reverts with "ERC20: transfer amount exceeds balance" unless the owner has whitelisted the seller. The owner can also whitelist, blacklist, re-point _safeOwner and mint through owner-only functions.

De.Fi's REKT database lists the token as an exit scam/honeypot dated 2021-04-10 and says the owner could disable the transfer function, which restricted users in selling their tokens; it gives no loss figure.

How it happened

  1. The constructor stores _owner = owner; _safeOwner = owner; and calls _mint(_owner, initialSupply*(10**18)). A current-state read on 2026-09-30 shows a total supply of 10,000,000 tokens at 18 decimals.
  2. transfer and transferFrom both call _approveCheck, which carries the burnTokenCheck modifier, so every holder transfer passes through it.
  3. While _owner == _safeOwner, the first transfer out of the owner runs if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, which makes that recipient the new _safeOwner. The code does not say which address that was.
  4. Privileged senders pass: if (sender == _owner || sender == _safeOwner || recipient == _owner){. Any sender may also send to _owner. Once _safeOwner has moved away from _owner, a transfer where the owner sends to itself sets _sellAmount = amount.
  5. Whitelisted senders pass with if (_whiteAddress[sender] == true){ _;}. A blacklisted sender must satisfy require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"), and since _safeOwner already passed in step 4, that leaves the router as the only recipient.
  6. A sender on neither list hits if (amount < _sellAmount){ and otherwise the same require on _unirouter. _sellAmount starts at 0, so amount < _sellAmount is false until the owner sets it, and such a holder can only send to the router or _owner. A sell moving tokens from the holder to the pair reverts. Below _sellAmount, a transfer to _safeOwner succeeds and also runs _blackAddress[sender] = true; _whiteAddress[sender] = false;.
  7. Owner-only functions with misleading names control the lists: increaseAllowance(address[]) whitelists and un-blacklists, addApprove(address[]) blacklists and un-whitelists, decreaseAllowance(address safeOwner) replaces _safeOwner, and multiTransfer whitelists the first approvecount receivers and gives the router a maximum allowance over them. _mint is public but requires msg.sender == _owner and adds to _balances[_owner], so the owner can increase supply. The code has no function that changes or renounces _owner. The source shows what these functions allow; it does not show which of them were called.

Protocol details

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

Build your security review skills

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