SaveFlipper Honeypot
What happened
De.Fi's REKT database lists SaveFlipper (SFR) on BNB Smart Chain as an Exit Scam/Honeypot and says the contract owner could disable the transfer function, which restricted users in selling their tokens. The code has no single switch for that. Instead every transfer goes through a burnTokenCheck modifier, and while _sellAmount is still 0, an ordinary holder can only send tokens to the hard-coded _unirouter address or to the owner; whitelisted addresses and the owner are exempt.
The owner alone controls the whitelist and blacklist, so the code lets the owner decide who can sell. It does not show which addresses were whitelisted or blacklisted.
How it happened
- The constructor sets
_owner = owner;and_safeOwner = owner;._unirouteris hard-coded as0x05fF2B0DB69458A0750badebc4f9e13aDd608C7Fand_sellAmountstarts at 0. transferandtransferFromboth run_approveCheck, guarded byburnTokenCheck(sender,recipient,amount). The first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, so the first time the owner sends tokens anywhere, the recipient becomes_safeOwner. The owner can also reassign it directly withdecreaseAllowance(address safeOwner).- After that, the owner,
_safeOwner, and any transfer whose recipient is the owner pass unrestricted:if (sender == _owner || sender == _safeOwner || recipient == _owner). Senders marked in_whiteAddressalso pass unrestricted. The owner marks them withincreaseAllowance(address[])ormultiTransfer, which also gives the firstapprovecountreceivers a maximum allowance to_unirouter. - Any other sender hits
require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");unlessamount < _sellAmount. With_sellAmountat 0, an ordinary holder's transfer to an address other than_unirouteror the owner reverts, even when the balance is sufficient. The check reads therecipientargument, which is where the tokens go, not the caller. - The owner can raise
_sellAmountby sending tokens to itself once_safeOwnerdiffers from_owner(if (sender == _owner && sender == recipient){_sellAmount = amount;}). Below that amount, an ordinary sender may transfer anywhere, but if the recipient is_safeOwnerthe sender is added to_blackAddress.addApprove(address[])blacklists addresses directly and clears their whitelist flag. _mintispublicbut requiresmsg.sender == _ownerand always credits_balances[_owner], so the owner can add supply to its own balance.- What happened: De.Fi's REKT database lists the token as an Exit Scam/Honeypot. No transaction was opened, so the code evidence does not show which addresses were allowed to sell or when.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.