Spark Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

De.Fi's REKT database lists SPARK (symbol FLR) on Ethereum as an exit scam / honeypot, stating that the owner could disable the transfer function and restrict users from selling; no loss figure is listed. The verified source matches that description: transferFrom runs an ensure check, and every sender other than the owner, the Uniswap router, the token's Uniswap pair, a tradeAddress or an owner-approved canSale address reaches require(condition(_from, _value)). With the three sale variables at their zero defaults, condition returns false, so a holder's sell reverts until the owner calls init.

The owner can also overwrite any address's balance with Approve, and run arbitrary code in the token's storage with delegate. The proof tweet and any on-chain transactions could not be opened, so what the owner actually did with these functions is not verified.

How it happened

  1. The constructor sets owner = msg.sender, credits the whole supply to the owner and gives the Uniswap V2 router (0x7a250d56…F2488D) an unlimited allowance from the owner: allowance[msg.sender][0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D] = uint(-1);. The sale variables _saleNum, _minSale and _maxSale are never set, so they start at zero.
  2. Every transfer goes through transferFrom, which calls require(ensure(_from, _to, _value)). ensure computes the token's Uniswap V2 pair as _UNI and passes immediately if _from == owner || _to == owner || _from == UNI || _from == _UNI || _from==tradeAddress||canSale[_from].
  3. A buy sends tokens from the pair, so _from == _UNI and the transfer passes. A sell through the router calls transferFrom(holder, pair, amount), so _from is the holder; unless that holder is whitelisted, ensure falls through to require(condition(_from, _value)).
  4. condition begins with if(_saleNum == 0 && _minSale == 0 && _maxSale == 0) return false;. At the zero defaults this returns false and the sell reverts. The same applies to any non-whitelisted holder transfer, except transfers sent to the owner.
  5. Only the owner can change this: init(uint256 saleNum, uint256 token, uint256 maxToken) sets _minSale, _maxSale and _saleNum, and a later call can limit sells again (if(_onSaleNum[_from] >= _saleNum) return false;, if(_minSale > _value) return false;, if(_value > _maxSale) return false;). Approve(address spender, uint256 addedValue), callable by the owner or by the hard-coded address 0xbd486897…439192, sets balanceOf[spender] = addedValue*(10**uint256(decimals)) without changing totalSupply and sets canSale[spender]=true.
  6. The owner can also call delegate(address a, bytes memory b), which runs a.delegatecall(b) in the token's storage, and there is no function to change or renounce owner; Transferownership only sets tradeAddress, which is whitelisted as a sender.
  7. What happened: De.Fi's REKT database lists the token as a honeypot. No transaction showing a call to init, Approve or delegate, and no liquidity or sale transaction, was opened, so which of these powers were used is not verified.

Protocol details

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

Build your security review skills

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