DipBitcoin Honeypot

Reported loss Not disclosed
BNB Chain
Honeypot

What happened

DipBitcoin is a BEP-20 token on BNB Smart Chain, deployed from 0x514142F2…4B62c8 in transaction 0x5fee0476…11124c on 2021-05-19. De.Fi's REKT database lists it as an Exit Scam/Honeypot, saying the contract owner could disable the transfer function and so restrict users from selling. The verified source overrides transferFrom, the call a router uses to pull tokens from a seller, so that it requires the flag trans, the deployer, or the pool pair as sender; trans starts as false and only a holder of MINTER_ROLE can change it.

The functions named renounceOwnership and lockLiquidity only emit events and change nothing. The source does not show whether trans was ever switched or whether any sale failed.

How it happened

  1. The constructor creates the pool pair, stores the deployer as the private immutable moi, sets trans = false, grants the deployer the admin, pauser and minter roles, and mints the supply to the deployer: _mint(msg.sender, 1000000000000 * 10 ** decimals());.
  2. transferFrom is overridden with a gate: require (trans || moi == sender || moi == recipient || sender == UNI);, where UNI is uniswapV2Pair. While trans is false, a holder who is not the deployer can pass it only when the recipient is the deployer; a call with the holder as sender and the pair as recipient reverts.
  3. A sale through a router pulls the holder's tokens into the pair with transferFrom, so it hits this require and reverts with no message. The revert happens before _transfer, so the holder's balance is not debited. Plain transfer is not overridden, so direct wallet-to-wallet transfers are not gated by this check.
  4. Liquidity removal is not affected for the deployer, who is moi; any transferFrom where the deployer is sender or recipient passes.
  5. setTrans(bool value) requires hasRole(MINTER_ROLE, msg.sender), so the minter can open or close the gate at any time. Whether it was opened is not shown by the source.
  6. Further powers: pause() and unpause() need PAUSER_ROLE, and while paused _beforeTokenTransfer is whenNotPaused, so every transfer reverts. piocher(address to, uint256 amount) mints new tokens for any MINTER_ROLE holder, and the deployer holds DEFAULT_ADMIN_ROLE, which can grant roles.
  7. renounceOwnership() is function renounceOwnership() public { emit OwnershipRenounced(address(0), address(this)); } and lockLiquidity() is emit liquidityLocked(uniswapV2Pair, address(0));. Both are callable by anyone, change no state and move no liquidity, so the events they emit do not show that ownership or liquidity changed.

Protocol details

Classification Token
Protocol Type Exit Scam/Honeypot
Affected asset / contract DipBitcoin

Build your security review skills

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