Towelie Rug Pull
What happened
Towelie (TOWELIE) is an Ethereum ERC20 whose _transfer carries a hidden gate: a transfer only goes through if the transaction origin is the deployer, if the sender received its tokens fewer than _allowance blocks ago, or if the recipient is the transaction origin. _allowance starts at 3,000,000 blocks but is set to 2 whenever any transfer sends tokens to a hard-coded address, or when the deployer calls setAllowance. Once it is 2, a holder selling through a DEX router (recipient is the pair, not the tx origin) is blocked unless their first receipt was in the previous block, while the deployer is always exempt.
CertiK Skynet reported on 2023-08-23 that the deployer unlocked LP tokens and removed about 89K USD of liquidity. De.Fi's REKT database lists the loss as 88,861 USD (54.72 ETH) from the Uniswap pool, with the funds moved to another EOA and then split between several addresses (about half to ChangeNOW, a quarter to Binance, a quarter left on EOAs, per the listing). Deployer: 0x9FAc5E13…C45488.
Scammer address listed by De.Fi: 0x6b883c49…B445D3. Funds holder as of September 4, 2023 per the listing: 0x55f03F60…AD9071. Liquidity removal transaction listed by De.Fi: 0x007aef7e…44537f.
How it happened
What the code allows:
- The base
ERC20constructor records the creator as the privileged address:_tokenAddress = msg.sender;and_pairToken[_tokenAddress] = true;. - Every transfer must pass
require(_pairToken[tx.origin] == true || block.number - _addressAllowance[from] < _allowance || to == tx.origin, "ERC20: Reverted");. A transaction started by the privileged address always passes. A buy through a router passes the third condition because the buyer is both recipient and tx origin. _afterTokenTransferstamps each recipient's first-receipt block (if (_addressAllowance[to] == 0) _addressAllowance[to] = block.number;) and contains the triggerif (to == _uniswapFactory) _allowance = 2;, where_uniswapFactoryis the hard-coded address 0x94C26B66…61E15e. The source does not show who controls it.setAllowance(uint256 _a)lets_tokenAddress(the deployer) change_allowanceat any time. It depends on the immutable_tokenAddress, not onOwnable, so the on-chain owner reading 0x0 (read 2026-09-30) does not remove it.- With
_allowanceat 2, a holder selling through a DEX hastoequal to the pair, not the tx origin, andblock.number - _addressAllowance[from]is almost always 2 or more, so the sell reverts withERC20: Reverted. The deployer keeps selling and can move liquidity.
(per CertiK and the De.Fi listing):
- CertiK Skynet reported that the deployer unlocked LP tokens and removed about 89K USD of liquidity from Towelie on 2023-08-23.
- De.Fi lists 88,861 USD (54.72 ETH) removed from the Uniswap pool and moved through other EOAs. No opened transaction shows whether
_allowancewas set to 2 before or after the removal.
Protocol details
Evidence
- report @CertiKAlert incident report twitter.com
- report CertiK Alert post on Towelie (TOWELIE) liquidity removal (via fxtwitter) twitter.com
- transaction etherscan.io transaction 0x007a…537f etherscan.io
- address Etherscan verified source for 0x435940c749b012f53885a1f56dea68a1eb8e05d7 etherscan.io
- address etherscan.io address 0x55f0…9071 etherscan.io
- address etherscan.io address 0x6b88…45D3 etherscan.io
- address etherscan.io address 0x9FAc…5488 etherscan.io
- analysis Sourcify exact match for 0x435940c749b012f53885a1f56dea68a1eb8e05d7 repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.