Aphrodite Protocol Rug Pull

Reported loss $97K
Ethereum
Rugpull

What happened

Aphrodite Protocol (APHR) is an Ethereum reflection token with a fixed starting supply of 69,000 tokens, deployed on 2020-12-27. The deployer 0x0217f935…d2eEdc received the entire supply, and trading was locked for everyone else until the owner called enableTrading. De.Fi's REKT database lists the project as an exit scam with 97,147 USD lost and describes the sequence: the project announced a fundraising event on Telegram (archived at Source), funds were sent directly to the deployer address (transfers listed at Source), the deployer added initial liquidity in transaction 0xf0cc8a57…077bdb and later removed it in transaction 0x93245437…6d2f8d. On 2020-12-29 the Rug Detectives account flagged APHR as a scam project.

The verified code contains no function that withdraws ETH from the pool. What it does give the deployer is full initial supply, a trading lock it alone can lift, fee exemptions it controls, and uncapped fee setters; a liquidity removal needs the LP tokens, and the sources opened here do not show who held them.

How it happened

What the code allows (the sources do not show which owner functions were called):

  1. The constructor assigns the whole supply to the deployer: _reflectionBalance[_msgSender()] = _reflectionTotal; with _tokenTotal = 69_000e18, and marks the deployer and the token contract fee-exempt (isExcludedFromFee[_msgSender()] = true;).
  2. Before tradingEnabled is set, only the owner and fee-exempt addresses can trade: require(tradingEnabled || sender == owner() || recipient == owner() || isExcludedFromFee[sender] || isExcludedFromFee[recipient], "Trading is locked before presale.");. enableTrading() is onlyOwner and one-way; there is no function that locks trading again.
  3. Fees are owner-adjustable with no upper bound: setTaxFee(uint256 fee) and setLiquidityFee(uint256 fee) assign the value directly, and collectFee computes amount.mul(_taxFee).div(10**(_feeDecimal + 2)) with _feeDecimal = 1, so the defaults of 5 and 5 are 0.5% each. In _transfer the sender is debited amount.mul(rate) while the recipient is credited transferAmount.mul(rate), so the fee comes out of what the buyer or the pool receives; a combined value near 1000 would leave transfers with almost nothing, and a combined value above 1000 would make transferAmount.sub(...) revert.
  4. setExcludedFromFee lets the owner exempt chosen addresses from those fees, and excludeAccount / includeAccount change which addresses are reflection-excluded.
  5. Collected fee tokens sit in the contract and are swapped to ETH with 0 minimum output; the ETH stays in the contract and is used to buy and burn tokens, with _rebalanceCallerFee = 500 (50% of the bought tokens) paid to tx.origin of the transaction that triggers it. No function sends the contract's ETH to the owner.
  6. renounceOwnership exists in Ownable; the current on-chain owner() read still returns the deployer address.

What was reported:

  1. De.Fi lists the sequence as a Telegram fundraising announcement, deposits sent directly to the deployer address, initial liquidity added by the deployer in transaction 0xf0cc8a57…077bdb and removed by the deployer in transaction 0x93245437…6d2f8d, with 97,147 USD lost. Rug Detectives flagged the project as a scam on 2020-12-29.

Protocol details

Classification Other
Protocol Type Exit Scam/Rugpull
Affected asset / contract APHR
Protocol links Website @AphroditeDefi

Build your security review skills

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