Ispolink Token Honeypot
What happened
Every transfer and transferFrom in the ISP contract passes through a burnTokenCheck modifier. For a holder that is not the owner, not _safeOwner and not whitelisted, a transfer succeeds only if the recipient is the Uniswap V2 router address hard-coded as _unirouter or the owner, or if the amount is below _sellAmount (zero until the owner sets it). Sending to anything else, such as a pair, reverts with "ERC20: transfer amount exceeds balance" while the balance is unchanged.
The owner alone controls the whitelist, blacklist, _safeOwner and _sellAmount. De.Fi's REKT database lists the token as an exit scam/honeypot in which the owner could disable the transfer function, restricting users from selling.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mints the initial supply to the owner. - While
_owner == _safeOwner, the first transfer from the owner runs_safeOwner = recipient;and passes. After that,_safeOwneris whichever address received it; the code does not show who that is. - In
burnTokenCheck, transfers pass ifsender == _owner || sender == _safeOwner || recipient == _owner. A transfer from the owner to itself also sets_sellAmount = amount. - Any other sender passes if
_whiteAddress[sender]is true. Otherwise, if_blackAddress[sender]is true, it must haverecipient == _unirouter(thesender == _safeOwneralternative cannot be true here, since that case already passed in step 3). - A sender in neither list passes only if
amount < _sellAmount, in which case a transfer to_safeOwneralso runs_blackAddress[sender] = true. Otherwiserequire((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance")leaves only the router as an allowed recipient. With_sellAmountat its initial 0,amount < _sellAmountis never true. - The owner can whitelist with
increaseAllowance(address[]), blacklist withaddApprove(address[]), replace_safeOwnerwithdecreaseAllowance(address), and whitelist the firstapprovecountreceivers ofmultiTransfer. These functions are named like ERC-20 allowance helpers but change the transfer filter. _mintispublicbut requiresmsg.sender == _owner, and it credits_balances[_owner]whateveraccountis, so the owner can add supply. There is no function to change or renounce_owner.- What the code allows is not what happened: no transaction was opened showing the owner calling any of these functions or which holders were blocked.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.