Plethori Honeypot
What happened
Plethori (PLE), contract 0x4c9d1312…e838bb on Ethereum, wraps every transfer in a burnTokenCheck modifier. The owner, _safeOwner and whitelisted addresses are not restricted, and anyone may send tokens to the owner. Any other holder can send only to the hard-coded _unirouter address, or, if not blacklisted, in amounts below _sellAmount, which starts at 0; every other transfer, including one into a liquidity pool, reverts with an error that reads like a balance problem.
The owner can whitelist, blacklist, repoint _safeOwner, set _sellAmount and call a public _mint. De.Fi's REKT database lists the token as an Exit Scam/Honeypot dated 2021-04-19; its text speaks of disabling the transfer function, which the code does through this modifier.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mintsinitialSupply*(10**18)to the owner._owneris not assigned anywhere else, and the contract has no ownership-transfer or renounce function. transferandtransferFromboth call_approveCheck, which carriesburnTokenCheck. Its first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}: while the two are equal, the owner's first outgoing transfer, to any recipient, sets_safeOwnerto that recipient and passes. An owner self-transfer in this state is caught here and does not touch_sellAmount.- Once
_safeOwnerdiffers from_owner,if (sender == _owner || sender == _safeOwner || recipient == _owner)lets the owner,_safeOwner, and anyone sending to the owner (blacklisted senders included) transfer freely. In this branch, if the owner sends to itself,_sellAmount = amountis set; that is possible only while_safeOwner != _owner. - Every other sender (not the owner, not
_safeOwner, recipient not the owner) is checked in order. A whitelisted address passes any transfer, even if it is also blacklisted. A blacklisted, non-whitelisted address passes only if the recipient is_unirouter(0x7a250d56…F2488D), because thesender == _safeOwnerhalf of therequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance")is always false here; it cannot use the_sellAmountpath. An address on neither list passes ifamount < _sellAmount, otherwise it faces the samerequire. With_sellAmountat its initial 0, an unlisted holder can therefore send only to_unirouteror the owner; a transfer to a pool reverts, so the sender's balance is not debited. Whether buys from the pool succeed depends on whether the pool is_safeOwneror the buyer is whitelisted, which the code does not show. - When
_sellAmounthas been set and an unlisted sender transfers less than it to_safeOwner, the code runs_blackAddress[sender] = true; _whiteAddress[sender] = false;and still completes the transfer. From then on that sender can send only to_unirouteror the owner. Only senders on neither list reach this branch. - Owner-only functions:
increaseAllowance(address[])whitelists and un-blacklists,addApprove(address[])blacklists and un-whitelists,decreaseAllowance(address safeOwner)sets_safeOwner, andmultiTransfersends tokens and whitelists the firstapprovecountreceivers while approving_unirouterfor the maximum amount. _mint(address account, uint256 amount)ispublic, requiresmsg.sender == _owner, and addsamountto_totalSupplyand to_balances[_owner], so the owner can create new tokens.- What happened: the supplied sources do not show sale attempts, blacklisting transactions, minting or liquidity removal for this token. De.Fi's REKT database lists it as an Exit Scam/Honeypot on 2021-04-19.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.