Moonpad Honeypot
What happened
Moonpad (MPAD) is a BEP-20 token on BNB Smart Chain whose contract stops tokens from being transferred to one stored address, newun. The first time transferFrom runs while newun is empty, the contract stores that call's recipient as newun. A liquidity deposit is normally made through transferFrom, so the pool address would be the one stored.
After that, every transfer and transferFrom whose recipient is newun reverts with "please wait", which is the call a router makes when a holder sells into the pool. Buys, where the pool sends tokens out, are not blocked by this code. The owner can change newun with transfernewun.
De.Fi's REKT database lists MPAD as an Exit Scam/Honeypot and says the contract owner could disable the transfer function, which restricted users in selling their tokens. No loss amount is listed there.
How it happened
- The constructor mints the whole supply (
_totalSupply = 10000000000000000, 8 decimals, so 100 million tokens) to the deployer, who becomesowner.newunstarts as the zero address. transfercontainsrequire(to != newun, "please wait");, so no ordinary transfer can end at the address stored innewun.transferFrombegins withif(from != address(0) && newun == address(0)) newun = to; else require(to != newun, "please wait");. The first call made whilenewunis empty skips the check and records its recipient asnewun. The blog post cited in the listing describes this first call as the liquidity deposit, which setsnewunto the liquidity pool address. For this token the code allows that sequence; no transaction was opened to show which addressnewunholds.- Once
newunholds the pool address, a sale (router callstransferFrom(holder, pool, amount)) hits theelsebranch and reverts. A directtransferto the pool reverts the same way. Transfers out of the pool, such as buys, do not pass through the check, so holders can acquire tokens but cannot send them back to the pool. - The owner is not exempt from the
to != newuncheck, buttransfernewun(address _newun) public onlyOwnerlets the owner change it at any time. Setting it to the zero address re-arms the capture (the nexttransferFromrecords its recipient). Pointing it at an unused address lifts the block. Ownership can also be handed over throughtransferOwnershipandacceptOwnership; there is no renounce function. clearCNDAO()isonlyOwnerand sends the contract's own BNB balance to the owner. TheMoonpadcontract overrides the fallback with an emptypayablefunction, so the contract accepts BNB. This is separate from the sell block and does not touch pool liquidity.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.