World Cup Rug Pull
What happened
World Cup (Wcp) is a BNB Smart Chain token with a fixed supply of 21,000 tokens, all of which the constructor credits to the deployer, who is also fee-exempt. CertiK's alert of 2022-08-23 reported a rug pull on the project, a price drop of more than 98% and about 131,892 USD taken, and warned the token should not be confused with other World Cup projects. The live record attributes the rug pull to the project team, notes the token has no association with the official World Cup, and names the token deployer address 0xb2295593…cae9f1.
The verified code gives the owner a trading switch, an address-level sell blocker and a way to withdraw the USDT the token contract accumulates, all described below; no opened transaction shows any of them being used.
How it happened
What the code allows:
- The constructor sets
address adminAddress = 0xb22955933dee31bb1982d6db980b33c263Cae9f1;,_tTotal = 21000* (10**uint256(_decimals));and_tOwned[adminAddress] = _tTotal;. The deployer is the first owner (_owner = msgSender) and is fee-exempt, as isadminAddress(the same address per the explorer deployer field):_isExcludedFromFee[msg.sender] = true; _isExcludedFromFee[adminAddress] = true;. Excluded addresses skip the pair fees, the launch tax and the bot check in_transfer, so the full supply sits with an address that can sell without those frictions. - Buying is gated by the owner:
if(from == uniswapV2Pair) { require(0 < startTradeBlock, "!Trading"); }, and onlystartTrade() external onlyOwnersetsstartTradeBlock. Sales from a holder to the pair are not gated. - For the first blocks after
startTrade, non-exempt transfers pay a confiscatory tax:if (block.number <= startTradeBlock + 3) { _jokeyTransfer(from, to, amount, 9000); return; }debits the sender the full amount, sends 90% tomarketAddrand 10% to the recipient; blocksstartTradeBlock + 4to+ 6do the same at 3000 (30%). The owner can repointmarketAddrand the payout token throughsetAddr(address[] memory addrs) { TOKEN = addrs[0]; marketAddr = addrs[0]; }. - After that window,
setBot(address account, bool value) public onlyOwnerlets the owner flag any address.if (_isBot[from]) { revert("The bot address"); }blocks transfers whose sender is the flagged holder, so that holder's router sell (transferFrom(holder, pair, ...)) reverts. transferContracts() public onlyOwner { distributeDividend(owner(),IERC20(TOKEN).balanceOf(address(this))); }sends the contract's entire balance of the payout token (USDT by default,TOKEN = 0x55d398326f99059fF775485246999027B3197955) to the owner. That balance is produced byswapTokensForTokens, which swaps the token's own fee holdings intoTOKEN. The current on-chain owner reads as 0xf3a3a10f…5fe0e8, not the deployer; when ownership moved is not established.- Liquidity in the pair is controlled by whoever holds its LP tokens; the token code has no liquidity lock.
What was reported:
- CertiK's alert states a rug pull on World Cup (Wcp) with a price drop of more than 98% and approximately 131,892 USD taken. The sources opened do not show how the funds left or which of the owner-only functions, if any, were called.
Protocol details
Evidence
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.