MOAR Finance Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

De.Fi's REKT database lists MOAR Finance (MOAR) as an Exit Scam/Honeypot and says the contract owner could disable the transfer function, which restricted users in selling their tokens. The verified source at 0xc5691f93…b6de6f (Ethereum, deployed 2021-04-21) shows how a trap like that is built: the shared burnTokenCheck modifier wraps every transfer and transferFrom, and an ordinary holder's transfer reverts unless the recipient is the hard-coded Uniswap V2 router address or the owner, or the holder has been whitelisted by the owner. The owner can also whitelist or blacklist any address and can mint to itself.

The reports reviewed do not state any loss amount.

How it happened

  1. The token is the StandardERC20 contract. Its constructor stores the deployer as both owner and "safe owner": _owner = owner; _safeOwner = owner; followed by _mint(_owner, initialSupply*(10**18));.
  2. Both transfer and transferFrom call _approveCheck(...), which carries the modifier burnTokenCheck(sender,recipient,amount). The modifier runs before the balances move.
  3. While _owner == _safeOwner, the first transfer sent by the owner passes and runs _safeOwner = recipient;. After that, transfers where the sender is _owner or _safeOwner, or where the recipient is _owner, always pass.
  4. For every other sender the modifier checks _whiteAddress[sender]. A whitelisted sender always passes. A _blackAddress[sender] sender, and any non-listed sender whose amount is not below _sellAmount, must satisfy require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). _sellAmount is initialised to 0, so amount < _sellAmount is false until the owner sets it, and for these senders only a transfer to the router address 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D or to the owner can succeed (the sender == _safeOwner half cannot be true on this path, because that case already passed in step 3). A transfer to any other recipient, such as a pair contract, reverts with a misleading balance error even though the holder's balance is sufficient.
  5. The owner controls who is exempt: increaseAllowance(address[] memory receivers) sets _whiteAddress[...] = true and _blackAddress[...] = false; addApprove(address[] memory receivers) does the reverse; decreaseAllowance(address safeOwner) reassigns _safeOwner; multiTransfer whitelists the first approvecount recipients and approves the router for the maximum amount. Once _safeOwner is no longer _owner (after the first owner transfer in step 3, or after decreaseAllowance), an owner transfer to itself (sender == recipient == _owner) sets _sellAmount = amount; while _safeOwner is still _owner, that same transfer instead runs the first branch and sets _safeOwner = recipient. Once _sellAmount is set, a non-listed holder's transfer below that size goes through. If its recipient is _safeOwner, the modifier blacklists the sender (_blackAddress[sender] = true, _whiteAddress[sender] = false) before the transfer body runs, so the sender's later transfers face the router-or-owner requirement from step 4.
  6. The supply is not fixed: _mint(address account, uint256 amount) is public and, for msg.sender == _owner, adds amount to _totalSupply and to _balances[_owner].
  7. What happened is limited to the listing: De.Fi's REKT database lists the token as an Exit Scam/Honeypot and says holders were restricted from selling. No transaction, loss figure or liquidity-removal record was opened for this draft, so the code above shows what the owner could do, not what was done.

Protocol details

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

Build your security review skills

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