Pumpamental 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
- The constructor sets both control addresses to the address passed as the constructor's
ownerargument:_owner = owner;and_safeOwner = owner;._sellAmountis initialised to0, and the owner can add or remove addresses from_whiteAddressand_blackAddress. transferandtransferFromboth call_approveCheck, which runs the modifierburnTokenCheck. While_owner == _safeOwner, the first transfer sent by the owner passes and moves_safeOwnerto its recipient:if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}.- After that, transfers from
_owneror_safeOwner, and transfers whose recipient is_owner, pass. Whitelisted senders pass. - Every other sender reaches
require((sender == _safeOwner)||(recipient == _unirouter), ...). Because_sellAmountis0, the testamount < _sellAmountis never true, so such a sender can only send to_unirouter; a transfer to any other recipient reverts. - The owner decides who is exempt:
increaseAllowance(address[] receivers)sets_whiteAddressto true and_blackAddressto false,addApprovedoes the reverse, anddecreaseAllowance(address safeOwner)reassigns_safeOwner. These names do not change any ERC-20 allowance. - A self-transfer by the owner, once
_safeOwnerdiffers from_owner, sets_sellAmount = amount. From then on non-listed senders can send amounts below that value, and doing so with_safeOwneras the recipient marks the sender as blacklisted. - The owner can also mint:
_mintispublic, requiresmsg.sender == _ownerand 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
Evidence
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.