Mint-and-Airdrop Framework
A flexible, production-ready Solana program for creating SPL tokens and managing airdrop campaigns with multiple allocation modes and fee structures.
Overview
The Mint-and-Airdrop Framework provides a comprehensive solution for token creation and distribution on Solana. It supports multiple campaign management strategies, flexible fee structures, and various allocation methods (on-chain accounts, off-chain signatures, and merkle proofs).
Key Features
✅ Flexible Token Minting
- Create SPL tokens with Metaplex metadata support
- Custom mint addresses via PDA derivation with noise
- Automatic mint authority revocation for immutable supply caps
- Mint-specific treasury for token storage
✅ Multiple Allocation Modes
- On-chain Allocation: Creates allocation accounts for each recipient (via
Allocateinstruction) - Off-chain Record: Claims against off-chain database records (via
ClaimMethod 1, noAllocateneeded) - Merkle Mode: Efficient merkle tree-based claims for large campaigns (via
ClaimMethod 2, noAllocateneeded)
✅ Flexible Fee Structure
- Configurable fees per operation type
- Fair pricing based on actual costs
- Transparent fee tracking and withdrawal
✅ Multiple Distribution Methods
- On-chain allocation claims
- Off-chain signature-based claims
- Merkle proof-based claims
- Direct batch transfers (campaign owner)
✅ Security & Best Practices
- PDA-based treasury (no admin co-signing required)
- Program-controlled fee account
- Admin authority management
- Comprehensive account validation
Architecture
Core Components
Program Config (Singleton PDA)
├── Program Admin Authority
├── Fee Configuration
│ ├── Mint Fee (lamports)
│ ├── Allocation Fee Per Recipient (lamports)
│ ├── Merkle Fee Per Recipient (lamports)
│ └── Direct Transfer Fee Per Recipient (lamports)
├── Fee Account (PDA)
└── Initialization Status
Campaign Account (Per Campaign PDA)
├── Campaign Owner
├── Mint Address
├── Treasury Token Account
├── Merkle Root (optional)
└── Campaign Status
Allocation Account (Mode 0 Only)
├── Recipient
├── Amount
└── Claim Status
Instructions
1. Initialize
Initialize the program with admin and fee configuration.
Accounts:
- Initializer (signer)
- Config PDA
- Fee Account PDA
- System Program
- Rent Sysvar
2. CreateMint
Create a new SPL token mint with metadata. All tokens up to max_supply are minted upfront to the mint treasury, and mint authority is revoked.
Fee: mint_fee_lamports (recommended: 0.1 SOL)
3. CreateCampaign
Create a new campaign using an existing mint. Multiple campaigns can share the same mint.
Fee: merkle_fee_per_recipient_lamports × recipient_count (if merkle_root set)
4. Allocate
Allocate tokens to recipients by creating on-chain allocation accounts.
Mode: On-chain only (creates Allocation accounts for each recipient)
- Fee:
allocation_fee_per_recipient_lamports × count
Note: Off-chain allocations are handled via Claim Method 1 (record mode) without a prior Allocate call. Merkle-based claims use Claim Method 2 (merkle mode) without Allocate.
5. Claim
Claim allocated tokens. Supports three methods:
- Method 0 (allocation): Claim against on-chain Allocation account (requires prior
Allocatecall) - Method 1 (record): Claim against off-chain database record (with signature, no
Allocateneeded) - Method 2 (merkle): Claim against merkle proof (requires merkle root in campaign, no
Allocateneeded)
Fee: None (recipient pays transaction fee)
6. DirectTransfer
Campaign owner transfers tokens directly to recipients in batches (no claim step required).
Fee: direct_transfer_fee_per_recipient_lamports × count
Batch Size: Limited to 10 recipients per transaction
7. Replenish
Transfer additional tokens from mint treasury to campaign treasury.
Fee: None
8. MintTokens
Mint additional tokens to campaign treasury (if mint authority not revoked).
Fee: None
9. UpdateConfig
Update fee rates and admin authority (admin-only).
10. WithdrawFees
Withdraw accumulated fees to beneficiary (admin-only).
Fee Structure
Recommended Default Fees
| Fee Type | Amount | Description |
|---|---|---|
| Mint Fee | 0.1 SOL (100M lamports) | Per mint creation |
| Allocation Fee | 0.001 SOL (1M lamports) | Per recipient (Mode 0 only) |
| Merkle Fee | 0.0001 SOL (100K lamports) | Per recipient (when merkle root set) |
| Direct Transfer Fee | 0.0005 SOL (500K lamports) | Per recipient (batch transfers) |
Fee Collection Points
- Mint Fee: Collected during
CreateMint - Allocation Fee: Collected during
Allocate(on-chain allocation accounts) - Merkle Fee: Collected during
CreateCampaign(if merkle root set) - Direct Transfer Fee: Collected during
DirectTransfer - Off-chain Record Claims: No fees (recipient pays transaction fee only)
Account Structure
Config Account
Campaign Account
Allocation Account (Mode 0 Only)
Usage Examples
Complete Campaign Lifecycle
use sdk;
// 1. Initialize program (one-time setup)
let initialize_ix = initialize?;
// 2. Create mint
let mint_id = ;
let noise = ;
let create_mint_ix = create_mint?;
// 3. Create campaign (with merkle root)
let campaign_id = ;
let merkle_root = compute_merkle_root;
let create_campaign_ix = create_campaign?;
// 4. Allocate tokens (Mode 0 - on-chain)
let allocate_ix = allocate_onchain?;
// 5. Claim tokens (Method 0 - on-chain)
let claim_ix = claim_onchain?;
// 6. Direct transfer (batch)
let direct_transfer_ix = direct_transfer?;
Merkle Claim Example
// Generate merkle proof off-chain
let merkle_proof = generate_merkle_proof?;
// Claim using merkle proof
let claim_ix = claim_merkle?;
Project Structure
.
├── api/ # API crate (types, SDK, PDA functions)
│ ├── src/
│ │ ├── lib.rs # Main exports
│ │ ├── consts.rs # Constants
│ │ ├── error.rs # Error types
│ │ ├── instruction.rs # Instruction definitions
│ │ ├── event.rs # Event definitions
│ │ ├── sdk.rs # SDK helper functions
│ │ ├── pda.rs # PDA derivation functions
│ │ ├── merkle.rs # Merkle proof utilities
│ │ ├── loaders.rs # Account validation traits
│ │ └── state/ # State structs
│ │ ├── config.rs
│ │ ├── campaign.rs
│ │ └── allocation.rs
│ └── Cargo.toml
├── program/ # Program crate (instruction handlers)
│ ├── src/
│ │ ├── lib.rs # Entrypoint and dispatch
│ │ ├── initialize.rs
│ │ ├── create_mint.rs
│ │ ├── create_campaign.rs
│ │ ├── allocate.rs
│ │ ├── claim.rs
│ │ ├── direct_transfer.rs
│ │ ├── replenish.rs
│ │ ├── mint_tokens.rs
│ │ ├── update_config.rs
│ │ └── withdraw_fees.rs
│ └── Cargo.toml
├── docs/ # Design documentation
├── Cargo.toml # Workspace configuration
└── README.md
Setup & Installation
Prerequisites
- Rust 1.70+ (with rust-toolchain specified)
- Solana CLI tools
- Anchor CLI (optional, for testing)
Build
# Build all crates
# Build program specifically
# Run tests
Deployment
# Deploy to devnet
# Set program ID in code
# Update api/src/lib.rs with actual program ID
Design Philosophy
"Simple Is Best, Yet Elegant"
- ✅ Simple: Clear fee structure, straightforward operations
- ✅ Elegant: Follows Steel framework patterns, consistent codebase
- ✅ Professional: Thoughtful fee pricing and account management
- ✅ Secure: PDA-based accounts, comprehensive validation
- ✅ Flexible: Configurable fees, multiple allocation modes
Security Features
- PDA Treasury: No admin co-signing required for claims
- Account Validation: Comprehensive checks using Steel's chainable API
- Fee Account: Program-controlled PDA for secure fee storage
- Admin Verification: All admin operations verify authority
- Mint Authority: Can be revoked for immutable supply caps
- Merkle Verification: Cryptographic proof validation for claims
Reference Projects
This project follows patterns from:
miracle-copy: Merkle tree implementation, account validation patternsescrow-copy: Fee account design, PDA treasury patternssteel-master-copy: Framework idioms and best practices
License
Apache-2.0
Contributing
Contributions welcome! Please follow the existing code patterns and Steel framework idioms.
Status
✅ Production Ready - All core features implemented and tested
- ✅ Initialize program
- ✅ Create mint with metadata
- ✅ Create campaigns
- ✅ Allocate tokens (on-chain allocation accounts)
- ✅ Claim tokens (Methods 0, 1, 2)
- ✅ Direct transfer batches
- ✅ Fee collection and withdrawal
- ✅ Config management
For detailed design documentation, see the docs/ directory.