Vegetables Finance Rug Pull

Reported loss $3K
Ethereum
Rugpull

What happened

Vegetables Finance (VEGE) is an ERC-20 token whose _transfer reverts for every sender except the owner, unless the recipient has been added to an exceptions list or the owner has switched on a global allow flag. A separate governance address can add itself as a minter and mint any amount through mint, which bypasses the transfer gate entirely. Etherscan shows the deployer address 0x74C96b9D…B108D9 added itself as a minter, minted 1 billion VEGE to itself, and about 40 seconds later swapped 1 billion VEGE for 52.5 ETH through Uniswap V2 Router 2, all on 2020-10-05.

De.Fi's REKT database lists the token as an exit scam / rug pull with 2,652 USD lost and also lists the initial-liquidity transaction at 0x35f450fc…fb3e83.

How it happened

  1. At deployment the constructor ERC20(tx.origin) sets _owner and governance = tx.origin to the deploying address, and allow starts as false.
  2. _transfer runs the normal balance update only if if(sender == _owner || allow ). Otherwise it checks if(exceptions[recipient]) and runs revert(); in the final else. A holder who is not the owner can therefore only send tokens to addresses on the exceptions list while allow is false; only the owner can set allow to true through setAllow().
  3. governance can call addMinter(_minter), and any minter can call mint(address account, uint256 amount), which calls _mint directly with no supply cap and without passing through _transfer. Etherscan shows the deployer called addMinter(0x74C96b9DbaDC775dab6805Cd601B1e966cB108D9) on its own address at 12:37:14 UTC on 2020-10-05 (tx 0x2f6fcef6…fedad0).
  4. At 18:20:17 UTC the same address called mint and received 1 billion VEGE (tx 0xd1e7efa2…8d2e87).
  5. At 18:20:56 UTC that address called swapExactTokensForETH on Uniswap V2 Router 2, sending 1 billion VEGE and receiving 52.5 ETH (tx 0x98fed3dd…3bb1b0). Etherscan does not show the internal calls here; per the code, the router's transferFrom pulls the tokens from the owner address, and _transfer takes its first branch because that sender equals _owner (if _owner was never reset with burnOwner()).

Protocol details

Classification Token
Protocol Type Exit Scam/Rugpull
Affected asset / contract VEGE

Build your security review skills

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