├── proxy.txt
├── requirements.txt
├── accounts.json
├── README.md
├── setup.py
└── bot.py
/proxy.txt:
--------------------------------------------------------------------------------
1 | ip:port # Default Protcol HTTP.
2 | protocol://ip:port
3 | protocol://user:pass@ip:port
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.11.10
2 | aiohttp-socks==0.9.1
3 | colorama==0.4.6
4 | pytz==2024.1
--------------------------------------------------------------------------------
/accounts.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "email": "your_email_address_1",
4 | "passcode": "your_passcode",
5 | "interlinkId": "your_interlink_id ( without xxxx@, only number )"
6 | },
7 | {
8 | "email": "your_email_address_2",
9 | "passcode": "your_passcode",
10 | "interlinkId": "your_interlink_id ( without xxxx@, only number )"
11 | }
12 | ]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🌅 Interlink BOT
2 |
3 | > Automated Mining $ITLG with multi-account and proxy support
4 |
5 | [](https://www.python.org/downloads/)
6 | [](LICENSE)
7 | [](https://github.com/vonssy/Interlink-BOT/stargazers)
8 |
9 | ## 📋 Table of Contents
10 |
11 | - [Overview](#overview)
12 | - [Features](#features)
13 | - [Requirements](#requirements)
14 | - [Installation](#installation)
15 | - [Configuration](#configuration)
16 | - [Setup & Usage](#setup--usage)
17 | - [Proxy Recommendation](#proxy-recommendation)
18 | - [Support](#support)
19 | - [Contributing](#contributing)
20 |
21 | ## 🎯 Overview
22 |
23 | Interlink BOT is an automated tool designed to mining $ITLG tokens across multiple accounts. It provides seamless offers robust proxy support for enhanced security and reliability.performance.
24 |
25 | **🔗 Get Started:** [Register on Interlink Validator](https://interlinklabs.ai/referral?refCode=26122003)
26 |
27 | > **Referral Code:** Use code `26122003` during registration for benefits!
28 |
29 | ## ✨ Features
30 |
31 | - 🔄 **Automated Account Management** - Retrieve account information automatically
32 | - 🌐 **Flexible Proxy Support** - Run with or without proxy configuration
33 | - 🔀 **Smart Proxy Rotation** - Automatic rotation of invalid proxies
34 | - ⛏️ **Mining $ITLG Tokens** - Automated claim $ITLG tokens every 4 hours
35 | - 👥 **Multi-Account Support** - Manage multiple accounts simultaneously
36 |
37 | ## 📋 Requirements
38 |
39 | - **Python:** Version 3.9 or higher
40 | - **pip:** Latest version recommended
41 |
42 | ## 🛠 Installation
43 |
44 | ### 1. Clone the Repository
45 |
46 | ```bash
47 | git clone https://github.com/vonssy/Interlink-BOT.git
48 | cd Interlink-BOT
49 | ```
50 |
51 | ### 2. Install Dependencies
52 |
53 | ```bash
54 | pip install -r requirements.txt
55 | # or for Python 3 specifically
56 | pip3 install -r requirements.txt
57 | ```
58 |
59 | ## ⚙️ Configuration
60 |
61 | ### Account Configuration
62 |
63 | Create or edit `accounts.josn` in the project directory:
64 |
65 | ```json
66 | [
67 | {
68 | "email": "your_email_address_1",
69 | "passcode": "your_passcode",
70 | "interlinkId": "your_interlink_id ( without xxxx@, only number )"
71 | },
72 | {
73 | "email": "your_email_address_2",
74 | "passcode": "your_passcode",
75 | "interlinkId": "your_interlink_id ( without xxxx@, only number )"
76 | }
77 | ]
78 | ```
79 |
80 | ### Proxy Configuration (Optional)
81 |
82 | Create or edit `proxy.txt` in the project directory:
83 |
84 | ```
85 | # Simple format (HTTP protocol by default)
86 | 192.168.1.1:8080
87 |
88 | # With protocol specification
89 | http://192.168.1.1:8080
90 | https://192.168.1.1:8080
91 |
92 | # With authentication
93 | http://username:password@192.168.1.1:8080
94 | ```
95 |
96 | ## 🚀 Setup & Usage
97 |
98 | ### Automatic Token Setup
99 |
100 | Run the setup script to automatically fetch tokens using your configured account credentials:
101 |
102 | ```bash
103 | python setup.py
104 | # or for Python 3 specifically
105 | python3 setup.py
106 | ```
107 |
108 | > **💡 What does setup.py do?**
109 | > - Automatically logs in to your Interlink App accounts
110 | > - Extracts bearer tokens automatically
111 | > - Saves tokens to `tokens.json` for the bot to use
112 |
113 | ### Start the Bot
114 |
115 | After running the setup, launch the Interlink BOT:
116 |
117 | ```bash
118 | python bot.py
119 | # or for Python 3 specifically
120 | python3 bot.py
121 | ```
122 |
123 | ### Runtime Options
124 |
125 | When starting the bot, you'll be prompted to choose:
126 |
127 | 1. **Proxy Mode Selection:**
128 | - Option `1`: Run with proxy
129 | - Option `2`: Run without proxy
130 |
131 | 2. **Auto-Rotation:**
132 | - `y`: Enable automatic invalid proxy rotation
133 | - `n`: Disable auto-rotation
134 |
135 | ## 🌐 Proxy Recommendation
136 |
137 |
138 |

139 |
140 |
141 | For reliable multi-wallet automation and geo-restriction bypass, we recommend **Nstproxy**:
142 |
143 | ### Why Nstproxy?
144 | - 💰 **Affordable pricing** starting from $0.1/GB
145 | - 🌍 **Global coverage** with multiple locations
146 | - 🔄 **Advanced rotation control**
147 | - 🛡️ **Anti-ban technology**
148 |
149 | ### Get Started with Nstproxy
150 | - 🔗 **Website:** [Nstproxy.com](https://www.nstproxy.com/?utm_source=vonssy)
151 | - 💬 **Telegram:** [@nstproxy](https://t.me/nstproxy)
152 | - 🎮 **Discord:** [Join Server](https://discord.gg/5jjWCAmvng)
153 | - 📚 **GitHub:** [Nstproxy Repository](https://github.com/Nstproxy)
154 |
155 | > 🎁 **Special Offer:** Use code `VONSSY` for **10% OFF** your first purchase!
156 |
157 | ## 💖 Support the Project
158 |
159 | If this project has been helpful to you, consider supporting its development:
160 |
161 | ### Cryptocurrency Donations
162 |
163 | | Network | Address |
164 | |---------|---------|
165 | | **EVM** | `0xe3c9ef9a39e9eb0582e5b147026cae524338521a` |
166 | | **TON** | `UQBEFv58DC4FUrGqinBB5PAQS7TzXSm5c1Fn6nkiet8kmehB` |
167 | | **SOL** | `E1xkaJYmAFEj28NPHKhjbf7GcvfdjKdvXju8d8AeSunf` |
168 | | **SUI** | `0xa03726ecbbe00b31df6a61d7a59d02a7eedc39fe269532ceab97852a04cf3347` |
169 |
170 | ## 🤝 Contributing
171 |
172 | We welcome contributions from the community! Here's how you can help:
173 |
174 | 1. ⭐ **Star this repository** if you find it useful
175 | 2. 👥 **Follow** for updates on new features
176 | 3. 🐛 **Report issues** via GitHub Issues
177 | 4. 💡 **Suggest improvements** or new features
178 | 5. 🔧 **Submit pull requests** for bug fixes or enhancements
179 |
180 | ## 📞 Contact & Support
181 |
182 | - **Developer:** vonssy
183 | - **Issues:** [GitHub Issues](https://github.com/vonssy/Interlink-BOT/issues)
184 | - **Discussions:** [GitHub Discussions](https://github.com/vonssy/Interlink-BOT/discussions)
185 |
186 | ---
187 |
188 |
189 |
190 | **Made with ❤️ by [vonssy](https://github.com/vonssy)**
191 |
192 | *Thank you for using Interlink Validator BOT! Don't forget to ⭐ star this repository.*
193 |
194 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from aiohttp import ClientResponseError, ClientSession, ClientTimeout, BasicAuth
2 | from aiohttp_socks import ProxyConnector
3 | from datetime import datetime
4 | from colorama import *
5 | import asyncio, json, pytz, re, os
6 |
7 | wib = pytz.timezone('Asia/Jakarta')
8 |
9 | class Interlink:
10 | def __init__(self) -> None:
11 | self.HEADERS = {
12 | "Accept-Encoding": "*/*",
13 | "User-Agent": "okhttp/4.12.0",
14 | "Accept-Encoding": "gzip"
15 | }
16 | self.BASE_API = "https://prod.interlinklabs.ai/api/v1"
17 | self.proxies = []
18 | self.proxy_index = 0
19 | self.account_proxies = {}
20 |
21 | def clear_terminal(self):
22 | os.system('cls' if os.name == 'nt' else 'clear')
23 |
24 | def log(self, message):
25 | print(
26 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
27 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}{message}",
28 | flush=True
29 | )
30 |
31 | def log_status(self, action, status, message="", error=None):
32 | if status == "success":
33 | self.log(
34 | f"{Fore.CYAN+Style.BRIGHT}Action :{Style.RESET_ALL}"
35 | f"{Fore.WHITE+Style.BRIGHT} {action} {Style.RESET_ALL}"
36 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
37 | f"{Fore.GREEN+Style.BRIGHT} Success {Style.RESET_ALL}"
38 | f"{(Fore.MAGENTA+Style.BRIGHT + '- ' + Style.RESET_ALL + Fore.WHITE+Style.BRIGHT + message + Style.RESET_ALL) if message else ''}"
39 | )
40 | elif status == "failed":
41 | self.log(
42 | f"{Fore.CYAN+Style.BRIGHT}Action :{Style.RESET_ALL}"
43 | f"{Fore.WHITE+Style.BRIGHT} {action} {Style.RESET_ALL}"
44 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
45 | f"{Fore.RED+Style.BRIGHT} Failed {Style.RESET_ALL}"
46 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
47 | f"{Fore.YELLOW+Style.BRIGHT} {str(error)} {Style.RESET_ALL}"
48 | )
49 | elif status == "retry":
50 | self.log(
51 | f"{Fore.CYAN+Style.BRIGHT}Action :{Style.RESET_ALL}"
52 | f"{Fore.WHITE+Style.BRIGHT} {action} {Style.RESET_ALL}"
53 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
54 | f"{Fore.YELLOW+Style.BRIGHT} Retrying {Style.RESET_ALL}"
55 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
56 | f"{Fore.WHITE+Style.BRIGHT} {message} {Style.RESET_ALL}"
57 | )
58 |
59 | def welcome(self):
60 | print(
61 | f"""
62 | {Fore.GREEN + Style.BRIGHT}Interlink {Fore.BLUE + Style.BRIGHT}Auto BOT
63 | """
64 | f"""
65 | {Fore.GREEN + Style.BRIGHT}Rey? {Fore.YELLOW + Style.BRIGHT}
66 | """
67 | )
68 |
69 | def format_seconds(self, seconds):
70 | hours, remainder = divmod(seconds, 3600)
71 | minutes, seconds = divmod(remainder, 60)
72 | return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}"
73 |
74 | def load_accounts(self):
75 | filename = "accounts.json"
76 | try:
77 | if not os.path.exists(filename):
78 | self.log(f"{Fore.RED}File {filename} Not Found.{Style.RESET_ALL}")
79 | return
80 |
81 | with open(filename, 'r') as file:
82 | data = json.load(file)
83 | if isinstance(data, list):
84 | return data
85 | return []
86 | except json.JSONDecodeError:
87 | return []
88 |
89 | def save_tokens(self, new_accounts):
90 | filename = "tokens.json"
91 | try:
92 | if os.path.exists(filename) and os.path.getsize(filename) > 0:
93 | with open(filename, 'r') as file:
94 | existing_accounts = json.load(file)
95 | else:
96 | existing_accounts = []
97 |
98 | account_dict = {acc["email"]: acc for acc in existing_accounts}
99 |
100 | for new_acc in new_accounts:
101 | account_dict[new_acc["email"]] = new_acc
102 |
103 | updated_accounts = list(account_dict.values())
104 |
105 | with open(filename, 'w') as file:
106 | json.dump(updated_accounts, file, indent=4)
107 |
108 | self.log_status("Save Tokens", "success", "Tokens saved to file")
109 |
110 | except Exception as e:
111 | self.log_status("Save Tokens", "failed", error=e)
112 | return []
113 |
114 | async def load_proxies(self):
115 | filename = "proxy.txt"
116 | try:
117 | if not os.path.exists(filename):
118 | self.log(f"{Fore.RED + Style.BRIGHT}File {filename} Not Found.{Style.RESET_ALL}")
119 | return
120 | with open(filename, 'r') as f:
121 | self.proxies = [line.strip() for line in f.read().splitlines() if line.strip()]
122 |
123 | if not self.proxies:
124 | self.log(f"{Fore.RED + Style.BRIGHT}No Proxies Found.{Style.RESET_ALL}")
125 | return
126 |
127 | self.log(
128 | f"{Fore.GREEN + Style.BRIGHT}Proxies Total : {Style.RESET_ALL}"
129 | f"{Fore.WHITE + Style.BRIGHT}{len(self.proxies)}{Style.RESET_ALL}"
130 | )
131 |
132 | except Exception as e:
133 | self.log(f"{Fore.RED + Style.BRIGHT}Failed To Load Proxies: {e}{Style.RESET_ALL}")
134 | self.proxies = []
135 |
136 | def check_proxy_schemes(self, proxies):
137 | schemes = ["http://", "https://", "socks4://", "socks5://"]
138 | if any(proxies.startswith(scheme) for scheme in schemes):
139 | return proxies
140 | return f"http://{proxies}"
141 |
142 | def get_next_proxy_for_account(self, account):
143 | if account not in self.account_proxies:
144 | if not self.proxies:
145 | return None
146 | proxy = self.check_proxy_schemes(self.proxies[self.proxy_index])
147 | self.account_proxies[account] = proxy
148 | self.proxy_index = (self.proxy_index + 1) % len(self.proxies)
149 | return self.account_proxies[account]
150 |
151 | def rotate_proxy_for_account(self, account):
152 | if not self.proxies:
153 | return None
154 | proxy = self.check_proxy_schemes(self.proxies[self.proxy_index])
155 | self.account_proxies[account] = proxy
156 | self.proxy_index = (self.proxy_index + 1) % len(self.proxies)
157 | return proxy
158 |
159 | def build_proxy_config(self, proxy=None):
160 | if not proxy:
161 | return None, None, None
162 |
163 | if proxy.startswith("socks"):
164 | connector = ProxyConnector.from_url(proxy)
165 | return connector, None, None
166 |
167 | elif proxy.startswith("http"):
168 | match = re.match(r"http://(.*?):(.*?)@(.*)", proxy)
169 | if match:
170 | username, password, host_port = match.groups()
171 | clean_url = f"http://{host_port}"
172 | auth = BasicAuth(username, password)
173 | return None, clean_url, auth
174 | else:
175 | return None, proxy, None
176 |
177 | raise Exception("Unsupported Proxy Type.")
178 |
179 | def mask_account(self, account):
180 | if "@" in account:
181 | local, domain = account.split('@', 1)
182 | mask_account = local[:3] + '*' * 3 + local[-3:]
183 | return f"{mask_account}@{domain}"
184 |
185 | def print_question(self):
186 | while True:
187 | try:
188 | print(f"{Fore.WHITE + Style.BRIGHT}1. Run With Proxy{Style.RESET_ALL}")
189 | print(f"{Fore.WHITE + Style.BRIGHT}2. Run Without Proxy{Style.RESET_ALL}")
190 | proxy_choice = int(input(f"{Fore.BLUE + Style.BRIGHT}Choose [1/2] -> {Style.RESET_ALL}").strip())
191 |
192 | if proxy_choice in [1, 2]:
193 | proxy_type = (
194 | "With" if proxy_choice == 1 else
195 | "Without"
196 | )
197 | print(f"{Fore.GREEN + Style.BRIGHT}Run {proxy_type} Proxy Selected.{Style.RESET_ALL}")
198 | break
199 | else:
200 | print(f"{Fore.RED + Style.BRIGHT}Please enter either 1 or 2.{Style.RESET_ALL}")
201 | except ValueError:
202 | print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter a number (1 or 2).{Style.RESET_ALL}")
203 |
204 | rotate_proxy = False
205 | if proxy_choice == 1:
206 | while True:
207 | rotate_proxy = input(f"{Fore.BLUE + Style.BRIGHT}Rotate Invalid Proxy? [y/n] -> {Style.RESET_ALL}").strip()
208 | if rotate_proxy in ["y", "n"]:
209 | rotate_proxy = rotate_proxy == "y"
210 | break
211 | else:
212 | print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter 'y' or 'n'.{Style.RESET_ALL}")
213 |
214 | return proxy_choice, rotate_proxy
215 |
216 | async def check_connection(self, proxy_url=None):
217 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
218 | try:
219 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=10)) as session:
220 | async with session.get(url="https://api.ipify.org?format=json", proxy=proxy, proxy_auth=proxy_auth) as response:
221 | response.raise_for_status()
222 | self.log_status("Check Connection", "success", "Connection OK")
223 | return True
224 | except (Exception, ClientResponseError) as e:
225 | self.log_status("Check Connection", "failed", error=e)
226 | return None
227 |
228 | async def request_otp(self, email: str, passcode: str, interlink_id: str, proxy_url=None, retries=5):
229 | url = f"{self.BASE_API}/auth/send-otp-email-verify-login"
230 | data = json.dumps({"loginId":int(interlink_id), "passcode":int(passcode), "email":email})
231 | headers = {
232 | **self.HEADERS,
233 | "Content-Length": str(len(data)),
234 | "Content-Type": "application/json"
235 | }
236 | for attempt in range(retries):
237 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
238 | try:
239 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
240 | async with session.post(url=url, headers=headers, data=data, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
241 | response.raise_for_status()
242 | result = await response.json()
243 | self.log_status("Request OTP", "success", "OTP request sent")
244 | return result
245 | except (Exception, ClientResponseError) as e:
246 | if attempt < retries - 1:
247 | self.log_status("Request OTP", "retry", f"Attempt {attempt + 1}/{retries}")
248 | await asyncio.sleep(5)
249 | continue
250 | else:
251 | self.log_status("Request OTP", "failed", error=e)
252 | return None
253 |
254 | async def verify_otp(self, interlink_id: str, otp_code: str, proxy_url=None, retries=5):
255 | url = f"{self.BASE_API}/auth/check-otp-email-verify-login"
256 | data = json.dumps({"loginId":int(interlink_id), "otp":int(otp_code)})
257 | headers = {
258 | **self.HEADERS,
259 | "Content-Length": str(len(data)),
260 | "Content-Type": "application/json"
261 | }
262 | for attempt in range(retries):
263 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
264 | try:
265 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
266 | async with session.post(url=url, headers=headers, data=data, proxy=proxy, proxy_auth=proxy_auth) as response:
267 | response.raise_for_status()
268 | result = await response.json()
269 | self.log_status("Verify OTP", "success", "OTP verified successfully")
270 | return result
271 | except (Exception, ClientResponseError) as e:
272 | if attempt < retries - 1:
273 | self.log_status("Verify OTP", "retry", f"Attempt {attempt + 1}/{retries}")
274 | await asyncio.sleep(5)
275 | continue
276 | else:
277 | self.log_status("Verify OTP", "failed", error=e)
278 | return None
279 |
280 | async def process_check_connection(self, email: str, use_proxy: bool, rotate_proxy: bool):
281 | while True:
282 | proxy = self.get_next_proxy_for_account(email) if use_proxy else None
283 | self.log(
284 | f"{Fore.CYAN+Style.BRIGHT}Proxy :{Style.RESET_ALL}"
285 | f"{Fore.WHITE+Style.BRIGHT} {proxy if proxy else 'No Proxy'} {Style.RESET_ALL}"
286 | )
287 |
288 | is_valid = await self.check_connection(proxy)
289 | if is_valid: return True
290 |
291 | if rotate_proxy:
292 | proxy = self.rotate_proxy_for_account(email)
293 | await asyncio.sleep(1)
294 | continue
295 |
296 | return False
297 |
298 | async def process_accounts(self, email: str, passcode: str, interlink_id: str, use_proxy: bool, rotate_proxy: bool):
299 | is_valid = await self.process_check_connection(email, use_proxy, rotate_proxy)
300 | if not is_valid:
301 | self.log_status("Process Account", "failed", error="Connection check failed")
302 | return
303 |
304 | proxy = self.get_next_proxy_for_account(email) if use_proxy else None
305 |
306 | request = await self.request_otp(email, passcode, interlink_id, proxy)
307 | if not request: return
308 |
309 | timestamp = (
310 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
311 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}"
312 | f"{Fore.CYAN + Style.BRIGHT}Action :{Style.RESET_ALL}"
313 | )
314 | otp_code = input(f"{timestamp}{Fore.BLUE + Style.BRIGHT} Enter OTP Code -> {Style.RESET_ALL}")
315 |
316 | verify = await self.verify_otp(interlink_id, otp_code, proxy)
317 | if not verify: return
318 |
319 | token = verify.get("data", {}).get("jwtToken")
320 | if not token:
321 | self.log_status("Process Account", "failed", error="No token received from authentication")
322 | return
323 |
324 | if email and token:
325 | account_data = [{"email":email, "token":token}]
326 | self.save_tokens(account_data)
327 | self.log_status("Process Account", "success", f"Account {self.mask_account(email)} processed successfully")
328 | else:
329 | self.log_status("Process Account", "failed", error="Invalid response data")
330 |
331 | async def main(self):
332 | try:
333 | accounts = self.load_accounts()
334 | if not accounts:
335 | print(f"{Fore.YELLOW + Style.BRIGHT}No Accounts Loaded{Style.RESET_ALL}")
336 | return
337 |
338 | proxy_choice, rotate_proxy = self.print_question()
339 |
340 | self.clear_terminal()
341 | self.welcome()
342 |
343 | use_proxy = True if proxy_choice == 1 else False
344 | if use_proxy:
345 | await self.load_proxies()
346 |
347 | separator = "=" * 27
348 | for idx, account in enumerate(accounts, start=1):
349 | email = account["email"]
350 | passcode = account["passcode"]
351 | interlink_id = account["interlinkId"]
352 |
353 | if not "@" in email or not passcode or not interlink_id:
354 | self.log_status("Account Validation", "failed", error="Invalid account format")
355 | continue
356 |
357 | self.log(
358 | f"{Fore.CYAN + Style.BRIGHT}{separator}[{Style.RESET_ALL}"
359 | f"{Fore.WHITE + Style.BRIGHT} {idx} {Style.RESET_ALL}"
360 | f"{Fore.CYAN + Style.BRIGHT}Of{Style.RESET_ALL}"
361 | f"{Fore.WHITE + Style.BRIGHT} {len(accounts)} {Style.RESET_ALL}"
362 | f"{Fore.CYAN + Style.BRIGHT}]{separator}{Style.RESET_ALL}"
363 | )
364 |
365 | self.log(
366 | f"{Fore.CYAN+Style.BRIGHT}Email :{Style.RESET_ALL}"
367 | f"{Fore.WHITE+Style.BRIGHT} {self.mask_account(email)} {Style.RESET_ALL}"
368 | )
369 |
370 | await self.process_accounts(email, passcode, interlink_id, use_proxy, rotate_proxy)
371 | await asyncio.sleep(3)
372 |
373 | except Exception as e:
374 | self.log_status("Main Process", "failed", error=e)
375 | raise e
376 |
377 | if __name__ == "__main__":
378 | try:
379 | bot = Interlink()
380 | asyncio.run(bot.main())
381 | except KeyboardInterrupt:
382 | print(
383 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
384 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}"
385 | f"{Fore.RED + Style.BRIGHT}[ EXIT ] Interlink - BOT{Style.RESET_ALL} ",
386 | )
--------------------------------------------------------------------------------
/bot.py:
--------------------------------------------------------------------------------
1 | from aiohttp import (
2 | ClientResponseError,
3 | ClientSession,
4 | ClientTimeout,
5 | BasicAuth
6 | )
7 | from aiohttp_socks import ProxyConnector
8 | from base64 import urlsafe_b64decode
9 | from datetime import datetime
10 | from colorama import *
11 | import asyncio, time, json, pytz, re, os
12 |
13 | wib = pytz.timezone('Asia/Jakarta')
14 |
15 | class Interlink:
16 | def __init__(self) -> None:
17 | self.HEADERS = {
18 | "Accept-Encoding": "*/*",
19 | "User-Agent": "okhttp/4.12.0",
20 | "Accept-Encoding": "gzip"
21 | }
22 | self.BASE_API = "https://prod.interlinklabs.ai/api/v1"
23 | self.proxies = []
24 | self.proxy_index = 0
25 | self.account_proxies = {}
26 | self.access_tokens = {}
27 |
28 | def clear_terminal(self):
29 | os.system('cls' if os.name == 'nt' else 'clear')
30 |
31 | def log(self, message):
32 | print(
33 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
34 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}{message}",
35 | flush=True
36 | )
37 |
38 | def welcome(self):
39 | print(
40 | f"""
41 | {Fore.GREEN + Style.BRIGHT}Auto Claim {Fore.BLUE + Style.BRIGHT}Interlink - BOT
42 | """
43 | f"""
44 | {Fore.GREEN + Style.BRIGHT}Rey? {Fore.YELLOW + Style.BRIGHT}
45 | """
46 | )
47 |
48 | def format_seconds(self, seconds):
49 | hours, remainder = divmod(seconds, 3600)
50 | minutes, seconds = divmod(remainder, 60)
51 | return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}"
52 |
53 | def load_accounts(self):
54 | filename = "tokens.json"
55 | try:
56 | if not os.path.exists(filename):
57 | self.log(f"{Fore.RED}File {filename} Not Found.{Style.RESET_ALL}")
58 | return
59 |
60 | with open(filename, 'r') as file:
61 | data = json.load(file)
62 | if isinstance(data, list):
63 | return data
64 | return []
65 | except json.JSONDecodeError:
66 | return []
67 |
68 | async def load_proxies(self):
69 | filename = "proxy.txt"
70 | try:
71 | if not os.path.exists(filename):
72 | self.log(f"{Fore.RED + Style.BRIGHT}File {filename} Not Found.{Style.RESET_ALL}")
73 | return
74 | with open(filename, 'r') as f:
75 | self.proxies = [line.strip() for line in f.read().splitlines() if line.strip()]
76 |
77 | if not self.proxies:
78 | self.log(f"{Fore.RED + Style.BRIGHT}No Proxies Found.{Style.RESET_ALL}")
79 | return
80 |
81 | self.log(
82 | f"{Fore.GREEN + Style.BRIGHT}Proxies Total : {Style.RESET_ALL}"
83 | f"{Fore.WHITE + Style.BRIGHT}{len(self.proxies)}{Style.RESET_ALL}"
84 | )
85 |
86 | except Exception as e:
87 | self.log(f"{Fore.RED + Style.BRIGHT}Failed To Load Proxies: {e}{Style.RESET_ALL}")
88 | self.proxies = []
89 |
90 | def check_proxy_schemes(self, proxies):
91 | schemes = ["http://", "https://", "socks4://", "socks5://"]
92 | if any(proxies.startswith(scheme) for scheme in schemes):
93 | return proxies
94 | return f"http://{proxies}"
95 |
96 | def get_next_proxy_for_account(self, account):
97 | if account not in self.account_proxies:
98 | if not self.proxies:
99 | return None
100 | proxy = self.check_proxy_schemes(self.proxies[self.proxy_index])
101 | self.account_proxies[account] = proxy
102 | self.proxy_index = (self.proxy_index + 1) % len(self.proxies)
103 | return self.account_proxies[account]
104 |
105 | def rotate_proxy_for_account(self, account):
106 | if not self.proxies:
107 | return None
108 | proxy = self.check_proxy_schemes(self.proxies[self.proxy_index])
109 | self.account_proxies[account] = proxy
110 | self.proxy_index = (self.proxy_index + 1) % len(self.proxies)
111 | return proxy
112 |
113 | def build_proxy_config(self, proxy=None):
114 | if not proxy:
115 | return None, None, None
116 |
117 | if proxy.startswith("socks"):
118 | connector = ProxyConnector.from_url(proxy)
119 | return connector, None, None
120 |
121 | elif proxy.startswith("http"):
122 | match = re.match(r"http://(.*?):(.*?)@(.*)", proxy)
123 | if match:
124 | username, password, host_port = match.groups()
125 | clean_url = f"http://{host_port}"
126 | auth = BasicAuth(username, password)
127 | return None, clean_url, auth
128 | else:
129 | return None, proxy, None
130 |
131 | raise Exception("Unsupported Proxy Type.")
132 |
133 | def decode_token(self, token: str):
134 | try:
135 | header, payload, signature = token.split(".")
136 | decoded_payload = urlsafe_b64decode(payload + "==").decode("utf-8")
137 | parsed_payload = json.loads(decoded_payload)
138 | exp_time = parsed_payload["exp"]
139 |
140 | return exp_time
141 | except Exception as e:
142 | return None
143 |
144 | def mask_account(self, account):
145 | if "@" in account:
146 | local, domain = account.split('@', 1)
147 | mask_account = local[:3] + '*' * 3 + local[-3:]
148 | return f"{mask_account}@{domain}"
149 |
150 | def print_question(self):
151 | while True:
152 | try:
153 | print(f"{Fore.WHITE + Style.BRIGHT}1. Run With Proxy{Style.RESET_ALL}")
154 | print(f"{Fore.WHITE + Style.BRIGHT}2. Run Without Proxy{Style.RESET_ALL}")
155 | proxy_choice = int(input(f"{Fore.BLUE + Style.BRIGHT}Choose [1/2] -> {Style.RESET_ALL}").strip())
156 |
157 | if proxy_choice in [1, 2]:
158 | proxy_type = (
159 | "With" if proxy_choice == 1 else
160 | "Without"
161 | )
162 | print(f"{Fore.GREEN + Style.BRIGHT}Run {proxy_type} Proxy Selected.{Style.RESET_ALL}")
163 | break
164 | else:
165 | print(f"{Fore.RED + Style.BRIGHT}Please enter either 1 or 2.{Style.RESET_ALL}")
166 | except ValueError:
167 | print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter a number (1 or 2).{Style.RESET_ALL}")
168 |
169 | rotate_proxy = False
170 | if proxy_choice == 1:
171 | while True:
172 | rotate_proxy = input(f"{Fore.BLUE + Style.BRIGHT}Rotate Invalid Proxy? [y/n] -> {Style.RESET_ALL}").strip()
173 | if rotate_proxy in ["y", "n"]:
174 | rotate_proxy = rotate_proxy == "y"
175 | break
176 | else:
177 | print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter 'y' or 'n'.{Style.RESET_ALL}")
178 |
179 | return proxy_choice, rotate_proxy
180 |
181 | async def check_connection(self, proxy_url=None):
182 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
183 | try:
184 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=10)) as session:
185 | async with session.get(url="https://api.ipify.org?format=json", proxy=proxy, proxy_auth=proxy_auth) as response:
186 | response.raise_for_status()
187 | return True
188 | except (Exception, ClientResponseError) as e:
189 | self.log(
190 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
191 | f"{Fore.RED+Style.BRIGHT} Connection Not 200 OK {Style.RESET_ALL}"
192 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
193 | f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
194 | )
195 | return None
196 |
197 | async def token_balance(self, email: str, proxy_url=None, retries=5):
198 | url = f"{self.BASE_API}/token/get-token"
199 | headers = {
200 | **self.HEADERS,
201 | "Authorization": f"Bearer {self.access_tokens[email]}"
202 | }
203 | await asyncio.sleep(3)
204 | for attempt in range(retries):
205 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
206 | try:
207 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
208 | async with session.get(url=url, headers=headers, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
209 | response.raise_for_status()
210 | return await response.json()
211 | except (Exception, ClientResponseError) as e:
212 | if attempt < retries - 1:
213 | await asyncio.sleep(5)
214 | continue
215 | self.log(
216 | f"{Fore.CYAN+Style.BRIGHT}Balance:{Style.RESET_ALL}"
217 | f"{Fore.RED+Style.BRIGHT} GET Token Earned Failed {Style.RESET_ALL}"
218 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
219 | f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
220 | )
221 |
222 | return None
223 |
224 | async def claimable_check(self, email: str, proxy_url=None, retries=5):
225 | url = f"{self.BASE_API}/token/check-is-claimable"
226 | headers = {
227 | **self.HEADERS,
228 | "Authorization": f"Bearer {self.access_tokens[email]}"
229 | }
230 | await asyncio.sleep(3)
231 | for attempt in range(retries):
232 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
233 | try:
234 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
235 | async with session.get(url=url, headers=headers, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
236 | response.raise_for_status()
237 | return await response.json()
238 | except (Exception, ClientResponseError) as e:
239 | if attempt < retries - 1:
240 | await asyncio.sleep(5)
241 | continue
242 | self.log(
243 | f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
244 | f"{Fore.RED+Style.BRIGHT} GET Status Failed {Style.RESET_ALL}"
245 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
246 | f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
247 | )
248 |
249 | return None
250 |
251 | async def claim_airdrop(self, email: str, proxy_url=None, retries=1):
252 | url = f"{self.BASE_API}/token/claim-airdrop"
253 | headers = {
254 | **self.HEADERS,
255 | "Authorization": f"Bearer {self.access_tokens[email]}",
256 | "Content-Length": "2",
257 | "Content-Type": "application/json"
258 | }
259 | await asyncio.sleep(3)
260 | for attempt in range(retries):
261 | connector, proxy, proxy_auth = self.build_proxy_config(proxy_url)
262 | try:
263 | async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session:
264 | async with session.post(url=url, headers=headers, json={}, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response:
265 | response.raise_for_status()
266 | return await response.json()
267 | except (Exception, ClientResponseError) as e:
268 | if attempt < retries - 1:
269 | await asyncio.sleep(5)
270 | continue
271 | self.log(
272 | f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
273 | f"{Fore.RED+Style.BRIGHT} Not Claimed {Style.RESET_ALL}"
274 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
275 | f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}"
276 | )
277 |
278 | return None
279 |
280 | async def process_check_connection(self, email: str, use_proxy: bool, rotate_proxy: bool):
281 | while True:
282 | proxy = self.get_next_proxy_for_account(email) if use_proxy else None
283 | self.log(
284 | f"{Fore.CYAN+Style.BRIGHT}Proxy :{Style.RESET_ALL}"
285 | f"{Fore.WHITE+Style.BRIGHT} {proxy if proxy else 'No Proxy'} {Style.RESET_ALL}"
286 | )
287 |
288 | is_valid = await self.check_connection(proxy)
289 | if is_valid: return True
290 |
291 | if rotate_proxy:
292 | proxy = self.rotate_proxy_for_account(email)
293 | await asyncio.sleep(1)
294 | continue
295 |
296 | return False
297 |
298 | async def process_accounts(self, email: str, use_proxy: bool, rotate_proxy: bool):
299 | is_valid = await self.process_check_connection(email, use_proxy, rotate_proxy)
300 | if not is_valid: return
301 |
302 | proxy = self.get_next_proxy_for_account(email) if use_proxy else None
303 |
304 | balance = await self.token_balance(email, proxy)
305 | if balance:
306 | token_balance = balance.get("data", {}).get("interlinkTokenAmount", 0)
307 | silver_balance = balance.get("data", {}).get("interlinkSilverTokenAmount", 0)
308 | gold_balance = balance.get("data", {}).get("interlinkGoldTokenAmount", 0)
309 | diamond_balance = balance.get("data", {}).get("interlinkDiamondTokenAmount", 0)
310 |
311 | self.log(f"{Fore.CYAN+Style.BRIGHT}Balance:{Style.RESET_ALL}")
312 | self.log(
313 | f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}"
314 | f"{Fore.BLUE+Style.BRIGHT}Interlink:{Style.RESET_ALL}"
315 | f"{Fore.WHITE+Style.BRIGHT} {token_balance} {Style.RESET_ALL}"
316 | )
317 | self.log(
318 | f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}"
319 | f"{Fore.BLUE+Style.BRIGHT}Silver :{Style.RESET_ALL}"
320 | f"{Fore.WHITE+Style.BRIGHT} {silver_balance} {Style.RESET_ALL}"
321 | )
322 | self.log(
323 | f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}"
324 | f"{Fore.BLUE+Style.BRIGHT}Gold :{Style.RESET_ALL}"
325 | f"{Fore.WHITE+Style.BRIGHT} {gold_balance} {Style.RESET_ALL}"
326 | )
327 | self.log(
328 | f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}"
329 | f"{Fore.BLUE+Style.BRIGHT}Diamond :{Style.RESET_ALL}"
330 | f"{Fore.WHITE+Style.BRIGHT} {diamond_balance} {Style.RESET_ALL}"
331 | )
332 |
333 | claimable = await self.claimable_check(email, proxy)
334 | if claimable:
335 | is_claimable = claimable.get("data", {}).get("isClaimable", False)
336 |
337 | if is_claimable:
338 | claim = await self.claim_airdrop(email, proxy)
339 | if claim:
340 | reward = claim.get("data") or "N/A"
341 |
342 | self.log(
343 | f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
344 | f"{Fore.GREEN+Style.BRIGHT} Claimed Successfully {Style.RESET_ALL}"
345 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
346 | f"{Fore.CYAN+Style.BRIGHT} Reward: {Style.RESET_ALL}"
347 | f"{Fore.WHITE+Style.BRIGHT}{reward}{Style.RESET_ALL}"
348 | )
349 |
350 | else:
351 | next_frame_ts = claimable.get("data", {}).get("nextFrame", 0) / 1000
352 | next_frame_wib = datetime.fromtimestamp(next_frame_ts).astimezone(wib).strftime('%x %X %Z')
353 |
354 | self.log(
355 | f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}"
356 | f"{Fore.YELLOW+Style.BRIGHT} Already Claimed {Style.RESET_ALL}"
357 | f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}"
358 | f"{Fore.CYAN+Style.BRIGHT} Next Claim at: {Style.RESET_ALL}"
359 | f"{Fore.WHITE+Style.BRIGHT}{next_frame_wib}{Style.RESET_ALL}"
360 | )
361 |
362 | async def main(self):
363 | try:
364 | accounts = self.load_accounts()
365 | if not accounts:
366 | self.log(f"{Fore.RED}No Accounts Loaded.{Style.RESET_ALL}")
367 | return
368 |
369 | proxy_choice, rotate_proxy = self.print_question()
370 |
371 | while True:
372 | self.clear_terminal()
373 | self.welcome()
374 | self.log(
375 | f"{Fore.GREEN + Style.BRIGHT}Account's Total: {Style.RESET_ALL}"
376 | f"{Fore.WHITE + Style.BRIGHT}{len(accounts)}{Style.RESET_ALL}"
377 | )
378 |
379 | use_proxy = True if proxy_choice == 1 else False
380 | if use_proxy:
381 | await self.load_proxies()
382 |
383 | separator = "=" * 27
384 | for idx, account in enumerate(accounts, start=1):
385 | if account:
386 | email = account["email"]
387 | token = account["token"]
388 | self.log(
389 | f"{Fore.CYAN + Style.BRIGHT}{separator}[{Style.RESET_ALL}"
390 | f"{Fore.WHITE + Style.BRIGHT} {idx} {Style.RESET_ALL}"
391 | f"{Fore.CYAN + Style.BRIGHT}Of{Style.RESET_ALL}"
392 | f"{Fore.WHITE + Style.BRIGHT} {len(accounts)} {Style.RESET_ALL}"
393 | f"{Fore.CYAN + Style.BRIGHT}]{separator}{Style.RESET_ALL}"
394 | )
395 |
396 | if not "@" in email or not token:
397 | self.log(
398 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
399 | f"{Fore.RED+Style.BRIGHT} Invalid Account Data {Style.RESET_ALL}"
400 | )
401 | continue
402 |
403 | self.log(
404 | f"{Fore.CYAN+Style.BRIGHT}Account:{Style.RESET_ALL}"
405 | f"{Fore.WHITE+Style.BRIGHT} {self.mask_account(email)} {Style.RESET_ALL}"
406 | )
407 |
408 | exp_time = self.decode_token(token)
409 | if not exp_time:
410 | self.log(
411 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
412 | f"{Fore.RED+Style.BRIGHT} Invalid Token {Style.RESET_ALL}"
413 | )
414 | continue
415 |
416 | if int(time.time()) > exp_time:
417 | self.log(
418 | f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}"
419 | f"{Fore.RED+Style.BRIGHT} Token Already Expired {Style.RESET_ALL}"
420 | )
421 | continue
422 |
423 | self.access_tokens[email] = token
424 |
425 | await self.process_accounts(email, use_proxy, rotate_proxy)
426 | await asyncio.sleep(3)
427 |
428 | self.log(f"{Fore.CYAN + Style.BRIGHT}={Style.RESET_ALL}"*65)
429 | seconds = 4 * 60 * 60
430 | while seconds > 0:
431 | formatted_time = self.format_seconds(seconds)
432 | print(
433 | f"{Fore.CYAN+Style.BRIGHT}[ Wait for{Style.RESET_ALL}"
434 | f"{Fore.WHITE+Style.BRIGHT} {formatted_time} {Style.RESET_ALL}"
435 | f"{Fore.CYAN+Style.BRIGHT}... ]{Style.RESET_ALL}"
436 | f"{Fore.WHITE+Style.BRIGHT} | {Style.RESET_ALL}"
437 | f"{Fore.BLUE+Style.BRIGHT}All Accounts Have Been Processed...{Style.RESET_ALL}",
438 | end="\r"
439 | )
440 | await asyncio.sleep(1)
441 | seconds -= 1
442 |
443 | except Exception as e:
444 | self.log(f"{Fore.RED+Style.BRIGHT}Error: {e}{Style.RESET_ALL}")
445 | raise e
446 |
447 | if __name__ == "__main__":
448 | try:
449 | bot = Interlink()
450 | asyncio.run(bot.main())
451 | except KeyboardInterrupt:
452 | print(
453 | f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}"
454 | f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}"
455 | f"{Fore.RED + Style.BRIGHT}[ EXIT ] Interlink - BOT{Style.RESET_ALL} "
456 | )
--------------------------------------------------------------------------------