MoneyWulf Honeypot

Reported loss Not disclosed
BNB Chain
Honeypot

What happened

MoneyWulf (Wulf) is a BEP20 token on BNB Smart Chain, deployed on 2021-06-20 as contract 0xe69382ba…39abd5. De.Fi's REKT database lists it as an exit scam / honeypot in which the owner could stop holders from selling. The verified source shows a switch called tracing, on by default, that makes transfer and transferFrom revert when the recipient equals a stored address nxOwner.

nxOwner is filled in automatically from the first transferFrom, so if that transfer is the one into the liquidity pair, sells through the pair revert while buys still work. The contract also has an onlyOwner function that credits the caller's balance with any amount.

How it happened

  1. The constructor gives the deployer the full supply: balances[owner] = _totalSupply; with _totalSupply = 69*10**15 and decimals = 0. The state variable bool tracing = true; means the recipient checks are active from deployment.
  2. transfer carries the requestHandler modifier: if(tracing) require(to != nxOwner, "Handling Request");.
  3. transferFrom carries the contextHandler modifier: if(from != address(0) && nxOwner == address(0)) nxOwner = to; else require(to != nxOwner, "Order ContextHandler");. While nxOwner is zero, the recipient of the first transferFrom is stored in it and that call succeeds. If the first transferFrom is the transfer into the liquidity pair, the pair becomes nxOwner. The code does not show which transaction set it on-chain.
  4. A buy pays out of the pair with transfer(buyer, ...), so the recipient is not nxOwner and it passes. A sell has the router call transferFrom(holder, pair, ...), so to == nxOwner and the call reverts with "Order ContextHandler" while tracing is true. No function other than that first capture ever writes nxOwner.
  5. The modifier onlyOwner is require(msg.sender == owner || msg.sender == nxOwner);, and setTracing(bool _tracing) onlyOwner can switch both checks off or back on. The owner can therefore lift or restore the block at will; the code does not show whether it did.
  6. emitTransfer(uint256 _input) public onlyOwner runs balances[msg.sender] = balances[msg.sender] + (_input); without changing _totalSupply, so the owner can credit itself tokens that were never part of the stated supply and emit a mint-style Transfer event from the zero address.
  7. renounceOwnership(address _newOwner) public has no access control and only writes currentOwner, a variable no other function reads, so it does not give up the owner role; owner is never reassigned after the constructor. _construct() sends the contract's own BNB balance to the owner. No source opened here shows liquidity being removed or tokens being sold.

Protocol details

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

Build your security review skills

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