Efinity Token Honeypot

Reported loss Not disclosed
Ethereum
Honeypot

What happened

De.Fi's REKT database lists this Ethereum token (contract 0xf183bcac…8ecb35, on-chain name Efinity Token, symbol EFI) as an exit scam/honeypot dated 2021-06-24, stating that the contract owner could disable the transfer function and so restrict users from selling. The verified source has no single on/off switch. Instead, transfer and transferFrom both pass through a burnTokenCheck modifier in which an ordinary holder's transfer only succeeds when the recipient is the address stored in _unirouter, unless the owner has whitelisted that holder.

Selling into a liquidity pool is a transfer to the pool, so it reverts for a non-whitelisted holder. The contract was deployed on 2021-06-24 at 06:52 UTC. No loss figure is listed, and the source shows what the code permits, not which holders were affected.

How it happened

  1. The constructor stores the same address in _owner and _safeOwner and mints the whole initial supply to _owner; no function in the contract changes _owner afterwards.
  2. Every holder transfer goes through _approveCheck(...), which carries the burnTokenCheck modifier. In its first branch, if (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, the recipient of the owner's first outgoing transfer becomes _safeOwner.
  3. Afterwards, transfers where the sender is _owner or _safeOwner, or where the recipient is _owner, always pass (if (sender == _owner || sender == _safeOwner || recipient == _owner)).
  4. Any other sender is checked in order: a whitelisted sender passes; a blacklisted sender, and a sender in neither list whose amount is not below _sellAmount, hit require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance"). _sellAmount starts at uint256 private _sellAmount = 0;, so the amount < _sellAmount branch cannot run until the owner raises it. A transfer from such a holder to anything other than _unirouter, including a liquidity pool or another wallet, therefore reverts.
  5. The owner controls who is exempt. increaseAllowance(address[] receivers) is owner-only and sets _whiteAddress[receivers[i]] = true; and clears the blacklist; addApprove does the reverse; multiTransfer whitelists the first approvecount recipients and gives them a maximum allowance for _unirouter; decreaseAllowance(address safeOwner) re-points _safeOwner. An owner transfer to itself sets the threshold: if (sender == _owner && sender == recipient){_sellAmount = amount;}.
  6. When _sellAmount is non-zero, a non-listed holder's transfer below it is allowed, but if the recipient is _safeOwner the code writes _blackAddress[sender] = true; _whiteAddress[sender] = false; while still completing that transfer, after which that sender is limited to transfers to _unirouter.
  7. _mint is declared public with require(msg.sender == _owner, ...) and credits _balances[_owner], so the owner can mint further supply to itself at any time. The source does not show whether it was ever called.
  8. What happened, per the listing: De.Fi's REKT database lists the token as an exit scam/honeypot with the owner able to disable transfers so users could not sell. No transaction was opened for this record, so which wallets were blocked or whitelisted is not established here.

Protocol details

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

Build your security review skills

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