A powerful, production-ready tool for distributing tokens (NFTs, Fungible Tokens, and HBAR) on the Hedera network with parallel processing, automatic retry, and resume capability.
- 🚀 Parallel Processing - Send up to 50 transactions concurrently for fast airdrops
- 🔄 Auto-Retry & Resume - Automatic retry on failures with checkpoint system for resuming interrupted runs
- 📊 Progress Tracking - Real-time progress bar shows airdrop status
- 💎 Multi-Token Support - Handle NFTs, Fungible Tokens, and HBAR in one airdrop
- ✅ Pre-Flight Validation - Validates balances, associations, and serials before sending
- 📝 Dual Output - Human-readable CSV + machine-readable JSON output
- 🌐 Network Flexibility - Supports mainnet, testnet, previewnet, and custom networks
- 🔐 Allowance Support - Can spend from approved allowances
- Installation
- Quick Start
- Configuration
- CSV File Format
- Usage Examples
- Command Line Options
- Output Files
- Advanced Features
- Troubleshooting
- Node.js 16+ installed
- A Hedera account with tokens/NFTs/HBAR to distribute
- Private key for the sender account
-
Clone or download this repository
-
Install dependencies
npm install
-
Configure your environment
Copy the example environment file:
cp .env.example .env
Edit
.envwith your details (see Configuration) -
Create your airdrop file
Use
example-airdrop.csvas a template or create your own -
Run a test
node tokenAirdrop.js your-airdrop.csv -test
Edit your .env file with the following settings:
# Network: mainnet, testnet, previewnet, or custom
NETWORK=mainnet
# Only needed if NETWORK=custom
CUSTOM_MIRROR_URL=# Your Hedera account ID
MY_ACCOUNT_ID=0.0.123456
# Your private key (keep this secret!)
MY_PRIVATE_KEY=302e020100300506032b657004220420...# Maximum tokens any single wallet can receive (optional)
# Leave empty for no limit
MAX_TRANSFER=
# Maximum concurrent transactions (default: 50)
# Adjust if you hit rate limits
MAX_CONCURRENT_TXS=50# Memo for all transactions
MEMO=Airdrop
# Wallets to exclude from airdrop (comma-separated)
EXCLUDE_WALLETS=0.0.111,0.0.222
# NFT serials to never send (comma-separated OR range)
# Examples: 1,2,3,4,5 OR 1-100
EXCLUDE_SERIALS=Your airdrop file should be a CSV with the following format:
# Lines starting with # are comments and will be ignored
# Format: destWallet,tokenToSend,quantity,serial(s)
# Send NFTs with specific serials
0.0.1234567,0.0.9876543,5,100,101,102,103,104
# Send random NFTs (use 0 for serial)
0.0.2345678,0.0.9876543,1,0
# Send fungible tokens (no serial needed)
0.0.3456789,0.0.8765432,100
# Send HBAR (use 'hbar' as token ID)
0.0.4567890,hbar,2.5| Field | Description | Required | Example |
|---|---|---|---|
| destWallet | Recipient Hedera account ID | Yes | 0.0.1234567 |
| tokenToSend | Token ID or hbar for HBAR |
Yes | 0.0.9876543 or hbar |
| quantity | Amount to send | Yes | 10 or 2.5 |
| serial(s) | NFT serial number(s) or 0 for random |
For NFTs | 123 or 0 |
- ✅ Comments: Lines starting with
#are ignored - ✅ Empty lines: Blank lines are ignored
- ✅ NFT Serials:
- Provide specific serials:
100,101,102(must match quantity) - Use
0to randomly select from your owned NFTs
- Provide specific serials:
- ✅ Fungible Tokens: Omit serial field or use
0 - ✅ HBAR: Use
hbaras the token ID (case insensitive) - ✅ Decimals: Automatically handled based on token configuration
⚠️ Association Required: Recipients must have associated the token first
Send tokens to recipients:
node tokenAirdrop.js my-airdrop.csvValidate your airdrop file without sending anything:
node tokenAirdrop.js my-airdrop.csv -testIf your airdrop was interrupted or had failures, resume from checkpoint:
node tokenAirdrop.js my-airdrop.csv -resumeSend tokens from an approved allowance:
node tokenAirdrop.js my-airdrop.csv -approval 0.0.999999Enable detailed logging for debugging:
node tokenAirdrop.js my-airdrop.csv -vThe old -process flag still works:
node tokenAirdrop.js -process my-airdrop.csv| Option | Description | Example |
|---|---|---|
<file> |
Required. CSV file with airdrop data | my-airdrop.csv |
-test |
Validate without sending transactions | -test |
-validate |
Alias for -test |
-validate |
-resume |
Resume from checkpoint (for failed runs) | -resume |
-approval <id> |
Use allowance from specified account | -approval 0.0.123456 |
-v |
Enable verbose logging | -v |
-h or -help |
Show help message | -h |
After running an airdrop, you'll get two output files:
Filename: output_<inputfile>_<timestamp>.csv
# Airdrop Results - 2025-11-22T10:30:45.123Z
# Status,Destination,Token,Quantity,Serials,Message,TransactionID
SUCCESS,0.0.1234567,0.0.9876543,5,100,101,102,103,104,Completed,0.0.123456@1732272645.123456789
FAILED,0.0.2345678,0.0.8765432,10,0,Error: INSUFFICIENT_TOKEN_BALANCE,
SKIPPED,0.0.3456789,0.0.7654321,1,0,NOT ASSOCIATED: **SKIPPED**,Filename: output_<inputfile>_<timestamp>.json
{
"timestamp": "2025-11-22T10:30:45.123Z",
"summary": {
"total": 100,
"completed": 95,
"failed": 2,
"skipped": 3
},
"transactions": {
"completed": [ /* array of completed transactions */ ],
"failed": [ /* array of failed transactions */ ],
"skipped": [ /* array of skipped transactions */ ]
}
}- SUCCESS: Transaction completed successfully
- FAILED: Transaction was attempted but failed (includes error message)
- SKIPPED: Transaction was not attempted due to validation failure
The script automatically creates checkpoint files (.checkpoint_*) during processing. These allow you to resume if:
- The script crashes
- Network issues occur
- Transactions fail
To resume: Simply run with -resume flag
node tokenAirdrop.js -process my-airdrop.csv -resumeThe checkpoint stores:
- ✅ All completed transactions
- ⏸️ All pending transactions
- 🔄 Retry counts
Failed transactions are automatically retried once with:
- 1-second delay between attempts
- Exponential backoff for network calls
- Detailed error messages for debugging
Transactions are sent in parallel batches (default: 50 concurrent) to maximize throughput while respecting network limits.
Adjust concurrency in .env:
MAX_CONCURRENT_TXS=50When you specify serial 0 for NFTs, the script will:
- Fetch all NFTs you own for that token
- Exclude any serials in
EXCLUDE_SERIALS - Randomly shuffle remaining serials
- Allocate them to recipients
This ensures fair distribution and prevents duplicate sends.
Before processing, the script:
- Checks if recipients have associated the token
- Skips transfers to non-associated wallets
- Provides clear feedback on which transfers were skipped
Problem: INVALID_ACCOUNT_ID error
- Solution: Check that wallet addresses in CSV start with
0.0.and are valid
Problem: INSUFFICIENT_TOKEN_BALANCE error
- Solution: Verify you own enough tokens/NFTs to complete the airdrop
Problem: Token not associated errors
- Solution: Recipients must associate tokens before receiving them
Problem: Rate limit errors
- Solution: Reduce
MAX_CONCURRENT_TXSin.env(try 25 or 10)
Problem: Script crashes mid-airdrop
- Solution: Run with
-resumeto continue from checkpoint
For detailed debugging information:
node tokenAirdrop.js -process my-airdrop.csv -vThis shows:
- Mirror node API calls
- Token balance queries
- Serial allocation details
- Detailed error stack traces
- Check the CSV file format matches examples
- Verify
.envconfiguration is correct - Run in
-testmode first to validate - Enable
-vfor verbose logging - Check the output JSON for detailed error messages
- Group similar tokens in your CSV for efficiency
- Use appropriate concurrency - default (50) works well for most cases
- Test first with
-testto catch issues early - Monitor progress - the progress bar shows real-time status
- Resume on failure - don't restart from scratch, use
-resume
⚠️ Never commit.envfile - it contains your private key⚠️ Keep private keys secure - treat them like passwords⚠️ Test on testnet first - useNETWORK=testnetfor testing⚠️ Review CSV carefully - double-check recipients and amounts
ISC License - see package.json for details
Stowerling
Version: 1.0.0
Last Updated: November 2025
For issues or questions, please review the troubleshooting section or check your CSV format and .env configuration.