Binary Protocol Rug Pull

Reported loss $4K
Ethereum
Rugpull

What happened

Binary Protocol (BP) contains an owner-style mint function whose lock never engages. initialSupply(address contractAddress, uint256 InitialSupply) is onlyGovernor and is meant to run once (require(initialSupplyFinished == false)), but it sets a different, similarly named variable (InitialSupplyFinished = true), so the checked flag stays false and the governor, who is the deployer, can mint again without limit. Etherscan shows the deployer 0xD97A7501…34050C called initialSupply crediting itself 1,000,000 BP (tx 0x7467abb5…93a521) and later 1,000,000,000 BP (tx 0xf4b6c140…c2293c); on-chain totalSupply() now reads 2,001,000,000 BP, which is 1,000,000,000 BP more than these two calls account for.

The same address added liquidity of 700,000 BP and 18 ETH at 06:36 UTC on 2021-01-29 (tx 0x1cdad510…825da5), and 68 seconds after the second mint swapped 1,000,000,000 BP for 20.8386 WETH on Uniswap V2 (tx 0x0c02a010…41b083). The third hash listed by De.Fi, 0x672689de…3dc887, is a 7.5 ETH transfer from the deployer to 0x3668C746…6096D1 at 07:31 UTC. De.Fi's REKT database lists the incident as an exit scam / rug pull with 3,924 USD lost.

How it happened

  1. The constructor makes the deployer the governor: Governed._initialize(msg.sender);. No tokens are minted at deployment; supply is created only through initialSupply.
  2. initialSupply credits any address with any amount: function initialSupply(address contractAddress, uint256 InitialSupply) public onlyGovernor { require(initialSupplyFinished == false); _totalSupply = _totalSupply.add(InitialSupply); _balances[contractAddress] = _balances[contractAddress].add(InitialSupply); InitialSupplyFinished = true; }.
  3. The lock is broken by a name mismatch. The require reads initialSupplyFinished (lowercase, declared in BinaryProtocol, initialised to false and never assigned again), while the function writes InitialSupplyFinished (capital I, declared in ERC20). The view isInitialSupplyFinished() returns the capitalised variable and reports true after the first call, yet the require still passes, so initialSupply stays callable.
  4. On 2021-01-29 the deployer called initialSupply with its own address as recipient: 1,000,000 BP at 04:53 UTC and 1,000,000,000 BP at 07:19 UTC. The first call's argument is hex 0xd3c21bcecceda1000000 and the second's 0x033b2e3c9fd0803ce8000000, which decode to 1e24 and 1e27 raw units at 18 decimals.
  5. At 06:36 UTC the deployer added 700,000 BP and 18 ETH to a new Uniswap V2 pair, and at 07:20 UTC, about a minute after the second call, it swapped 1,000,000,000 BP for 20.8386 WETH via swapExactTokensForETH, taking out more ETH than the 18 ETH it had added.

Protocol details

Classification Exchange (DEX)
Protocol Type Exit Scam/Rugpull
Affected asset / contract BP

Build your security review skills

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