Jigsaw saw you Rug Pull
What happened
SAW (Jigsaw saw you) is an Ethereum ERC-20 whose Ownable contract is renounced from the constructor, so it looks ownerless, but a second privileged role is kept in _play[0].red, set from the constructor argument mankind_. Through a function named Approve (capital A, separate from the standard approve), that address can write a per-account value into the _death mapping, and _transfer reverts for any sender whose value is at least the amount being sent. De.Fi's alert reports that on Aug 15, 2023 the deployer 0x5707b5D0…E925ab removed about 88 ETH (about 160k USD) from the liquidity pool. De.Fi's listing summary mentions about 216.3k USD, a figure that differs from the 160k USD in its own details.
Scammer address (as given in the listing): 0x5707b5d0…e925ab
Liquidity Removal tx: 0x4ef259f1…dff6cc
How it happened
What the code allows:
- The constructor calls
_setOwner(address(0)), soowner()is the zero address from deployment and there are noonlyOwnerpowers. The real control is a different role:_play.push(Mask(mankind_, 2));stores themankind_constructor argument as_play[0].red. Whether that address is the deployer is not shown in the source. Approve(address account, uint256 amount)is a custom function next to the standardapprove. It calls_live(from, account, amount), and in_live:if (from == _play[0].red) { ... total += amount; _death[account].punish = total; }. When the caller is theredaddress, this setspunishfor anyaccountto any amount. For every other caller the branch adds zero, so it does nothing. It also emitsApproval(from, address(this), amount), which looks like an ordinary approval event._transferapplies that value to the sender:require(amount - alien(sender) > 0, "alien");. With checked arithmetic,amount - punishreverts whenpunishis larger thanamount, and the> 0check fails when they are equal. So a sender whosepunishis at least the amount cannot move tokens.transferandtransferFromboth go through_transfer, and the check is onsender, so a holder with a high value cannot sell, and a value set on the liquidity pair address would block transfers out of the pool, which are buys.- The
redaddress can overwrite the value again with a newApprovecall, so the block can be lifted or re-applied per address.
, per De.Fi's alert and listing:
- The deployer 0x5707b5D0…E925ab removed about 88 ETH (about 160k USD) from the pool in transaction 0x4ef259f1…dff6cc and, per the listing, spread the funds across four wallets.
- The alert also states that the deployer wallet was initially funded through Tornado Cash and has a history of earlier rug pulls.
- No opened source shows a transaction in which the
redaddress calledApproveto block any holder or the pool, so whether the_deathblock was used is not established.
Protocol details
Evidence
- report @DeDotFiSecurity incident report twitter.com
- report Saw (SAW) verified source (Sourcify) repo.sourcify.dev
- report De.Fi Antivirus rug pull alert for SAW twitter.com
- transaction etherscan.io transaction 0x4ef2…f6cc etherscan.io
- address Saw (SAW) verified source (Etherscan) etherscan.io
- address etherscan.io address 0x5707…25ab etherscan.io
Build your security review skills
Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.