Rate limiting and abuse prevention
Designing gas faucets that prevent Sybil attacks. Why native gas payouts must be rate-limited and routed strictly to EOA addresses.

One of the greatest security challenges in Web3 is the Sybil Attack: a single user spawning thousands of automated bots to drain native tokens or spam on-chain smart contracts.
When Socio3 V2 migrated to an ERC-4337 Account Abstraction design, we wanted to make the app 100% free for users. To achieve this, we set up two systems:
- A Verifying Paymaster to sponsor transaction gas fees.
- A POL Gas Faucet to gift new users native gas tokens to fund their tipping wallets.
Within hours of launching the faucet, bots attempted to drain the entire faucet contract. This lesson details the defensive patterns required to protect Web3 gateways from bot abuse.
1. The Faucet Rate Limiting Proxy
You should never allow a frontend client to request gas tokens directly from an on-chain faucet contract. If you do, bots will scan your frontend code, extract the payout trigger, and loop it programmatically.
In Socio3, faucet requests are proxied through a rate-limited Express endpoint (POST /api/faucet).
Here is the implementation:
2. The Smart Contract Revert Trap (EOA Only)
A crucial architectural discovery in Socio3 V2 was that faucets must never send native tokens directly to a deployed Smart Account contract.
Here is why:
- Standard faucet transfers use a plain transaction with a fixed gas limit of 25,000 gas.
- If the recipient is an EOA (Externally Owned Account like MetaMask), the transfer consumes exactly 21,000 gas and succeeds.
- If the recipient is a Smart Account contract, the transfer invokes the contract's
receive()orfallback()function. This delegates execution to the implementation contract, consuming >25,000 gas. The transaction reverts silently due to out-of-gas limits.
The Design Solution:
Always route faucet payouts to the user's EOA signer wallet (privyUserAddress). Once the EOA has funds, display a "Bridge to Smart Account" card in the UI, allowing the user to initiate a contract call to transfer the funds to their Smart Account.
Web3 rate limiting requires off-chain state. A blockchain has no concept of time-based IP rate limits, and checking cooldowns in Solidity costs gas. Always use a hybrid backend (like Firestore or Redis) to rate limit requests before they touch the blockchain.
If a malicious user attempts to bypass your Firestore rate limiter by generating 10,000 new random EOA addresses, how would you protect your faucet? Hint: Think about OAuth verification (like Privy social logins) or Gitcoin Passport scores.
Was this lesson helpful?
Let us know what you think of this specification. (submitting anonymously)
