DDCX Rug Pull
What happened
DDCX is a BEP20 token (contract 0x2a895afa…5c9fbc) trading on PancakeSwap, and it should not be confused with other tokens that share the symbol. The verified code routes every transfer through an external Rule contract whose address the owner can set with setRule; that contract decides how many tokens the recipient is credited and can overwrite any balance or the total supply, and it can also emit fake Transfer events. CertiK's alert of 2022-10-18 reported an exit scam with a drop of more than 94% and roughly $193K taken; De.Fi's REKT database lists 148,019 USD and a price drop of more than 92%.
The live listing says the owner of the vault contract moved roughly 10,000 DDCX to an EOA address that drained the liquidity, naming the addresses 0x5e6b6888…dc785f and 0xe6f5f416…8c6b30 and the token-move transactions 0xb7ea8ca1…241ecb and 0xa2100e04…31abd3. The rule contract's code is not in the evidence, so the source shows what the hook allows, not what it did.
How it happened
- The constructor credits the entire 10,000,000 supply to the deployer:
_balances[msg.sender] = _totalSupply;. There is no mint function afterwards. - The owner can attach an arbitrary contract to every transfer:
function setRule(address a) external onlyOwner{ _ruleAddr = a; }. The token never checks what that contract is. - Each transfer asks the rule contract how much the recipient gets, but debits the sender in full:
sy = Rule(_ruleAddr).check(sender,recipient,amount);then_balances[sender] = _balances[sender].sub(amount, ...);and_balances[recipient] = _balances[recipient].add(sy);. Ifcheckreturns less thanamountthe difference simply disappears from the sender; if it reverts, the transfer fails, so the rule can block sells or any other route. TheTransferevent is emitted withsy. - The rule contract also has direct write access to balances and supply:
setBalance(address a,uint256 am)sets_balances[a] = am;andsetSupply(uint256 a)sets_totalSupply = a;, both guarded only byrequire( msg.sender==_ruleAddr);.setTransferEventlets it emit aTransferevent with any values, which explorers and wallets display as a real move. - Renouncing ownership does not remove these powers:
setInviter,excludeandincludeaccept either the owner or the rule address, andrenounceOwnershiponly removes the owner'ssetRuleright. A rule contract installed before renouncing keeps all of the above powers. The contract currently reports the zero address as owner, but the opened evidence does not show when that happened or whether a rule contract was ever set. - What was reported: CertiK recorded an exit scam with a drop above 94% and about $193K taken, and De.Fi's listing says the owner of the vault contract moved about 10,000 DDCX to an EOA that drained the liquidity. The two token-move transactions were not opened, so the use of
setRule,setBalanceor any rule contract is not shown.
Protocol details
Evidence
- report CertiK Alert tweet on DDCX exit scam (2022-10-18) twitter.com
- transaction bscscan.com transaction 0xa210…abd3 bscscan.com
- transaction bscscan.com transaction 0xb7ea…1ecb bscscan.com
- address DDCX (0x2a895afa...) verified source on BscScan bscscan.com
- address bscscan.com address 0x5e6b…785f bscscan.com
- address bscscan.com address 0xe6f5…6b30 bscscan.com
- analysis Sourcify match for DDCX on BNB Chain repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.