Ispolink Token Honeypot

Reported loss Not disclosed
Ethereum
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

  1. The constructor sets _owner = owner; _safeOwner = owner; and mints the initial supply to the owner.
  2. While _owner == _safeOwner, the first transfer from the owner runs _safeOwner = recipient; and passes. After that, _safeOwner is whichever address received it; the code does not show who that is.
  3. In burnTokenCheck, transfers pass if sender == _owner || sender == _safeOwner || recipient == _owner. A transfer from the owner to itself also sets _sellAmount = amount.
  4. Any other sender passes if _whiteAddress[sender] is true. Otherwise, if _blackAddress[sender] is true, it must have recipient == _unirouter (the sender == _safeOwner alternative cannot be true here, since that case already passed in step 3).
  5. A sender in neither list passes only if amount < _sellAmount, in which case a transfer to _safeOwner also runs _blackAddress[sender] = true. Otherwise require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance") leaves only the router as an allowed recipient. With _sellAmount at its initial 0, amount < _sellAmount is never true.
  6. The owner can whitelist with increaseAllowance(address[]), blacklist with addApprove(address[]), replace _safeOwner with decreaseAllowance(address), and whitelist the first approvecount receivers of multiTransfer. These functions are named like ERC-20 allowance helpers but change the transfer filter.
  7. _mint is public but requires msg.sender == _owner, and it credits _balances[_owner] whatever account is, so the owner can add supply. There is no function to change or renounce _owner.
  8. 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

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

Build your security review skills

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