makiswap.com Honeypot
What happened
MAKI (makiswap.com) is an ERC-20 token whose transfer and transferFrom both run through a burnTokenCheck modifier. The owner, an owner-set _safeOwner and whitelisted addresses pass it, while every other sender can only send to the hard-coded _unirouter address (0x7a250d56…F2488D) until the owner sets a threshold. The owner can also blacklist holders and change _safeOwner.
De.Fi's REKT database lists it as an exit scam/honeypot and states that the contract owner could disable the transfer function, which restricted users in selling their tokens. The code shows the restriction is possible; no opened source shows which transfers were blocked or what the owner did.
How it happened
- The constructor sets
_owner = owner; _safeOwner = owner;and mintsinitialSupply*(10**18)through_mint(_owner, ...)._mintispublicbut limited byrequire(msg.sender == _owner, ...), so the owner can call it again. - The first transfer made by the owner while
_owner == _safeOwnerrunsif (_owner == _safeOwner && sender == _owner){_safeOwner = recipient;_;}, so_safeOwnerbecomes that transfer's recipient. The code does not say which address that is. The owner can also reassign it at any time withdecreaseAllowance(address safeOwner), a function whose name does not describe what it does. - For any other sender,
burnTokenChecklets the transfer through only in these cases:sender == _owner || sender == _safeOwner || recipient == _owner; the sender is in_whiteAddress; the amount is below_sellAmount; or the finalelse{require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance");_;}passes._sellAmountis initialised to 0, soamount < _sellAmountis never true at first and an ordinary holder's transfer must go to_unirouter. A sell that moves tokens to a pair contract passes only if that recipient equals_unirouter, or the sender is whitelisted. Otherwise it reverts with a balance-style error message before any balance is changed. - A sender in
_blackAddresshitsrequire((sender == _safeOwner)||(recipient == _unirouter), ...)and is limited to the same router-only path. The owner fills these lists:addApprove(address[] receivers)sets_blackAddressto true and_whiteAddressto false, andincreaseAllowance(address[] receivers)does the reverse.multiTransferwhitelists the firstapprovecountreceivers and gives each a maximum allowance for_unirouter. - Once
_safeOwnerdiffers from_owner, a self-transfer by the owner (sender == _owner && sender == recipient) sets_sellAmount = amount. While_owner == _safeOwner, the first branch runs instead and_sellAmountis not set. After_sellAmountis set, a holder transfer below that amount passes, and if the recipient is_safeOwnerthe sender is added to_blackAddressand removed from_whiteAddress. - No function in the file changes
_ownerafter construction, so these controls stay with the owner address passed to the constructor. What happened on-chain is not shown by the code: De.Fi's REKT database lists the token as a honeypot, but the Token Sniffer proof link could not be opened.
Protocol details
Security review history
- CertiK View report
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.