RCums Honeypot
What happened
RCums (ROCKET CUMS, BNB Chain, contract 0xf4326430…130677) contains an owner-controlled tracing switch that is off by default. While it is on, the first transferFrom from a non-zero sender stores its recipient in nxOwner, and from then on every transfer or transferFrom to that address reverts. If the stored address is the trading pair, sells fail while buys from the pair still work, and no function can change nxOwner afterwards, although the owner can switch the check off and on with setTracing.
De.Fi's REKT database lists the token as an Exit Scam/Honeypot dated 2021-06-15 and says the owner could disable the transfer function, which restricted users in selling their tokens; the listing gives no loss amount.
How it happened
- The constructor mints the whole supply to the deployer (
_totalSupply = 10000000000000000000000;, 9 decimals). Thetracingflag starts asbool tracing = false;, so at first nothing is blocked. setTracing(bool _tracing) onlyOwnerlets the owner switch the check on or off at any time.- With
tracingon, thecontextHandlermodifier ontransferFromrunsif(from != address(0) && nxOwner == address(0)) nxOwner = to; else require(to != nxOwner, "Order ContextHandler");. The firsttransferFromafter the switch is on passes and stores its recipient innxOwner; the sender need not be the owner. If that call is the router moving tokens into the pair, the pair is stored. - From then on
transferFromreverts whento == nxOwner, andtransfercarriesrequire(to != nxOwner, "Handling Request");through therequestHandlermodifier. Neither check exempts the owner. A sale through the router is atransferFromfrom the holder to the pair, so it reverts. A buy is a transfer from the pair to the buyer and passes. nxOwneris assigned only in that one line and only while it is zero, so the stored address cannot be cleared or replaced. The owner can still callsetTracing(false)to let transfers to it through andsetTracing(true)to block them again.- Other owner-related code:
onlyOwneracceptsmsg.sender == owner || msg.sender == nxOwner, so the stored address also passes owner-only checks.emitTransfer(uint256 _input) onlyOwnerrunsbalances[msg.sender] = balances[msg.sender] + (_input);without changing_totalSupply, which adds to the caller's balance.renounceOwnership(address _newOwner)ispublicwith no access check and only writescurrentOwner, which nothing else reads; it does not changeowner.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.