Mother of All Ponzis Rug Pull
What happened
Mother of All Ponzis (MOAP) is an ERC-20 whose _transfer path is replaced by a burnTokenCheck modifier. By default, anyone other than the owner, a whitelisted address or the pool can only send tokens to the Uniswap router address, so a sale through the router, which pulls tokens from the holder into the pair, reverts with a fake transfer amount exceeds balance message. The owner alone controls the whitelist, the blacklist, the recorded pool address and an unlimited _mint.
Per Etherscan, the deployer address 0x6a0Fe346…5360e8 added 158 ETH and 7,372 MOAP to Uniswap V2 on 2020-12-22 (tx 0x1eacfa0f…d2a246) and removed 173.74 ETH and 6,708.04 MOAP of liquidity on 2020-12-23 (tx 0xbb5e7942…f60e09). De.Fi's REKT database lists the incident as an Exit Scam/Rugpull with a 1,336 USD loss.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mints the initial supply to the owner. There is notransferOwnershiporrenounceOwnership, so_ownernever changes. - Every
transferandtransferFromruns through_approveCheck, which carries theburnTokenCheck(sender,recipient,amount)modifier. While_owner == _safeOwner, the first transfer sent by the owner executes_safeOwner = recipient;, so the first recipient of the owner's tokens, for example a pool receiving the liquidity deposit, becomes_safeOwner. - In that modifier, transfers pass freely when
sender == _owner || sender == _safeOwner || recipient == _owner, and when_whiteAddress[sender] == true. Sends from the pool (buys) therefore pass if the pool is_safeOwner. - Every other sender falls to
if (amount < _sellAmount){...}else{require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}._sellAmountstarts at 0, soamount < _sellAmountis false and therequireruns. A router sale callstransferFrom(holder, pair, amount): the recipient is the pair, not_unirouter, so it reverts for a non-whitelisted holder. - The owner can change who is trapped:
increaseAllowance(receivers)whitelists and un-blacklists,addApprove(receivers)blacklists,multiTransferwhitelists the firstapprovecountreceivers and gives them a maximum allowance to the router, anddecreaseAllowance(safeOwner)overwrites_safeOwner. An owner self-transfer sets_sellAmount = amount; after that, a non-listed holder selling less than that amount to_safeOwnersucceeds but is blacklisted by_blackAddress[sender] = true;. _mint(address account, uint256 amount)ispublicand restricted only byrequire(msg.sender == _owner, ...), so the owner can also create more supply.- What happened, per Etherscan: the deployer address added 158 ETH and 7,372 MOAP to Uniswap V2 on 2020-12-22 and removed 173.74 ETH and 6,708.04 MOAP on 2020-12-23, about 14.5 hours later.
Protocol details
Evidence
- report @DetectivesRug incident report twitter.com
- transaction Etherscan tx 0x1eacfa0f... (addLiquidityETH) etherscan.io
- transaction Etherscan tx 0xbb5e7942... (removeLiquidityETHWithPermit) etherscan.io
- address MOAP ERC20 verified source (Etherscan) etherscan.io
- analysis Sourcify exact match for 0xe5fb5febbef64588dcba54aeb643d05a8ed02b91 repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.