Ramifi.org Honeypot
What happened
RAM is an ERC-20 token on Ethereum whose transfer and transferFrom both pass through a burnTokenCheck modifier controlled by a single _owner. While _sellAmount keeps its initial value of 0, an ordinary holder can only send tokens to the address stored in _unirouter or to the owner, so a sale to any other address (such as a liquidity pair) reverts with "ERC20: transfer amount exceeds balance". The owner can whitelist or blacklist addresses, change the privileged _safeOwner address, set _sellAmount, and call a public _mint that credits new tokens to the owner.
De.Fi's REKT database lists the token as an exit scam/honeypot and says the owner could disable the transfer function, which restricted users from selling. The code shows how selling can be blocked; no transaction was opened that shows which of these switches the owner actually used.
How it happened
- The constructor sets
_owner = owner;and_safeOwner = owner;, then mints the initial supply to the owner with_mint(_owner, initialSupply*(10**18));. - Every holder
transferandtransferFromruns_approveCheck, which is wrapped inburnTokenCheck(sender,recipient,amount). - The modifier lets these through: the owner (and, while
_safeOwnerstill equals the owner, the owner's first outgoing transfer also sets_safeOwner = recipient), the current_safeOwner, any transfer whose recipient is_owner, and senders in_whiteAddress. - Every other sender hits
require((sender == _safeOwner)||(recipient == _unirouter), "ERC20: transfer amount exceeds balance")wheneveramount < _sellAmountis false._sellAmountstarts at 0, so that comparison is never true at first, and a non-privileged sender can only send to_unirouter(or to the owner). A sale to a pair address reverts. - The owner can change who is exempt:
increaseAllowance(address[])whitelists,addApprove(address[])blacklists,decreaseAllowance(address safeOwner)replaces_safeOwner, andmultiTransferwhitelists the firstapprovecountreceivers. A transfer from the owner to itself sets_sellAmount = amount. Once it is set, a non-listed sender sending less than that amount passes, and if the recipient is_safeOwnerthe sender is added to_blackAddress; blacklisted senders can then only send to_unirouteror the owner. _mintispublicand checksrequire(msg.sender == _owner, ...), then runs_balances[_owner] = _balances[_owner].add(amount);, so the owner can create more tokens for itself at any time. The file has notransferOwnershiporrenounceOwnership, so_ownernever changes.
Protocol details
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.