RFI Protocol 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
- The constructor sets
_owner = owner; _safeOwner = owner;and mints the initial supply to the owner. transferandtransferFromboth call_approveCheck, which runs theburnTokenCheck(sender,recipient,amount)modifier before moving any balance.- While
_owner == _safeOwner(the initial state) andsender == _owner, the modifier sets_safeOwner = recipientand 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_safeOwnerdiffers from_owner, a transfer passes unconditionally ifsender == _owner,sender == _safeOwnerorrecipient == _owner; in that state, if the owner sends to itself, the amount is stored as_sellAmount. - 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 ifrecipient == _unirouter. A sender in neither list passes ifamount < _sellAmount; otherwise therequire((sender == _safeOwner)||(recipient == _unirouter), ...)check applies, and since such a sender is never_safeOwner, onlyrecipient == _unirouterpasses. With_sellAmountat its default of 0, no amount is below it, so an ordinary holder can send only to_unirouteror to the owner address. - A router sells by calling
transferFrom(holder, pair, amount). Unless the recipient is_unirouteror 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. - For a sender in neither list, a transfer with
amount < _sellAmountgoes through, and ifrecipient == _safeOwnerit sets_blackAddress[sender] = true; _whiteAddress[sender] = false;, after which that sender is limited to_unirouterand the owner address as in step 4. - Owner-only functions can change who is exempt:
increaseAllowance(address[])whitelists and un-blacklists,addApprove(address[])blacklists,decreaseAllowance(address)sets_safeOwner, andmultiTransfersends tokens and whitelists the firstapprovecountreceivers._mintis public but requiresmsg.sender == _owner, and adds the amount to_balances[_owner]and_totalSupply. - 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
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.