Metropolis.finance Rug Pull

Reported loss $8K
Ethereum
Rugpull

What happened

MetropolisToken (MTR) is a plain ERC-20 whose owner-only burnFrom function does not burn anything. It writes whatever balance the caller passes in as an argument straight into _balances and _totalSupply, without reading the stored balance, so the owner can set any account to any amount without a Transfer event. The constructor created 100,000 MTR for the deployer, of which 80,000 MTR went into the Uniswap pool alongside 50 ETH at 12:54:33 UTC on 2020-12-25 (tx 0x975570ce…4ce793).

At 13:16:34 UTC the deployer address called burnFrom on itself with a balance argument of 99,999,999.9 MTR (tx 0x2154b52e…9f84f1), and 66 seconds later the same address swapped 99,999,999.9 MTR for about 62.49 ETH through Uniswap V2 (tx 0xfbc4caf5…d0b3f3). De.Fi's REKT database lists the incident as an exit scam / rug pull with $7,805 lost.

How it happened

  1. The MetropolisToken constructor credits the deployer with initialTokens: _balances[msg.sender] = _balances[msg.sender].add(initialTokens);. Etherscan's constructor arguments show 100,000 MTR (0x152d02c7e14af6800000 base units). The contract was deployed at 12:19:59 UTC on 2020-12-25.
  2. At 12:54:33 UTC the deployer added liquidity: 80,000 MTR and 50 ETH to a new Uniswap V2 pool, leaving at most 20,000 MTR with the deployer (tx 0x975570ce…4ce793).
  3. The contract contains a function labelled as a burn: function burnFrom(address account, uint256 balance, uint256 subtractValue) external ownerOnly. Its body is _balances[account] = balance.sub(subtractValue, "ERC20: burn amount exceeds balance"); followed by _totalSupply = balance.sub(subtractValue);. The balance value comes from the caller and is never compared with _balances[account], so with subtractValue set to 0 the owner can assign any account any balance. No Transfer event is emitted.
  4. At 13:16:34 UTC the deployer address called burnFrom(0x9ecd4d3689f767d688e28b63febdc896545e9518, 0x52b7d2db64c75a86760000, 0). 0x52b7d2db64c75a86760000 is 99,999,999.9 MTR, about a thousand times the 100,000 MTR the constructor created. Etherscan shows no token transfers in that receipt (tx 0x2154b52e…9f84f1).
  5. At 13:17:40 UTC the same address called swapExactTokensForETH on Uniswap V2 Router 2, sending 99,999,999.9 MTR into the pool and receiving about 62.49 ETH, against the 50 ETH it had added 23 minutes earlier (tx 0xfbc4caf5…d0b3f3).

Protocol details

Classification Token
Protocol Type Exit Scam/Rugpull
Affected asset / contract MTR
Protocol links Website

Build your security review skills

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