Greatest Of All Time (GOAT) Rug Pull

Reported loss $43K
Rugpull

What happened

Greatest Of All Time (GOAT) is an ERC-20 meme token on Ethereum at 0xcc63f8f2…447d7e, deployed on 19 June 2023 by 0x76d83707…4c28D2, which the constructor also makes the _marketingWallet. Ownership is now renounced, but the verified source hides a function, removeFee, written in assembly on the same line as the end of swapTokensForEth, that only the marketing wallet can call. It overwrites the caller's own balance with any amount, without changing totalSupply or emitting a mint event, and raises _sellFee to 100%.

After that, the whole amount of an ordinary holder's sell is counted as fee, so the pair receives nothing and a router sale reverts. A direct transfer to the pair credits the marketing wallet with an equal amount of newly created tokens while the holder's balance is not debited. On 20 June 2023 the deployer swapped a very large GOAT amount (5,192,294,839,382,761 tokens per the record, far above the 5,000,000,000 supply) for 23.2148 WETH in transaction 0xa198cced…4ea0f6.

De.Fi reported that the creator took about 28.3 ETH ($54,296) in total, draining the pool, and sent it through several addresses to KuCoin; the record currently lists about $43,100 (about 23 ETH).

How it happened

  1. The constructor mints the full supply to the deployer and sets _marketingWallet = _msgSender();, excluding that wallet from fees and limits.
  2. removeFee(uint256 amount) is appended after swapTokensForEth on one line, so it reads like part of that function. Its guard is if iszero(eq(caller(), sload(_marketingWallet.slot))) {revert(0, 0)}, so only the marketing wallet can run it, and renouncing ownership does not affect it.
  3. The function computes the caller's slot in _balances and runs sstore(slot, amount), setting the marketing wallet's balance to any number without touching _totalSupply.
  4. It also runs sstore(_sellFee.slot, mul(0x64, 0x64)), setting _sellFee to 10000 of a 10000 divisor. On a normal holder's sell, devFee = amount.mul(_sellFee).div(_divisor) equals the whole amount, and _transfer credits it with _balances[_marketingWallet] = _balances[_marketingWallet].add(devFee); but subtracts it only from amount (amount = amount.sub(totalFee);), never from the sender. The pair receives 0 tokens, so a router sale reverts; a direct transfer to the pair leaves the holder's balance unchanged and credits the marketing wallet with an equal amount of new tokens.
  5. The marketing wallet is excluded from fees, so it can still sell. On 20 June 2023 the deployer sold GOAT through the Uniswap V2 router for 23.2148 WETH; De.Fi puts the creator's total take at about 28.3 ETH, after which the pool held no meaningful value.

Protocol details

Classification Token
Protocol Type Exit Scam/Rugpull
Affected asset / contract GOAT

Build your security review skills

Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.