ElonSperm Honeypot
What happened
ElonSperm (SPERM) is a BNB Smart Chain token whose verified source gives its owner several levers over whether holders can trade. setTaxFeePercent and setLiquidityFeePercent have no upper bound, and setMaxTxPercent accepts 0, which makes every transfer that does not involve the owner revert. De.Fi's REKT database lists SPERM as an "Exit Scam/Honeypot" dated 2021-09-10 and describes it as the contract owner being able to disable the transfer function, which restricted users in selling their tokens; the listing gives no loss figure or proof link, and no transaction showing the owner using these functions was opened.
How it happened
- At deployment the whole supply is credited to the deployer (
_rOwned[_msgSender()] = _rTotal;) and the owner is exempted from fees (_isExcludedFromFee[owner()] = true;). - The fee setters carry no cap:
function setTaxFeePercent(uint256 taxFee) external onlyOwner() { _taxFee = taxFee; }, andsetLiquidityFeePercenthas the same shape. Both default to 5. - In
_transferStandardthe sender is debited the full amount (_rOwned[sender] = _rOwned[sender].sub(rAmount);) while the recipient is creditedrTransferAmount, which is the amount minus both fees. If the two percentages sum to 100, a transfer between two addresses that are not fee-exempt credits the recipient nothing; if they sum to more than 100,tAmount.sub(tFee).sub(tLiquidity)reverts. setMaxTxPercentcomputes_maxTxAmount = _tTotal.mul(maxTxPercent).div(10**2);, so an input of 0 sets the limit to 0._transferthen requiresamount <= _maxTxAmountwheneverif(from != owner() && to != owner())holds, and separately requiresamount > 0. With the limit at 0, every transfer that does not involve the owner reverts, whether it is a sale into a pool, a purchase from it or a wallet-to-wallet send.- Liquidity tokens produced by the contract's own swap-and-liquify routine are sent to the owner:
addLiquidityETH{value: ethAmount}(address(this), tokenAmount, 0, 0, owner(), block.timestamp). Ownership is not given up in the code:lock(uint256 time)sets_owner = address(0), butunlock()lets_previousOwnertake it back oncenow > _lockTime, and an eth_call on 2026-09-30 still returned the deployer 0x82661068…8b308d as owner.
Protocol details
Evidence
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.