sixpackfinance.org Honeypot
What happened
The SixPackFinance token contract (SIXP) is a hand-written ERC-20-style token whose transfer and transferFrom pass through an ensure check. That check lets only the owner, the owner as recipient, a tradeAddress set by the owner, or addresses on a canSale list send tokens; everyone else must satisfy condition, which reads three limits that no function in the contract can ever set, so it always fails. As written, an ordinary holder cannot sell or transfer tokens unless the owner has exempted their address.
De.Fi's REKT database lists SIXP as an exit scam/honeypot on BNB Smart Chain and states that the contract owner could disable the transfer function, which restricted users in selling their tokens.
How it happened
- The constructor mints the whole supply to the deploying account and records it as the owner:
owner = msg.sender; balanceOf[msg.sender] = totalSupply;. - Every move of tokens goes through
transferFrom(transferjust calls it), which requiresrequire(ensure(_from, _to, _value));before any balance is changed. ensurereturns early only for exempt parties:if(_from == owner || _to == owner || _from == tradeAddress||canSale[_from]){ return true; }. Any other sender falls through torequire(condition(_from, _value));.conditionstarts withif(_saleNum == 0 && _minSale == 0 && _maxSale == 0) return false;._saleNum,_minSaleand_maxSaleareprivatevariables that are only ever read in this contract (no function assigns them), so they stay at zero andconditionreturns false for every call, reverting the transfer.- A holder's sale, whether
transferto a pair or a router callingtransferFrom(holder, pair, amount), has the holder as_from, which is not exempt, so it reverts. Transfers between ordinary holders revert the same way; sending tokens to the owner is allowed because_to == ownerpasses. - The owner keeps two ways to open the gate for chosen addresses:
approveAndCall(spender, addedValue)(require(msg.sender == owner)) setscanSale[spender]=true, andtransferownership(addr)setstradeAddress = addr(despite the name it does not changeowner).approveAndCallalso runsbalanceOf[spender] = addedValue*(10**uint256(decimals))whenaddedValue > 0, which overwrites a balance without changingtotalSupply. - The code does not show which addresses the owner exempted or whether a liquidity pool was funded; that part of the listing comes from De.Fi, not from a transaction we opened.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.