Xcademy Token Honeypot
What happened
De.Fi's REKT database lists Xcademy Token (XCAD, Ethereum, contract 0x782d972d…af18b9) 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 contains a sender and recipient filter, the burnTokenCheck modifier, on every transfer and transferFrom. Unless the sender is the owner, a designated _safeOwner or a whitelisted address, the modifier only lets tokens move to one hard-coded _unirouter address, and the owner controls the lists and addresses it consults.
How it happened
- The constructor sets
_owner = ownerand_safeOwner = ownerand mintsinitialSupply*(10**18)to_owner; the currenttotalSupply()read in the record metadata is 200,000,000 whole tokens. There is no function that changes_ownerafterwards. transferandtransferFromboth call_approveCheck, which is wrapped inburnTokenCheck(sender,recipient,amount). Its first branch isif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}: while_safeOwnerstill equals_owner, the owner's next transfer stores that transfer's recipient in_safeOwner.- Senders that pass unconditionally are
_owner,_safeOwner, any sender whose recipient is_owner, and any address with_whiteAddress[sender] == true. - Every other sender reaches
else{require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}. Since_safeOwneralready passed in step 3, such a sender can only send to_unirouter, which is set to 0x7a250d56…F2488D. A swap router pulls the seller's tokens into the pair withtransferFrom, so that recipient is the pair and not_unirouter; the call reverts and the holder's balance is not debited. - Blacklisted senders (
_blackAddress[sender] == true) face the samerequire, so they can also only send to_unirouter. The owner controls both lists:addApprove(address[])blacklists and un-whitelists,increaseAllowance(address[])whitelists and un-blacklists,decreaseAllowance(address safeOwner)replaces_safeOwner, andmultiTransferwhitelists the firstapprovecountreceivers and approves_unirouterfor the maximum amount on their tokens. - A threshold exception exists: once the owner sends tokens to itself while
_safeOwnerdiffers from_owner,_sellAmount = amountis stored. Senders then pass whenamount < _sellAmount(strictly smaller), and if the recipient is_safeOwner,_blackAddress[sender] = trueis written for them. With the initial_sellAmount = 0no amount qualifies. _mint(address account, uint256 amount)ispublicand owner-only; it addsamountto_balances[_owner]whateveraccountis, so the owner can mint more supply at any time.
The code allows steps 4 to 7. Which address _safeOwner held, whether the lists were filled and whether _mint was used after deployment is not shown by the source.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.