Peace doge X Rug Pull
What happened
Peace doge X is a BNB Smart Chain token whose verified contract keeps several owner-only switches over trading, fees and blacklisting, and gives the deployer the entire supply at creation. PeckShield Alert posted on 2022-03-08 that the token was a scam, citing a 23% selling fee, deployer funds that originated from Tornado Cash, and an owner able to modify the contract, for example to disable selling or change fees. De.Fi's REKT database lists the project as an exit scam with a loss of 18,144 USD: the project ran a presale on PinkSale (Source), the deployer withdrew liquidity in bscscan.com transaction 0x0ccef5b6…3fc140, and the funds were sent to an external address and deposited into the Tornado Cash mixer in 0xef589ed5…f45d8d.
These two transactions and the presale page are as listed by De.Fi.
How it happened
- The constructor passes
msg.sendertoAuthand sets_rBalance[msg.sender] = rSupply;, so the deployer is the owner and starts with the entire supply. Default fees are 2 + 3 + 3 + 2 = 10 out offeeDenominator = 100, andtradingOpen = true. - On a sell (
recipient == pair),takeFeecomputesrAmount.div(feeDenominator * 100).mul(totalFee).mul(multiplier)withmultiplier = sellMultiplier.set_sell_multiplier(uint256 Multiplier) external onlyOwnerhas no limit, and the 33% check insetFees(require(totalFee < feeDenominator / 3, ...)) does not cover it. With the default fees a multiplier of 1000 makesfeeAmountequal to the whole sale, which is credited to the token contract, so the seller receives nothing. Any higher multiplier makesrAmount.sub(feeAmount)revert, so the whole sell transaction fails and the seller's balance is left unchanged. blacklistMode = trueby default, and_transferFromrequires!isBlacklisted[sender] && !isBlacklisted[recipient].manage_blacklist(address[] calldata addresses, bool status)isonlyOwner, so a listed holder cannot sell (the pair is the recipient) or receive tokens, and listing the pair address would stop trading for everyone.setBot/_isBotblocks the same way and is always enforced.tradingStatus(bool _status, uint256 _deadBlocks)isonlyOwner. WhentradingOpenis false,if (!authorizations[sender] && !authorizations[recipient]) { require(tradingOpen, "Trading not open yet"); }makes every transfer between ordinary holders and the pool revert, while authorized addresses (the owner and anyone the owner authorizes) can still move tokens.- For taking value out,
rescueToken(address tokenAddress, uint256 tokens) onlyOwnertransfers any BEP20 held by the contract to the owner andrescueBNBsends the contract's whole BNB balance to a chosen address.swapBackandrebase1000mint liquidity tokens toautoLiquidityReceiver(set to the deployer in the constructor) and toaddress(this)respectively. The code does not show who added the first liquidity or holds those liquidity tokens. - What happened, per PeckShield's alert and De.Fi's listing: the sell fee was 23% (the constructor default is 10%, so a fee or multiplier setting different from the default was in force; the transaction that set it was not opened), and the deployer withdrew the pool liquidity, moved the proceeds to an external address and deposited them into Tornado Cash, for a listed loss of 18,144 USD.
Protocol details
Evidence
- report PeckShield Alert post on Peace doge X (2022-03-08) twitter.com
- transaction bscscan.com transaction 0x0cce…c140 bscscan.com
- transaction bscscan.com transaction 0xef58…5d8d bscscan.com
- address PEACEDOGEX.sol verified source on BscScan bscscan.com
- analysis Sourcify full match for 0x06Fa8DEb5E82D2c05C7cE51f8c82E5E3De3F2a29 repo.sourcify.dev
- analysis www.pinksale.finance page 0x1b32…992f pinksale.finance
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.