MoonPilot Honeypot
What happened
MoonPilot (MOONPILOT) routes every transfer and transferFrom through a burnTokenCheck modifier that sorts senders into owner, whitelist, blacklist and everyone else. With the default _sellAmount = 0, an ordinary holder who is on neither list can only send tokens to the hardcoded address _unirouter (0x05fF2B0D…608C7F) or to the owner address; any other recipient, including a liquidity pool, reverts with a fake "transfer amount exceeds balance" message. The owner can whitelist chosen wallets, blacklist others, set _sellAmount, and mint new tokens to itself.
De.Fi's REKT database lists the token as an Exit Scam/Honeypot with no loss figure and says the owner could restrict users from selling.
How it happened
transferandtransferFromboth call_approveCheck(sender, recipient, amount), which is wrapped byburnTokenCheck. The constructor sets_safeOwner = owner;,_unirouteris fixed at 0x05fF2B0D…608C7F, and_sellAmountstarts at 0.- Privileged transfers pass:
if (sender == _owner || sender == _safeOwner || recipient == _owner)runs the transfer, so the owner and_safeOwnercan send anywhere and any sender can send to the owner. While_owner == _safeOwner, the first transfer the owner sends hitsif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, so_safeOwnerbecomes whoever received it. If that recipient is the liquidity pool, the pool's outgoing transfers (buys) are privileged; the code does not itself show who the recipient was. - Every other transfer is checked against the owner's lists.
if (_whiteAddress[sender] == true){ _;}lets whitelisted wallets move tokens to any recipient.if (_blackAddress[sender] == true){ require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}lets blacklisted wallets send only to_unirouter(or to the owner, which the previous branch already allowed). - A sender on neither list reaches
if (amount < _sellAmount){ if(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}_; }else{require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}. With_sellAmount == 0the conditionamount < 0is never true, so theelsebranch requires the recipient to be_unirouter; the only other recipient that passes is the owner, through the earlier branch. A sell into a pool that is neither reverts. - If the owner sets
_sellAmount(once_safeOwnerdiffers from_owner, an owner self-transfer runsif (sender == _owner && sender == recipient){_sellAmount = amount;}), amounts below it are allowed, but a transfer to_safeOwnergoes through and blacklists the sender, so the next sell reverts. Amounts at or above_sellAmountstill need the recipient to be_unirouteror the owner. - The owner-only functions
increaseAllowance(address[])(whitelist),addApprove(address[])(blacklist),decreaseAllowance(address)(sets_safeOwner) andmultiTransferreuse standard ERC-20 names for these roles._mint(address account, uint256 amount)ispublicbut requiresmsg.sender == _ownerand adds to_balances[_owner]. There is no function that changes or renounces_owner. - What happened: De.Fi's REKT database lists the token as an Exit Scam/Honeypot dated 2021-07-03. No transaction showing a failed sell, a blacklisting or a mint was opened, so the code shows what the owner can do, not what was done.
Protocol details
Evidence
- report @Token_Sniffer incident report twitter.com
- address BscScan verified source for MoonPilot 0x52b1395fd199e33aa71994868f944faa119c4f76 bscscan.com
- analysis Sourcify match for 0x52b1395fd199e33aa71994868f944faa119c4f76 (chain 56) repo.sourcify.dev
- analysis De.Fi REKT database listing for MOONPILOT (Exit Scam/Honeypot, 2021-07-03) de.fi
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.