Every blockchain testnet needs a faucet - a way for developers to get test tokens. Every faucet eventually gets abused. Here's how we built one that stays running.
The Faucet Problem
Testnets need tokens for:
- Deploying contracts
- Testing transactions
- Running integration tests
- Development workflows
But faucets attract abuse:
- Drainers: Scripts that empty the faucet
- Hoarders: Requesting far more than needed
- Bots: Automated requests at scale
- Resellers: Selling "rare" testnet tokens
Anti-Abuse Layers
Our faucet has multiple defense layers:
Layer 1: Rate Limiting
// Per-IP rate limiting
limiter := ratelimit.New(
ratelimit.PerIP(1, time.Hour), // 1 request per hour per IP
ratelimit.PerWallet(1, time.Hour), // 1 request per hour per wallet
ratelimit.Global(100, time.Hour), // 100 total per hour
)Basic, but catches casual abuse.
Layer 2: Proof of Humanity
Before requesting tokens, users must prove they're human:
- CAPTCHA: Traditional image challenges
- PoW: Compute a proof-of-work (hashcash style)
- Social: Verify via GitHub/Twitter account
- Farcaster/Lens: Web3 social verification
const proof = await faucet.proveHumanity({
method: "github",
minAge: 30, // Account must be 30+ days old
minRepos: 1 // Must have at least 1 repo
});Layer 3: Smart Rationing
Not everyone gets the same amount:
| Developer Type | Amount | Frequency |
|---|---|---|
| New address | 0.1 LUX | Daily |
| Verified GitHub | 1 LUX | Daily |
| Active developer | 10 LUX | Daily |
| Ecosystem project | 100 LUX | Weekly |
Activity determines allocation.
Layer 4: Behavioral Analysis
Machine learning flags suspicious patterns:
- Address clustering: Same entity, multiple wallets
- Request timing: Bot-like regularity
- Usage patterns: Tokens transferred immediately
- Network analysis: Connected to known drainers
risk_score = analyzer.score(request)
if risk_score > 0.7:
require_additional_verification()
elif risk_score > 0.9:
block_request()Layer 5: Economic Friction
Make abuse unprofitable:
- Drip distribution: 10% now, 90% over 24 hours
- Activity bonding: Tokens locked until used
- Reputation stake: Abuse loses future access
Architecture
Request → Rate Limit → PoH Challenge → Risk Score → Allocation → Drip
↓ ↓ ↓ ↓ ↓ ↓
Block Challenge Verify Score Approve Distribute
↓
RecordEvery request is logged for pattern analysis.
Results
Since launch:
- 100K+ developers served
- Zero complete drains
- 99.9% uptime
- <5s average request time
Compared to other testnets where faucets are regularly emptied.
Open Source
The faucet is open source. Use it for your testnet:
git clone https://github.com/luxfi/faucet
cd faucet
cp .env.example .env
# Configure your chain
docker compose upLessons Learned
- Defense in depth: No single layer is enough
- Assume abuse: Design for attackers from day one
- Reward good actors: Make legitimate use easy
- Monitor constantly: Patterns emerge over time
- Iterate quickly: Attackers adapt, so must you
The best faucet is one nobody notices - it just works for developers while silently blocking abuse.
This post is part of our retrospective series exploring the technical foundations of Hanzo and Lux.
Read more
Netrunner: Testing Blockchains at Scale
How we built Netrunner to simulate blockchain networks and catch bugs before they hit production.
The Full Arc: Commerce, Blockchain, AI, and Why It's All the Same Problem
Looking back from 2026: the through-line from a commerce platform in 2008 to frontier AI models today is a single consistent thesis about infrastructure, openness, and who gets to build.
ACI: The AI Compute Infrastructure Network
Introducing ACI, a decentralized network for AI compute that enables trustless, verifiable AI inference.