BWR Rug Pull

Reported loss $47K
Rugpull

What happened

On March 29, 2023, CertiK Alert reported a large liquidity removal on the BWR token (BNB Smart Chain, contract 0x0725A391…6616c2): the deployer removed about $47,000 from the liquidity pool and CertiK said the token appeared to be a honeypot. De.Fi's REKT database lists the incident as an exit scam/rugpull with $47,000 lost and says the deployer sold a large quantity of tokens after removing liquidity, which dropped the price by about 90%.

The verified source shows what the owner could do: the deployer address 0xbd07ab4a…b3c849 receives the full supply, is exempt from fees and limits, and can blacklist addresses, set transfer and sell limits, and set buy and sell tax rates with no upper bound. A sell tax of 100% or more, a tiny _maxTxAmount or a blacklisted holder would stop non-exempt holders from selling, but the opened sources do not show that the owner called any of these functions; what is documented is the liquidity removal.

Deployer: Address 0xbd07…c849

Example liquidity removal transaction listed by De.Fi: 0x8100f4f7…a5afec (could not be opened).

How it happened

  1. The constructor creates a token/USD pair and sends the whole supply to the owner passed in as owner: _balances[owner] = _totalSupply;. That address is also made exempt from fees, wallet limits and transaction limits (isExcludedFromFee[owner] = true;, isTxLimitExempt[owner] = true;). On-chain, the owner is 0xbd07ab4a…b3c849, the deployer.
  2. Buy and sell tax start at 2%, but the owner can change them with no ceiling: function setSelTaxes(uint256 newLiquidityTax, uint256 newMarketingTax, uint256 newTeamTax) external onlyOwner() and setSellDestFee. On a sale to a market pair takeFee computes feeAmount = amount.mul(_totalTaxIfSelling.sub(_sellDestroyFee)).div(100);. The seller's balance is already debited the full amount (_balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");) and the pair receives amount.sub(feeAmount.add(destAmount)). At 100% the pool receives nothing for the sale; above 100% the subtraction reverts and every sale fails. Fee-exempt addresses, including the owner, skip this.
  3. The owner can also stop other addresses from moving tokens. _transfer requires !_isBlacklisted[sender] && !_isBlacklisted[recipient], and multipleBotlistAddress(address[] calldata accounts, bool excluded) public onlyOwner fills the list in bulk. Separately, if(!isTxLimitExempt[sender] && !isTxLimitExempt[recipient]) { require(amount <= _maxTxAmount, ... applies to every sale to the pair, and setMaxTxAmount(uint256 maxTxAmount) external onlyOwner() has no minimum, so setting it very low blocks all non-exempt sales while the exempt owner keeps trading.
  4. The pair's liquidity sits outside the token logic: the contract has no function that locks it, and addLiquidityUSDT sends LP tokens to owner() when the contract adds liquidity from fees. Whoever holds the LP tokens can remove the liquidity.
  5. What happened: CertiK Alert reported on March 29, 2023 that the deployer removed about $47,000 from the LP and that the token appeared to be a honeypot. De.Fi's REKT database lists the incident as a rug pull with $47,000 lost, says the deployer sold a large quantity of tokens, and says the price fell about 90%. The sources opened do not show whether the owner changed the tax, limit or blacklist settings, so those are what the code allows rather than what is documented.
  6. waiveOwnership() would have let the owner give up these powers (_owner = address(0);); the on-chain owner read is still the deployer.

Protocol details

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

Build your security review skills

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