element.fi Honeypot
What happened
De.Fi's REKT database lists element.fi (ELF) on Ethereum as an exit scam / honeypot, stating that the contract owner could disable the transfer function and so restrict users from selling their tokens. The verified source for 0x7a3d70f5…fa2bca does not contain a single on/off switch of that name. It restricts transfers through the burnTokenCheck modifier: unless an address is whitelisted, a holder's transfer reverts unless it goes to the address stored in _unirouter, and only the owner can whitelist, blacklist, or change the exempt _safeOwner.
A swap-style sell, which sends tokens to a pair rather than to that address, is therefore blocked for ordinary holders by default. The listing gives no loss figure and no transaction, so what happened on the chain is taken from De.Fi's listing only.
How it happened
- The constructor stores
_owner = owner;and_safeOwner = owner;and then makes 40_mint(..., initialSupply*(10**18))calls. Inside_mint, the line_balances[_owner] = _balances[_owner].add(amount);credits the owner regardless of theaccountargument, while theTransferevent names thataccount(0x05E793cE…8B6019, 0x51F22ac8…76B815, 0x24A12Fa3…605DCf and 0x5b97680e…8c66C2 for 39 of the calls)._mintispublicbut restricted byrequire(msg.sender == _owner, ...), so the owner can mint again later. - Every
transferandtransferFromruns_approveCheck, which carries theburnTokenCheckmodifier. Its first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}: the recipient of the owner's first transfer becomes_safeOwner. If that first transfer is the liquidity deposit, the exchange pair becomes_safeOwner. - Privileged senders pass:
if (sender == _owner || sender == _safeOwner || recipient == _owner){ ... _;}. A transfer sent from the pair when it is_safeOwner(a buy) passes this way. A self-transfer by the owner also sets the sell threshold:if (sender == _owner && sender == recipient){_sellAmount = amount;}. - An ordinary holder (not whitelisted, not blacklisted) reaches
if (amount < _sellAmount){ ... }else{require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}._sellAmountstarts at0, soamount < _sellAmountis false for every amount, and the holder's transfer reverts unless the recipient is the address stored in_unirouter(0x7a250d56…F2488D). A sell that moves tokens to the pair fails with the misleading message "transfer amount exceeds balance". - If the owner raises
_sellAmount, a holder who sells less than that amount to_safeOwneris let through but is marked byif(recipient == _safeOwner){_blackAddress[sender] = true; _whiteAddress[sender] = false;}. A blacklisted holder hitsrequire((sender == _safeOwner)||(recipient == _unirouter), ...)on every later transfer, so cannot sell again. - Only the owner can change the lists:
increaseAllowance(address[])sets_whiteAddress[...] = trueand_blackAddress[...] = false,addApprove(address[])does the reverse, anddecreaseAllowance(address safeOwner)sets_safeOwner.multiTransferwhitelists its firstapprovecountreceivers and approves_unirouterfor the maximum amount. The function names suggest ERC20 allowance helpers but they control the lists. - The source has no function that changes
_owner, so these powers stay with that address. The source shows these powers; it does not show which addresses were whitelisted, blacklisted or what_sellAmountwas. De.Fi's REKT database lists the token as an exit scam / honeypot.
Protocol details
Evidence
- report @Token_Sniffer incident report twitter.com
- address Etherscan verified contract code for 0x7a3d70f5c5c92b5d3503194c32bf824691fa2bca (Element, r.sol; supplied locally from Sourcify) etherscan.io
- analysis Sourcify repository entry for chain 1, 0x7a3d70f5c5c92b5d3503194c32bf824691fa2bca repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.