HolderFinance Honeypot
What happened
HolderFinance (HFI) is a BNB Smart Chain token contract deployed on 2021-06-02 by 0x529aECE1…6Df103 in transaction 0x1667983d…b6cdb0. De.Fi's REKT database lists it as an Exit Scam/Honeypot, noting that the contract owner could disable the transfer function, which restricted users in selling their tokens. In the verified source, an owner-only setTracing switch turns on a check in transferFrom that records the recipient of the first call as nxOwner and then reverts every later transfer to that address; if the recorded address is the liquidity pair, router sales revert.
The constructor also sends half of the 1,000-token supply to the dead address while totalSupply() still reports 1,000. The code shows what the owner can do; no transaction showing setTracing being called was opened for this entry.
How it happened
- The constructor sets
balances[owner] = _totalSupply(1000 * 10**9, 9 decimals) and callstransfer(dead, burnedAmount)with500 * 10**9, moving half to 0x00000000…00dEaD.totalSupply()returns_totalSupply.sub(balances[address(0)]), so it still reports the full 1,000 tokens. tracingisfalseby default.setTracing(bool _tracing)can flip it, andonlyOwneracceptsmsg.sender == owner || msg.sender == nxOwner.- With tracing on,
transferFromrunscontextHandler(from, to):if(from != address(0) && nxOwner == address(0)) nxOwner = to; else require(to != nxOwner, "Order ContextHandler");. The firsttransferFromafter tracing is enabled succeeds and stores its recipient asnxOwner; every latertransferFromto that address reverts. - A router sale pulls the holder's tokens into the pair with
transferFrom(holder, pair, amount). If the pair is the storednxOwner, every later sale reverts.transferhas a matchingrequestHandlerthat appliesrequire(to != nxOwner, "Handling Request")while tracing is on. - A buy is a
transferfrom the pair to the buyer, which stays allowed unless the buyer isnxOwner. The address stored asnxOwneralso passesonlyOwner, so it can callsetTracingandemitTransfer. emitTransfer(uint256 _input)isonlyOwnerand doesbalances[msg.sender] = balances[msg.sender] + (_input)without touching_totalSupply, so an authorised caller can raise its own balance and emit aTransferevent from the zero address.renounceOwnership(address _newOwner)is public and unrestricted but only writescurrentOwner, which no access check reads; no function reassignsowner.- What the code allows is separate from what happened: De.Fi's REKT database lists the token as a honeypot, but no transaction showing
setTracing, the value stored innxOwneror a failed sale was opened.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.