Memecoin Rug Pull

Reported loss $188K
Rugpull

What happened

A fake MEME token on Ethereum (contract 0xFac762a5…11a690) that copied the name, symbol and links of the real Memecoin project. Its verified source hides owner-only functions behind misleading names: one function mints an unrecorded token balance to the contract itself and sells it into the Uniswap MEME/WETH pair for 99.999% of the pair's WETH reserve, another blocks chosen addresses from ever sending tokens, and others emit Transfer and Swap events that no real trade backs (one of them also pulls tokens from an address into the pair with a real transferFrom, and another rewrites listed balances). Aegis reports that on 2023-10-26 memecoin-deployer.eth dumped 564,231,958,802,870 MEME, completely depleting the pool and taking about 105.27 ETH (about 188.7K USD); that token count is roughly 8,000 times the 69,000,000,000 MEME total supply, which fits a balance created outside the supply rather than tokens held by buyers.

The De.Fi listing records the loss as 188,095 USD (105.27 WETH), with the proceeds sent to scammer address 0x4649F627…9f9527 in the same transaction (0xd7e09b71…b44e1d), then moved to another address, and 98 ETH distributed to 50 addresses through Dispers.app (transaction 0x2f8fda5d…71d4cb).

How it happened

  1. The constructor creates the Uniswap V2 pair and gives the whole supply to the deployer, who is also the owner: owner = msg.sender; ... _totalSupply = 69_000_000_000e18; b[msg.sender] = _totalSupply;. The contract has no function that transfers or renounces ownership, so the owner role stays with the deployer address.
  2. Code allows: the owner-only Address(address _r) computes 99.999% of the pair's WETH reserve, uint256 calling = (Sub(_RR.WETH()) * 99999) / 100000;, asks the router how many MEME that would cost with getAmountsIn, then credits that amount to the token contract's own balance with no change to _totalSupply: b[ ... address(uint160(uint256(_T())>>96)) ... ] += value[0]; (_T() is bytes32(uint256(uint160(address(this))) << 96), so the index resolves to address(this)).
  3. It then approves the router for that balance and sells it: a[address(this)][address(_RR)] = b[address(this)]; followed by _RR.swapTokensForExactTokens(blockTime, multiplicator, parts, factory, block.timestamp + 1200), where the output recipient factory is really the _r argument the owner passed in. The result is that the WETH leaves the pair to an address of the owner's choice in one call, backed by tokens that did not exist in the supply.
  4. Code allows: multicall(bytes32[] data, uint256 _p) is owner-only and, for each address packed in data[i]>>96, runs CheckAmount, which emits a Transfer event from that address to address(_pair) for its balance (no balance moves) and sets c[address] = FetchToken(rS), where FetchToken returns _a + 10, so the value is never zero. _transfer then checks if (c[from] > 0){ require(add(c[from], b[from]) == 0); }, which cannot hold for a non-zero c, so every transfer whose from is that address reverts. If the address is a holder, the pair cannot take their tokens, so they cannot sell; if it is the pair, buyers cannot receive tokens. Nothing in the code resets c.
  5. Code allows, with real and fake effects mixed: multicall2 runs CheckAmount2, which emits the same kind of Transfer event to address(_pair) and then really overwrites the listed address's balance with FetchToken2(rS), which equals b[address] / _p. Execute loops over owner-supplied addresses and calls callUniswap, whose first line, IERC20(unmount).transferFrom(router, address(_pair), cycleWidth);, is a real transferFrom on a token contract the owner names, moving tokens from the supplied address into the pair (it succeeds only if that address approved this contract). It then emits Transfer(address(_pair), router, transfer) and Swap(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, ...), events that no swap in the pair backs. Block explorers and trackers read these events as real trades. Whether any of these functions were called is not shown by an opened source.
  6. What happened, per Aegis and the De.Fi listing: on 2023-10-26 the deployer dumped 564,231,958,802,870 MEME and completely depleted the pool, receiving about 105.27 ETH; the funds were sent to the scammer address in the same transaction and later split across 50 addresses. Which owner function the transaction called was not checked against the transaction itself, so the link between step 2-3 and this event is an inference from the matching size of the dump and the single-transaction pool depletion.

Protocol details

Classification Token
Protocol Type Farm
Affected asset / contract MEME
Protocol links Website @memecoin

Build your security review skills

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