Skip to main content

pumpfun_vanity/
lib.rs

1//! Library for generating Solana vanity addresses.
2
3use solana_sdk::{signature::{Keypair, Signer}, pubkey::Pubkey};
4use rayon::prelude::*;
5
6/// Result of a successful vanity address search.
7pub struct VanityResult {
8    pub keypair: Keypair,
9    pub elapsed: std::time::Duration,
10    pub attempts: u64,
11}
12
13/// Searches for a Solana keypair whose public key starts with the given prefix.
14/// Uses the specified number of threads.
15pub fn find_vanity_address(prefix: &str, num_threads: usize) -> VanityResult {
16    use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
17    use std::sync::{Arc, Mutex};
18    use std::time::Instant;
19
20    let found = AtomicBool::new(false);
21    let attempts = AtomicU64::new(0);
22    let start_time = Instant::now();
23    let result = Arc::new(Mutex::new(None::<Keypair>));
24
25    rayon::ThreadPoolBuilder::new().num_threads(num_threads).build_global().ok();
26
27    while !found.load(Ordering::SeqCst) {
28        let result_clone = Arc::clone(&result);
29        (0..100_000).into_par_iter().for_each(|_| {
30            if found.load(Ordering::SeqCst) {
31                return;
32            }
33            let keypair = Keypair::new();
34            let pubkey_str = keypair.pubkey().to_string();
35            attempts.fetch_add(1, Ordering::Relaxed);
36            if pubkey_str.starts_with(prefix) {
37                found.store(true, Ordering::SeqCst);
38                // Now thread-safe with Mutex
39                let mut result_guard = result_clone.lock().unwrap();
40                *result_guard = Some(keypair);
41            }
42        });
43    }
44
45    VanityResult {
46        keypair: result.lock().unwrap().take().expect("Keypair should be found"),
47        elapsed: start_time.elapsed(),
48        attempts: attempts.load(Ordering::Relaxed),
49    }
50}
51
52/// Searches for a Solana keypair whose public key ends with the given suffix.
53/// Uses the specified number of threads.
54pub fn find_vanity_address_with_suffix(suffix: &str, num_threads: usize) -> VanityResult {
55    use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
56    use std::sync::{Arc, Mutex};
57    use std::time::Instant;
58
59    let found = AtomicBool::new(false);
60    let attempts = AtomicU64::new(0);
61    let start_time = Instant::now();
62    let result = Arc::new(Mutex::new(None::<Keypair>));
63
64    rayon::ThreadPoolBuilder::new().num_threads(num_threads).build_global().ok();
65
66    while !found.load(Ordering::SeqCst) {
67        let result_clone = Arc::clone(&result);
68        (0..100_000).into_par_iter().for_each(|_| {
69            if found.load(Ordering::SeqCst) {
70                return;
71            }
72            let keypair = Keypair::new();
73            let pubkey_str = keypair.pubkey().to_string();
74            attempts.fetch_add(1, Ordering::Relaxed);
75            if pubkey_str.ends_with(suffix) {
76                found.store(true, Ordering::SeqCst);
77                let mut result_guard = result_clone.lock().unwrap();
78                *result_guard = Some(keypair);
79            }
80        });
81    }
82
83    VanityResult {
84        keypair: result.lock().unwrap().take().expect("Keypair should be found"),
85        elapsed: start_time.elapsed(),
86        attempts: attempts.load(Ordering::Relaxed),
87    }
88}