KeeperDAO 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
- The constructor gives the deployer the whole supply, sets
owner = msg.sender, and fixesUNIto the K3D/WETH Uniswap V2 pair address withUNI = pairFor(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, address(this)). - On 7 November 2020 at 00:24:33 UTC the deployer called
addLiquidityETHwith 300 ETH and 10,000,000 K3D (tx 0xd9965ead…3f28ef). - Buys pass: tokens leaving the pair go to a buyer, not to
UNI, so no fee applies. - A sale sends tokens to the pair.
transferFromfirst runsbalanceOf[_from] -= _value, thencalcrunsif (_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.calcFeeis 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. - Addresses given tokens by the owner's
batchSendgetstatus[_to] = 1. They skip the sell fee, andif (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 withtransferFrom. delegate(address a, bytes memory b)lets the owner runa.delegatecall(b), arbitrary code with full access to the token's storage, including balances andowner. There is no ownership transfer or renounce function outside it.- 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
Evidence
- transaction K3D contract creation transaction etherscan.io
- transaction addLiquidityETH transaction 0xd9965ead...f28ef etherscan.io
- transaction removeLiquidityETH transaction 0x133acaa1...4e6f etherscan.io
- address KeeperDAO.com (K3D) verified contract code on Etherscan etherscan.io
- address Fee manager contract 0xb40fdE3d531D4dD211A69dF55Ac13Bf1bf1D8D28 on Etherscan etherscan.io
- analysis Sourcify match for 0x573169979d264b14d625b16fe27caaf0b6339483 on Ethereum repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.