from solana.rpc.api import Client
from solana.keypair import Keypair
import base58
import time
import multiprocessing as mp
import os

# Χρησιμοποιούμε το public RPC endpoint της Solana mainnet
SOLANA_RPC_URL = "https://api.mainnet-beta.solana.com"
client = Client(SOLANA_RPC_URL)

def check_balance(pubkey_str):
    resp = client.get_balance(pubkey_str)
    if resp['result'] and resp['result']['value'] > 0:
        return resp['result']['value']  # balance σε lamports (1 SOL = 1_000_000_000 lamports)
    return 0

def worker(prefix, found_flag, result_queue, attempts_counter, last_pubkey):
    while not found_flag.value:
        keypair = Keypair.generate()
        pubkey = str(keypair.public_key)
        secret_b58 = base58.b58encode(keypair.secret_key).decode()

        with attempts_counter.get_lock():
            attempts_counter.value += 1

        # Ενημέρωση τελευταίου δημόσιου κλειδιού
        with last_pubkey.get_lock():
            last_pubkey.value = pubkey.encode('utf-8')[:32].ljust(32, b' ')

        if not pubkey.startswith(prefix):
            continue

        # Ελέγχουμε αν το wallet έχει υπόλοιπο
        balance = check_balance(pubkey)
        if balance > 0:
            found_flag.value = True
            result_queue.put((pubkey, secret_b58, balance))
            break

def format_time(seconds):
    if seconds < 60:
        return f"{seconds:.1f} δευτ."
    elif seconds < 3600:
        return f"{int(seconds // 60)} λεπτά {int(seconds % 60)} δευτ."
    else:
        h = int(seconds // 3600)
        m = int((seconds % 3600) // 60)
        s = int(seconds % 60)
        return f"{h} ώρες {m} λεπτά {s} δευτ."

def generate_vanity_address_check_balance(prefix: str):
    prefix = prefix.strip()

    print(f"Ξεκινά αναζήτηση για διεύθυνση που ξεκινά με '{prefix}' και έχει υπόλοιπα (balance)...")

    start_time = time.time()

    manager = mp.Manager()
    found_flag = manager.Value('b', False)
    result_queue = manager.Queue()
    attempts_counter = mp.Value('i', 0)
    last_pubkey = mp.Array('c', 32)

    processes = []
    for _ in range(os.cpu_count()):
        p = mp.Process(target=worker, args=(prefix, found_flag, result_queue, attempts_counter, last_pubkey))
        p.start()
        processes.append(p)

    try:
        while not found_flag.value:
            time.sleep(1)
            elapsed = time.time() - start_time
            with attempts_counter.get_lock():
                attempts = attempts_counter.value

            speed = attempts / elapsed if elapsed > 0 else 0

            with last_pubkey.get_lock():
                last_key = bytes(last_pubkey[:]).rstrip(b' ').decode('utf-8', errors='ignore')

            print(f"[{int(elapsed)}s] Προσπάθειες: {attempts:,} | Ταχύτητα: {speed:,.0f} προσπάθειες/δευτ. | "
                  f"Τελευταίο δημόσιο κλειδί: {last_key} ...")

    except KeyboardInterrupt:
        print("\nΔιακοπή από χρήστη. Τερματισμός...")
        found_flag.value = True

    for p in processes:
        p.terminate()

    if not result_queue.empty():
        pubkey, secret, balance = result_queue.get()
        elapsed = time.time() - start_time
        sol = balance / 1_000_000_000
        print(f"\nΒρέθηκε πορτοφόλι με υπόλοιπο {sol:.9f} SOL σε {elapsed:.2f} δευτερόλεπτα!")
        print(f"Δημόσιο κλειδί: {pubkey}")
        print(f"Μυστικό κλειδί (base58): {secret}")
    else:
        print("Δεν βρέθηκε πορτοφόλι με υπόλοιπο.")

if __name__ == "__main__":
    prefix = input("Δώσε το επιθυμητό prefix (π.χ. SOL, 123, MoON): ").strip()
    generate_vanity_address_check_balance(prefix) πως μπορει να γινει πιο πρακτικος και γρηγορος βασικα πως μπορει να βελτιοθει ωστε να βρισκει υπολιπτα