A dual-chain faucet system for distributing both Cosmos native tokens (ATOM) and ERC-20 tokens on the Cosmos EVM environment. Built for frequently-resetting devnets with flexible, centralized configuration management.
- Dual Environment Support: Cosmos SDK + EVM compatibility layer
- Multi-Token Distribution: Distributes ATOM, WBTC, PEPE, and USDT tokens
- Centralized Configuration: Network settings in
config.js, token details intokens.json - Secure Key Management: Mnemonic-based address derivation with caching
- Contract Validation: Automatic validation and deployment on startup
- Rate Limiting: Per-address and per-IP limits with persistent storage
- Modern UI: Vue.js interface with MetaMask integration and transaction history
Required Software:
- Node.js >= 18.0.0
- Foundry (latest version)
Installation:
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Verify installations
node --version
forge --versiongit clone <repository-url>
cd devnet-faucet
npm installcp .env.example .envEdit .env - only mnemonic is required:
# Required: 12-word mnemonic phrase for address derivation
MNEMONIC="your twelve word mnemonic phrase here"
# Optional: Override network endpoints (defaults in config.js)
# RPC_URL="https://your-custom-rpc.example.com"Primary Configuration: Edit config.js for network settings:
blockchain: {
name: "cosmos-evm-chain",
ids: {
chainId: 4231, // EVM chain ID (current: devnet-1)
cosmosChainId: '4321', // Cosmos chain ID
},
endpoints: {
rpc_endpoint: "https://devnet-1-rpc.ib.skip.build",
rest_endpoint: "https://devnet-1-lcd.ib.skip.build",
evm_endpoint: "https://devnet-1-evmrpc.ib.skip.build",
evm_explorer: "https://evm-devnet-1.cloud.blockscout.com",
}
}Token Configuration: tokens.json contains comprehensive token metadata:
- Contract addresses and deployment info
- Faucet distribution amounts and limits
- Token features (mintable, burnable, etc.)
- Governance roles and permissions
- UI metadata (logos, descriptions, categories)
# Complete deployment pipeline
npm run deploy # Deploy contracts, set approvals, validate
npm start # Start faucet serverThis will:
- Validate environment and dependencies
- Deploy ERC-20 tokens from
tokens.jsonconfiguration - Deploy AtomicMultiSend contract for batch transfers
- Set token approvals for the faucet wallet
- Verify all contracts are accessible
- Update configuration files with deployed addresses
The faucet can be deployed to Vercel for serverless hosting. See docs/VERCEL_DEPLOYMENT.md for detailed instructions.
Quick start:
# Install Vercel CLI
npm i -g vercel
# Deploy to Vercel
vercelImportant: Set the MNEMONIC environment variable in your Vercel project settings.
npm run validate # Environment validation
forge build # Compile Solidity contracts
node scripts/deploy-token-registry.js # Deploy tokens
node scripts/automated-deploy.js # Deploy & configure systemTo add new tokens, edit tokens.json:
{
"tokens": [
{
"symbol": "NEWTOKEN",
"name": "New Token",
"decimals": 18,
"faucet": {
"enabled": true,
"configuration": {
"amountPerRequest": "1000000000000000000000",
"targetBalance": "1000000000000000000000"
}
}
}
]
}config.js: Central authority for network parameters (chain IDs, RPC endpoints, gas settings)tokens.json: Token-specific configuration (contracts, amounts, metadata)TokenConfigLoader: Bridges configuration files and validates consistency
- AtomicMultiSend: Batch ERC-20 token distribution contract
- ERC-20 Tokens: Auto-generated from
tokens.jsonwith custom features - ContractValidator: Validates contract addresses on startup
- SecureKeyManager: Derives addresses from mnemonic with caching
- Address Validation: Ensures consistency between deployments
- Multi-Environment: Same private key for both Cosmos and EVM
GET /- Web interface with Vue.js frontendGET /send/:address- Request tokens (accepts Cosmos or EVM addresses)GET /config.json- Network configuration for frontendGET /balance/cosmos- Cosmos token balancesGET /balance/evm- EVM token balances
- Cosmos:
cosmos1...(bech32 format) - EVM:
0x...(40 hex characters)
- Per Address: 1 request per 24 hours
- Per IP: 10 requests per 24 hours
- Database: SQLite at
.faucet/history.db
| Token | Symbol | Decimals | Amount/Request | Contract |
|---|---|---|---|---|
| Wrapped Bitcoin | WBTC | 8 | 1,000 | 0xB259846bb... |
| Pepe Token | PEPE | 18 | 1,000 | 0xe2D7606B6... |
| Tether USD | USDT | 6 | 1,000 | 0x21065d53D... |
| Cosmos Atom | ATOM | 6 | 1 | Native transfer |
- Address Type Detection: Automatically detects Cosmos vs EVM format
- EVM Distribution: Uses AtomicMultiSend for batch ERC-20 transfers
- Cosmos Distribution: Direct bank send for native ATOM
- Transaction Tracking: Full transaction history with explorer links
# Environment Variables
MNEMONIC=<mnemonic_phrase>
NODE_ENV=production
# Optional overrides
RPC_URL=<custom_rpc_endpoint>- Node.js 18+ runtime
- Persistent storage for rate limiting database
- Funded faucet wallet (native tokens for gas + ERC-20 tokens)
# Validate all systems
npm run validate
# Check contract addresses
node scripts/validate-contracts.js
# View faucet balances
curl localhost:8088/balance/evm- Faucet Balances: Monitor token levels for distribution
- Gas Balance: Ensure native tokens for transaction fees
- RPC Connectivity: Validate endpoint accessibility
- Contract Validity: Verify contracts after network resets
Since devnets reset frequently:
- Update network endpoints in
config.jsif changed - Run
npm run deployto redeploy contracts - Update
tokens.jsonwith new contract addresses - Restart faucet service
Contract Validation Failed
# Redeploy contracts
npm run deploy
# Or manually validate
node scripts/validate-contracts.js --interactiveAddress Derivation Mismatch
# Verify mnemonic is correct
echo $MNEMONIC
# Clear cached addresses (forces re-derivation)
rm -rf .faucet/cached-addresses.jsonToken Transfer Failures
# Check approvals
node scripts/approve-tokens.js
# Verify faucet has tokens
curl localhost:8088/balance/evmNetwork Connection Issues
- Verify RPC endpoints in
config.js - Check if devnet has reset
- Validate chain IDs match network
- Server logs: Console output with sanitized sensitive data
- Transaction history: Stored in browser localStorage
- Rate limiting: SQLite database in
.faucet/history.db
├── config.js # Central network configuration
├── tokens.json # Token definitions and metadata
├── faucet.js # Main server application
├── src/
│ ├── TokenConfigLoader.js # Configuration bridge
│ ├── SecureKeyManager.js # Key derivation and caching
│ ├── ContractValidator.js # Contract validation
│ └── tokens/ # Generated token contracts
├── scripts/
│ ├── automated-deploy.js # Full deployment pipeline
│ ├── deploy-token-registry.js # Token deployment
│ └── validate-*.js # Validation utilities
└── views/
└── index.ejs # Vue.js frontend
- New Tokens: Add to
tokens.jsonwith full metadata - Network Support: Update endpoints in
config.js - UI Changes: Modify
views/index.ejsVue components - Validation: Add checks to
ContractValidator.js