LIGMA Honeypot
What happened
De.Fi's REKT database lists LIGMA ($BALLS, Ethereum, contract 0x61395d8c…1322d0) as an Exit Scam/Honeypot dated 2021-05-22 and says the owner could disable the transfer function so holders could not sell. The verified source has no single on/off switch. Instead every transfer passes through the burnTokenCheck modifier, which lets the owner, a variable called _safeOwner, and transfers to the owner pass.
A holder who is neither whitelisted nor blacklisted can send tokens to the hard-coded _unirouter address, to the owner, or to any recipient when the amount is below _sellAmount (which starts at 0). Other transfers revert with "ERC20: transfer amount exceeds balance". The source does not state what _unirouter is.
The owner controls the whitelist, the blacklist, _safeOwner and, through a self-transfer, _sellAmount.
How it happened
- The constructor sets
_owner = owner;and_safeOwner = owner;and mints the initial supply to_owner. - Every
transferandtransferFromruns_approveCheck(...), which carries theburnTokenCheckmodifier. Its first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}: while the owner is still_safeOwner, a transfer sent by the owner passes and moves_safeOwnerto that transfer's recipient. - Once
_safeOwneris no longer the owner, the second branch lets_owner,_safeOwner, or any transfer to_ownerthrough. For other senders, a whitelisted sender passes. A blacklisted sender must satisfyrequire((sender == _safeOwner)||(recipient == _unirouter), ...). A sender in neither list passes whenamount < _sellAmount; otherwise the samerequireapplies. _sellAmountstarts at 0 (uint256 private _sellAmount = 0;), soamount < _sellAmountis never true until the owner sets it. The owner can set it with a transfer to itself,if (sender == _owner && sender == recipient){_sellAmount = amount;}, but only once_safeOwneris no longer the owner: while_owner == _safeOwner, a self-transfer takes the first branch and does not reach that line.- With
_sellAmountat 0, a non-listed holder can therefore send tokens to_unirouter(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, hard-coded; the source does not say what it is) or to_owner. A transfer to any other recipient, such as a pair address, reverts with "ERC20: transfer amount exceeds balance". The revert undoes the balance change, so the holder keeps the tokens but cannot send them there. - The owner-only functions are named misleadingly:
increaseAllowance(address[] receivers)whitelists,addApprove(address[] receivers)blacklists,decreaseAllowance(address safeOwner)sets_safeOwner, andmultiTransfer(...)whitelists the firstapprovecountreceivers and approves_unirouterfor the maximum amount. Whether any address was whitelisted, and whether a pair was_safeOwner, is not shown by the code alone. _mint(address account, uint256 amount)ispublicand gated only byrequire(msg.sender == _owner, ...); it adds to_balances[_owner], so the owner can mint more supply.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.