Private Token Offering Honeypot
What happened
De.Fi's REKT database lists Private Token Offering (PTO) as an exit scam/honeypot on BNB Smart Chain, saying the owner could disable transfers so holders could not sell. The verified source implements a hidden address variable, newun: the first transferFrom call records its recipient in newun, and from then on every transfer or transferFrom to that address reverts with "please wait". If the recorded address is a liquidity pool, sells into it are blocked while buys out of it are not.
The owner can also overwrite newun through transfernewun.
How it happened
- The constructor mints the whole supply to the deployer:
balances[owner] = _totalSupply;with_totalSupply = 16000000000000000;at 8 decimals, which is 160,000,000 tokens. The file contains no mint function. - A public variable
newunstarts as the zero address.transferrejects any recipient equal to it:require(to != newun, "please wait");. transferFromcontains the capture step:if(from != address(0) && newun == address(0)) newun = to; else require(to != newun, "please wait");. The firsttransferFromwith a non-zerofromsucceeds and stores itstoinnewun; the caller does not have to be the owner. A DEX router adding liquidity moves tokens withtransferFrom, so if that is the first such call, the pool address is the one stored. The code alone does not show which call came first on-chain.- After that, any
transferortransferFromwhose recipient is the stored address reverts. A sale through a pool sends tokens to the pool, so a stored pool address blocks sells, while transfers out of the pool to buyers do not hit the check. - The owner can change the stored address at any time:
function transfernewun(address _newun) public onlyOwner { newun = _newun; }. Setting it to the zero address re-arms the capture on the nexttransferFrom; setting it to an unused address lifts the block. - The owner can also withdraw any native-currency balance held by the token contract through
clearCNDAO(). - A write-up of this code pattern on BSC tokens describes the same sequence: the initial liquidity add sets the hidden variable to the pool address, later transfers to it are stopped, and liquidity is withdrawn at the inflated price. The write-up names other tokens, not this one.
Protocol details
Evidence
- report @Token_Sniffer incident report twitter.com
- address BscScan verified source, Private Token Offering 0xdd5221508ba8ae8f8ccf3c7552e1e143f7ce9b29 bscscan.com
- analysis Scam explained: BSC stealthy LP block (cryptot3ddybear) cryptot3ddybear.gitlab.io
- analysis Sourcify repository copy of PrivateTokenOffering.sol repo.sourcify.dev
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.