Plethori Honeypot

Reported loss Not disclosed
Ethereum
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

  1. The constructor sets _owner = owner; _safeOwner = owner; and mints initialSupply*(10**18) to the owner. _owner is not assigned anywhere else, and the contract has no ownership-transfer or renounce function.
  2. transfer and transferFrom both call _approveCheck, which carries burnTokenCheck. Its first branch is if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}: while the two are equal, the owner's first outgoing transfer, to any recipient, sets _safeOwner to that recipient and passes. An owner self-transfer in this state is caught here and does not touch _sellAmount.
  3. Once _safeOwner differs 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 = amount is set; that is possible only while _safeOwner != _owner.
  4. 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 the sender == _safeOwner half of the require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance") is always false here; it cannot use the _sellAmount path. An address on neither list passes if amount < _sellAmount, otherwise it faces the same require. With _sellAmount at its initial 0, an unlisted holder can therefore send only to _unirouter or 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 _safeOwner or the buyer is whitelisted, which the code does not show.
  5. When _sellAmount has 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 _unirouter or the owner. Only senders on neither list reach this branch.
  6. Owner-only functions: increaseAllowance(address[]) whitelists and un-blacklists, addApprove(address[]) blacklists and un-whitelists, decreaseAllowance(address safeOwner) sets _safeOwner, and multiTransfer sends tokens and whitelists the first approvecount receivers while approving _unirouter for the maximum amount.
  7. _mint(address account, uint256 amount) is public, requires msg.sender == _owner, and adds amount to _totalSupply and to _balances[_owner], so the owner can create new tokens.
  8. 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

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

Build your security review skills

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