RFI Protocol Honeypot

Reported loss Not disclosed
BNB Chain
Honeypot

What happened

RFI Protocol (RFIP) is a BNB Smart Chain token whose every transfer passes through a burnTokenCheck modifier. By default, a holder who is not whitelisted can send tokens only to the hard-coded _unirouter address or to the owner address; a transfer to any other address reverts with "ERC20: transfer amount exceeds balance". The owner can whitelist or blacklist holders, change the privileged _safeOwner address, set a _sellAmount threshold, and mint more supply.

De.Fi's REKT database lists the token as an exit scam/honeypot, stating that the contract owner could disable the transfer function and restricted users from selling.

How it happened

  1. The constructor sets _owner = owner; _safeOwner = owner; and mints the initial supply to the owner.
  2. transfer and transferFrom both call _approveCheck, which runs the burnTokenCheck(sender,recipient,amount) modifier before moving any balance.
  3. While _owner == _safeOwner (the initial state) and sender == _owner, the modifier sets _safeOwner = recipient and lets the transfer through, so the first transfer sent by the owner makes its recipient the privileged _safeOwner (sending to itself leaves it unchanged). Once _safeOwner differs from _owner, a transfer passes unconditionally if sender == _owner, sender == _safeOwner or recipient == _owner; in that state, if the owner sends to itself, the amount is stored as _sellAmount.
  4. For any other sender (not owner, not _safeOwner, and not sending to the owner): a whitelisted sender (_whiteAddress) passes to any recipient. A blacklisted sender (_blackAddress) passes only if recipient == _unirouter. A sender in neither list passes if amount < _sellAmount; otherwise the require((sender == _safeOwner)||(recipient == _unirouter), ...) check applies, and since such a sender is never _safeOwner, only recipient == _unirouter passes. With _sellAmount at its default of 0, no amount is below it, so an ordinary holder can send only to _unirouter or to the owner address.
  5. A router sells by calling transferFrom(holder, pair, amount). Unless the recipient is _unirouter or the owner, an ordinary holder's sell reverts at step 4. The code does not show whether the pair address is _safeOwner, so it does not by itself show how buys behave.
  6. For a sender in neither list, a transfer with amount < _sellAmount goes through, and if recipient == _safeOwner it sets _blackAddress[sender] = true; _whiteAddress[sender] = false;, after which that sender is limited to _unirouter and the owner address as in step 4.
  7. Owner-only functions can change who is exempt: increaseAllowance(address[]) whitelists and un-blacklists, addApprove(address[]) blacklists, decreaseAllowance(address) sets _safeOwner, and multiTransfer sends tokens and whitelists the first approvecount receivers. _mint is public but requires msg.sender == _owner, and adds the amount to _balances[_owner] and _totalSupply.
  8. These are powers the code allows. No opened transaction shows which addresses were whitelisted or blacklisted, and the sell failures are attributed only to De.Fi's REKT database listing.

Protocol details

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

Build your security review skills

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