Pumpamental Honeypot

Reported loss Not disclosed
BNB Chain
Honeypot

What happened

Pumpamental is a BNB Smart Chain token whose transfers pass through a modifier, burnTokenCheck, that lets only privileged addresses move tokens freely. Any other holder can send tokens only to the hard-coded _unirouter address (or to the owner) unless the owner whitelists that holder, so a sale that sends tokens anywhere else reverts with the message ERC20: transfer amount exceeds balance. De.Fi's REKT database lists Pumpamental as an exit scam / honeypot in which the owner could disable the transfer function and restrict users from selling.

How it happened

  1. The constructor sets both control addresses to the address passed as the constructor's owner argument: _owner = owner; and _safeOwner = owner;. _sellAmount is initialised to 0, and the owner can add or remove addresses from _whiteAddress and _blackAddress.
  2. transfer and transferFrom both call _approveCheck, which runs the modifier burnTokenCheck. While _owner == _safeOwner, the first transfer sent by the owner passes and moves _safeOwner to its recipient: if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}.
  3. After that, transfers from _owner or _safeOwner, and transfers whose recipient is _owner, pass. Whitelisted senders pass.
  4. Every other sender reaches require((sender == _safeOwner)||(recipient == _unirouter), ...). Because _sellAmount is 0, the test amount < _sellAmount is never true, so such a sender can only send to _unirouter; a transfer to any other recipient reverts.
  5. The owner decides who is exempt: increaseAllowance(address[] receivers) sets _whiteAddress to true and _blackAddress to false, addApprove does the reverse, and decreaseAllowance(address safeOwner) reassigns _safeOwner. These names do not change any ERC-20 allowance.
  6. A self-transfer by the owner, once _safeOwner differs from _owner, sets _sellAmount = amount. From then on non-listed senders can send amounts below that value, and doing so with _safeOwner as the recipient marks the sender as blacklisted.
  7. The owner can also mint: _mint is public, requires msg.sender == _owner and always credits _balances[_owner].

The code allows this; the sources opened for this entry do not include transactions showing which addresses were whitelisted or blacklisted, or what _safeOwner pointed to. The code has no function that changes or renounces _owner. The contract header lists a 3% liquidity fee and a 2% holder reward, but no function in the source applies a fee.

Protocol details

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

Build your security review skills

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