Binary Protocol Rug Pull
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
- The constructor makes the deployer the governor:
Governed._initialize(msg.sender);. No tokens are minted at deployment; supply is created only throughinitialSupply. initialSupplycredits 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; }.- The lock is broken by a name mismatch. The
requirereadsinitialSupplyFinished(lowercase, declared inBinaryProtocol, initialised tofalseand never assigned again), while the function writesInitialSupplyFinished(capital I, declared inERC20). The viewisInitialSupplyFinished()returns the capitalised variable and reportstrueafter the first call, yet therequirestill passes, soinitialSupplystays callable. - On 2021-01-29 the deployer called
initialSupplywith 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. - 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
Evidence
- report @CaptainJackAPE incident report twitter.com
- transaction Etherscan transaction 0x7467abb573c49a7f9afa29a0d086db87b05470132e5a3e4f1c32cee80293a521 etherscan.io
- transaction Etherscan transaction 0xf4b6c14069f1d9761c40c11f4132be2cc0361d86b2b069c551e51deadbc2293c etherscan.io
- transaction Etherscan transaction 0x672689de6495180d7301f9282dac828d6aad609d9a1fb7bb7f36b7a6623dc887 etherscan.io
- transaction Etherscan transaction 0x1cdad510f30826e2d54b15a61942d9a33fdb0271a6d1b11c935a1f99ea825da5 etherscan.io
- transaction Etherscan transaction 0x0c02a010cf511dc7ef859e8f64daaa38ce4f1d0021523bfc5cc29a9feb41b083 etherscan.io
- address Binary Protocol (BP) verified source on Etherscan etherscan.io
- analysis Sourcify exact match for 0x561568fbb12631bee08e2186d23eda8641d8dc0b repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.