├── .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 |
--------------------------------------------------------------------------------