KeeperDAO Honeypot

Reported loss $170K
Ethereum
Honeypot

What happened

KeeperDAO.com (K3D) is an Ethereum token that used the KeeperDAO name, deployed on 7 November 2020 at 0x57316997…339483 by 0x9daa3a64…908C95. Every transfer into its Uniswap V2 pair from a wallet other than the owner or a flagged address asks an external, unverified contract at 0xb40fdE3d…1D8D28 for a fee, so that contract decides whether a sale gets through, how much of it arrives, or whether it reverts. The owner can also run arbitrary code inside the token through delegate, and wallets flagged by batchSend skip the fee and, when they start a transaction, can move any holder's tokens without an allowance.

The deployer added 300 ETH and 10,000,000 K3D of liquidity at 00:24 UTC, and at 16:11 UTC the same address removed it, taking out 691.2 WETH and 4,354,390.7 K3D. De.Fi's REKT database lists K3D as an exit scam/honeypot.

How it happened

  1. The constructor gives the deployer the whole supply, sets owner = msg.sender, and fixes UNI to the K3D/WETH Uniswap V2 pair address with UNI = pairFor(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, address(this)).
  2. On 7 November 2020 at 00:24:33 UTC the deployer called addLiquidityETH with 300 ETH and 10,000,000 K3D (tx 0xd9965ead…3f28ef).
  3. Buys pass: tokens leaving the pair go to a buyer, not to UNI, so no fee applies.
  4. A sale sends tokens to the pair. transferFrom first runs balanceOf[_from] -= _value, then calc runs if (_to == UNI && _from != owner && status[_from] == 0) { fee = Management(manager).calcFee(address(this), UNI, _value); } and credits the pair only _value - fee. The fee is not credited to anyone. calcFee is a state-changing call to an unverified contract, so it can return any fee or revert; if the pair receives less than the swap expects, the Uniswap swap fails. The seller's balance is debited in full either way within a successful call.
  5. Addresses given tokens by the owner's batchSend get status[_to] = 1. They skip the sell fee, and if (msg.sender != _from && status[tx.origin] == 0) skips the allowance check whenever such a wallet starts the transaction, so it can move any holder's K3D with transferFrom.
  6. delegate(address a, bytes memory b) lets the owner run a.delegatecall(b), arbitrary code with full access to the token's storage, including balances and owner. There is no ownership transfer or renounce function outside it.
  7. At 16:11:18 UTC the deployer called removeLiquidityETH, burning 54,772.2558 LP tokens (the amount minted at deposit) and withdrawing 691.2044 WETH and 4,354,390.7041 K3D (tx 0x133acaa1…e34e6f).

Protocol details

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

Build your security review skills

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