├── .gitignore ├── Dragon ├── data │ ├── Proxies │ │ └── proxies.txt │ ├── Solana │ │ ├── BulkWallet │ │ │ └── wallets.txt │ │ ├── EarlyBuyers │ │ │ └── tokens.txt │ │ ├── TopHolders │ │ │ └── tokens.txt │ │ ├── TimestampTxns │ │ │ └── placeholder.txt │ │ ├── bundleData │ │ │ └── placeholder.txt │ │ └── TopTraders │ │ │ └── tokens.txt │ ├── Ethereum │ │ ├── BulkWallet │ │ │ └── wallets.txt │ │ ├── TopTraders │ │ │ └── tokens.txt │ │ ├── ScanAllTx │ │ │ └── placeholder.txt │ │ └── TimestampTxns │ │ │ └── placeholder.txt │ └── GMGN │ │ ├── Moonshot │ │ ├── BondedToken │ │ │ └── placeholder.txt │ │ ├── NewToken │ │ │ └── placeholder.txt │ │ ├── CompletingToken │ │ │ └── placeholder.txt │ │ └── SoaringToken │ │ │ └── placeholder.txt │ │ └── Pump.Fun │ │ ├── BondedToken │ │ └── placeholder.txt │ │ ├── NewToken │ │ └── placeholder.txt │ │ ├── CompletingToken │ │ └── placeholder.txt │ │ └── SoaringToken │ │ └── placeholder.txt ├── __init__.py ├── ethScan.py ├── ethTimestamp.py ├── ethTraders.py ├── utils.py ├── bundle.py ├── scan.py ├── timestamp.py ├── traders.py ├── copyWalletFinder.py ├── earlyBuyers.py ├── gmgn.py ├── ethWallet.py ├── holders.py └── wallet.py ├── requirements.txt ├── README.md └── dragon.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | -------------------------------------------------------------------------------- /Dragon/data/Proxies/proxies.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Dragon/data/Solana/BulkWallet/wallets.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Dragon/data/Solana/EarlyBuyers/tokens.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Dragon/data/Solana/TopHolders/tokens.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Dragon/data/Ethereum/BulkWallet/wallets.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/Ethereum/TopTraders/tokens.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/Ethereum/ScanAllTx/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/Solana/TimestampTxns/placeholder.txt: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /Dragon/data/Solana/bundleData/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/Ethereum/TimestampTxns/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Moonshot/BondedToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Moonshot/NewToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Pump.Fun/BondedToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Pump.Fun/NewToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Moonshot/CompletingToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Moonshot/SoaringToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Pump.Fun/CompletingToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/GMGN/Pump.Fun/SoaringToken/placeholder.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dragon/data/Solana/TopTraders/tokens.txt: -------------------------------------------------------------------------------- 1 | 8dZgq72oX7bT31n38PZ6NPgPmaDZb4aBzMfLrURQpump -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | colorama 2 | tls_client 3 | cloudscraper 4 | fake_useragent 5 | typing_extensions 6 | -------------------------------------------------------------------------------- /Dragon/__init__.py: -------------------------------------------------------------------------------- 1 | from Dragon.utils import * 2 | from Dragon.scan import ScanAllTx 3 | from Dragon.traders import TopTraders 4 | from Dragon.holders import TopHolders 5 | from Dragon.bundle import BundleFinder 6 | from Dragon.wallet import BulkWalletChecker 7 | from Dragon.timestamp import TimestampTransactions 8 | from Dragon.copyWalletFinder import CopyTradeWalletFinder 9 | from Dragon.earlyBuyers import EarlyBuyers 10 | from Dragon.ethWallet import EthBulkWalletChecker 11 | from Dragon.ethTraders import EthTopTraders 12 | from Dragon.ethTimestamp import EthTimestampTransactions 13 | from Dragon.ethScan import EthScanAllTx 14 | from Dragon.gmgn import GMGN 15 | -------------------------------------------------------------------------------- /Dragon/ethScan.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tls_client 3 | import cloudscraper 4 | import concurrent.futures 5 | from fake_useragent import UserAgent 6 | from threading import Lock 7 | import time 8 | 9 | ua = UserAgent(os='linux', browsers=['firefox']) 10 | 11 | class EthScanAllTx: 12 | 13 | def __init__(self): 14 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 15 | self.cloudScraper = cloudscraper.create_scraper() 16 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 17 | self.lock = Lock() 18 | 19 | def request(self, url: str): 20 | headers = { 21 | "User-Agent": ua.random 22 | } 23 | retries = 3 24 | 25 | for attempt in range(retries): 26 | try: 27 | response = self.sendRequest.get(url, headers=headers) 28 | if response.status_code == 200: 29 | data = response.json()['data']['history'] 30 | paginator = response.json()['data'].get('next') 31 | return data, paginator 32 | except Exception: 33 | print(f"[🐲] Error fetching data, trying backup...") 34 | finally: 35 | try: 36 | response = self.cloudScraper.get(url, headers=headers) 37 | if response.status_code == 200: 38 | data = response.json()['data']['history'] 39 | paginator = response.json()['data'].get('next') 40 | return data, paginator 41 | except Exception: 42 | print(f"[🐲] Backup scraper failed, retrying...") 43 | 44 | time.sleep(1) 45 | 46 | print(f"[🐲] Failed to fetch data after {retries} attempts for URL: {url}") 47 | return [], None 48 | 49 | def getAllTxMakers(self, contractAddress: str, threads: int): 50 | base_url = f"https://gmgn.ai/defi/quotation/v1/trades/eth/{contractAddress}?limit=100" 51 | paginator = None 52 | urls = [] 53 | 54 | headers = { 55 | "User-Agent": ua.random 56 | } 57 | 58 | print(f"[🐲] Starting... please wait.\n") 59 | 60 | while True: 61 | url = f"{base_url}&cursor={paginator}" if paginator else base_url 62 | urls.append(url) 63 | 64 | try: 65 | response = self.sendRequest.get(url, headers=headers) 66 | if response.status_code != 200: 67 | raise Exception("Error in initial request") 68 | except Exception: 69 | print(f"[🐲] Error fetching data, trying backup..") 70 | response = self.cloudScraper.get(url, headers=headers) 71 | paginator = response.json()['data'].get('next') 72 | 73 | if not paginator: 74 | break 75 | 76 | with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: 77 | future_to_url = {executor.submit(self.request, url): url for url in urls} 78 | all_makers = set() 79 | 80 | for future in concurrent.futures.as_completed(future_to_url): 81 | history, _ = future.result() 82 | with self.lock: 83 | for maker in history: 84 | event = maker['event'] 85 | if event == "buy": 86 | print(f"[🐲] Wallet: {maker['maker']} | Hash: {maker['tx_hash']} | Type: {event}") 87 | all_makers.add(maker['maker']) 88 | 89 | filename = f"wallets_{self.shorten(contractAddress)}__{random.randint(1111, 9999)}.txt" 90 | 91 | with open(f"Dragon/data/Ethereum/ScanAllTx/{filename}", "w") as file: 92 | for maker in sorted(all_makers): 93 | file.write(f"{maker}\n") 94 | print(f"[🐲] Found and wrote {len(all_makers)} wallets from {contractAddress} to {filename}") 95 | -------------------------------------------------------------------------------- /Dragon/ethTimestamp.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tls_client 3 | import cloudscraper 4 | from fake_useragent import UserAgent 5 | import concurrent.futures 6 | import time 7 | 8 | ua = UserAgent(os='linux', browsers=['firefox']) 9 | 10 | class EthTimestampTransactions: 11 | 12 | def __init__(self): 13 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 14 | self.cloudScraper = cloudscraper.create_scraper() 15 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 16 | 17 | def fetch_url(self, url, headers): 18 | retries = 3 19 | for attempt in range(retries): 20 | try: 21 | response = self.sendRequest.get(url, headers=headers).json() 22 | return response 23 | except Exception: 24 | print(f"[🐲] Error fetching data, trying backup...") 25 | finally: 26 | try: 27 | response = self.cloudScraper.get(url, headers=headers).json() 28 | return response 29 | except Exception: 30 | print(f"[🐲] Backup scraper failed, retrying...") 31 | 32 | time.sleep(1) 33 | 34 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 35 | return {} 36 | 37 | def getMintTimestamp(self, contractAddress): 38 | headers = { 39 | "User-Agent": ua.random 40 | } 41 | url = f"https://gmgn.ai/defi/quotation/v1/tokens/eth/{contractAddress}" 42 | retries = 3 43 | 44 | for attempt in range(retries): 45 | try: 46 | response = self.sendRequest.get(url, headers=headers).json()['data']['token']['creation_timestamp'] 47 | return response 48 | except Exception: 49 | print(f"[🐲] Error fetching data, trying backup...") 50 | finally: 51 | try: 52 | response = self.cloudScraper.get(url, headers=headers).json()['data']['token']['creation_timestamp'] 53 | return response 54 | except Exception: 55 | print(f"[🐲] Backup scraper failed, retrying...") 56 | 57 | time.sleep(1) 58 | 59 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 60 | return None 61 | 62 | def getTxByTimestamp(self, contractAddress, threads, start, end): 63 | base_url = f"https://gmgn.ai/defi/quotation/v1/trades/eth/{contractAddress}?limit=100" 64 | paginator = None 65 | urls = [] 66 | all_trades = [] 67 | 68 | headers = { 69 | "User-Agent": ua.random 70 | } 71 | 72 | print(f"[🐲] Starting... please wait.") 73 | 74 | start = int(start) 75 | end = int(end) 76 | 77 | while True: 78 | url = f"{base_url}&cursor={paginator}" if paginator else base_url 79 | urls.append(url) 80 | 81 | response = self.fetch_url(url, headers) 82 | trades = response.get('data', {}).get('history', []) 83 | 84 | if not trades or trades[-1]['timestamp'] < start: 85 | break 86 | 87 | paginator = response['data'].get('next') 88 | if not paginator: 89 | break 90 | 91 | with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: 92 | future_to_url = {executor.submit(self.fetch_url, url, headers): url for url in urls} 93 | for future in concurrent.futures.as_completed(future_to_url): 94 | response = future.result() 95 | trades = response.get('data', {}).get('history', []) 96 | filtered_trades = [trade for trade in trades if start <= trade['timestamp'] <= end] 97 | all_trades.extend(filtered_trades) 98 | 99 | wallets = [] 100 | filename = f"Dragon/data/Ethereum/TimestampTxns/txns_{self.shorten(contractAddress)}__{random.randint(1111, 9999)}.txt" 101 | 102 | for trade in all_trades: 103 | wallets.append(trade.get("maker")) 104 | 105 | with open(filename, 'a') as f: 106 | for wallet in wallets: 107 | f.write(f"{wallet}\n") 108 | 109 | print(f"[🐲] {len(wallets)} trades successfully saved to {filename}") 110 | -------------------------------------------------------------------------------- /Dragon/ethTraders.py: -------------------------------------------------------------------------------- 1 | import json 2 | import tls_client 3 | import cloudscraper 4 | from fake_useragent import UserAgent 5 | from concurrent.futures import ThreadPoolExecutor, as_completed 6 | from collections import defaultdict 7 | import time 8 | 9 | ua = UserAgent(os='linux', browsers=['firefox']) 10 | 11 | class EthTopTraders: 12 | 13 | def __init__(self): 14 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 15 | self.cloudScraper = cloudscraper.create_scraper() 16 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 17 | self.allData = {} 18 | self.allAddresses = set() 19 | self.addressFrequency = defaultdict(int) 20 | self.totalTraders = 0 21 | 22 | def fetchTopTraders(self, contractAddress: str): 23 | url = f"https://gmgn.ai/defi/quotation/v1/tokens/top_traders/eth/{contractAddress}?orderby=profit&direction=desc" 24 | retries = 3 25 | headers = { 26 | "User-Agent": ua.random 27 | } 28 | 29 | for attempt in range(retries): 30 | try: 31 | response = self.sendRequest.get(url, headers=headers) 32 | data = response.json().get('data', None) 33 | if data: 34 | return data 35 | except Exception: 36 | print(f"[🐲] Error fetching data on attempt, trying backup...") 37 | finally: 38 | try: 39 | response = self.cloudScraper.get(url, headers=headers) 40 | data = response.json().get('data', None) 41 | if data: 42 | return data 43 | except Exception: 44 | print(f"[🐲] Backup scraper failed, retrying...") 45 | 46 | time.sleep(1) 47 | 48 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 49 | return [] 50 | 51 | def topTraderData(self, contractAddresses, threads): 52 | with ThreadPoolExecutor(max_workers=threads) as executor: 53 | futures = {executor.submit(self.fetchTopTraders, address): address for address in contractAddresses} 54 | 55 | for future in as_completed(futures): 56 | contract_address = futures[future] 57 | response = future.result() 58 | 59 | self.allData[contract_address] = {} 60 | self.totalTraders += len(response) 61 | 62 | for top_trader in response: 63 | multiplier_value = top_trader['profit_change'] 64 | 65 | if multiplier_value: 66 | address = top_trader['address'] 67 | self.addressFrequency[address] += 1 68 | self.allAddresses.add(address) 69 | 70 | bought_usd = f"${top_trader['total_cost']:,.2f}" 71 | total_profit = f"${top_trader['realized_profit']:,.2f}" 72 | unrealized_profit = f"${top_trader['unrealized_profit']:,.2f}" 73 | multiplier = f"{multiplier_value:.2f}x" 74 | buys = f"{top_trader['buy_tx_count_cur']}" 75 | sells = f"{top_trader['sell_tx_count_cur']}" 76 | 77 | self.allData[address] = { 78 | "boughtUsd": bought_usd, 79 | "totalProfit": total_profit, 80 | "unrealizedProfit": unrealized_profit, 81 | "multiplier": multiplier, 82 | "buys": buys, 83 | "sells": sells 84 | } 85 | 86 | repeatedAddresses = [address for address, count in self.addressFrequency.items() if count > 1] 87 | 88 | identifier = self.shorten(list(self.allAddresses)[0]) 89 | 90 | with open(f'Dragon/data/Ethereum/TopTraders/allTopAddresses_{identifier}.txt', 'w') as av: 91 | for address in self.allAddresses: 92 | av.write(f"{address}\n") 93 | 94 | if len(repeatedAddresses) != 0: 95 | with open(f'Dragon/data/Ethereum/TopTraders/repeatedTopTraders_{identifier}.txt', 'w') as ra: 96 | for address in repeatedAddresses: 97 | ra.write(f"{address}\n") 98 | print(f"[🐲] Saved {len(repeatedAddresses)} repeated addresses to repeatedTopTraders_{identifier}.txt") 99 | 100 | with open(f'Dragon/data/Ethereum/TopTraders/topTraders_{identifier}.json', 'w') as tt: 101 | json.dump(self.allData, tt, indent=4) 102 | 103 | print(f"[🐲] Saved {self.totalTraders} top traders for {len(contractAddresses)} tokens to allTopAddresses_{identifier}.txt") 104 | print(f"[🐲] Saved {len(self.allAddresses)} top trader addresses to topTraders_{identifier}.json") 105 | 106 | return 107 | -------------------------------------------------------------------------------- /Dragon/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glob 3 | 4 | from colorama import Fore, init 5 | 6 | def clear(): 7 | os.system("cls||clear") 8 | 9 | def banner(): 10 | banner = f"""{Fore.RED} 11 | WELCOME TO.. 12 | 13 | ( ) /\ _ ( 14 | \ | ( \ ( \.( ) _____ 15 | \ \ \ ` ` ) \ ( ___ / _ \\ 16 | (_` \+ . x ( .\ \\/ \____-----------/ (o) \\_ 17 | - .- \+ ; ( O \\____ 18 | DRAGON ) \_____________ ` \\ / 19 | (__ +- .( -'.- <. - _ VVVVVVV VV V\\ \\/ 20 | (_____ ._._: <_ - <- _ (-- _AAAAAAA__A_/ | 21 | . /./.+- . .- / +-- - . \______________//_ \\_______ 22 | (__ ' /x / x _/ ( \___' \\ / 23 | , x / ( ' . / . / | \\ / 24 | / / _/ / + / \\/ 25 | ' (__/ / \\ 26 | {Fore.WHITE}""" 27 | return banner 28 | 29 | def checkProxyFile(): 30 | with open('Dragon/data/Proxies/proxies.txt', 'r') as f: 31 | return bool(f.readlines()) 32 | 33 | def chains(): 34 | options: list = ["Solana", "Ethereum", "GMGN Tools"] 35 | optionsChoice = "[🐲] Please select a chain:\n\n" + "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {option}" for index, option in enumerate(options)]) 36 | 37 | return options, optionsChoice 38 | 39 | def gmgnTools(site: str): 40 | if site.lower() == "pump.fun": 41 | options: list = ["Pump.Fun New Token Scraper", "Pump.Fun Completing Token Scraper", "Pump.Fun Soaring Token Scraper", "Pump.Fun Bonded Token Scraper"] 42 | optionsChoice = "[🐲] Please select a module:\n\n" + "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {option}" for index, option in enumerate(options)]) 43 | elif site.lower() == "moonshot": 44 | options: list = ["Moonshot New Token Scraper", "Moonshot Completing Token Scraper", "Moonshot Soaring Token Scraper", "Moonshot Bonded Token Scraper"] 45 | optionsChoice = "[🐲] Please select a module:\n\n" + "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {option}" for index, option in enumerate(options)]) 46 | else: 47 | return f"[🐲] Error, Dragon does not support the site '{site}'" 48 | 49 | return options, optionsChoice 50 | 51 | def choices(chain: str): 52 | if chain.lower() == "solana": 53 | options: list = ["Bundle Checker", "Bulk Wallet Checker", "Top Traders Scraper", "All Transaction Scan", "Get Transaction By Timestamp", "Copy Wallet Finder", "Top Holders Scraper", "Early Buyers Scraper", "Purge All Files", "Quit"] 54 | optionsChoice = "[🐲] Please select a module:\n\n" + "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {option}" for index, option in enumerate(options)]) 55 | elif chain.lower() == "ethereum": 56 | options: list = ["Placeholder", "Bulk Wallet Checker", "Top Traders Scraper", "All Transaction Scan", "Get Transaction By Timestamp", "Purge All Files", "Quit"] 57 | optionsChoice = "[🐲] Please select a module:\n\n" + "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {option}" for index, option in enumerate(options)]) 58 | elif chain.lower() == "gmgn": 59 | options: list = ["Pump.Fun", "Moonshot", "Purge All Files", "Quit"] 60 | optionsChoice = "[🐲] Please select a module:\n\n" + "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {option}" for index, option in enumerate(options)]) 61 | else: 62 | return f"[🐲] Error, Dragon does not support the chain '{chain}'" 63 | 64 | return options, optionsChoice 65 | 66 | def clear(): 67 | os.system("cls||clear") 68 | 69 | import os 70 | import glob 71 | from colorama import Fore 72 | 73 | def searchForTxt(chain: str): 74 | if chain.lower() == "solana": 75 | chain = "Solana" 76 | elif chain.lower() == "ethereum": 77 | chain = "Ethereum" 78 | elif chain.lower() == "gmgn": 79 | chain = "GMGN" 80 | else: 81 | return f"[🐲] Error, Dragon does not support the chain '{chain}'" 82 | 83 | search_directory = os.path.normpath(os.path.join(os.getcwd(), f'Dragon/data/{chain}')) 84 | additional_directory = os.path.normpath(os.path.join(os.getcwd(), 'Dragon/data/GMGN')) 85 | txtFiles = [] 86 | 87 | for directory in [search_directory, additional_directory]: 88 | txtFiles.extend(glob.glob(os.path.join(directory, '**', '*.txt'), recursive=True)) 89 | 90 | excluded_files = [ 91 | #os.path.relpath(os.path.join(search_directory, 'TopTraders/tokens.txt'), search_directory) 92 | ] 93 | 94 | files = [ 95 | os.path.relpath(file, search_directory).replace("\\", "/") 96 | for file in txtFiles 97 | if os.path.relpath(file, search_directory) not in excluded_files and 98 | os.path.basename(file) != "placeholder.txt" 99 | ] 100 | files.append("Select Own File") 101 | filesChoice = "\n".join([f"[{Fore.RED}{index + 1}{Fore.WHITE}] {file}" for index, file in enumerate(files)]) 102 | 103 | 104 | return filesChoice, files 105 | 106 | def purgeFiles(chain: str): 107 | if chain.lower() == "solana": 108 | chain = "Solana" 109 | elif chain.lower() == "ethereum": 110 | chain = "Ethereum" 111 | elif chain.lower() == "gmgn": 112 | chain = "GMGN" 113 | else: 114 | return f"[🐲] Error, Dragon does not support the chain '{chain}'" 115 | 116 | base_directory = os.path.normpath(f"Dragon/data/{chain}") 117 | 118 | if chain == "GMGN": 119 | subfolders = ["BondedToken", "NewToken", "CompletingToken", "SoaringToken"] 120 | for main_subdir in os.listdir(base_directory): 121 | main_subdir_path = os.path.join(base_directory, main_subdir) 122 | if os.path.isdir(main_subdir_path): 123 | for folder in subfolders: 124 | folder_path = os.path.join(main_subdir_path, folder) 125 | 126 | if os.path.exists(folder_path): 127 | for dirpath, _, filenames in os.walk(folder_path): 128 | for file in filenames: 129 | file_path = os.path.join(dirpath, file) 130 | if file.endswith(('.txt', '.csv', '.json')): 131 | if file in ['wallets.txt', 'tokens.txt']: 132 | with open(file_path, 'w') as f: 133 | pass 134 | else: 135 | os.remove(file_path) 136 | else: 137 | for dirpath, _, filenames in os.walk(base_directory): 138 | for file in filenames: 139 | file_path = os.path.join(dirpath, file) 140 | if file.endswith(('.txt', '.csv', '.json')): 141 | if file in ['wallets.txt', 'tokens.txt']: 142 | with open(file_path, 'w') as f: 143 | pass 144 | else: 145 | os.remove(file_path) 146 | init(autoreset=True) 147 | -------------------------------------------------------------------------------- /Dragon/bundle.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import tls_client 4 | import cloudscraper 5 | from fake_useragent import UserAgent 6 | import time 7 | 8 | ua = UserAgent(os='linux', browsers=['firefox']) 9 | 10 | class BundleFinder: 11 | 12 | def __init__(self): 13 | self.txHashes = set() 14 | self.formatTokens = lambda x: float(x) / 1_000_000 15 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 16 | self.cloudScraper = cloudscraper.create_scraper() 17 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else "?" 18 | 19 | def randomise(self): 20 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 21 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 22 | 23 | parts = self.identifier.split('_') 24 | identifier, version, *rest = parts 25 | other = rest[0] if rest else None 26 | 27 | os = 'windows' 28 | if identifier == 'opera': 29 | identifier = 'chrome' 30 | elif version == 'ios': 31 | os = 'ios' 32 | else: 33 | os = 'windows' 34 | 35 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 36 | 37 | self.headers = { 38 | 'Host': 'gmgn.ai', 39 | 'accept': 'application/json, text/plain, */*', 40 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 41 | 'dnt': '1', 42 | 'priority': 'u=1, i', 43 | 'referer': 'https://gmgn.ai/?chain=sol', 44 | 'user-agent': self.user_agent 45 | } 46 | 47 | def prettyPrint(self, bundleData: dict, contractAddress: str): 48 | isBundled = bundleData['bundleDetected'] 49 | developerInformation = bundleData['developerInfo'] 50 | transactions = bundleData['transactions'] 51 | bundledAmount = developerInformation['bundledAmount'] 52 | bundledPercentage = developerInformation['percentageOfSupply'] 53 | 54 | text = ( 55 | f"[🐲] Bundled: ✅\n" if isBundled else f"[🐲] Bundled: ❌\n" 56 | f"[🐲] Transactions: {transactions:,}" 57 | ) 58 | 59 | text += f"\n[🐲] Total Amount: {bundledAmount:,.2f}\n[🐲] Total Percentage: {bundledPercentage * 100:,.2f}%" 60 | 61 | filename = f"bundle_{self.shorten(contractAddress)}_{random.randint(1111, 9999)}.json" 62 | 63 | with open(f'Dragon/data/Solana/bundleData/{filename}', 'w') as f: 64 | json.dump(bundleData, f, indent=4) 65 | 66 | text += f"\n[🐲] Saved data to {filename}\n" 67 | 68 | return text 69 | 70 | def teamTrades(self, contractAddress): 71 | url = f"https://gmgn.ai/defi/quotation/v1/trades/sol/{contractAddress}?limit=100&maker=&tag%5B%5D=creator&tag%5B%5D=dev_team" 72 | retries = 3 73 | 74 | for attempt in range(retries): 75 | self.randomise() 76 | try: 77 | info = self.sendRequest.get(f"https://gmgn.ai/defi/quotation/v1/tokens/sol/{contractAddress}", headers=self.headers, allow_redirects=True).json()['data']['token'] 78 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True).json()['data']['history'] 79 | break 80 | except Exception: 81 | print(f"[🐲] Error fetching data on attempt, trying backup..") 82 | finally: 83 | self.randomise() 84 | try: 85 | info = self.cloudScraper.get(f"https://gmgn.ai/defi/quotation/v1/tokens/sol/{contractAddress}", headers=self.headers, allow_redirects=True).json()['data']['token'] 86 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True).json()['data']['history'] 87 | break 88 | except Exception: 89 | print(f"[🐲] Backup scraper failed, retrying...") 90 | 91 | time.sleep(1) 92 | 93 | if info['launchpad'].lower() == "pump.fun": 94 | totalSupply = 1_000_000_000 95 | else: 96 | totalSupply = info['total_supply'] 97 | 98 | for buy in response: 99 | if buy['event'] == "buy": 100 | self.txHashes.add(buy['tx_hash']) 101 | 102 | return self.txHashes, totalSupply 103 | 104 | def checkBundle(self, txHashes: set, totalSupply: int): 105 | total_amount = 0.00 106 | transactions = 0 107 | 108 | data = { 109 | "transactions": 0, 110 | "totalAmount": 0.00, 111 | "bundleDetected": False, 112 | "transactionDetails": {} 113 | } 114 | 115 | for txHash in self.txHashes: 116 | url = f"https://api.solana.fm/v0/transfers/{txHash}" 117 | retries = 3 118 | 119 | for attempt in range(retries): 120 | try: 121 | response = self.sendRequest.get(url).json().get('result', {}).get('data', []) 122 | if response: 123 | break 124 | except Exception as e: 125 | print(f"[🐲] Error fetching transaction data for {txHash} on attempt {attempt + 1}.") 126 | time.sleep(1) 127 | 128 | if isinstance(response, list): 129 | for action in response: 130 | if action.get('action') == "transfer" and action.get("token") != "": 131 | amount = self.formatTokens(action.get('amount')) 132 | total_amount += amount 133 | transactions += 1 134 | 135 | data['transactions'] = transactions 136 | data['totalAmount'] = total_amount 137 | 138 | if transactions > 1: 139 | data['bundleDetected'] = True 140 | 141 | transactionsDetails = {} 142 | 143 | for txHash in txHashes: 144 | url = f"https://api.solana.fm/v0/transfers/{txHash}" 145 | 146 | for attempt in range(retries): 147 | try: 148 | response = self.sendRequest.get(url).json().get('result', {}).get('data', []) 149 | if response: 150 | break 151 | except Exception as e: 152 | print(f"Error fetching transaction data for {txHash} on attempt {attempt + 1}.") 153 | time.sleep(1) 154 | 155 | if isinstance(response, list): 156 | amounts = [] 157 | for action in response: 158 | if action.get('action') == "transfer" and action.get("token") != "": 159 | amount = self.formatTokens(action.get('amount')) 160 | amounts.append(amount) 161 | if amounts: 162 | amountsPercentages = [(amount / totalSupply * 100) for amount in amounts] 163 | 164 | transactionsDetails[txHash] = { 165 | "amounts": amounts, 166 | "amountsPercentages": amountsPercentages 167 | } 168 | 169 | data['transactionDetails'] = transactionsDetails 170 | 171 | developerInfo = { 172 | "bundledAmount": total_amount, 173 | "percentageOfSupply": total_amount / totalSupply 174 | } 175 | 176 | data['developerInfo'] = developerInfo 177 | 178 | return data 179 | -------------------------------------------------------------------------------- /Dragon/scan.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tls_client 3 | import cloudscraper 4 | import concurrent.futures 5 | from fake_useragent import UserAgent 6 | from threading import Lock 7 | import time 8 | 9 | ua = UserAgent(os='linux', browsers=['firefox']) 10 | 11 | class ScanAllTx: 12 | 13 | def __init__(self): 14 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 15 | self.cloudScraper = cloudscraper.create_scraper() 16 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 17 | self.lock = Lock() 18 | self.proxyPosition = 0 19 | 20 | def randomise(self): 21 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 22 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 23 | 24 | parts = self.identifier.split('_') 25 | identifier, version, *rest = parts 26 | other = rest[0] if rest else None 27 | 28 | os = 'windows' 29 | if identifier == 'opera': 30 | identifier = 'chrome' 31 | elif version == 'ios': 32 | os = 'ios' 33 | else: 34 | os = 'windows' 35 | 36 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 37 | 38 | self.headers = { 39 | 'Host': 'gmgn.ai', 40 | 'accept': 'application/json, text/plain, */*', 41 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 42 | 'dnt': '1', 43 | 'priority': 'u=1, i', 44 | 'referer': 'https://gmgn.ai/?chain=sol', 45 | 'user-agent': self.user_agent 46 | } 47 | 48 | def loadProxies(self): 49 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 50 | proxies = file.read().splitlines() 51 | 52 | formatted_proxies = [] 53 | for proxy in proxies: 54 | if ':' in proxy: 55 | parts = proxy.split(':') 56 | if len(parts) == 4: 57 | ip, port, username, password = parts 58 | formatted_proxies.append({ 59 | 'http': f"http://{username}:{password}@{ip}:{port}", 60 | 'https': f"http://{username}:{password}@{ip}:{port}" 61 | }) 62 | else: 63 | formatted_proxies.append({ 64 | 'http': f"http://{proxy}", 65 | 'https': f"http://{proxy}" 66 | }) 67 | else: 68 | formatted_proxies.append(f"http://{proxy}") 69 | return formatted_proxies 70 | 71 | def configureProxy(self, proxy): 72 | if isinstance(proxy, dict): 73 | self.sendRequest.proxies = { 74 | 'http': proxy.get('http'), 75 | 'https': proxy.get('https') 76 | } 77 | elif isinstance(proxy, str): 78 | self.sendRequest.proxies = { 79 | 'http': proxy, 80 | 'https': proxy 81 | } 82 | else: 83 | self.sendRequest.proxies = None 84 | return proxy 85 | 86 | def getNextProxy(self): 87 | proxies = self.loadProxies() 88 | proxy = proxies[self.proxyPosition % len(proxies)] 89 | self.proxyPosition += 1 90 | return proxy 91 | 92 | 93 | def request(self, url: str, useProxies): 94 | retries = 3 95 | 96 | for attempt in range(retries): 97 | try: 98 | proxy = self.getNextProxy() if useProxies else None 99 | self.configureProxy(proxy) 100 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 101 | if response.status_code == 200: 102 | data = response.json()['data']['history'] 103 | paginator = response.json()['data'].get('next') 104 | return data, paginator 105 | except Exception: 106 | print(f"[🐲] Error fetching data, trying backup...") 107 | finally: 108 | self.randomise() 109 | try: 110 | proxy = self.getNextProxy() if useProxies else None 111 | proxies = {'http': proxy, 'https': proxy} if proxy else None 112 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 113 | if response.status_code == 200: 114 | data = response.json()['data']['history'] 115 | paginator = response.json()['data'].get('next') 116 | return data, paginator 117 | except Exception: 118 | print(f"[🐲] Backup scraper failed, retrying...") 119 | 120 | time.sleep(1) 121 | 122 | print(f"[🐲] Failed to fetch data after {retries} attempts for URL: {url}") 123 | return [], None 124 | 125 | def getAllTxMakers(self, contractAddress: str, threads: int, useProxies): 126 | base_url = f"https://gmgn.ai/defi/quotation/v1/trades/sol/{contractAddress}?limit=100" 127 | paginator = None 128 | urls = [] 129 | 130 | print(f"[🐲] Starting... please wait.\n") 131 | 132 | while True: 133 | url = f"{base_url}&cursor={paginator}" if paginator else base_url 134 | urls.append(url) 135 | 136 | try: 137 | proxy = self.getNextProxy() if useProxies else None 138 | self.configureProxy(proxy) 139 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 140 | if response.status_code != 200: 141 | raise Exception("Error in initial request") 142 | except Exception: 143 | self.randomise() 144 | print(f"[🐲] Error fetching data, trying backup..") 145 | proxy = self.getNextProxy() if useProxies else None 146 | proxies = {'http': proxy, 'https': proxy} if proxy else None 147 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 148 | 149 | paginator = response.json()['data'].get('next') 150 | 151 | if not paginator: 152 | break 153 | 154 | with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: 155 | future_to_url = {executor.submit(self.request, url, useProxies): url for url in urls} 156 | all_makers = set() 157 | 158 | for future in concurrent.futures.as_completed(future_to_url): 159 | history, _ = future.result() 160 | with self.lock: 161 | for maker in history: 162 | event = maker['event'] 163 | if event == "buy": 164 | print(f"[🐲] Wallet: {maker['maker']} | Hash: {maker['tx_hash']} | Type: {event}") 165 | all_makers.add(maker['maker']) 166 | 167 | filename = f"wallets_{self.shorten(contractAddress)}__{random.randint(1111, 9999)}.txt" 168 | 169 | with open(f"Dragon/data/Solana/ScanAllTx/{filename}", "w") as file: 170 | for maker in sorted(all_makers): 171 | file.write(f"{maker}\n") 172 | print(f"[🐲] Found and wrote {len(all_makers)} wallets from {contractAddress} to {filename}") 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | Dragon 4 |

5 |

Use code "DRAGON" at BirdProxies for a 10% discount.

6 |

7 | The all-in-one tool to help you find profitable wallets on Solana and Ethereum. 8 |


9 |

Suggestions

10 | Drop Suggestions! (and a follow) 11 |

Tutorial

12 | YouTube Video 13 |

14 | Setup 15 |

16 | 17 | ` 18 | pip install -r requirements.txt 19 | ` 20 |

21 | ` 22 | python dragon.py 23 | ` 24 | 25 |

26 | Bundle Checker 27 |

28 |

Check if a Solana contract has had multiple buys bundled into one transaction.

29 |

30 | 1. Enter a contract address.
31 | 2. Receive the bundle data.

32 | Note: This will only recognise a bundle if the bundled wallets are shown under the "DEV" tab on GMGN.ai - Example 33 |

34 | 35 |

36 | Bulk Wallet Checker 37 |

38 |

Check a large list of wallets to receive their PnL, winrate and more data.

39 |

40 | 1. Select your .txt file or enter your own directory.
41 | 2. Enter the amount of threads you'd like to use.
42 | 3. Select whether you'd like to use proxies or not.
43 | 4. Enter whether you'd like to skip certain wallets.
44 | 5. Receive your wallet data. 45 |

46 | 47 |

48 | Top Traders Scraper 49 |

50 |

Scrape the top 100 traders of Solana tokens to receive their PnL, winrate and more data.

51 |

52 | 1. Load data/Solana/TopTraders/tokens.txt with contract addresses.
53 | 2. Enter the amount of threads you'd like to use.
54 | 3. Select whether you'd like to use proxies or not.
55 | 4. Receive your top traders data. 56 |

57 | 58 |

59 | All Transaction Scan 60 |

61 |

Grab every single wallet address that made a buy transaction of a Solana token. I do not recommend a large market cap token.

62 |

63 | 1. Enter a contract address.
64 | 2. Enter the amount of threads you'd like to use.
65 | 3. Select whether you'd like to use proxies or not.
66 | 4. Wait and receive your wallet addresses. 67 |

68 | 69 |

70 | Get Transaction By Timestamp 71 |

72 |

Grab every single wallet address that made a buy transaction of a Solana token between 2 timestamps.

73 |

74 | 1. Enter a contract address.
75 | 2. Enter the amount of threads you'd like to use.
76 | 3. Select whether you'd like to use proxies or not.
77 | 4. Enter first & second timestamps.
78 | 5. Wait and receive your wallet addresses. 79 |

80 | 81 |

82 | Copy Wallet Finder 83 |

84 |

Grab the 10 transaction makers ahead of a wallet on a contract address to see if they have copytraders.

85 |

86 | 1. Enter a contract address.
87 | 2. Enter the wallet address you'd like to check.
88 | 3. Enter the amount of threads you'd like to use.
89 | 4. Select whether you'd like to use proxies or not.
90 | 5. Wait and receive your wallet addresses. 91 |

92 | 93 |

94 | Top Holders Scraper 95 |

96 |

Scrape the top 100 holders of Solana tokens to receive their PnL, winrate and more data.

97 |

98 | 1. Load data/Solana/TopHolders/tokens.txt with contract addresses.
99 | 2. Enter the amount of threads you'd like to use.
100 | 3. Select whether you'd like to use proxies or not.
101 | 4. Receive your top traders data. 102 |

103 | 104 |

105 | Early Buyers Scraper 106 |

107 |

Scrape the early buyers, excluding the dev, of Solana tokens to receive their PnL and more data.

108 |

109 | 1. Load data/Solana/EarlyBuyers/tokens.txt with contract addresses.
110 | 2. Enter the amount of early buyers you'd like to scrape per contract address.
111 | 3. Enter the amount of threads you'd like to use.
112 | 4. Select whether you'd like to use proxies or not.
113 | 5. Receive your top traders data. 114 |

115 | 116 |

117 | GMGN Modules 118 |

119 |

Scrape the contract addresses of new, soaring, completing and bonding tokens on Pump.Fun and Moonshot.

120 |

121 | 1. Select the module you want to use from the four listed.
122 | 2. Enter the amount of threads you'd like to use.
123 | 3. Select whether you'd like to use proxies or not.
124 | 4. Receive your contract addresses.

125 | Note, here are the links to where the data is being grabbed from:
126 | New Token
127 | Completing Token
128 | Soaring Token
129 | Bonded Token 130 |

131 | 132 |

133 | Updates 134 |

135 |

136 | 19/08/2024
137 | - General logic fixes.
138 | - Thread cap of 100. 139 |

140 |

141 | 20/08/2024
142 | - Added backup requests using cloudscraper, please reinstall requirements.txt. 143 |

144 |

145 | 21/08/2024
146 | - General logic fixes.
147 | - Added random user agent generator to all requests, please reinstall requirements.txt. 148 |

149 | 22/08/2024
150 | - Added clear client function when a general exception occurs.
151 | - Added new module to find wallet address by transaction timestamp. 152 |


153 | 29/08/2024
154 | - General logic fixes.
155 | - Added option to purge all files.
156 | - Added token distribution data to the Bulk Wallet Checker.
157 | - Added request retries, will attempt 3 times until data is found, boosting request success rate by 80% roughly. 158 |

159 | 02/09/2024
160 | - General logic fixes.
161 | - Added chain selection.
162 | - Added Tron Bulk Wallet Checker. (Inaccurate at the moment, thanks GMGN.)
163 | - Added Tron Top Trader Scraper. 164 |


165 | 08/09/2024
166 | - Added SOL Balance & Trading Platform data to Bulk Wallet Checker.
167 | - Slowing down on the updates due to market conditions & the tool is stacked. 168 |

169 |

170 | 23/09/2024
171 | - Added Ethereum support.
172 |

173 |

174 | 09/10/2024
175 | - Added proxy support to Solana modules.
176 | - Added Top Holders scraper to Solana modules.
177 | - Added Copy Wallet Finder to Solana modules.
178 |

179 |

180 | 16/10/2024
181 | - Fixed Copytrade Wallet Finder showing previous 10 instead of after 10.
182 | - Added attempts to filter out volume & MEV bots from the 10 traders. 183 |

184 |

185 | 23/10/2024
186 | - Added TLS session randomisation to support GMGN's recent API endpoint changes. 187 |

188 |

189 | 04/11/2024
190 | - Added Early Buyers scraper to Solana modules. 191 |

192 |

193 | 05/11/2024
194 | - Added GMGN Contract Address scraping modules for Pump.Fun and Moonshot. 195 |

196 |

197 | 06/11/2024
198 | - Deprecated Tron modules. 199 |

200 |

201 | 27/11/2024
202 | - Fixed Bundle Checker for Solana module. 203 |

204 | 205 |

206 | Donations 207 |

208 | Donations are appreciated! (Solana) 209 | 210 | ``` 211 | FF3gkF88aJ6DayFHVmUw7TvNYJnXzmGBu6P5RrEcoins 212 | ``` 213 | 214 |

215 | Credits 216 |

217 | 218 | Me
219 |
220 | 221 | Azek
222 |
223 | -------------------------------------------------------------------------------- /Dragon/timestamp.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tls_client 3 | import cloudscraper 4 | from fake_useragent import UserAgent 5 | import concurrent.futures 6 | import time 7 | import random 8 | 9 | ua = UserAgent(os='linux', browsers=['firefox']) 10 | 11 | class TimestampTransactions: 12 | 13 | def __init__(self): 14 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 15 | self.cloudScraper = cloudscraper.create_scraper() 16 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 17 | self.proxyPosition = 0 18 | 19 | def randomise(self): 20 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 21 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 22 | 23 | parts = self.identifier.split('_') 24 | identifier, version, *rest = parts 25 | other = rest[0] if rest else None 26 | 27 | os = 'windows' 28 | if identifier == 'opera': 29 | identifier = 'chrome' 30 | elif version == 'ios': 31 | os = 'ios' 32 | else: 33 | os = 'windows' 34 | 35 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 36 | 37 | self.headers = { 38 | 'Host': 'gmgn.ai', 39 | 'accept': 'application/json, text/plain, */*', 40 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 41 | 'dnt': '1', 42 | 'priority': 'u=1, i', 43 | 'referer': 'https://gmgn.ai/?chain=sol', 44 | 'user-agent': self.user_agent 45 | } 46 | 47 | def loadProxies(self): 48 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 49 | proxies = file.read().splitlines() 50 | 51 | formatted_proxies = [] 52 | for proxy in proxies: 53 | if ':' in proxy: 54 | parts = proxy.split(':') 55 | if len(parts) == 4: 56 | ip, port, username, password = parts 57 | formatted_proxies.append({ 58 | 'http': f"http://{username}:{password}@{ip}:{port}", 59 | 'https': f"http://{username}:{password}@{ip}:{port}" 60 | }) 61 | else: 62 | formatted_proxies.append({ 63 | 'http': f"http://{proxy}", 64 | 'https': f"http://{proxy}" 65 | }) 66 | else: 67 | formatted_proxies.append(f"http://{proxy}") 68 | return formatted_proxies 69 | 70 | def configureProxy(self, proxy): 71 | if isinstance(proxy, dict): 72 | self.sendRequest.proxies = { 73 | 'http': proxy.get('http'), 74 | 'https': proxy.get('https') 75 | } 76 | elif isinstance(proxy, str): 77 | self.sendRequest.proxies = { 78 | 'http': proxy, 79 | 'https': proxy 80 | } 81 | else: 82 | self.sendRequest.proxies = None 83 | return proxy 84 | 85 | def getNextProxy(self): 86 | proxies = self.loadProxies() 87 | proxy = proxies[self.proxyPosition % len(proxies)] 88 | self.proxyPosition += 1 89 | return proxy 90 | 91 | def fetch_url(self, url, useProxies): 92 | retries = 3 93 | for attempt in range(retries): 94 | try: 95 | proxy = self.getNextProxy() if useProxies else None 96 | self.configureProxy(proxy) 97 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True).json() 98 | return response 99 | except Exception: 100 | print(f"[🐲] Error fetching data, trying backup...") 101 | finally: 102 | self.randomise() 103 | try: 104 | proxy = self.getNextProxy() if useProxies else None 105 | proxies = {'http': proxy, 'https': proxy} if proxy else None 106 | response = self.cloudScraper.get(url, headers=self.headers, allow_redirects=True, proxies=proxies).json() 107 | return response 108 | except Exception: 109 | print(f"[🐲] Backup scraper failed, retrying...") 110 | 111 | time.sleep(1) 112 | 113 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 114 | return {} 115 | 116 | def getMintTimestamp(self, contractAddress, useProxies): 117 | url = f"https://gmgn.ai/defi/quotation/v1/tokens/sol/{contractAddress}" 118 | retries = 3 119 | 120 | for attempt in range(retries): 121 | self.randomise() 122 | try: 123 | proxy = self.getNextProxy() if useProxies else None 124 | self.configureProxy(proxy) 125 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True).json()['data']['token']['creation_timestamp'] 126 | return response 127 | except Exception: 128 | print(f"[🐲] Error fetching data, trying backup...") 129 | finally: 130 | self.randomise() 131 | try: 132 | proxy = self.getNextProxy() if useProxies else None 133 | proxies = {'http': proxy, 'https': proxy} if proxy else None 134 | response = self.cloudScraper.get(url, headers=self.headers, allow_redirects=True, proxies=proxies).json()['data']['token']['creation_timestamp'] 135 | return response 136 | except Exception: 137 | print(f"[🐲] Backup scraper failed, retrying...") 138 | 139 | time.sleep(1) 140 | 141 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 142 | return None 143 | 144 | def getTxByTimestamp(self, contractAddress, threads, start, end, useProxies): 145 | base_url = f"https://gmgn.ai/defi/quotation/v1/trades/sol/{contractAddress}?limit=100" 146 | paginator = None 147 | urls = [] 148 | all_trades = [] 149 | 150 | print(f"[🐲] Starting... please wait.") 151 | 152 | start = int(start) 153 | end = int(end) 154 | 155 | while True: 156 | self.randomise() 157 | url = f"{base_url}&cursor={paginator}" if paginator else base_url 158 | urls.append(url) 159 | 160 | response = self.fetch_url(url, useProxies) 161 | trades = response.get('data', {}).get('history', []) 162 | 163 | if not trades or trades[-1]['timestamp'] < start: 164 | break 165 | 166 | paginator = response['data'].get('next') 167 | if not paginator: 168 | break 169 | 170 | with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: 171 | future_to_url = {executor.submit(self.fetch_url, url, useProxies): url for url in urls} 172 | for future in concurrent.futures.as_completed(future_to_url): 173 | response = future.result() 174 | trades = response.get('data', {}).get('history', []) 175 | filtered_trades = [trade for trade in trades if start <= trade['timestamp'] <= end] 176 | all_trades.extend(filtered_trades) 177 | 178 | wallets = [] 179 | filename = f"Dragon/data/Solana/TimestampTxns/txns_{self.shorten(contractAddress)}__{random.randint(1111, 9999)}.txt" 180 | 181 | for trade in all_trades: 182 | wallets.append(trade.get("maker")) 183 | 184 | with open(filename, 'a') as f: 185 | for wallet in wallets: 186 | f.write(f"{wallet}\n") 187 | 188 | print(f"[🐲] {len(wallets)} trades successfully saved to {filename}") 189 | -------------------------------------------------------------------------------- /Dragon/traders.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | import random 4 | import tls_client 5 | import cloudscraper 6 | from fake_useragent import UserAgent 7 | from concurrent.futures import ThreadPoolExecutor, as_completed 8 | from collections import defaultdict 9 | 10 | ua = UserAgent(os='linux', browsers=['firefox']) 11 | 12 | class TopTraders: 13 | 14 | def __init__(self): 15 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 16 | self.cloudScraper = cloudscraper.create_scraper() 17 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 18 | self.allData = {} 19 | self.allAddresses = set() 20 | self.addressFrequency = defaultdict(int) 21 | self.totalTraders = 0 22 | self.proxyPosition = 0 23 | 24 | def randomise(self): 25 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 26 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 27 | 28 | parts = self.identifier.split('_') 29 | identifier, version, *rest = parts 30 | other = rest[0] if rest else None 31 | 32 | os = 'windows' 33 | if identifier == 'opera': 34 | identifier = 'chrome' 35 | elif version == 'ios': 36 | os = 'ios' 37 | else: 38 | os = 'windows' 39 | 40 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 41 | 42 | self.headers = { 43 | 'Host': 'gmgn.ai', 44 | 'accept': 'application/json, text/plain, */*', 45 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 46 | 'dnt': '1', 47 | 'priority': 'u=1, i', 48 | 'referer': 'https://gmgn.ai/?chain=sol', 49 | 'user-agent': self.user_agent 50 | } 51 | 52 | 53 | def loadProxies(self): 54 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 55 | proxies = file.read().splitlines() 56 | 57 | formatted_proxies = [] 58 | for proxy in proxies: 59 | if ':' in proxy: 60 | parts = proxy.split(':') 61 | if len(parts) == 4: 62 | ip, port, username, password = parts 63 | formatted_proxies.append({ 64 | 'http': f"http://{username}:{password}@{ip}:{port}", 65 | 'https': f"http://{username}:{password}@{ip}:{port}" 66 | }) 67 | else: 68 | formatted_proxies.append({ 69 | 'http': f"http://{proxy}", 70 | 'https': f"http://{proxy}" 71 | }) 72 | else: 73 | formatted_proxies.append(f"http://{proxy}") 74 | return formatted_proxies 75 | 76 | def configureProxy(self, proxy): 77 | if isinstance(proxy, dict): 78 | self.sendRequest.proxies = { 79 | 'http': proxy.get('http'), 80 | 'https': proxy.get('https') 81 | } 82 | elif isinstance(proxy, str): 83 | self.sendRequest.proxies = { 84 | 'http': proxy, 85 | 'https': proxy 86 | } 87 | else: 88 | self.sendRequest.proxies = None 89 | return proxy 90 | 91 | def getNextProxy(self): 92 | proxies = self.loadProxies() 93 | proxy = proxies[self.proxyPosition % len(proxies)] 94 | self.proxyPosition += 1 95 | return proxy 96 | 97 | def fetchTopTraders(self, contractAddress: str, useProxies): 98 | url = f"https://gmgn.ai/defi/quotation/v1/tokens/top_traders/sol/{contractAddress}?orderby=profit&direction=desc" 99 | retries = 3 100 | 101 | for attempt in range(retries): 102 | try: 103 | self.randomise() 104 | proxy = self.getNextProxy() if useProxies else None 105 | self.configureProxy(proxy) 106 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 107 | data = response.json().get('data', None) 108 | 109 | if data: 110 | return data 111 | except Exception as e: 112 | print(f"[🐲] Error fetching data on attempt, trying backup... {e}") 113 | finally: 114 | self.randomise() 115 | try: 116 | proxy = self.getNextProxy() if useProxies else None 117 | proxies = {'http': proxy, 'https': proxy} if proxy else None 118 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 119 | data = response.json().get('data', None) 120 | if data: 121 | return data 122 | except Exception as e: 123 | print(f"[🐲] Backup scraper failed, retrying...") 124 | 125 | time.sleep(1) 126 | 127 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 128 | return [] 129 | 130 | def topTraderData(self, contractAddresses, threads, useProxies): 131 | with ThreadPoolExecutor(max_workers=threads) as executor: 132 | futures = {executor.submit(self.fetchTopTraders, address, useProxies): address for address in contractAddresses} 133 | 134 | for future in as_completed(futures): 135 | contract_address = futures[future] 136 | response = future.result() 137 | 138 | self.allData[contract_address] = {} 139 | self.totalTraders += len(response) 140 | 141 | for top_trader in response: 142 | multiplier_value = top_trader['profit_change'] 143 | 144 | if multiplier_value: 145 | address = top_trader['address'] 146 | self.addressFrequency[address] += 1 147 | self.allAddresses.add(address) 148 | 149 | bought_usd = f"${top_trader['total_cost']:,.2f}" 150 | total_profit = f"${top_trader['realized_profit']:,.2f}" 151 | unrealized_profit = f"${top_trader['unrealized_profit']:,.2f}" 152 | multiplier = f"{multiplier_value:.2f}x" 153 | buys = f"{top_trader['buy_tx_count_cur']}" 154 | sells = f"{top_trader['sell_tx_count_cur']}" 155 | 156 | self.allData[address] = { 157 | "boughtUsd": bought_usd, 158 | "totalProfit": total_profit, 159 | "unrealizedProfit": unrealized_profit, 160 | "multiplier": multiplier, 161 | "buys": buys, 162 | "sells": sells 163 | } 164 | 165 | repeatedAddresses = [address for address, count in self.addressFrequency.items() if count > 1] 166 | 167 | identifier = self.shorten(list(self.allAddresses)[0]) 168 | 169 | with open(f'Dragon/data/Solana/TopTraders/allTopAddresses_{identifier}.txt', 'w') as av: 170 | for address in self.allAddresses: 171 | av.write(f"{address}\n") 172 | 173 | if len(repeatedAddresses) != 0: 174 | with open(f'Dragon/data/Solana/TopTraders/repeatedTopTraders_{identifier}.txt', 'w') as ra: 175 | for address in repeatedAddresses: 176 | ra.write(f"{address}\n") 177 | print(f"[🐲] Saved {len(repeatedAddresses)} repeated addresses to repeatedTopTraders_{identifier}.txt") 178 | 179 | with open(f'Dragon/data/Solana/TopTraders/topTraders_{identifier}.json', 'w') as tt: 180 | json.dump(self.allData, tt, indent=4) 181 | 182 | print(f"[🐲] Saved {self.totalTraders} top traders for {len(contractAddresses)} tokens to allTopAddresses_{identifier}.txt") 183 | print(f"[🐲] Saved {len(self.allAddresses)} top trader addresses to topTraders_{identifier}.json") 184 | 185 | return 186 | -------------------------------------------------------------------------------- /Dragon/copyWalletFinder.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tls_client 3 | import cloudscraper 4 | import concurrent.futures 5 | from fake_useragent import UserAgent 6 | from threading import Lock 7 | import time 8 | import base64 9 | 10 | ua = UserAgent(os='linux', browsers=['firefox']) 11 | 12 | class CopyTradeWalletFinder: 13 | 14 | def __init__(self): 15 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 16 | self.cloudScraper = cloudscraper.create_scraper() 17 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 18 | self.lock = Lock() 19 | self.proxyPosition = 0 20 | 21 | def randomise(self): 22 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 23 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 24 | 25 | parts = self.identifier.split('_') 26 | identifier, version, *rest = parts 27 | other = rest[0] if rest else None 28 | 29 | os = 'windows' 30 | if identifier == 'opera': 31 | identifier = 'chrome' 32 | elif version == 'ios': 33 | os = 'ios' 34 | else: 35 | os = 'windows' 36 | 37 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 38 | 39 | self.headers = { 40 | 'Host': 'gmgn.ai', 41 | 'accept': 'application/json, text/plain, */*', 42 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 43 | 'dnt': '1', 44 | 'priority': 'u=1, i', 45 | 'referer': 'https://gmgn.ai/?chain=sol', 46 | 'user-agent': self.user_agent 47 | } 48 | 49 | def loadProxies(self): 50 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 51 | proxies = file.read().splitlines() 52 | 53 | formatted_proxies = [] 54 | for proxy in proxies: 55 | if ':' in proxy: 56 | parts = proxy.split(':') 57 | if len(parts) == 4: 58 | ip, port, username, password = parts 59 | formatted_proxies.append({ 60 | 'http': f"http://{username}:{password}@{ip}:{port}", 61 | 'https': f"http://{username}:{password}@{ip}:{port}" 62 | }) 63 | else: 64 | formatted_proxies.append({ 65 | 'http': f"http://{proxy}", 66 | 'https': f"http://{proxy}" 67 | }) 68 | else: 69 | formatted_proxies.append(f"http://{proxy}") 70 | return formatted_proxies 71 | 72 | def configureProxy(self, proxy): 73 | if isinstance(proxy, dict): 74 | self.sendRequest.proxies = proxy 75 | elif proxy: 76 | self.sendRequest.proxies = { 77 | 'http': proxy, 78 | 'https': proxy 79 | } 80 | return proxy 81 | 82 | def getNextProxy(self): 83 | proxies = self.loadProxies() 84 | proxy = proxies[self.proxyPosition % len(proxies)] 85 | self.proxyPosition += 1 86 | return proxy 87 | 88 | def request(self, url: str, useProxies): 89 | headers = { 90 | "User-Agent": ua.random 91 | } 92 | retries = 3 93 | 94 | for attempt in range(retries): 95 | self.randomise() 96 | try: 97 | proxy = self.getNextProxy() if useProxies else None 98 | self.configureProxy(proxy) 99 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 100 | if response.status_code == 200: 101 | data = response.json()['data']['history'] 102 | paginator = response.json()['data'].get('next') 103 | return data, paginator 104 | except Exception: 105 | print(f"[🐲] Error fetching data, trying backup...") 106 | finally: 107 | self.randomise() 108 | try: 109 | proxy = self.getNextProxy() if useProxies else None 110 | proxies = {'http': proxy, 'https': proxy} if proxy else None 111 | response = self.cloudScraper.get(url, headers=self.headers, allow_redirects=True, proxies=proxies) 112 | if response.status_code == 200: 113 | data = response.json()['data']['history'] 114 | paginator = response.json()['data'].get('next') 115 | return data, paginator 116 | except Exception: 117 | print(f"[🐲] Backup scraper failed, retrying...") 118 | 119 | time.sleep(1) 120 | 121 | print(f"[🐲] Failed to fetch data after {retries} attempts for URL: {url}") 122 | return [], None 123 | 124 | def findWallets(self, contractAddress: str, targetMaker: str, threads: int, useProxies): 125 | base_url = f"https://gmgn.ai/defi/quotation/v1/trades/sol/{contractAddress}?limit=100&event=buy" 126 | paginator = None 127 | urls = [] 128 | 129 | print(f"\n[🐲] Starting... please wait.\n") 130 | 131 | while True: 132 | self.randomise() 133 | url = f"{base_url}&cursor={paginator}" if paginator else base_url 134 | urls.append(url) 135 | try: 136 | proxy = self.getNextProxy() if useProxies else None 137 | self.configureProxy(proxy) 138 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 139 | if response.status_code != 200: 140 | raise Exception("Error in initial request") 141 | except Exception: 142 | self.randomise() 143 | print(f"[🐲] Error fetching data, trying backup..") 144 | proxy = self.getNextProxy() if useProxies else None 145 | proxies = {'http': proxy, 'https': proxy} if proxy else None 146 | response = self.cloudScraper.get(url, headers=self.headers, allow_redirects=True, proxies=proxies) 147 | paginator = response.json()['data'].get('next') 148 | 149 | if paginator: 150 | print(f"[🐲] Page: {base64.b64decode(paginator).decode('utf-8')}", end="\r") 151 | 152 | if not paginator: 153 | break 154 | 155 | found_target = False 156 | temp_makers = [] 157 | 158 | with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: 159 | future_to_url = {executor.submit(self.request, url, useProxies): url for url in urls} 160 | 161 | for future in concurrent.futures.as_completed(future_to_url): 162 | history, _ = future.result() 163 | 164 | with self.lock: 165 | for maker in history: 166 | event = maker['event'] 167 | txns = maker.get('total_trade', 0) 168 | if event == "buy" and txns < 200: 169 | if maker['maker'] == targetMaker: 170 | found_target = True 171 | break 172 | 173 | if maker['maker'] not in temp_makers: 174 | temp_makers.append(maker['maker']) 175 | 176 | if found_target: 177 | break 178 | 179 | makers = temp_makers[-10:] 180 | 181 | if found_target: 182 | print(f"[🐲] Found target maker: {targetMaker}") 183 | print(f"[🐲] The first 10 makers ahead of target maker:") 184 | for idx, maker in enumerate(makers, 1): 185 | print(f"{idx}. {maker}") 186 | else: 187 | print(f"[🐲] Target maker {targetMaker} not found.") 188 | 189 | filename = f"wallets_after_{self.shorten(targetMaker)}_{random.randint(1111, 9999)}.txt" 190 | with open(f"Dragon/data/Solana/CopyWallets/{filename}", "w") as file: 191 | for maker in makers: 192 | file.write(f"{maker}\n") 193 | print(f"[🐲] Saved the 10 makers after {targetMaker} to {filename}") 194 | -------------------------------------------------------------------------------- /Dragon/earlyBuyers.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | import random 4 | import tls_client 5 | import cloudscraper 6 | from fake_useragent import UserAgent 7 | from concurrent.futures import ThreadPoolExecutor, as_completed 8 | from collections import defaultdict 9 | 10 | class EarlyBuyers: 11 | 12 | def __init__(self): 13 | self.cloudScraper = cloudscraper.create_scraper() 14 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 15 | self.allData = {} 16 | self.allAddresses = set() 17 | self.addressFrequency = defaultdict(int) 18 | self.totalBuyers = 0 19 | self.proxyPosition = 0 20 | 21 | def randomise(self): 22 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 23 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 24 | 25 | parts = self.identifier.split('_') 26 | identifier, version, *rest = parts 27 | other = rest[0] if rest else None 28 | 29 | os = 'windows' 30 | if identifier == 'opera': 31 | identifier = 'chrome' 32 | elif version == 'ios': 33 | os = 'ios' 34 | else: 35 | os = 'windows' 36 | 37 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 38 | 39 | self.headers = { 40 | 'Host': 'gmgn.ai', 41 | 'accept': 'application/json, text/plain, */*', 42 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 43 | 'dnt': '1', 44 | 'priority': 'u=1, i', 45 | 'referer': 'https://gmgn.ai/?chain=sol', 46 | 'user-agent': self.user_agent 47 | } 48 | 49 | def loadProxies(self): 50 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 51 | proxies = file.read().splitlines() 52 | 53 | formatted_proxies = [] 54 | for proxy in proxies: 55 | if ':' in proxy: 56 | parts = proxy.split(':') 57 | if len(parts) == 4: 58 | ip, port, username, password = parts 59 | formatted_proxies.append({ 60 | 'http': f"http://{username}:{password}@{ip}:{port}", 61 | 'https': f"http://{username}:{password}@{ip}:{port}" 62 | }) 63 | else: 64 | formatted_proxies.append({ 65 | 'http': f"http://{proxy}", 66 | 'https': f"http://{proxy}" 67 | }) 68 | else: 69 | formatted_proxies.append(f"http://{proxy}") 70 | return formatted_proxies 71 | 72 | def configureProxy(self, proxy): 73 | if isinstance(proxy, dict): 74 | self.sendRequest.proxies = { 75 | 'http': proxy.get('http'), 76 | 'https': proxy.get('https') 77 | } 78 | elif isinstance(proxy, str): 79 | self.sendRequest.proxies = { 80 | 'http': proxy, 81 | 'https': proxy 82 | } 83 | else: 84 | self.sendRequest.proxies = None 85 | return proxy 86 | 87 | def getNextProxy(self): 88 | proxies = self.loadProxies() 89 | proxy = proxies[self.proxyPosition % len(proxies)] 90 | self.proxyPosition += 1 91 | return proxy 92 | 93 | def fetchEarlyBuyers(self, contractAddress: str, useProxies, buyers): 94 | url = f"https://gmgn.ai/defi/quotation/v1/trades/sol/{contractAddress}?revert=true" 95 | retries = 3 96 | 97 | for attempt in range(retries): 98 | try: 99 | self.randomise() 100 | proxy = self.getNextProxy() if useProxies else None 101 | self.configureProxy(proxy) 102 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 103 | data = response.json().get('data', {}).get('history', []) 104 | if isinstance(data, list): 105 | for item in data: 106 | if item.get('event') == "buy" and "creator" not in item.get('maker_token_tags'): 107 | return data 108 | except Exception as e: 109 | print(f"[🐲] Error fetching data on attempt, trying backup... {e}") 110 | finally: 111 | self.randomise() 112 | try: 113 | proxy = self.getNextProxy() if useProxies else None 114 | proxies = {'http': proxy, 'https': proxy} if proxy else None 115 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 116 | data = response.json().get('data', {}).get('history', []) 117 | if isinstance(data, list): 118 | for item in data: 119 | if item.get('event') == "buy" and "creator" not in item.get('maker_token_tags'): 120 | return data 121 | except Exception as e: 122 | print(f"[🐲] Backup scraper failed, retrying...") 123 | time.sleep(1) 124 | 125 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 126 | return [] 127 | 128 | def earlyBuyersdata(self, contractAddresses, threads, useProxies, buyers): 129 | with ThreadPoolExecutor(max_workers=threads) as executor: 130 | futures = {executor.submit(self.fetchEarlyBuyers, address, useProxies, buyers): address for address in contractAddresses} 131 | 132 | for future in as_completed(futures): 133 | contract_address = futures[future] 134 | response = future.result() 135 | limited_response = response[:buyers] if len(response) >= buyers else response 136 | 137 | if contract_address not in self.allData: 138 | self.allData[contract_address] = [] 139 | 140 | self.totalBuyers += len(limited_response) 141 | 142 | for earlyBuyer in limited_response: 143 | address = earlyBuyer['maker'] 144 | print(address) 145 | 146 | if address: 147 | self.addressFrequency[address] += 1 148 | self.allAddresses.add(address) 149 | 150 | bought_usd = f"${earlyBuyer['amount_usd']:,.2f}" if earlyBuyer['amount_usd'] is not None else "?" 151 | total_profit = f"${earlyBuyer['realized_profit']:,.2f}" if earlyBuyer['realized_profit'] is not None else "?" 152 | unrealized_profit = f"${earlyBuyer['unrealized_profit']:,.2f}" if earlyBuyer['unrealized_profit'] is not None else "?" 153 | trades = f"{earlyBuyer['total_trade']}" if earlyBuyer['total_trade'] is not None else "?" 154 | 155 | buyer_data = { 156 | "boughtUsd": bought_usd, 157 | "totalProfit": total_profit, 158 | "unrealizedProfit": unrealized_profit, 159 | "trades": trades, 160 | } 161 | self.allData[contract_address].append({address: buyer_data}) 162 | 163 | repeatedAddresses = [address for address, count in self.addressFrequency.items() if count > 1] 164 | identifier = self.shorten(list(self.allAddresses)[0]) 165 | 166 | with open(f'Dragon/data/Solana/EarlyBuyers/allTopAddresses_{identifier}.txt', 'w') as av: 167 | for address in self.allAddresses: 168 | av.write(f"{address}\n") 169 | 170 | if len(repeatedAddresses) != 0: 171 | with open(f'Dragon/data/Solana/EarlyBuyers/repeatedEarlyBuyers_{identifier}.txt', 'w') as ra: 172 | for address in repeatedAddresses: 173 | ra.write(f"{address}\n") 174 | print(f"[🐲] Saved {len(repeatedAddresses)} repeated addresses to repeatedEarlyBuyers_{identifier}.txt") 175 | 176 | with open(f'Dragon/data/Solana/EarlyBuyers/EarlyBuyers_{identifier}.json', 'w') as tt: 177 | json.dump(self.allData, tt, indent=4) 178 | 179 | print(f"[🐲] Saved {self.totalBuyers} early buyers for {len(contractAddresses)} tokens to allTopAddresses_{identifier}.txt") 180 | print(f"[🐲] Saved {len(self.allAddresses)} early buyer addresses to EarlyBuyers_{identifier}.json") 181 | 182 | return 183 | -------------------------------------------------------------------------------- /Dragon/gmgn.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | import tls_client 4 | import cloudscraper 5 | from fake_useragent import UserAgent 6 | from concurrent.futures import ThreadPoolExecutor, as_completed 7 | 8 | class GMGN: 9 | 10 | def __init__(self): 11 | self.cloudScraper = cloudscraper.create_scraper() 12 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 13 | self.proxyPosition = 0 14 | 15 | def randomise(self): 16 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 17 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 18 | 19 | parts = self.identifier.split('_') 20 | identifier, version, *rest = parts 21 | other = rest[0] if rest else None 22 | 23 | os = 'windows' 24 | if identifier == 'opera': 25 | identifier = 'chrome' 26 | elif version == 'ios': 27 | os = 'ios' 28 | else: 29 | os = 'windows' 30 | 31 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 32 | 33 | self.headers = { 34 | 'Host': 'gmgn.ai', 35 | 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 36 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 37 | 'dnt': '1', 38 | 'priority': 'u=0, i', 39 | 'referer': 'https://gmgn.ai/?chain=sol', 40 | 'user-agent': self.user_agent 41 | } 42 | 43 | def loadProxies(self): 44 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 45 | proxies = file.read().splitlines() 46 | 47 | formatted_proxies = [] 48 | for proxy in proxies: 49 | if ':' in proxy: 50 | parts = proxy.split(':') 51 | if len(parts) == 4: 52 | ip, port, username, password = parts 53 | formatted_proxies.append({ 54 | 'http': f"http://{username}:{password}@{ip}:{port}", 55 | 'https': f"http://{username}:{password}@{ip}:{port}" 56 | }) 57 | else: 58 | formatted_proxies.append({ 59 | 'http': f"http://{proxy}", 60 | 'https': f"http://{proxy}" 61 | }) 62 | else: 63 | formatted_proxies.append(f"http://{proxy}") 64 | return formatted_proxies 65 | 66 | def configureProxy(self, proxy): 67 | if isinstance(proxy, dict): 68 | self.sendRequest.proxies = { 69 | 'http': proxy.get('http'), 70 | 'https': proxy.get('https') 71 | } 72 | elif isinstance(proxy, str): 73 | self.sendRequest.proxies = { 74 | 'http': proxy, 75 | 'https': proxy 76 | } 77 | else: 78 | self.sendRequest.proxies = None 79 | return proxy 80 | 81 | def getNextProxy(self): 82 | proxies = self.loadProxies() 83 | proxy = proxies[self.proxyPosition % len(proxies)] 84 | self.proxyPosition += 1 85 | return proxy 86 | 87 | def newToken(self, siteChoice): 88 | if siteChoice == "Pump.Fun": 89 | url = "https://gmgn.ai/defi/quotation/v1/rank/sol/pump/1h?limit=100&orderby=created_timestamp&direction=desc&new_creation=true" 90 | else: 91 | url = "https://gmgn.ai/defi/quotation/v1/rank/sol/moonshot/1h?limit=100&orderby=created_timestamp&direction=desc&new_creation=true" 92 | return url 93 | 94 | def completingToken(self, siteChoice): 95 | if siteChoice == "Pump.Fun": 96 | url = "https://gmgn.ai/defi/quotation/v1/rank/sol/pump/1h?limit=100&orderby=progress&direction=desc&pump=true" 97 | else: 98 | url = "https://gmgn.ai/defi/quotation/v1/rank/sol/moonshot/1h?limit=100&orderby=progress&direction=desc&moonshot=true" 99 | return url 100 | 101 | def soaringToken(self, siteChoice): 102 | if siteChoice == "Pump.Fun": 103 | url = "https://gmgn.ai/defi/quotation/v1/rank/sol/pump/1h?limit=100&orderby=market_cap_5m&direction=desc&soaring=true" 104 | else: 105 | url = "https://gmgn.ai/defi/quotation/v1/rank/sol/moonshot/1h?limit=100&orderby=market_cap_5m&direction=desc&soaring=true" 106 | return url 107 | 108 | def bondedToken(self, siteChoice): 109 | if siteChoice == "Pump.Fun": 110 | url = "https://gmgn.ai/defi/quotation/v1/pairs/sol/new_pairs/1h?limit=100&orderby=market_cap&direction=desc&launchpad=pump&period=1h&filters[]=not_honeypot&filters[]=pump" 111 | else: 112 | url = "https://gmgn.ai/defi/quotation/v1/pairs/sol/new_pairs/1h?limit=100&orderby=open_timestamp&direction=desc&launchpad=moonshot&period=1h&filters[]=not_honeypot&filters[]=moonshot" 113 | return url 114 | 115 | def fetchContracts(self, urlIndicator, useProxies, siteChoice): 116 | retries = 3 117 | 118 | contracts = set() 119 | 120 | if urlIndicator == "NewToken": 121 | url = self.newToken(siteChoice) 122 | elif urlIndicator == "CompletingToken": 123 | url = self.completingToken(siteChoice) 124 | elif urlIndicator == "SoaringToken": 125 | url = self.soaringToken(siteChoice) 126 | else: 127 | url = self.bondedToken(siteChoice) 128 | 129 | for attempt in range(retries): 130 | try: 131 | self.randomise() 132 | proxy = self.getNextProxy() if useProxies else None 133 | self.configureProxy(proxy) 134 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 135 | if response.status_code == 200: 136 | 137 | if urlIndicator == "BondedToken": 138 | data = response.json().get('data', {}).get('pairs', []) 139 | 140 | for item in data: 141 | if item.get('base_address') and item.get('base_address') != "": 142 | contract = item.get('base_address') 143 | contracts.add(contract) 144 | else: 145 | data = response.json().get('data', {}).get('rank', []) 146 | 147 | for item in data: 148 | if item.get('address') and item.get('address') != "": 149 | contract = item.get('address') 150 | contracts.add(contract) 151 | except Exception as e: 152 | print(f"[🐲] Error fetching data on attempt, trying backup... {e}") 153 | finally: 154 | self.randomise() 155 | try: 156 | proxy = self.getNextProxy() if useProxies else None 157 | proxies = {'http': proxy, 'https': proxy} if proxy else None 158 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 159 | 160 | if response.status_code == 200: 161 | if urlIndicator == "BondedToken": 162 | data = response.json().get('data', {}).get('pairs', []) 163 | else: 164 | data = response.json().get('data', {}).get('rank', []) 165 | for item in data: 166 | if item.get('address') and item.get('address') != "": 167 | contract = item.get('address') 168 | contracts.add(contract) 169 | except Exception as e: 170 | print(f"[🐲] Backup scraper failed, retrying... {e}") 171 | time.sleep(1) 172 | 173 | return list(contracts) 174 | 175 | def contractsData(self, urlIndicator, threads, useProxies, siteChoice): 176 | contract_addresses = set() 177 | 178 | with ThreadPoolExecutor(max_workers=threads) as executor: 179 | futures = [executor.submit(self.fetchContracts, urlIndicator, useProxies, siteChoice) for _ in range(threads)] 180 | for future in as_completed(futures): 181 | contract_addresses.update(future.result()) 182 | 183 | identifier = self.shorten(list(contract_addresses)[0]) 184 | 185 | with open(f"Dragon/data/GMGN/{siteChoice}/{urlIndicator}/contracts_{identifier}.txt", "w") as file: 186 | for address in contract_addresses: 187 | file.write(f"{address}\n") 188 | print(f"[🐲] {len(contract_addresses)} contract addresses have been written to Dragon/data/GMGN/{urlIndicator}/contracts_{identifier}.txt") 189 | -------------------------------------------------------------------------------- /Dragon/ethWallet.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import random 3 | import tls_client 4 | import cloudscraper 5 | from fake_useragent import UserAgent 6 | from concurrent.futures import ThreadPoolExecutor, as_completed 7 | import time 8 | 9 | ua = UserAgent(os='linux', browsers=['firefox']) 10 | 11 | class EthBulkWalletChecker: 12 | 13 | def __init__(self): 14 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 15 | self.cloudScraper = cloudscraper.create_scraper() 16 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 17 | self.skippedWallets = 0 18 | self.results = [] 19 | 20 | def getTokenDistro(self, wallet: str): 21 | url = f"https://gmgn.ai/defi/quotation/v1/rank/eth/wallets/{wallet}/unique_token_7d?interval=30d" 22 | headers = { 23 | "User-Agent": ua.random 24 | } 25 | retries = 3 26 | tokenDistro = [] 27 | 28 | for attempt in range(retries): 29 | try: 30 | response = self.sendRequest.get(url, headers=headers).json() 31 | tokenDistro = response['data']['tokens'] 32 | if tokenDistro: 33 | break 34 | except Exception: 35 | time.sleep(1) 36 | 37 | try: 38 | response = self.cloudScraper.get(url, headers=headers).json() 39 | tokenDistro = response['data']['tokens'] 40 | if tokenDistro: 41 | break 42 | except Exception: 43 | time.sleep(1) 44 | 45 | if not tokenDistro: 46 | return { 47 | "No Token Distribution Data": None 48 | } 49 | 50 | FiftyPercentOrMore = 0 51 | ZeroToFifty = 0 52 | FiftyTo100 = 0 53 | TwoToFour = 0 54 | FiveToSix = 0 55 | SixPlus = 0 56 | NegativeToFifty = 0 57 | 58 | for profit in tokenDistro: 59 | total_profit_pnl = profit.get('total_profit_pnl') 60 | if total_profit_pnl is not None: 61 | profitMultiplier = total_profit_pnl * 100 62 | 63 | if profitMultiplier <= -50: 64 | FiftyPercentOrMore += 1 65 | elif -50 < profitMultiplier < 0: 66 | NegativeToFifty += 1 67 | elif 0 <= profitMultiplier < 50: 68 | ZeroToFifty += 1 69 | elif 50 <= profitMultiplier < 199: 70 | FiftyTo100 += 1 71 | elif 200 <= profitMultiplier < 499: 72 | TwoToFour += 1 73 | elif 500 <= profitMultiplier < 600: 74 | FiveToSix += 1 75 | elif profitMultiplier >= 600: 76 | SixPlus += 1 77 | 78 | return { 79 | "-50% +": FiftyPercentOrMore, 80 | "0% - -50%": NegativeToFifty, 81 | "0 - 50%": ZeroToFifty, 82 | "50% - 199%": FiftyTo100, 83 | "200% - 499%": TwoToFour, 84 | "500% - 600%": FiveToSix, 85 | "600% +": SixPlus 86 | } 87 | 88 | def getWalletData(self, wallet: str, skipWallets: bool): 89 | url = f"https://gmgn.ai/defi/quotation/v1/smartmoney/eth/walletNew/{wallet}?period=7d" 90 | headers = { 91 | "User-Agent": ua.random 92 | } 93 | retries = 3 94 | 95 | for attempt in range(retries): 96 | try: 97 | response = self.sendRequest.get(url, headers=headers) 98 | if response.status_code == 200: 99 | data = response.json() 100 | if data['msg'] == "success": 101 | data = data['data'] 102 | 103 | if skipWallets: 104 | if 'buy_30d' in data and isinstance(data['buy_30d'], (int, float)) and data['buy_30d'] > 0 and float(data['sol_balance']) >= 1.0: 105 | return self.processWalletData(wallet, data, headers) 106 | else: 107 | self.skippedWallets += 1 108 | print(f"[🐲] Skipped {self.skippedWallets} wallets", end="\r") 109 | return None 110 | else: 111 | return self.processWalletData(wallet, data, headers) 112 | 113 | except Exception as e: 114 | print(f"[🐲] Error fetching data, trying backup...") 115 | 116 | try: 117 | response = self.cloudScraper.get(url, headers=headers) 118 | if response.status_code == 200: 119 | data = response.json() 120 | if data['msg'] == "success": 121 | data = data['data'] 122 | 123 | if skipWallets: 124 | if 'buy_30d' in data and isinstance(data['buy_30d'], (int, float)) and data['buy_30d'] > 0 and float(data['sol_balance']) >= 1.0: 125 | return self.processWalletData(wallet, data, headers) 126 | else: 127 | self.skippedWallets += 1 128 | print(f"[🐲] Skipped {self.skippedWallets} wallets", end="\r") 129 | return None 130 | else: 131 | return self.processWalletData(wallet, data, headers) 132 | 133 | except Exception: 134 | print(f"[🐲] Backup scraper failed, retrying...") 135 | 136 | time.sleep(1) 137 | 138 | print(f"[🐲] Failed to fetch data for wallet {wallet} after {retries} attempts.") 139 | return None 140 | 141 | 142 | def processWalletData(self, wallet, data, headers): 143 | direct_link = f"https://gmgn.ai/eth/address/{wallet}" 144 | total_profit_percent = f"{data['total_profit_pnl'] * 100:.2f}%" if data['total_profit_pnl'] is not None else "error" 145 | realized_profit_7d_usd = f"${data['realized_profit_7d']:,.2f}" if data['realized_profit_7d'] is not None else "error" 146 | realized_profit_30d_usd = f"${data['realized_profit_30d']:,.2f}" if data['realized_profit_30d'] is not None else "error" 147 | winrate_7d = f"{data['winrate'] * 100:.2f}%" if data['winrate'] is not None else "?" 148 | sol_balance = f"{float(data['sol_balance']):.2f}" if data['sol_balance'] is not None else "?" 149 | 150 | try: 151 | winrate_30data = self.sendRequest.get(f"https://gmgn.ai/defi/quotation/v1/smartmoney/eth/walletNew/{wallet}?period=30d", headers=headers).json()['data'] 152 | winrate_30d = f"{winrate_30data['winrate'] * 100:.2f}%" if winrate_30data['winrate'] is not None else "?" 153 | except Exception as e: 154 | print(f"[🐲] Error fetching winrate 30d data, trying backup..") 155 | winrate_30data = self.cloudScraper.get(f"https://gmgn.ai/defi/quotation/v1/smartmoney/eth/walletNew/{wallet}?period=30d", headers=headers).json()['data'] 156 | winrate_30d = f"{winrate_30data['winrate'] * 100:.2f}%" if winrate_30data['winrate'] is not None else "?" 157 | 158 | if "Skipped" in data.get("tags", []): 159 | return { 160 | "wallet": wallet, 161 | "tags": ["Skipped"], 162 | "directLink": direct_link 163 | } 164 | tokenDistro = self.getTokenDistro(wallet) 165 | 166 | try: 167 | tags = data['tags'] 168 | except Exception: 169 | tags = "?" 170 | 171 | return { 172 | "wallet": wallet, 173 | "totalProfitPercent": total_profit_percent, 174 | "7dUSDProfit": realized_profit_7d_usd, 175 | "30dUSDProfit": realized_profit_30d_usd, 176 | "winrate_7d": winrate_7d, 177 | "winrate_30d": winrate_30d, 178 | "tags": tags, 179 | "sol_balance": sol_balance, 180 | "token_distribution": tokenDistro if tokenDistro else {}, 181 | "directLink": direct_link 182 | } 183 | 184 | def fetchWalletData(self, wallets, threads, skipWallets): 185 | with ThreadPoolExecutor(max_workers=threads) as executor: 186 | futures = {executor.submit(self.getWalletData, wallet.strip(), skipWallets): wallet for wallet in wallets} 187 | for future in as_completed(futures): 188 | result = future.result() 189 | if result is not None: 190 | self.results.append(result) 191 | 192 | result_dict = {} 193 | for result in self.results: 194 | wallet = result.get('wallet') 195 | if wallet: 196 | result_dict[wallet] = result 197 | result.pop('wallet', None) 198 | else: 199 | print(f"[🐲] Missing 'wallet' key in result: {result}") 200 | 201 | if self.results and 'token_distribution' in self.results[0]: 202 | token_dist_keys = self.results[0]['token_distribution'].keys() 203 | else: 204 | token_dist_keys = [] 205 | 206 | identifier = self.shorten(list(result_dict)[0]) 207 | filename = f"{identifier}_{random.randint(1111, 9999)}.csv" 208 | 209 | path = f"Dragon/data/Ethereum/BulkWallet/wallets_{filename}" 210 | 211 | with open(path, 'w', newline='') as outfile: 212 | writer = csv.writer(outfile) 213 | 214 | header = ['Identifier'] + list(next(iter(result_dict.values())).keys()) 215 | 216 | if 'token_distribution' in header: 217 | header.remove('token_distribution') 218 | 219 | header.extend(token_dist_keys) 220 | 221 | writer.writerow(header) 222 | 223 | for key, value in result_dict.items(): 224 | row = [key] 225 | for h in header[1:]: 226 | if h in value: 227 | row.append(value[h]) 228 | elif 'token_distribution' in value and h in value['token_distribution']: 229 | row.append(value['token_distribution'][h]) 230 | else: 231 | row.append(None) 232 | writer.writerow(row) 233 | 234 | print(f"[🐲] Saved data for {len(result_dict.items())} wallets to {filename}") 235 | -------------------------------------------------------------------------------- /Dragon/holders.py: -------------------------------------------------------------------------------- 1 | import json 2 | import tls_client 3 | import cloudscraper 4 | from fake_useragent import UserAgent 5 | from concurrent.futures import ThreadPoolExecutor, as_completed 6 | from collections import defaultdict 7 | import time 8 | import random 9 | 10 | ua = UserAgent(os='linux', browsers=['firefox']) 11 | 12 | class TopHolders: 13 | 14 | def __init__(self): 15 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 16 | self.cloudScraper = cloudscraper.create_scraper() 17 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 18 | self.allData = {} 19 | self.allAddresses = set() 20 | self.addressFrequency = defaultdict(int) 21 | self.totalTraders = 0 22 | self.proxyPosition = 0 23 | 24 | def randomise(self): 25 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 26 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 27 | 28 | parts = self.identifier.split('_') 29 | identifier, version, *rest = parts 30 | other = rest[0] if rest else None 31 | 32 | os = 'windows' 33 | if identifier == 'opera': 34 | identifier = 'chrome' 35 | elif version == 'ios': 36 | os = 'ios' 37 | else: 38 | os = 'windows' 39 | 40 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 41 | 42 | self.headers = { 43 | 'Host': 'gmgn.ai', 44 | 'accept': 'application/json, text/plain, */*', 45 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 46 | 'dnt': '1', 47 | 'priority': 'u=1, i', 48 | 'referer': 'https://gmgn.ai/?chain=sol', 49 | 'user-agent': self.user_agent 50 | } 51 | 52 | def loadProxies(self): 53 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 54 | proxies = file.read().splitlines() 55 | 56 | formatted_proxies = [] 57 | for proxy in proxies: 58 | if ':' in proxy: 59 | parts = proxy.split(':') 60 | if len(parts) == 4: 61 | ip, port, username, password = parts 62 | formatted_proxies.append({ 63 | 'http': f"http://{username}:{password}@{ip}:{port}", 64 | 'https': f"http://{username}:{password}@{ip}:{port}" 65 | }) 66 | else: 67 | formatted_proxies.append({ 68 | 'http': f"http://{proxy}", 69 | 'https': f"http://{proxy}" 70 | }) 71 | else: 72 | formatted_proxies.append(f"http://{proxy}") 73 | return formatted_proxies 74 | 75 | def configureProxy(self, proxy): 76 | if isinstance(proxy, dict): 77 | self.sendRequest.proxies = { 78 | 'http': proxy.get('http'), 79 | 'https': proxy.get('https') 80 | } 81 | elif isinstance(proxy, str): 82 | self.sendRequest.proxies = { 83 | 'http': proxy, 84 | 'https': proxy 85 | } 86 | else: 87 | self.sendRequest.proxies = None 88 | return proxy 89 | 90 | def getNextProxy(self): 91 | proxies = self.loadProxies() 92 | proxy = proxies[self.proxyPosition % len(proxies)] 93 | self.proxyPosition += 1 94 | return proxy 95 | 96 | def getBondingCurve(self, contractAddress: str, useProxies): 97 | retries = 3 98 | url = f"https://gmgn.ai/defi/quotation/v1/tokens/sol/{contractAddress}" 99 | 100 | for attempt in range(retries): 101 | self.randomise() 102 | try: 103 | proxy = self.getNextProxy() if useProxies else None 104 | self.configureProxy(proxy) 105 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 106 | data = response.json().get('data', None) 107 | if data: 108 | try: 109 | bondingCurve = data['token']['pool_info']['pool_address'] 110 | except Exception: 111 | bondingCurve = "" 112 | return bondingCurve 113 | except Exception: 114 | print(f"[🐲] Error fetching data on attempt, trying backup") 115 | finally: 116 | self.randomise() 117 | try: 118 | proxy = self.getNextProxy() if useProxies else None 119 | proxies = {'http': proxy, 'https': proxy} if proxy else None 120 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 121 | data = response.json().get('data', None) 122 | if data: 123 | try: 124 | bondingCurve = data['token']['pool_info']['pool_address'] 125 | except Exception: 126 | bondingCurve = "" 127 | return bondingCurve 128 | except Exception as e: 129 | print(f"[🐲] Error fetching data on attempt, trying backup {e}") 130 | time.sleep(1) 131 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 132 | return "" 133 | 134 | 135 | def fetchTopHolders(self, contractAddress: str, useProxies): 136 | url = f"https://gmgn.ai/defi/quotation/v1/tokens/top_holders/sol/{contractAddress}?orderby=amount_percentage&direction=desc" 137 | retries = 3 138 | 139 | for attempt in range(retries): 140 | self.randomise() 141 | try: 142 | proxy = self.getNextProxy() if useProxies else None 143 | self.configureProxy(proxy) 144 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True) 145 | data = response.json().get('data', None) 146 | if data: 147 | return data 148 | except Exception as e: 149 | print(f"[🐲] Error fetching data on attempt, trying backup... {e}") 150 | finally: 151 | self.randomise() 152 | try: 153 | proxy = self.getNextProxy() if useProxies else None 154 | proxies = {'http': proxy, 'https': proxy} if proxy else None 155 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True) 156 | data = response.json().get('data', None) 157 | if data: 158 | return data 159 | except Exception as e: 160 | print(f"[🐲] Backup scraper failed, retrying... {e}") 161 | 162 | time.sleep(1) 163 | 164 | print(f"[🐲] Failed to fetch data after {retries} attempts.") 165 | return [] 166 | 167 | def topHolderData(self, contractAddresses, threads, useProxies): 168 | 169 | excludeAddress = ["5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM"] 170 | 171 | with ThreadPoolExecutor(max_workers=threads) as executor: 172 | futures = {executor.submit(self.fetchTopHolders, address, useProxies): address for address in contractAddresses} 173 | 174 | for future in as_completed(futures): 175 | contract_address = futures[future] 176 | response = future.result() 177 | 178 | bondingCurve = self.getBondingCurve(contract_address, useProxies) 179 | excludeAddress.append(bondingCurve) 180 | self.allData[contract_address] = {} 181 | self.totalTraders += len(response) 182 | 183 | for top_trader in response: 184 | 185 | if top_trader['address'] in excludeAddress or top_trader['cost_cur'] < 50: 186 | continue 187 | 188 | multiplier_value = top_trader['profit_change'] 189 | 190 | if multiplier_value: 191 | address = top_trader['address'] 192 | self.addressFrequency[address] += 1 193 | self.allAddresses.add(address) 194 | 195 | bought_usd = f"${top_trader['total_cost']:,.2f}" 196 | total_profit = f"${top_trader['realized_profit']:,.2f}" 197 | unrealized_profit = f"${top_trader['unrealized_profit']:,.2f}" 198 | multiplier = f"{multiplier_value:.2f}x" 199 | buys = f"{top_trader['buy_tx_count_cur']}" 200 | sells = f"{top_trader['sell_tx_count_cur']}" 201 | 202 | self.allData[address] = { 203 | "boughtUsd": bought_usd, 204 | "totalProfit": total_profit, 205 | "unrealizedProfit": unrealized_profit, 206 | "multiplier": multiplier, 207 | "buys": buys, 208 | "sells": sells 209 | } 210 | 211 | repeatedAddresses = [address for address, count in self.addressFrequency.items() if count > 1] 212 | 213 | identifier = self.shorten(list(self.allAddresses)[0]) 214 | 215 | with open(f'Dragon/data/Solana/TopHolders/allTopAddresses_{identifier}.txt', 'w') as av: 216 | for address in self.allAddresses: 217 | av.write(f"{address}\n") 218 | 219 | if len(repeatedAddresses) != 0: 220 | with open(f'Dragon/data/Solana/TopHolders/repeatedTopTraders_{identifier}.txt', 'w') as ra: 221 | for address in repeatedAddresses: 222 | ra.write(f"{address}\n") 223 | print(f"[🐲] Saved {len(repeatedAddresses)} repeated addresses to repeatedTopTraders_{identifier}.txt") 224 | 225 | with open(f'Dragon/data/Solana/TopHolders/topTraders_{identifier}.json', 'w') as tt: 226 | json.dump(self.allData, tt, indent=4) 227 | 228 | print(f"[🐲] Saved {self.totalTraders} top traders for {len(contractAddresses)} tokens to allTopAddresses_{identifier}.txt") 229 | print(f"[🐲] Saved {len(self.allAddresses)} top trader addresses to topTraders_{identifier}.json") 230 | 231 | return 232 | -------------------------------------------------------------------------------- /Dragon/wallet.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import random 3 | import tls_client 4 | import cloudscraper 5 | from fake_useragent import UserAgent 6 | from concurrent.futures import ThreadPoolExecutor, as_completed 7 | import time 8 | 9 | ua = UserAgent(os='linux', browsers=['firefox']) 10 | 11 | class BulkWalletChecker: 12 | 13 | def __init__(self): 14 | self.sendRequest = tls_client.Session(client_identifier='chrome_103') 15 | self.cloudScraper = cloudscraper.create_scraper() 16 | self.shorten = lambda s: f"{s[:4]}...{s[-5:]}" if len(s) >= 9 else s 17 | self.skippedWallets = 0 18 | self.proxyPosition = 0 19 | self.results = [] 20 | 21 | def randomise(self): 22 | self.identifier = random.choice([browser for browser in tls_client.settings.ClientIdentifiers.__args__ if browser.startswith(('chrome', 'safari', 'firefox', 'opera'))]) 23 | self.sendRequest = tls_client.Session(random_tls_extension_order=True, client_identifier=self.identifier) 24 | self.sendRequest.timeout_seconds = 60 25 | 26 | parts = self.identifier.split('_') 27 | identifier, version, *rest = parts 28 | other = rest[0] if rest else None 29 | 30 | os = 'windows' 31 | if identifier == 'opera': 32 | identifier = 'chrome' 33 | elif version == 'ios': 34 | os = 'ios' 35 | else: 36 | os = 'windows' 37 | 38 | self.user_agent = UserAgent(browsers=[identifier], os=[os]).random 39 | 40 | self.headers = { 41 | 'Host': 'gmgn.ai', 42 | 'accept': 'application/json, text/plain, */*', 43 | 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7', 44 | 'dnt': '1', 45 | 'priority': 'u=1, i', 46 | 'referer': 'https://gmgn.ai/?chain=sol', 47 | 'user-agent': self.user_agent 48 | } 49 | 50 | def loadProxies(self): 51 | with open("Dragon/data/Proxies/proxies.txt", 'r') as file: 52 | proxies = file.read().splitlines() 53 | 54 | formatted_proxies = [] 55 | for proxy in proxies: 56 | if ':' in proxy: 57 | parts = proxy.split(':') 58 | if len(parts) == 4: 59 | ip, port, username, password = parts 60 | formatted_proxies.append({ 61 | 'http': f"http://{username}:{password}@{ip}:{port}", 62 | 'https': f"http://{username}:{password}@{ip}:{port}" 63 | }) 64 | else: 65 | formatted_proxies.append({ 66 | 'http': f"http://{proxy}", 67 | 'https': f"http://{proxy}" 68 | }) 69 | else: 70 | formatted_proxies.append(f"http://{proxy}") 71 | return formatted_proxies 72 | 73 | def configureProxy(self, proxy): 74 | if isinstance(proxy, dict): 75 | self.sendRequest.proxies = { 76 | 'http': proxy.get('http'), 77 | 'https': proxy.get('https') 78 | } 79 | elif isinstance(proxy, str): 80 | self.sendRequest.proxies = { 81 | 'http': proxy, 82 | 'https': proxy 83 | } 84 | else: 85 | self.sendRequest.proxies = None 86 | return proxy 87 | 88 | def getNextProxy(self): 89 | proxies = self.loadProxies() 90 | proxy = proxies[self.proxyPosition % len(proxies)] 91 | self.proxyPosition += 1 92 | return proxy 93 | 94 | 95 | def getTokenDistro(self, wallet: str, useProxies): 96 | url = f"https://gmgn.ai/defi/quotation/v1/rank/sol/wallets/{wallet}/unique_token_7d?interval=30d" 97 | retries = 3 98 | tokenDistro = [] 99 | 100 | for attempt in range(retries): 101 | self.randomise() 102 | try: 103 | proxy = self.getNextProxy() if useProxies else None 104 | self.configureProxy(proxy) 105 | response = self.sendRequest.get(url, headers=self.headers, allow_redirects=True).json() 106 | tokenDistro = response['data']['tokens'] 107 | if tokenDistro: 108 | break 109 | except Exception: 110 | time.sleep(1) 111 | 112 | try: 113 | proxy = self.getNextProxy() if useProxies else None 114 | proxies = {'http': proxy, 'https': proxy} if proxy else None 115 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies, allow_redirects=True).json() 116 | tokenDistro = response['data']['tokens'] 117 | if tokenDistro: 118 | break 119 | except Exception: 120 | 121 | time.sleep(1) 122 | 123 | if not tokenDistro: 124 | return { 125 | "No Token Distribution Data": None 126 | } 127 | 128 | FiftyPercentOrMore = 0 129 | ZeroToFifty = 0 130 | FiftyTo100 = 0 131 | TwoToFour = 0 132 | FiveToSix = 0 133 | SixPlus = 0 134 | NegativeToFifty = 0 135 | 136 | for profit in tokenDistro: 137 | total_profit_pnl = profit.get('total_profit_pnl') 138 | if total_profit_pnl is not None: 139 | profitMultiplier = total_profit_pnl * 100 140 | 141 | if profitMultiplier <= -50: 142 | FiftyPercentOrMore += 1 143 | elif -50 < profitMultiplier < 0: 144 | NegativeToFifty += 1 145 | elif 0 <= profitMultiplier < 50: 146 | ZeroToFifty += 1 147 | elif 50 <= profitMultiplier < 199: 148 | FiftyTo100 += 1 149 | elif 200 <= profitMultiplier < 499: 150 | TwoToFour += 1 151 | elif 500 <= profitMultiplier < 600: 152 | FiveToSix += 1 153 | elif profitMultiplier >= 600: 154 | SixPlus += 1 155 | 156 | return { 157 | "-50% +": FiftyPercentOrMore, 158 | "0% - -50%": NegativeToFifty, 159 | "0 - 50%": ZeroToFifty, 160 | "50% - 199%": FiftyTo100, 161 | "200% - 499%": TwoToFour, 162 | "500% - 600%": FiveToSix, 163 | "600% +": SixPlus 164 | } 165 | 166 | def getWalletData(self, wallet: str, skipWallets: bool, useProxies): 167 | url = f"https://gmgn.ai/defi/quotation/v1/smartmoney/sol/walletNew/{wallet}?period=7d" 168 | retries = 3 169 | 170 | for attempt in range(retries): 171 | try: 172 | self.randomise() 173 | proxy = self.getNextProxy() if useProxies else None 174 | self.configureProxy(proxy) 175 | response = self.sendRequest.get(url, headers=self.headers) 176 | if response.status_code == 200: 177 | data = response.json() 178 | if data['msg'] == "success": 179 | data = data['data'] 180 | 181 | if skipWallets: 182 | if 'buy_30d' in data and isinstance(data['buy_30d'], (int, float)) and data['buy_30d'] > 0:# and float(data['sol_balance']) >= 1.0: (uncomment this to filter out insiders that cashed out already) 183 | return self.processWalletData(wallet, data, self.headers, useProxies) 184 | else: 185 | self.skippedWallets += 1 186 | print(f"[🐲] Skipped {self.skippedWallets} wallets", end="\r") 187 | return None 188 | else: 189 | return self.processWalletData(wallet, data, self.headers, useProxies) 190 | 191 | except Exception as e: 192 | print(f"[🐲] Error fetching data, trying backup...") 193 | 194 | try: 195 | self.randomise() 196 | proxy = self.getNextProxy() if useProxies else None 197 | proxies = {'http': proxy, 'https': proxy} if proxy else None 198 | response = self.cloudScraper.get(url, headers=self.headers, proxies=proxies) 199 | if response.status_code == 200: 200 | data = response.json() 201 | if data['msg'] == "success": 202 | data = data['data'] 203 | 204 | if skipWallets: 205 | if 'buy_30d' in data and isinstance(data['buy_30d'], (int, float)) and data['buy_30d'] > 0:# and float(data['sol_balance']) >= 1.0: (uncomment this to filter out insiders that cashed out already) 206 | return self.processWalletData(wallet, data, self.headers, useProxies) 207 | 208 | else: 209 | self.skippedWallets += 1 210 | print(f"[🐲] Skipped {self.skippedWallets} wallets", end="\r") 211 | return None 212 | else: 213 | return self.processWalletData(wallet, data, self.headers, useProxies) 214 | 215 | 216 | except Exception as e: 217 | print(f"[🐲] Backup scraper failed, retrying...") 218 | 219 | time.sleep(1) 220 | 221 | print(f"[🐲] Failed to fetch data for wallet {wallet} after {retries} attempts.") 222 | return None 223 | 224 | 225 | def processWalletData(self, wallet, data, headers, useProxies): 226 | direct_link = f"https://gmgn.ai/sol/address/{wallet}" 227 | total_profit_percent = f"{data['total_profit_pnl'] * 100:.2f}%" if data['total_profit_pnl'] is not None else "error" 228 | realized_profit_7d_usd = f"${data['realized_profit_7d']:,.2f}" if data['realized_profit_7d'] is not None else "error" 229 | realized_profit_30d_usd = f"${data['realized_profit_30d']:,.2f}" if data['realized_profit_30d'] is not None else "error" 230 | winrate_7d = f"{data['winrate'] * 100:.2f}%" if data['winrate'] is not None else "?" 231 | sol_balance = f"{float(data['sol_balance']):.2f}" if data['sol_balance'] is not None else "?" 232 | buy_7d = f"{data['buy_7d']}" if data['buy_7d'] is not None else "?" 233 | 234 | try: 235 | self.randomise() 236 | winrate_30data = self.sendRequest.get( 237 | f"https://gmgn.ai/defi/quotation/v1/smartmoney/sol/walletNew/{wallet}?period=30d", 238 | headers=self.headers, 239 | allow_redirects=True 240 | ).json()['data'] 241 | winrate_30d = f"{winrate_30data['winrate'] * 100:.2f}%" if winrate_30data['winrate'] is not None else "?" 242 | except Exception as e: 243 | self.randomise() 244 | print(f"[🐲] Error fetching winrate 30d data, trying backup..") 245 | winrate_30data = self.cloudScraper.get( 246 | f"https://gmgn.ai/defi/quotation/v1/smartmoney/sol/walletNew/{wallet}?period=30d", 247 | headers=self.headers, 248 | allow_redirects=True 249 | ).json()['data'] 250 | winrate_30d = f"{winrate_30data['winrate'] * 100:.2f}%" if winrate_30data['winrate'] is not None else "?" 251 | finally: 252 | winrate_30d = "?" 253 | 254 | #try: 255 | # total_profit_percent_value = float(data['total_profit_pnl']) * 100 if data['total_profit_pnl'] is not None else 0 256 | #except Exception: 257 | # total_profit_percent_value = 0 258 | 259 | #if total_profit_percent_value <= 75: 260 | # return None 261 | 262 | if "Skipped" in data.get("tags", []): 263 | return { 264 | "wallet": wallet, 265 | "tags": ["Skipped"], 266 | "directLink": direct_link 267 | } 268 | 269 | tokenDistro = self.getTokenDistro(wallet, useProxies) 270 | 271 | try: 272 | tags = data['tags'] 273 | except Exception: 274 | tags = "?" 275 | 276 | return { 277 | "wallet": wallet, 278 | "totalProfitPercent": total_profit_percent, 279 | "7dUSDProfit": realized_profit_7d_usd, 280 | "30dUSDProfit": realized_profit_30d_usd, 281 | "winrate_7d": winrate_7d, 282 | "winrate_30d": winrate_30d, 283 | "tags": tags, 284 | "sol_balance": sol_balance, 285 | "token_distribution": tokenDistro if tokenDistro else {}, 286 | "directLink": direct_link, 287 | "buy_7d": buy_7d 288 | } 289 | 290 | def fetchWalletData(self, wallets, threads, skipWallets, useProxies): 291 | with ThreadPoolExecutor(max_workers=threads) as executor: 292 | futures = {executor.submit(self.getWalletData, wallet.strip(), skipWallets, useProxies): wallet for wallet in wallets} 293 | for future in as_completed(futures): 294 | result = future.result() 295 | if result is not None: 296 | self.results.append(result) 297 | 298 | result_dict = {} 299 | for result in self.results: 300 | wallet = result.get('wallet') 301 | if wallet: 302 | result_dict[wallet] = result 303 | result.pop('wallet', None) 304 | else: 305 | print(f"[🐲] Missing 'wallet' key in result: {result}") 306 | 307 | if self.results and 'token_distribution' in self.results[0]: 308 | token_dist_keys = self.results[0]['token_distribution'].keys() 309 | else: 310 | token_dist_keys = [] 311 | 312 | identifier = self.shorten(list(result_dict)[0]) 313 | filename = f"{identifier}_{random.randint(1111, 9999)}.csv" 314 | 315 | path = f"Dragon/data/Solana/BulkWallet/wallets_{filename}" 316 | 317 | with open(path, 'w', newline='') as outfile: 318 | writer = csv.writer(outfile) 319 | 320 | header = ['Identifier'] + list(next(iter(result_dict.values())).keys()) 321 | 322 | if 'token_distribution' in header: 323 | header.remove('token_distribution') 324 | 325 | header.extend(token_dist_keys) 326 | 327 | writer.writerow(header) 328 | 329 | for key, value in result_dict.items(): 330 | row = [key] 331 | for h in header[1:]: 332 | if h in value: 333 | row.append(value[h]) 334 | elif 'token_distribution' in value and h in value['token_distribution']: 335 | row.append(value['token_distribution'][h]) 336 | else: 337 | row.append(None) 338 | writer.writerow(row) 339 | 340 | print(f"[🐲] Saved data for {len(result_dict.items())} wallets to {filename}") 341 | -------------------------------------------------------------------------------- /dragon.py: -------------------------------------------------------------------------------- 1 | from Dragon import utils, BundleFinder, ScanAllTx, BulkWalletChecker, TopTraders, TimestampTransactions, purgeFiles, CopyTradeWalletFinder, TopHolders, EarlyBuyers, checkProxyFile 2 | from Dragon import EthBulkWalletChecker, EthTopTraders, EthTimestampTransactions, EthScanAllTx 3 | from Dragon import gmgnTools, GMGN 4 | 5 | purgeFiles = utils.purgeFiles 6 | clear = utils.clear 7 | 8 | def gmgn(): 9 | gmgnai = GMGN() 10 | options, optionsChoice = utils.choices(chain="GMGN") 11 | 12 | print(f"{optionsChoice}\n") 13 | 14 | while True: 15 | try: 16 | while True: 17 | optionsInput = int(input("[❓] Choice > ")) 18 | siteChoice = options[optionsInput - 1] 19 | if optionsInput in [1, 2, 3, 4]: 20 | print(f"[🐲] Selected {siteChoice}") 21 | break 22 | else: 23 | print("[🐲] Invalid choice.") 24 | if optionsInput == 1: 25 | site = options[optionsInput - 1] 26 | gmgnOptions, gmgnOptionsChoice = gmgnTools(site) 27 | print(f"{gmgnOptionsChoice}\n") 28 | try: 29 | while True: 30 | gmgnoptionsInput = int(input("[❓] Choice > ")) 31 | choice = gmgnOptions[gmgnoptionsInput - 1] 32 | if gmgnoptionsInput in [1, 2, 3, 4]: 33 | print(f"[🐲] Selected {choice}") 34 | break 35 | if gmgnoptionsInput == 1: 36 | while True: 37 | threads = input("[❓] Threads > ") 38 | 39 | try: 40 | threads = int(threads) 41 | if threads > 100: 42 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 43 | threads = 40 44 | except ValueError: 45 | threads = 40 46 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 47 | break 48 | break 49 | 50 | while True: 51 | proxies = input("[❓] Use Proxies? (Y/N) > ") 52 | 53 | try: 54 | useProxies = None 55 | checkProxies = checkProxyFile() 56 | if not checkProxies: 57 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 58 | useProxies = False 59 | break 60 | if proxies.lower() == "y": 61 | useProxies = True 62 | print(f"[🐲] Using proxies.") 63 | else: 64 | useProxies = False 65 | except Exception: 66 | print(f"[🐲] Invalid input") 67 | break 68 | break 69 | 70 | urlIndicator = "NewToken" 71 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 72 | 73 | print(f"{optionsChoice}\n") 74 | if gmgnoptionsInput == 2: 75 | while True: 76 | threads = input("[❓] Threads > ") 77 | 78 | try: 79 | threads = int(threads) 80 | if threads > 100: 81 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 82 | threads = 40 83 | except ValueError: 84 | threads = 40 85 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 86 | break 87 | break 88 | 89 | while True: 90 | proxies = input("[❓] Use Proxies? (Y/N) > ") 91 | 92 | try: 93 | useProxies = None 94 | checkProxies = checkProxyFile() 95 | if not checkProxies: 96 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 97 | useProxies = False 98 | break 99 | if proxies.lower() == "y": 100 | useProxies = True 101 | print(f"[🐲] Using proxies.") 102 | else: 103 | useProxies = False 104 | except Exception: 105 | print(f"[🐲] Invalid input") 106 | break 107 | break 108 | 109 | urlIndicator = "CompletingToken" 110 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 111 | 112 | print(f"{optionsChoice}\n") 113 | if gmgnoptionsInput == 3: 114 | while True: 115 | threads = input("[❓] Threads > ") 116 | 117 | try: 118 | threads = int(threads) 119 | if threads > 100: 120 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 121 | threads = 40 122 | except ValueError: 123 | threads = 40 124 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 125 | break 126 | break 127 | 128 | while True: 129 | proxies = input("[❓] Use Proxies? (Y/N) > ") 130 | 131 | try: 132 | useProxies = None 133 | checkProxies = checkProxyFile() 134 | if not checkProxies: 135 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 136 | useProxies = False 137 | break 138 | if proxies.lower() == "y": 139 | useProxies = True 140 | print(f"[🐲] Using proxies.") 141 | else: 142 | useProxies = False 143 | except Exception: 144 | print(f"[🐲] Invalid input") 145 | break 146 | break 147 | 148 | urlIndicator = "SoaringToken" 149 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 150 | 151 | print(f"{optionsChoice}\n") 152 | if gmgnoptionsInput == 4: 153 | while True: 154 | threads = input("[❓] Threads > ") 155 | 156 | try: 157 | threads = int(threads) 158 | if threads > 100: 159 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 160 | threads = 40 161 | except ValueError: 162 | threads = 40 163 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 164 | break 165 | break 166 | 167 | while True: 168 | proxies = input("[❓] Use Proxies? (Y/N) > ") 169 | 170 | try: 171 | useProxies = None 172 | checkProxies = checkProxyFile() 173 | if not checkProxies: 174 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 175 | useProxies = False 176 | break 177 | if proxies.lower() == "y": 178 | useProxies = True 179 | print(f"[🐲] Using proxies.") 180 | else: 181 | useProxies = False 182 | except Exception: 183 | print(f"[🐲] Invalid input") 184 | break 185 | break 186 | 187 | urlIndicator = "BondedToken" 188 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 189 | 190 | print(f"{optionsChoice}\n") 191 | 192 | except Exception as e: 193 | clear() 194 | print(banner) 195 | print(f"\n{optionsChoice}\n") 196 | print("[🐲] Invalid input.") 197 | 198 | if optionsInput == 2: 199 | site = options[optionsInput - 1] 200 | gmgnOptions, gmgnOptionsChoice = gmgnTools(site) 201 | print(f"{gmgnOptionsChoice}\n") 202 | try: 203 | while True: 204 | gmgnoptionsInput = int(input("[❓] Choice > ")) 205 | choice = gmgnOptions[gmgnoptionsInput - 1] 206 | if gmgnoptionsInput in [1, 2, 3, 4]: 207 | print(f"[🐲] Selected {choice}") 208 | break 209 | if gmgnoptionsInput == 1: 210 | while True: 211 | threads = input("[❓] Threads > ") 212 | 213 | try: 214 | threads = int(threads) 215 | if threads > 100: 216 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 217 | threads = 40 218 | except ValueError: 219 | threads = 40 220 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 221 | break 222 | break 223 | 224 | while True: 225 | proxies = input("[❓] Use Proxies? (Y/N) > ") 226 | 227 | try: 228 | useProxies = None 229 | checkProxies = checkProxyFile() 230 | if not checkProxies: 231 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 232 | useProxies = False 233 | break 234 | if proxies.lower() == "y": 235 | useProxies = True 236 | print(f"[🐲] Using proxies.") 237 | else: 238 | useProxies = False 239 | except Exception: 240 | print(f"[🐲] Invalid input") 241 | break 242 | break 243 | 244 | urlIndicator = "NewToken" 245 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 246 | 247 | print(f"{optionsChoice}\n") 248 | if gmgnoptionsInput == 2: 249 | while True: 250 | threads = input("[❓] Threads > ") 251 | 252 | try: 253 | threads = int(threads) 254 | if threads > 100: 255 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 256 | threads = 40 257 | except ValueError: 258 | threads = 40 259 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 260 | break 261 | break 262 | 263 | while True: 264 | proxies = input("[❓] Use Proxies? (Y/N) > ") 265 | 266 | try: 267 | useProxies = None 268 | checkProxies = checkProxyFile() 269 | if not checkProxies: 270 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 271 | useProxies = False 272 | break 273 | if proxies.lower() == "y": 274 | useProxies = True 275 | print(f"[🐲] Using proxies.") 276 | else: 277 | useProxies = False 278 | except Exception: 279 | print(f"[🐲] Invalid input") 280 | break 281 | break 282 | 283 | urlIndicator = "CompletingToken" 284 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 285 | 286 | print(f"{optionsChoice}\n") 287 | if gmgnoptionsInput == 3: 288 | while True: 289 | threads = input("[❓] Threads > ") 290 | 291 | try: 292 | threads = int(threads) 293 | if threads > 100: 294 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 295 | threads = 40 296 | except ValueError: 297 | threads = 40 298 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 299 | break 300 | break 301 | 302 | while True: 303 | proxies = input("[❓] Use Proxies? (Y/N) > ") 304 | 305 | try: 306 | useProxies = None 307 | checkProxies = checkProxyFile() 308 | if not checkProxies: 309 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 310 | useProxies = False 311 | break 312 | if proxies.lower() == "y": 313 | useProxies = True 314 | print(f"[🐲] Using proxies.") 315 | else: 316 | useProxies = False 317 | except Exception: 318 | print(f"[🐲] Invalid input") 319 | break 320 | break 321 | 322 | urlIndicator = "SoaringToken" 323 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 324 | 325 | print(f"{optionsChoice}\n") 326 | if gmgnoptionsInput == 4: 327 | while True: 328 | threads = input("[❓] Threads > ") 329 | 330 | try: 331 | threads = int(threads) 332 | if threads > 100: 333 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 334 | threads = 40 335 | except ValueError: 336 | threads = 40 337 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 338 | break 339 | break 340 | 341 | while True: 342 | proxies = input("[❓] Use Proxies? (Y/N) > ") 343 | 344 | try: 345 | useProxies = None 346 | checkProxies = checkProxyFile() 347 | if not checkProxies: 348 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 349 | useProxies = False 350 | break 351 | if proxies.lower() == "y": 352 | useProxies = True 353 | print(f"[🐲] Using proxies.") 354 | else: 355 | useProxies = False 356 | except Exception: 357 | print(f"[🐲] Invalid input") 358 | break 359 | break 360 | 361 | urlIndicator = "BondedToken" 362 | contracts = gmgnai.contractsData(urlIndicator, threads, useProxies, siteChoice) 363 | 364 | print(f"{optionsChoice}\n") 365 | except Exception as e: 366 | clear() 367 | print(banner) 368 | print(f"\n{optionsChoice}\n") 369 | print("[🐲] Invalid input.") 370 | if optionsInput == 3: 371 | purgeFiles(chain="GMGN") 372 | print(f"[🐲] Successfully purged files.") 373 | print(f"\n{optionsChoice}\n") 374 | if optionsInput == 4: 375 | print(f"[🐲] Thank you for using Dragon.") 376 | break 377 | 378 | except ValueError as e: 379 | clear() 380 | print(banner) 381 | print(f"\n{optionsChoice}\n") 382 | print("[🐲] Invalid input.") 383 | 384 | except ValueError as e: 385 | utils.clear() 386 | print(banner) 387 | print(f"[🐲] Error occured. Please retry or use a VPN/Proxy. {e}") 388 | print(f"\n{optionsChoice}\n") 389 | print("[🐲] Invalid input.") 390 | 391 | 392 | 393 | def eth(): 394 | walletCheck = EthBulkWalletChecker() 395 | topTraders = EthTopTraders() 396 | timestamp = EthTimestampTransactions() 397 | scan = EthScanAllTx() 398 | 399 | filesChoice, files = utils.searchForTxt(chain="Ethereum") 400 | options, optionsChoice = utils.choices(chain="Ethereum") 401 | 402 | print(f"{optionsChoice}\n") 403 | 404 | while True: 405 | try: 406 | while True: 407 | optionsInput = int(input("[❓] Choice > ")) 408 | if optionsInput in [1, 2, 3, 4, 5, 6, 7, 8, 9]: 409 | print(f"[🐲] Selected {options[optionsInput - 1]}") 410 | break 411 | else: 412 | print("[🐲] Invalid choice.") 413 | if optionsInput == 1: 414 | print(f"[🐲] This is a placeholder.") 415 | print(f"\n{optionsChoice}\n") 416 | elif optionsInput == 2: 417 | if len(files) < 2: 418 | print("[🐲] No files available.") 419 | print(f"\n{optionsChoice}\n") 420 | continue 421 | print(f"\n{filesChoice}\n") 422 | 423 | try: 424 | while True: 425 | fileSelectionOption = int(input("[❓] File Choice > ")) 426 | if fileSelectionOption > len(files): 427 | print("[🐲] Invalid input.") 428 | elif files[fileSelectionOption - 1] == "Select Own File": 429 | print(f"[🐲] Selected {files[fileSelectionOption - 1]}") 430 | while True: 431 | fileDirectory = input("[🐲] Enter filename/path > ") 432 | try: 433 | with open(fileDirectory, 'r') as f: 434 | wallets = f.read().splitlines() 435 | if wallets and wallets != []: 436 | print(f"[🐲] Loaded {len(wallets)} wallets") 437 | break 438 | else: 439 | print(f"[🐲] Error occurred, file may be empty. Go to the ") 440 | continue 441 | except Exception as e: 442 | print(f"[🐲] File directory not found.") 443 | continue 444 | break 445 | else: 446 | print(f"[🐲] Selected {files[fileSelectionOption - 1]}") 447 | fileDirectory = f"Dragon/data/Ethereum/{files[fileSelectionOption - 1]}" 448 | 449 | with open(fileDirectory, 'r') as f: 450 | wallets = f.read().splitlines() 451 | if wallets and wallets != []: 452 | print(f"[🐲] Loaded {len(wallets)} wallets") 453 | break 454 | else: 455 | print(f"[🐲] Error occurred, file may be empty.") 456 | continue 457 | while True: 458 | threads = input("[❓] Threads > ") 459 | try: 460 | threads = int(threads) 461 | if threads > 100: 462 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 463 | threads = 40 464 | except ValueError: 465 | threads = 40 466 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 467 | break 468 | break 469 | while True: 470 | skipWallets = False 471 | skipWalletsInput = input("[❓] Skip wallets with no buys in 30d (Y/N)> ") 472 | 473 | if skipWalletsInput.upper() not in ["Y", "N"]: 474 | print("[🐲] Invalid input.") 475 | continue 476 | if skipWalletsInput.upper() == "N": 477 | skipWallets = False 478 | else: 479 | skipWallets = True 480 | walletData = walletCheck.fetchWalletData(wallets, threads=threads, skipWallets=skipWallets) 481 | print(f"\n{optionsChoice}\n") 482 | break 483 | except IndexError as e: 484 | print("[🐲] File choice out of range.") 485 | print(f"\n{optionsChoice}\n") 486 | except ValueError: 487 | print("[🐲] Invalid input.") 488 | print(f"\n{optionsChoice}\n") 489 | continue 490 | elif optionsInput == 3: 491 | while True: 492 | threads = input("[❓] Threads > ") 493 | try: 494 | threads = int(threads) 495 | if threads > 100: 496 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 497 | threads = 40 498 | except ValueError: 499 | threads = 40 500 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 501 | break 502 | with open('Dragon/data/Ethereum/TopTraders/tokens.txt', 'r') as fp: 503 | contractAddresses = fp.read().splitlines() 504 | if contractAddresses and contractAddresses != []: 505 | print(f"[🐲] Loaded {len(contractAddresses)} contract addresses") 506 | else: 507 | print(f"[🐲] Error occurred, file may be empty. Go to the file here: Draon/data/Ethereum/tokens.txt") 508 | print(f"\n{optionsChoice}\n") 509 | continue 510 | data = topTraders.topTraderData(contractAddresses, threads) 511 | 512 | print(f"\n{optionsChoice}\n") 513 | elif optionsInput == 4: 514 | while True: 515 | contractAddress = input("[❓] Contract Address > ") 516 | 517 | if len(contractAddress) not in [40, 41, 42]: 518 | print(f"[🐲] Invalid length.") 519 | else: 520 | break 521 | 522 | while True: 523 | threads = input("[❓] Threads > ") 524 | 525 | try: 526 | threads = int(threads) 527 | if threads > 100: 528 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 529 | threads = 40 530 | except ValueError: 531 | threads = 40 532 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 533 | break 534 | break 535 | 536 | go = scan.getAllTxMakers(contractAddress, threads) 537 | print(f"\n{optionsChoice}\n") 538 | elif optionsInput == 5: 539 | while True: 540 | contractAddress = input("[❓] Contract Address > ") 541 | 542 | if len(contractAddress) not in [40, 41, 42]: 543 | print(f"[🐲] Invalid length.") 544 | else: 545 | break 546 | while True: 547 | threads = input("[❓] Threads > ") 548 | try: 549 | threads = int(threads) 550 | if threads > 100: 551 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 552 | threads = 40 553 | except ValueError: 554 | threads = 40 555 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 556 | break 557 | break 558 | print(f"[🐲] Get UNIX Timetstamps Here > https://www.unixtimestamp.com") 559 | print(f"[🐲] This token was minted at {timestamp.getMintTimestamp(contractAddress)}") 560 | while True: 561 | start = input("[❓] Start UNIX Timestamp > ") 562 | try: 563 | start = int(start) 564 | except ValueError: 565 | print(f"[🐲] Invalid input.") 566 | break 567 | break 568 | while True: 569 | end = input("[❓] End UNIX Timestamp > ") 570 | try: 571 | start = int(start) 572 | except ValueError: 573 | print(f"[🐲] Invalid input.") 574 | break 575 | break 576 | timestampTxns = timestamp.getTxByTimestamp(contractAddress, threads, start, end) 577 | print(f"\n{optionsChoice}\n") 578 | elif optionsInput == 6: 579 | purgeFiles(chain="Ethereum") 580 | print(f"[🐲] Successfully purged files.") 581 | print(f"\n{optionsChoice}\n") 582 | elif optionsInput == 7: 583 | print(f"[🐲] Thank you for using Dragon.") 584 | break 585 | except ValueError as e: 586 | clear() 587 | print(banner) 588 | print(f"\n{optionsChoice}\n") 589 | print("[🐲] Invalid input.") 590 | except ValueError as e: 591 | utils.clear() 592 | print(banner) 593 | print(f"[🐲] Error occured. Please retry or use a VPN/Proxy. {e}") 594 | print(f"\n{optionsChoice}\n") 595 | print("[🐲] Invalid input.") 596 | 597 | def solana(): 598 | timestamp = TimestampTransactions() 599 | filesChoice, files = utils.searchForTxt(chain="Solana") 600 | #gmgnfilesChoice, gmgnFiles = utils.searchForTxt(chain="GMGN") 601 | bundle = BundleFinder() 602 | scan = ScanAllTx() 603 | walletCheck = BulkWalletChecker() 604 | topTraders = TopTraders() 605 | copytrade = CopyTradeWalletFinder() 606 | topHolders = TopHolders() 607 | earlyBuyers = EarlyBuyers() 608 | 609 | options, optionsChoice = utils.choices(chain="Solana") 610 | print(f"{optionsChoice}\n") 611 | while True: 612 | try: 613 | while True: 614 | optionsInput = int(input("[❓] Choice > ")) 615 | if optionsInput in [1, 2, 3, 4, 5, 6, 7, 8, 9]: 616 | print(f"[🐲] Selected {options[optionsInput - 1]}") 617 | break 618 | else: 619 | print("[🐲] Invalid choice.") 620 | 621 | 622 | if optionsInput == 1: 623 | while True: 624 | contractAddress = input("[❓] Contract Address > ") 625 | 626 | if len(contractAddress) not in [43, 44]: 627 | print(f"[🐲] Invalid length.") 628 | else: 629 | transactionHashes = bundle.teamTrades(contractAddress) 630 | bundleData = bundle.checkBundle(transactionHashes[0], transactionHashes[1]) 631 | formatData = bundle.prettyPrint(bundleData, contractAddress) 632 | print(f"\n{formatData}") 633 | print(f"\n{optionsChoice}\n") 634 | break 635 | elif optionsInput == 2: 636 | if len(files) < 2: 637 | print("[🐲] No files available.") 638 | continue 639 | 640 | print(f"\n{filesChoice}\n") 641 | 642 | try: 643 | while True: 644 | fileSelectionOption = int(input("[❓] File Choice > ")) 645 | if fileSelectionOption > len(files): 646 | print("[🐲] Invalid input.") 647 | elif files[fileSelectionOption - 1] == "Select Own File": 648 | print(f"[🐲] Selected {files[fileSelectionOption - 1]}") 649 | while True: 650 | fileDirectory = input("[🐲] Enter filename/path > ") 651 | try: 652 | with open(fileDirectory, 'r') as f: 653 | wallets = f.read().splitlines() 654 | if wallets and wallets != []: 655 | print(f"[🐲] Loaded {len(wallets)} wallets") 656 | break 657 | else: 658 | print(f"[🐲] Error occurred, file may be empty. Go to the ") 659 | continue 660 | except Exception as e: 661 | print(f"[🐲] File directory not found.") 662 | continue 663 | break 664 | 665 | else: 666 | print(f"[🐲] Selected {files[fileSelectionOption - 1]}") 667 | fileDirectory = f"Dragon/data/Solana/{files[fileSelectionOption - 1]}" 668 | 669 | with open(fileDirectory, 'r') as f: 670 | wallets = f.read().splitlines() 671 | if wallets and wallets != []: 672 | print(f"[🐲] Loaded {len(wallets)} wallets") 673 | break 674 | else: 675 | print(f"[🐲] Error occurred, file may be empty.") 676 | continue 677 | 678 | while True: 679 | threads = input("[❓] Threads > ") 680 | try: 681 | threads = int(threads) 682 | if threads > 100: 683 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 684 | threads = 40 685 | except ValueError: 686 | threads = 40 687 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 688 | break 689 | break 690 | 691 | while True: 692 | proxies = input("[❓] Use Proxies? (Y/N) > ") 693 | 694 | try: 695 | useProxies = None 696 | 697 | checkProxies = checkProxyFile() 698 | 699 | if not checkProxies: 700 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 701 | useProxies = False 702 | break 703 | 704 | if proxies.lower() == "y": 705 | useProxies = True 706 | print(f"[🐲] Using proxies.") 707 | else: 708 | useProxies = False 709 | except Exception: 710 | print(f"[🐲] Invalid input") 711 | break 712 | break 713 | 714 | while True: 715 | skipWallets = False 716 | skipWalletsInput = input("[❓] Skip wallets with no buys in 30d (Y/N) > ") 717 | 718 | if skipWalletsInput.upper() not in ["Y", "N"]: 719 | print("[🐲] Invalid input.") 720 | continue 721 | if skipWalletsInput.upper() == "N": 722 | skipWallets = False 723 | else: 724 | skipWallets = True 725 | walletData = walletCheck.fetchWalletData(wallets, threads=threads, skipWallets=skipWallets, useProxies=useProxies) 726 | print(f"\n{optionsChoice}\n") 727 | break 728 | 729 | except IndexError as e: 730 | print("[🐲] File choice out of range.") 731 | print(f"\n{optionsChoice}\n") 732 | except ValueError as e: 733 | print(f"[🐲] Invalid input. - {e}") 734 | print(f"\n{optionsChoice}\n") 735 | continue 736 | elif optionsInput == 3: 737 | 738 | if len(files) < 2: 739 | print("[🐲] No files available.") 740 | continue 741 | 742 | print(f"\n{filesChoice}\n") 743 | 744 | try: 745 | while True: 746 | fileSelectionOption = int(input("[❓] File Choice > ")) 747 | if fileSelectionOption > len(files): 748 | print("[🐲] Invalid input.") 749 | elif files[fileSelectionOption - 1] == "Select Own File": 750 | print(f"[🐲] Selected {files[fileSelectionOption - 1]}") 751 | while True: 752 | fileDirectory = input("[🐲] Enter filename/path > ") 753 | try: 754 | with open(fileDirectory, 'r') as f: 755 | wallets = f.read().splitlines() 756 | if wallets and wallets != []: 757 | print(f"[🐲] Loaded {len(wallets)} wallets") 758 | break 759 | else: 760 | print(f"[🐲] Error occurred, file may be empty. Go to the ") 761 | continue 762 | except Exception as e: 763 | print(f"[🐲] File directory not found.") 764 | continue 765 | break 766 | 767 | else: 768 | print(f"[🐲] Selected {files[fileSelectionOption - 1]}") 769 | fileDirectory = f"Dragon/data/Solana/{files[fileSelectionOption - 1]}" 770 | 771 | with open(fileDirectory, 'r') as f: 772 | contractAddresses = f.read().splitlines() 773 | if contractAddresses and contractAddresses != []: 774 | print(f"[🐲] Loaded {len(contractAddresses)} contract addresses") 775 | break 776 | else: 777 | print(f"[🐲] Error occurred, file may be empty.") 778 | continue 779 | 780 | while True: 781 | threads = input("[❓] Threads > ") 782 | try: 783 | threads = int(threads) 784 | if threads > 100: 785 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 786 | threads = 40 787 | except ValueError: 788 | threads = 40 789 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 790 | break 791 | break 792 | 793 | while True: 794 | proxies = input("[❓] Use Proxies? (Y/N) > ") 795 | 796 | try: 797 | useProxies = None 798 | 799 | checkProxies = checkProxyFile() 800 | 801 | if not checkProxies: 802 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 803 | useProxies = False 804 | break 805 | 806 | if proxies.lower() == "y": 807 | useProxies = True 808 | print(f"[🐲] Using proxies.") 809 | else: 810 | useProxies = False 811 | except Exception: 812 | print(f"[🐲] Invalid input") 813 | break 814 | break 815 | 816 | 817 | data = topTraders.topTraderData(contractAddresses, threads, useProxies) 818 | 819 | print(f"\n{optionsChoice}\n") 820 | 821 | except IndexError as e: 822 | print("[🐲] File choice out of range.") 823 | print(f"\n{optionsChoice}\n") 824 | except ValueError as e: 825 | print(f"[🐲] Invalid input. - {e}") 826 | print(f"\n{optionsChoice}\n") 827 | continue 828 | elif optionsInput == 4: 829 | while True: 830 | contractAddress = input("[❓] Contract Address > ") 831 | 832 | if len(contractAddress) not in [43, 44]: 833 | print(f"[🐲] Invalid length.") 834 | else: 835 | break 836 | 837 | while True: 838 | threads = input("[❓] Threads > ") 839 | 840 | try: 841 | threads = int(threads) 842 | if threads > 100: 843 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 844 | threads = 40 845 | except ValueError: 846 | threads = 40 847 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 848 | break 849 | break 850 | 851 | while True: 852 | proxies = input("[❓] Use Proxies? (Y/N) > ") 853 | 854 | try: 855 | useProxies = None 856 | 857 | checkProxies = checkProxyFile() 858 | 859 | if not checkProxies: 860 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 861 | useProxies = False 862 | break 863 | 864 | if proxies.lower() == "y": 865 | useProxies = True 866 | print(f"[🐲] Using proxies.") 867 | else: 868 | useProxies = False 869 | except Exception: 870 | print(f"[🐲] Invalid input") 871 | break 872 | break 873 | 874 | go = scan.getAllTxMakers(contractAddress, threads, useProxies) 875 | print(f"\n{optionsChoice}\n") 876 | 877 | elif optionsInput == 5: 878 | while True: 879 | contractAddress = input("[❓] Contract Address > ") 880 | 881 | if len(contractAddress) not in [43, 44]: 882 | print(f"[🐲] Invalid length.") 883 | else: 884 | break 885 | while True: 886 | threads = input("[❓] Threads > ") 887 | try: 888 | threads = int(threads) 889 | if threads > 100: 890 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 891 | threads = 40 892 | except ValueError: 893 | threads = 40 894 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 895 | break 896 | break 897 | while True: 898 | proxies = input("[❓] Use Proxies? (Y/N) > ") 899 | 900 | try: 901 | useProxies = None 902 | 903 | checkProxies = checkProxyFile() 904 | 905 | if not checkProxies: 906 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 907 | useProxies = False 908 | break 909 | 910 | if proxies.lower() == "y": 911 | useProxies = True 912 | print(f"[🐲] Using proxies.") 913 | else: 914 | useProxies = False 915 | except Exception: 916 | print(f"[🐲] Invalid input") 917 | break 918 | break 919 | print(f"[🐲] Get UNIX Timetstamps Here > https://www.unixtimestamp.com") 920 | print(f"[🐲] This token was minted at {timestamp.getMintTimestamp(contractAddress, useProxies)}") 921 | while True: 922 | start = input("[❓] Start UNIX Timestamp > ") 923 | try: 924 | start = int(start) 925 | except ValueError: 926 | print(f"[🐲] Invalid input.") 927 | break 928 | break 929 | while True: 930 | end = input("[❓] End UNIX Timestamp > ") 931 | try: 932 | start = int(start) 933 | except ValueError: 934 | print(f"[🐲] Invalid input.") 935 | break 936 | break 937 | timestampTxns = timestamp.getTxByTimestamp(contractAddress, threads, start, end, useProxies) 938 | break 939 | elif optionsInput == 6: 940 | while True: 941 | contractAddress = input("[❓] Contract Address > ") 942 | 943 | if len(contractAddress) not in [43, 44]: 944 | print(f"[🐲] Invalid length.") 945 | else: 946 | break 947 | while True: 948 | walletAddress = input("[❓] Wallet Address > ") 949 | 950 | if len(walletAddress) not in [43, 44]: 951 | print(f"[🐲] Invalid length.") 952 | else: 953 | break 954 | while True: 955 | threads = input("[❓] Threads > ") 956 | try: 957 | threads = int(threads) 958 | if threads > 10000: 959 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 960 | threads = 40 961 | except ValueError: 962 | threads = 40 963 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 964 | break 965 | break 966 | 967 | while True: 968 | proxies = input("[❓] Use Proxies? (Y/N) > ") 969 | 970 | try: 971 | useProxies = None 972 | 973 | checkProxies = checkProxyFile() 974 | 975 | if not checkProxies: 976 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 977 | useProxies = False 978 | break 979 | 980 | if proxies.lower() == "y": 981 | useProxies = True 982 | print(f"[🐲] Using proxies.") 983 | else: 984 | useProxies = False 985 | except Exception: 986 | print(f"[🐲] Invalid input") 987 | break 988 | break 989 | 990 | findWallets = copytrade.findWallets(contractAddress, walletAddress, threads, useProxies) 991 | 992 | elif optionsInput == 7: 993 | while True: 994 | threads = input("[❓] Threads > ") 995 | try: 996 | threads = int(threads) 997 | if threads > 100: 998 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 999 | threads = 40 1000 | except ValueError: 1001 | threads = 40 1002 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 1003 | break 1004 | while True: 1005 | proxies = input("[❓] Use Proxies? (Y/N) > ") 1006 | 1007 | try: 1008 | useProxies = None 1009 | 1010 | checkProxies = checkProxyFile() 1011 | 1012 | if not checkProxies: 1013 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 1014 | useProxies = False 1015 | break 1016 | 1017 | if proxies.lower() == "y": 1018 | useProxies = True 1019 | print(f"[🐲] Using proxies.") 1020 | else: 1021 | useProxies = False 1022 | except Exception: 1023 | print(f"[🐲] Invalid input") 1024 | break 1025 | break 1026 | with open('Dragon/data/Solana/TopHolders/tokens.txt', 'r') as fp: 1027 | contractAddresses = fp.read().splitlines() 1028 | if contractAddresses and contractAddresses != []: 1029 | print(f"[🐲] Loaded {len(contractAddresses)} contract addresses") 1030 | else: 1031 | print(f"[🐲] Error occurred, file may be empty. Go to the file here: Draon/data/TopTraders/tokens.txt") 1032 | print(f"\n{optionsChoice}\n") 1033 | continue 1034 | 1035 | data = topHolders.topHolderData(contractAddresses, threads, useProxies) 1036 | 1037 | print(f"\n{optionsChoice}\n") 1038 | 1039 | elif optionsInput == 8: 1040 | while True: 1041 | buyers = int(input("[❓] Amount of Early Buyers > ")) 1042 | try: 1043 | buyers = int(buyers) 1044 | if buyers > 100: 1045 | print(f"[🐲] Cannot grab more than 100 early buyers. Automatically set buyers to 40.") 1046 | buyers = 40 1047 | except ValueError: 1048 | buyers = 40 1049 | print(f"[🐲] Invalid input. Defaulting to 40 buyers.") 1050 | break 1051 | while True: 1052 | threads = input("[❓] Threads > ") 1053 | try: 1054 | threads = int(threads) 1055 | if threads > 100: 1056 | print(f"[🐲] Do not use more than 100 threads. Automatically set threads to 40.") 1057 | threads = 40 1058 | except ValueError: 1059 | threads = 40 1060 | print(f"[🐲] Invalid input. Defaulting to 40 threads.") 1061 | break 1062 | while True: 1063 | proxies = input("[❓] Use Proxies? (Y/N) > ") 1064 | try: 1065 | useProxies = None 1066 | 1067 | checkProxies = checkProxyFile() 1068 | 1069 | if not checkProxies: 1070 | print(f"[🐲] Dragon/data/Proxies/proxies.txt is empty, please add proxies to use them.") 1071 | useProxies = False 1072 | break 1073 | 1074 | if proxies.lower() == "y": 1075 | useProxies = True 1076 | print(f"[🐲] Using proxies.") 1077 | else: 1078 | useProxies = False 1079 | except Exception: 1080 | print(f"[🐲] Invalid input") 1081 | break 1082 | break 1083 | with open('Dragon/data/Solana/EarlyBuyers/tokens.txt', 'r') as fp: 1084 | contractAddresses = fp.read().splitlines() 1085 | if contractAddresses and contractAddresses != []: 1086 | print(f"[🐲] Loaded {len(contractAddresses)} contract addresses") 1087 | else: 1088 | print(f"[🐲] Error occurred, file may be empty. Go to the file here: Draon/data/EarlyBuyers/tokens.txt") 1089 | print(f"\n{optionsChoice}\n") 1090 | continue 1091 | 1092 | data = earlyBuyers.earlyBuyersdata(contractAddresses, threads, useProxies, buyers) 1093 | 1094 | print(f"\n{optionsChoice}\n") 1095 | 1096 | 1097 | elif optionsInput == 9: 1098 | purgeFiles(chain="Solana") 1099 | print(f"[🐲] Successfully purged files.") 1100 | print(f"\n{optionsChoice}\n") 1101 | 1102 | elif optionsInput == 10: 1103 | print(f"[🐲] Thank you for using Dragon.") 1104 | break 1105 | 1106 | except ValueError as e: 1107 | utils.clear() 1108 | print(banner) 1109 | print(f"[🐲] Error occured. Please retry or use a VPN/Proxy. {e}") 1110 | print(f"\n{optionsChoice}\n") 1111 | print("[🐲] Invalid input.") 1112 | 1113 | banner = utils.banner() 1114 | print(banner) 1115 | 1116 | chains = utils.chains()[0] 1117 | chainsChoice = utils.chains()[1] 1118 | print(f"{chainsChoice}\n") 1119 | 1120 | while True: 1121 | try: 1122 | while True: 1123 | chainsInput = int(input("[❓] Choice > ")) 1124 | if chainsInput in [1, 2, 3, 4]: 1125 | print(f"[🐲] Selected {chains[chainsInput - 1]}") 1126 | break 1127 | else: 1128 | print("[🐲] Invalid choice.") 1129 | if chainsInput == 1: 1130 | solana() 1131 | elif chainsInput == 2: 1132 | eth() 1133 | elif chainsInput == 3: 1134 | gmgn() 1135 | else: 1136 | print(f"[🐲] Invalid choice.") 1137 | break 1138 | except ValueError as e: 1139 | utils.clear() 1140 | print(banner) 1141 | print(f"{chainsChoice}\n") 1142 | print(e) 1143 | --------------------------------------------------------------------------------