├── accounts.txt ├── proxy.txt ├── requirements.txt ├── README.md └── bot.py /accounts.txt: -------------------------------------------------------------------------------- 1 | your_private_key_1 2 | your_private_key_2 -------------------------------------------------------------------------------- /proxy.txt: -------------------------------------------------------------------------------- 1 | ip:port # Default Protcol HTTP. 2 | protocol://ip:port 3 | protocol://user:pass@ip:port -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp 2 | aiohttp-socks 3 | fake-useragent 4 | eth-account 5 | colorama 6 | pytz -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multiple Lite Node BOT 2 | Multiple Lite Node BOT 3 | 4 | - Register Here : [Multiple Lite Node](https://www.app.multiple.cc/#/signup?inviteCode=2GEg01qD) 5 | - Download Extension Here: [Multiple Lite Node Extension](https://chromewebstore.google.com/detail/multiple-lite-node/ciljbjmmdhnhgbihlcohoadafmhikgib) 6 | - Use Code : 2GEg01qD 7 | 8 | ## Features 9 | 10 | - Auto Get Account Information 11 | - Auto Run With [Monosans](https://raw.githubusercontent.com/monosans/proxy-list/main/proxies/all.txt) Proxy - Choose 1 12 | - Auto Run With Private Proxy - Choose 2 13 | - Auto Run Without Proxy - Choose 3 14 | - Auto Send Keep Alive Every 10 Minutes 15 | - Multi Accounts With Threads 16 | 17 | ## Requiremnets 18 | 19 | - Make sure you have Python3.9 or higher installed and pip. 20 | 21 | ## Instalation 22 | 23 | 1. **Clone The Repositories:** 24 | ```bash 25 | git clone https://github.com/vonssy/MultipleLite-BOT.git 26 | ``` 27 | ```bash 28 | cd MultipleLite-BOT 29 | ``` 30 | 31 | 2. **Install Requirements:** 32 | ```bash 33 | pip install -r requirements.txt #or pip3 install -r requirements.txt 34 | ``` 35 | 36 | ## Configuration 37 | 38 | - **accounts.txt:** You will find the file `accounts.txt` inside the project directory. Make sure `accounts.txt` contains data that matches the format expected by the script. Here are examples of file formats: 39 | 40 | ```bash 41 | your_private_key_1 42 | your_private_key_2 43 | ``` 44 | - **proxy.txt:** You will find the file `proxy.txt` inside the project directory. Make sure `proxy.txt` contains data that matches the format expected by the script. Here are examples of file formats: 45 | ```bash 46 | ip:port # Default Protcol HTTP. 47 | protocol://ip:port 48 | protocol://user:pass@ip:port 49 | ``` 50 | 51 | ## Run 52 | 53 | ```bash 54 | python bot.py #or python3 bot.py 55 | ``` 56 | 57 | ## Buy Me a Coffee 58 | 59 | - **EVM:** 0xe3c9ef9a39e9eb0582e5b147026cae524338521a 60 | - **TON:** UQBEFv58DC4FUrGqinBB5PAQS7TzXSm5c1Fn6nkiet8kmehB 61 | - **SOL:** E1xkaJYmAFEj28NPHKhjbf7GcvfdjKdvXju8d8AeSunf 62 | - **SUI:** 0xa03726ecbbe00b31df6a61d7a59d02a7eedc39fe269532ceab97852a04cf3347 63 | 64 | Thank you for visiting this repository, don't forget to contribute in the form of follows and stars. 65 | If you have questions, find an issue, or have suggestions for improvement, feel free to contact me or open an *issue* in this GitHub repository. 66 | 67 | **vonssy** -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | from aiohttp import ( 2 | ClientResponseError, 3 | ClientSession, 4 | ClientTimeout 5 | ) 6 | from aiohttp_socks import ProxyConnector 7 | from eth_account import Account 8 | from eth_account.messages import encode_defunct 9 | from fake_useragent import FakeUserAgent 10 | from datetime import datetime 11 | from colorama import * 12 | import asyncio, json, random, os, pytz 13 | 14 | wib = pytz.timezone('Asia/Jakarta') 15 | 16 | class MultipleLite: 17 | def __init__(self) -> None: 18 | self.headers = { 19 | "Accept": "application/json, text/plain, */*", 20 | "Accept-Language": "id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7", 21 | "Sec-Fetch-Dest": "empty", 22 | "Sec-Fetch-Mode": "cors", 23 | "User-Agent": FakeUserAgent().random 24 | } 25 | self.proxies = [] 26 | self.proxy_index = 0 27 | self.account_proxies = {} 28 | 29 | def clear_terminal(self): 30 | os.system('cls' if os.name == 'nt' else 'clear') 31 | 32 | def log(self, message): 33 | print( 34 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}" 35 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}{message}", 36 | flush=True 37 | ) 38 | 39 | def welcome(self): 40 | print( 41 | f""" 42 | {Fore.GREEN + Style.BRIGHT}Auto Ping {Fore.BLUE + Style.BRIGHT}Multiple Lite Node - BOT 43 | """ 44 | f""" 45 | {Fore.GREEN + Style.BRIGHT}Rey? {Fore.YELLOW + Style.BRIGHT} 46 | """ 47 | ) 48 | 49 | def format_seconds(self, seconds): 50 | hours, remainder = divmod(seconds, 3600) 51 | minutes, seconds = divmod(remainder, 60) 52 | return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}" 53 | 54 | def format_time(self, seconds): 55 | days = seconds // 86400 56 | seconds %= 86400 57 | hours = seconds // 3600 58 | seconds %= 3600 59 | minutes = seconds // 60 60 | return f"{days}d {hours}h {minutes}m" 61 | 62 | def load_accounts(self): 63 | filename = "accounts.json" 64 | try: 65 | if not os.path.exists(filename): 66 | self.log(f"{Fore.RED}File {filename} Not Found.{Style.RESET_ALL}") 67 | return 68 | 69 | with open(filename, 'r') as file: 70 | data = json.load(file) 71 | if isinstance(data, list): 72 | return data 73 | return [] 74 | except json.JSONDecodeError: 75 | return [] 76 | 77 | async def load_proxies(self, use_proxy_choice: bool): 78 | filename = "proxy.txt" 79 | try: 80 | if use_proxy_choice == 1: 81 | async with ClientSession(timeout=ClientTimeout(total=30)) as session: 82 | async with session.get("https://raw.githubusercontent.com/monosans/proxy-list/main/proxies/all.txt") as response: 83 | response.raise_for_status() 84 | content = await response.text() 85 | with open(filename, 'w') as f: 86 | f.write(content) 87 | self.proxies = content.splitlines() 88 | else: 89 | if not os.path.exists(filename): 90 | self.log(f"{Fore.RED + Style.BRIGHT}File {filename} Not Found.{Style.RESET_ALL}") 91 | return 92 | with open(filename, 'r') as f: 93 | self.proxies = f.read().splitlines() 94 | 95 | if not self.proxies: 96 | self.log(f"{Fore.RED + Style.BRIGHT}No Proxies Found.{Style.RESET_ALL}") 97 | return 98 | 99 | self.log( 100 | f"{Fore.GREEN + Style.BRIGHT}Proxies Total : {Style.RESET_ALL}" 101 | f"{Fore.WHITE + Style.BRIGHT}{len(self.proxies)}{Style.RESET_ALL}" 102 | ) 103 | 104 | except Exception as e: 105 | self.log(f"{Fore.RED + Style.BRIGHT}Failed To Load Proxies: {e}{Style.RESET_ALL}") 106 | self.proxies = [] 107 | 108 | def check_proxy_schemes(self, proxies): 109 | schemes = ["http://", "https://", "socks4://", "socks5://"] 110 | if any(proxies.startswith(scheme) for scheme in schemes): 111 | return proxies 112 | return f"http://{proxies}" 113 | 114 | def get_next_proxy_for_account(self, account): 115 | if account not in self.account_proxies: 116 | if not self.proxies: 117 | return None 118 | proxy = self.check_proxy_schemes(self.proxies[self.proxy_index]) 119 | self.account_proxies[account] = proxy 120 | self.proxy_index = (self.proxy_index + 1) % len(self.proxies) 121 | return self.account_proxies[account] 122 | 123 | def rotate_proxy_for_account(self, account): 124 | if not self.proxies: 125 | return None 126 | proxy = self.check_proxy_schemes(self.proxies[self.proxy_index]) 127 | self.account_proxies[account] = proxy 128 | self.proxy_index = (self.proxy_index + 1) % len(self.proxies) 129 | return proxy 130 | 131 | def generate_address(self, private_key: str): 132 | try: 133 | account = Account.from_key(private_key) 134 | address = account.address 135 | 136 | return address 137 | except Exception as e: 138 | return None 139 | 140 | def generate_payload_data(self, account: str, address: str, timestamp: str, nonce: int): 141 | try: 142 | message = f"www.multiple.cc wants you to sign in with your Ethereum account: {address}\n\t \nmessage:\nwebsite: www.multiple.cc\nwalletaddress: {address}\ntimestamp: {timestamp}\nNonce: {nonce}" 143 | encoded_message = encode_defunct(text=message) 144 | 145 | signed_message = Account.sign_message(encoded_message, private_key=account) 146 | signature = signed_message.signature.hex() 147 | 148 | data = { 149 | "walletAddr": address, 150 | "message": message, 151 | "signature": signature 152 | } 153 | 154 | return data 155 | except Exception as e: 156 | return None 157 | 158 | def mask_account(self, account): 159 | mask_account = account[:6] + '*' * 6 + account[-6:] 160 | return mask_account 161 | 162 | def print_message(self, account, proxy, color, message): 163 | self.log( 164 | f"{Fore.CYAN + Style.BRIGHT}[ Account:{Style.RESET_ALL}" 165 | f"{Fore.WHITE + Style.BRIGHT} {self.mask_account(account)} {Style.RESET_ALL}" 166 | f"{Fore.MAGENTA + Style.BRIGHT}-{Style.RESET_ALL}" 167 | f"{Fore.CYAN + Style.BRIGHT} Proxy: {Style.RESET_ALL}" 168 | f"{Fore.WHITE + Style.BRIGHT}{proxy}{Style.RESET_ALL}" 169 | f"{Fore.MAGENTA + Style.BRIGHT} - {Style.RESET_ALL}" 170 | f"{Fore.CYAN + Style.BRIGHT}Status:{Style.RESET_ALL}" 171 | f"{color + Style.BRIGHT} {message} {Style.RESET_ALL}" 172 | f"{Fore.CYAN + Style.BRIGHT}]{Style.RESET_ALL}" 173 | ) 174 | 175 | def print_question(self): 176 | while True: 177 | try: 178 | print("1. Run With Monosans Proxy") 179 | print("2. Run With Private Proxy") 180 | print("3. Run Without Proxy") 181 | choose = int(input("Choose [1/2/3] -> ").strip()) 182 | 183 | if choose in [1, 2, 3]: 184 | proxy_type = ( 185 | "Run With Monosans Proxy" if choose == 1 else 186 | "Run With Private Proxy" if choose == 2 else 187 | "Run Without Proxy" 188 | ) 189 | print(f"{Fore.GREEN + Style.BRIGHT}{proxy_type} Selected.{Style.RESET_ALL}") 190 | return choose 191 | else: 192 | print(f"{Fore.RED + Style.BRIGHT}Please enter either 1, 2 or 3.{Style.RESET_ALL}") 193 | except ValueError: 194 | print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter a number (1, 2 or 3).{Style.RESET_ALL}") 195 | 196 | async def dashboard_login(self, account: str, address: str, timestamp: str, nonce: int, proxy=None, retries=5): 197 | url = "https://api.app.multiple.cc/WalletLogin" 198 | data = json.dumps(self.generate_payload_data(account, address, timestamp, nonce)) 199 | headers = { 200 | **self.headers, 201 | "Authorization": "Bearer", 202 | "Content-Length": str(len(data)), 203 | "Content-Type": "application/json", 204 | "Origin": "https://www.app.multiple.cc", 205 | "Referer": "https://www.app.multiple.cc/", 206 | "Sec-Fetch-Site": "same-site", 207 | } 208 | for attempt in range(retries): 209 | connector = ProxyConnector.from_url(proxy) if proxy else None 210 | try: 211 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: 212 | async with session.post(url=url, headers=headers, data=data) as response: 213 | response.raise_for_status() 214 | result = await response.json() 215 | return result['data']['token'] 216 | except (Exception, ClientResponseError) as e: 217 | if attempt < retries - 1: 218 | timestamp = datetime.strptime(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') 219 | nonce = int(timestamp.timestamp() * 1000) 220 | await asyncio.sleep(5) 221 | continue 222 | 223 | return self.print_message(address, proxy, Fore.RED, f"GET Dashboard Token Failed {Fore.YELLOW+Style.BRIGHT}{str(e)}") 224 | 225 | async def extension_login(self, account: str, address: str, dashboard_token: str, use_proxy: bool, proxy=None, retries=5): 226 | url = "https://api.app.multiple.cc/ChromePlugin/Login" 227 | headers = { 228 | **self.headers, 229 | "Authorization": f"Bearer {dashboard_token}", 230 | "Content-Length": '2', 231 | "Content-Type": "application/json", 232 | "Origin": "chrome-extension://ciljbjmmdhnhgbihlcohoadafmhikgib", 233 | "Sec-Fetch-Site": "none", 234 | } 235 | for attempt in range(retries): 236 | connector = ProxyConnector.from_url(proxy) if proxy else None 237 | try: 238 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: 239 | async with session.post(url=url, headers=headers, json={}) as response: 240 | if response.status == 401: 241 | dashboard_token = await self.get_dashboard_token(account, address, use_proxy) 242 | headers["Authorization"] = f"Bearer {dashboard_token}" 243 | continue 244 | 245 | response.raise_for_status() 246 | result = await response.json() 247 | return result['data']['token'] 248 | except (Exception, ClientResponseError) as e: 249 | if attempt < retries - 1: 250 | await asyncio.sleep(5) 251 | continue 252 | 253 | return self.print_message(address, proxy, Fore.RED, f"GET Extension Token Failed {Fore.YELLOW+Style.BRIGHT}{str(e)}") 254 | 255 | async def user_information(self, account: str, address: str, extension_token: str, use_proxy: bool, proxy=None, retries=5): 256 | url = "https://api.app.multiple.cc/ChromePlugin/GetInformation" 257 | headers = { 258 | **self.headers, 259 | "Authorization": f"Bearer {extension_token}" 260 | } 261 | for attempt in range(retries): 262 | connector = ProxyConnector.from_url(proxy) if proxy else None 263 | try: 264 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: 265 | async with session.get(url=url, headers=headers) as response: 266 | if response.status == 401: 267 | dashboard_token = await self.get_extension_token(account, address, dashboard_token, use_proxy) 268 | headers["Authorization"] = f"Bearer {extension_token}" 269 | continue 270 | 271 | response.raise_for_status() 272 | result = await response.json() 273 | return result['data'] 274 | except (Exception, ClientResponseError) as e: 275 | if attempt < retries - 1: 276 | await asyncio.sleep(5) 277 | continue 278 | 279 | return self.print_message(address, proxy, Fore.RED, f"GET User Info Failed {Fore.YELLOW+Style.BRIGHT}{str(e)}") 280 | 281 | async def send_keepalive(self, account: str, address: str, extension_token: str, use_proxy: bool, proxy=None, retries=5): 282 | url = "https://api.app.multiple.cc/ChromePlugin/KeepAlive" 283 | headers = { 284 | **self.headers, 285 | "Authorization": f"Bearer {extension_token}", 286 | "Content-Length": '0', 287 | "Content-Type": "application/x-www-form-urlencoded", 288 | "Origin": "chrome-extension://ciljbjmmdhnhgbihlcohoadafmhikgib", 289 | "Sec-Fetch-Site": "none", 290 | } 291 | for attempt in range(retries): 292 | connector = ProxyConnector.from_url(proxy) if proxy else None 293 | try: 294 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: 295 | async with session.post(url=url, headers=headers) as response: 296 | if response.status == 401: 297 | dashboard_token = await self.get_extension_token(account, address, dashboard_token, use_proxy) 298 | headers["Authorization"] = f"Bearer {extension_token}" 299 | continue 300 | 301 | response.raise_for_status() 302 | return await response.json() 303 | except (Exception, ClientResponseError) as e: 304 | if attempt < retries - 1: 305 | await asyncio.sleep(5) 306 | continue 307 | 308 | proxy = self.rotate_proxy_for_account(account) if use_proxy else None 309 | return self.print_message(address, proxy, Fore.RED, f"PING Failed {Fore.YELLOW+Style.BRIGHT}{str(e)}") 310 | 311 | async def get_user_information(self, account: str, address: str, extension_token: str, use_proxy: bool): 312 | while True: 313 | proxy = self.get_next_proxy_for_account(account) if use_proxy else None 314 | user = await self.user_information(account, address, extension_token, use_proxy, proxy) 315 | 316 | if user: 317 | runing_time = user['totalRunningTime'] 318 | is_online = user['isOnline'] 319 | status = "Node Connected" if is_online else "Node Disconnected" 320 | 321 | self.print_message(address, proxy, Fore.GREEN if is_online else Fore.RED, 322 | f"{status} " 323 | f"{Fore.MAGENTA + Style.BRIGHT}-{Style.RESET_ALL}" 324 | f"{Fore.CYAN + Style.BRIGHT} Run Time: {Style.RESET_ALL}" 325 | f"{Fore.WHITE + Style.BRIGHT}{self.format_time(runing_time)}{Style.RESET_ALL}" 326 | ) 327 | 328 | await asyncio.sleep(11 * 60) 329 | 330 | async def process_send_ping(self, account: str, address: str, extension_token: str, use_proxy: bool): 331 | while True: 332 | proxy = self.get_next_proxy_for_account(account) if use_proxy else None 333 | print( 334 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}" 335 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}" 336 | f"{Fore.BLUE + Style.BRIGHT}Try To Send PING...{Style.RESET_ALL}", 337 | end="\r", 338 | flush=True 339 | ) 340 | 341 | ping = await self.send_keepalive(account, address, extension_token, use_proxy, proxy) 342 | if ping: 343 | self.print_message(address, proxy, Fore.GREEN, "PING Success") 344 | 345 | print( 346 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}" 347 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}" 348 | f"{Fore.BLUE + Style.BRIGHT}Wait For 10 Minutes For Next PING...{Style.RESET_ALL}", 349 | end="\r", 350 | flush=True 351 | ) 352 | 353 | await asyncio.sleep(10 * 60) 354 | 355 | async def get_dashboard_token(self, account: str, address: str, use_proxy: bool): 356 | proxy = self.get_next_proxy_for_account(account) if use_proxy else None 357 | dashboard_token = None 358 | while dashboard_token is None: 359 | timestamp = datetime.strptime(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') 360 | nonce = int(timestamp.timestamp() * 1000) 361 | dashboard_token = await self.dashboard_login(account, address, timestamp, nonce, proxy) 362 | if not dashboard_token: 363 | proxy = self.rotate_proxy_for_account(account) if use_proxy else None 364 | continue 365 | 366 | self.print_message(address, proxy, Fore.GREEN, "GET Dashboard Token Success") 367 | return dashboard_token 368 | 369 | async def get_extension_token(self, account: str, address: str, dashboard_token: str, use_proxy: bool): 370 | proxy = self.get_next_proxy_for_account(account) if use_proxy else None 371 | extension_token = None 372 | while extension_token is None: 373 | extension_token = await self.extension_login(account, address, dashboard_token, use_proxy, proxy) 374 | if not extension_token: 375 | proxy = self.rotate_proxy_for_account(account) if use_proxy else None 376 | continue 377 | 378 | self.print_message(address, proxy, Fore.GREEN, "GET Extension Token Success") 379 | return extension_token 380 | 381 | async def process_accounts(self, account: str, address: str, use_proxy: bool): 382 | dashboard_token = await self.get_dashboard_token(account, address, use_proxy) 383 | if dashboard_token: 384 | extension_token = await self.get_extension_token(account, address, dashboard_token, use_proxy) 385 | if extension_token: 386 | 387 | tasks = [] 388 | tasks.append(self.get_user_information(account, address, extension_token, use_proxy)) 389 | tasks.append(self.process_send_ping(account, address, extension_token, use_proxy)) 390 | await asyncio.gather(*tasks) 391 | 392 | async def main(self): 393 | try: 394 | with open('accounts.txt', 'r') as file: 395 | accounts = [line.strip() for line in file if line.strip()] 396 | 397 | use_proxy_choice = self.print_question() 398 | 399 | use_proxy = False 400 | if use_proxy_choice in [1, 2]: 401 | use_proxy = True 402 | 403 | self.clear_terminal() 404 | self.welcome() 405 | self.log( 406 | f"{Fore.GREEN + Style.BRIGHT}Account's Total: {Style.RESET_ALL}" 407 | f"{Fore.WHITE + Style.BRIGHT}{len(accounts)}{Style.RESET_ALL}" 408 | ) 409 | 410 | if use_proxy: 411 | await self.load_proxies(use_proxy_choice) 412 | 413 | self.log(f"{Fore.CYAN + Style.BRIGHT}-{Style.RESET_ALL}"*75) 414 | 415 | while True: 416 | tasks = [] 417 | for account in accounts: 418 | if account: 419 | address = self.generate_address(account) 420 | tasks.append(self.process_accounts(account, address, use_proxy)) 421 | 422 | await asyncio.gather(*tasks) 423 | await asyncio.sleep(10) 424 | 425 | except FileNotFoundError as e: 426 | self.log(f"{Fore.RED+Style.BRIGHT}File 'accounts.txt' Not Found.{Style.RESET_ALL}") 427 | return 428 | except Exception as e: 429 | self.log(f"{Fore.RED+Style.BRIGHT}Error: {e}{Style.RESET_ALL}") 430 | 431 | if __name__ == "__main__": 432 | try: 433 | bot = MultipleLite() 434 | asyncio.run(bot.main()) 435 | except KeyboardInterrupt: 436 | print( 437 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}" 438 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}" 439 | f"{Fore.RED + Style.BRIGHT}[ EXIT ] Multiple Lite Node - BOT{Style.RESET_ALL} " 440 | ) --------------------------------------------------------------------------------