├── data.txt
├── bot
├── core
│ ├── __init__.py
│ ├── headers.py
│ ├── agents.py
│ ├── registrator.py
│ ├── query.py
│ └── tapper.py
├── __init__.py
├── config
│ ├── __init__.py
│ ├── proxies.txt
│ └── config.py
├── exceptions
│ └── __init__.py
└── utils
│ ├── __init__.py
│ ├── logger.py
│ └── launcher.py
├── .gitignore
├── proxy.json
├── .env-example
├── docker-compose.yml
├── main.py
├── Dockerfile
├── run.bat
├── run.sh
├── requirements.txt
├── README.md
└── LICENSE
/data.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bot/core/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bot/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = '1.0'
2 |
--------------------------------------------------------------------------------
/bot/config/__init__.py:
--------------------------------------------------------------------------------
1 | from .config import settings
2 |
--------------------------------------------------------------------------------
/bot/exceptions/__init__.py:
--------------------------------------------------------------------------------
1 | class InvalidSession(BaseException):
2 | ...
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | **/__pycache__
3 | bot/config/proxies.com
4 | sessions/*
5 | user_agents.json
--------------------------------------------------------------------------------
/proxy.json:
--------------------------------------------------------------------------------
1 | {
2 | "session file name(session mode) or telegram username(query mode)": "type:user:pass@ip:port"
3 | }
4 |
--------------------------------------------------------------------------------
/bot/config/proxies.txt:
--------------------------------------------------------------------------------
1 | https://38.154.227.167:5868:vanhbaka:Vanhdayyyy
2 | https://45.127.248.127:5128:vanhbaka:Vanhdayyyy
3 | https://207.244.217.165:6712:vanhbaka:Vanhdayyyy
4 |
--------------------------------------------------------------------------------
/bot/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .logger import logger
2 | from . import launcher
3 |
4 |
5 | import os
6 |
7 | if not os.path.exists(path="sessions"):
8 | os.mkdir(path="sessions")
9 |
--------------------------------------------------------------------------------
/.env-example:
--------------------------------------------------------------------------------
1 | API_ID=123
2 | API_HASH=abc
3 |
4 | REF_LINK=
5 |
6 | AUTO_TASK=True
7 | AUTO_GAME=True
8 | DELAY_EACH_ACCOUNT=[20, 30]
9 | SLEEP_TIME_EACH_ROUND=[2, 3]
10 |
11 | USE_PROXY_FROM_FILE=
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '1'
2 | services:
3 | bot:
4 | container_name: 'bybitSpace'
5 | build:
6 | context: .
7 | stop_signal: SIGINT
8 | restart: unless-stopped
9 | command: "python3 main.py -a 1 -m y"
10 | volumes:
11 | - .:/app
12 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from contextlib import suppress
3 |
4 | from bot.utils.launcher import process
5 |
6 |
7 | async def main():
8 | await process()
9 |
10 |
11 | if __name__ == '__main__':
12 | with suppress(KeyboardInterrupt):
13 | asyncio.run(main())
14 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10.11-alpine3.18
2 |
3 | WORKDIR app/
4 |
5 | COPY requirements.txt requirements.txt
6 |
7 | RUN pip3 install --upgrade pip setuptools wheel
8 | RUN pip3 install --no-warn-script-location --no-cache-dir -r requirements.txt
9 |
10 | COPY . .
11 |
12 | CMD ["python3", "main.py", "-a", "1"]
13 |
--------------------------------------------------------------------------------
/bot/utils/logger.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from loguru import logger
3 |
4 |
5 | logger.remove()
6 | logger.add(sink=sys.stdout, format="[Bybit space] | {time:YYYY-MM-DD HH:mm:ss}"
7 | " | {level: <8}"
8 | " | {line}"
9 | " - {message}")
10 | logger = logger.opt(colors=True)
11 |
--------------------------------------------------------------------------------
/bot/config/config.py:
--------------------------------------------------------------------------------
1 | from pydantic_settings import BaseSettings, SettingsConfigDict
2 |
3 |
4 | class Settings(BaseSettings):
5 | model_config = SettingsConfigDict(env_file=".env", env_ignore_empty=True)
6 |
7 | API_ID: int
8 | API_HASH: str
9 |
10 |
11 | REF_LINK: str = ""
12 |
13 |
14 | AUTO_TASK: bool = True
15 | AUTO_GAME: bool = True
16 |
17 |
18 | DELAY_EACH_ACCOUNT: list[int] = [20, 30]
19 | SLEEP_TIME_EACH_ROUND: list[int] = [2, 3]
20 |
21 | USE_PROXY_FROM_FILE: bool = False
22 |
23 |
24 | settings = Settings()
25 |
26 |
--------------------------------------------------------------------------------
/bot/core/headers.py:
--------------------------------------------------------------------------------
1 | headers = {
2 | 'Accept': 'application/json, text/plain, */*',
3 | 'Accept-Encoding': 'gzip, deflate',
4 | 'Accept-Language': 'en-US,en;q=0.9',
5 | 'Priority': "u=1, i",
6 | 'Origin': 'https://www.bybit.com',
7 | 'Referer': 'https://www.bybit.com/',
8 | 'Sec-Fetch-Dest': 'empty',
9 | 'Sec-Fetch-Mode': 'cors',
10 | 'Sec-Fetch-Site': 'same-site',
11 | 'Sec-Ch-Ua-mobile': '?1',
12 | 'Sec-Ch-Ua-platform': '"Android"',
13 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.165 Mobile Safari/537.36',
14 | }
15 |
--------------------------------------------------------------------------------
/bot/core/agents.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import ua_generator
4 | from ua_generator.options import Options
5 | from ua_generator.data.version import VersionRange
6 |
7 | def generate_random_user_agent(device_type='android', browser_type='chrome'):
8 | chrome_version_range = VersionRange(min_version=117, max_version=130)
9 | options = Options(version_ranges={'chrome': chrome_version_range})
10 | ua = ua_generator.generate(platform=device_type, browser=browser_type, options=options)
11 | return ua.text
12 |
13 |
14 | def fetch_version(ua):
15 | match = re.search(r"Chrome/(\d+)", ua)
16 |
17 | if match:
18 | major_version = match.group(1)
19 | return major_version
20 | else:
21 | return
--------------------------------------------------------------------------------
/bot/core/registrator.py:
--------------------------------------------------------------------------------
1 | from pyrogram import Client
2 |
3 | from bot.config import settings
4 | from bot.utils import logger
5 |
6 |
7 | async def register_sessions() -> None:
8 | API_ID = settings.API_ID
9 | API_HASH = settings.API_HASH
10 |
11 | if not API_ID or not API_HASH:
12 | raise ValueError("API_ID and API_HASH not found in the .env file.")
13 |
14 | session_name = input('\nEnter the session name (press Enter to exit): ')
15 |
16 | if not session_name:
17 | return None
18 |
19 | session = Client(
20 | name=session_name,
21 | api_id=API_ID,
22 | api_hash=API_HASH,
23 | workdir="sessions/"
24 | )
25 |
26 | async with session:
27 | user_data = await session.get_me()
28 |
29 | logger.success(f'Session added successfully @{user_data.username} | {user_data.first_name} {user_data.last_name}')
30 |
--------------------------------------------------------------------------------
/run.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | if not exist venv (
4 | echo Creating virtual environment...
5 | python -m venv venv
6 | )
7 |
8 | echo Activating virtual environment...
9 | call venv\Scripts\activate
10 |
11 | if not exist venv\Lib\site-packages\installed (
12 | if exist requirements.txt (
13 | echo installing wheel for faster installing
14 | pip install wheel
15 | echo Installing dependencies...
16 | pip install -r requirements.txt
17 | echo. > venv\Lib\site-packages\installed
18 | ) else (
19 | echo requirements.txt not found, skipping dependency installation.
20 | )
21 | ) else (
22 | echo Dependencies already installed, skipping installation.
23 | )
24 |
25 | if not exist .env (
26 | echo Copying configuration file
27 | copy .env-example .env
28 | ) else (
29 | echo Skipping .env copying
30 | )
31 |
32 | :loop
33 | python main.py
34 | echo Restarting the program in 2 seconds...
35 | timeout /t 2 /nobreak >nul
36 | goto :loop
37 |
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Проверка на наличие папки venv
4 | if [ ! -d "venv" ]; then
5 | echo "Creating virtual environment..."
6 | python3 -m venv venv
7 | fi
8 |
9 | echo "Activating virtual environment..."
10 | source venv/bin/activate
11 |
12 | # Проверка на наличие установленного флага в виртуальном окружении
13 | if [ ! -f "venv/installed" ]; then
14 | if [ -f "requirements.txt" ]; then
15 | echo "Installing wheel for faster installing"
16 | pip3 install wheel
17 | echo "Installing dependencies..."
18 | pip3 install -r requirements.txt
19 | touch venv/installed
20 | else
21 | echo "requirements.txt not found, skipping dependency installation."
22 | fi
23 | else
24 | echo "Dependencies already installed, skipping installation."
25 | fi
26 |
27 | if [ ! -f ".env" ]; then
28 | echo "Copying configuration file"
29 | cp .env-example .env
30 | else
31 | echo "Skipping .env copying"
32 | fi
33 |
34 | echo "Starting the bot..."
35 | python3 main.py
36 |
37 | echo "done"
38 | echo "PLEASE EDIT .ENV FILE"
39 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiocfscrape==1.0.0
2 | aiofile==3.9.0
3 | aiohttp==3.9.3
4 | aiohttp-proxy==0.1.2
5 | aiosignal==1.3.1
6 | annotated-types==0.6.0
7 | async-timeout==4.0.3
8 | attrs==23.2.0
9 | beautifulsoup4==4.12.3
10 | better-proxy==1.1.5
11 | Brotli==1.1.0
12 | caio==0.9.17
13 | certifi==2024.8.30
14 | charset-normalizer==3.3.2
15 | cloudscraper==1.2.71
16 | colorama==0.4.6
17 | DateTime==5.5
18 | Faker==29.0.0
19 | frozenlist==1.4.1
20 | idna==3.6
21 | Js2Py==0.74
22 | loguru==0.7.2
23 | multidict==6.0.5
24 | pyaes==1.6.1
25 | pycryptodome==3.20.0
26 | pydantic==2.6.4
27 | pydantic-settings==2.2.1
28 | pydantic_core==2.16.3
29 | pyjsparser==2.7.1
30 | pyparsing==3.1.4
31 | Pyrogram==2.0.106
32 | PySocks==1.7.1
33 | python-dateutil==2.9.0.post0
34 | python-dotenv==1.0.1
35 | pytz==2024.1
36 | requests==2.32.3
37 | requests-toolbelt==1.0.0
38 | six==1.16.0
39 | soupsieve==2.5
40 | TgCrypto==1.2.5
41 | typing_extensions==4.11.0
42 | tzdata==2024.1
43 | tzlocal==5.2
44 | ua-generator==1.0.6
45 | urllib3==2.2.2
46 | websockets==12.0
47 | win32-setctime==1.1.0
48 | yarl==1.9.4
49 | zope.interface==6.4.post2
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Table of Contents
2 | - [Recommendation before use](#recommendation-before-use)
3 | - [Features](#features)
4 | - [Settings](#settings)
5 | - [Wallet](#wallet)
6 | - [Quick Start](#quick-start)
7 | - [Prerequisites](#prerequisites)
8 | - [Obtaining API Keys](#obtaining-api-keys)
9 | - [Installation](#installation)
10 | - [Support](#support-this-project)
11 | - [Contacts](#contacts)
12 |
13 | > [!WARNING]
14 | > ⚠️ I do my best to avoid detection of bots, but using bots is forbidden in all airdrops. i cannot guarantee that you will not be detected as a bot. Use at your own risk. I am not responsible for any consequences of using this software.
15 |
16 |
17 | # 🔥🔥 Use PYTHON 3.11.5 🔥🔥
18 |
19 | ## Features
20 | | Feature | Supported |
21 | |---------------------------------------------------------------|:----------------:|
22 | | Multithreading | ✅ |
23 | | Proxy binding to session | ✅ |
24 | | Auto ref | ✅ |
25 | | Auto tasks | ✅ |
26 | | Auto play game | ✅ |
27 | | Auto start farming | ✅ |
28 | | Support for pyrogram .session / Query | ✅ |
29 |
30 | ## [Settings](https://github.com/vanhbakaa/Bybit-space/blob/main/.env-example)
31 | | Settings | Description |
32 | |----------------------------|:-------------------------------------------------------------------------------------------------------------:|
33 | | **API_ID / API_HASH** | Platform data from which to run the Telegram session (default - android) |
34 | | **REF_LINK** | Put your ref link here (default: "") |
35 | | **AUTO_TASK** | Auto do tasks (default: True) |
36 | | **AUTO_GAME** | Auto play game (default: True) |
37 | | **DELAY_EACH_ACCOUNT** | Random delay bewteen accounts (default: [20, 30] seconds) |
38 | | **SLEEP_TIME_EACH_ROUND** | Random delay bewteen each round (default: [2, 3] hours) |
39 | | **ADVANCED_ANTI_DETECTION** | Add more protection for your account (default: True) |
40 | | **USE_PROXY_FROM_FILE** | Whether to use a proxy from the bot/config/proxies.txt file (True / False) |
41 |
42 |
43 |
44 | ## Quick Start
45 |
46 | To install libraries and run bot - open run.bat on Windows
47 |
48 | ## Prerequisites
49 | Before you begin, make sure you have the following installed:
50 | - [Python](https://www.python.org/downloads/) **IMPORTANT**: Make sure to use **3.11.5**.
51 |
52 | ## Obtaining API Keys
53 | 1. Go to my.telegram.org and log in using your phone number.
54 | 2. Select "API development tools" and fill out the form to register a new application.
55 | 3. Record the API_ID and API_HASH provided after registering your application in the .env file.
56 |
57 |
58 | ## Installation
59 | You can download the [**repository**](https://github.com/vanhbakaa/Bybit-space) by cloning it to your system and installing the necessary dependencies:
60 | ```shell
61 | git clone https://github.com/vanhbakaa/Bybit-space.git
62 | cd Bybit-space
63 | ```
64 |
65 | Then you can do automatic installation by typing:
66 |
67 | Windows:
68 | ```shell
69 | run.bat
70 | ```
71 |
72 | Linux:
73 | ```shell
74 | run.sh
75 | ```
76 |
77 | # Linux manual installation
78 | ```shell
79 | python3 -m venv venv
80 | source venv/bin/activate
81 | pip3 install -r requirements.txt
82 | cp .env-example .env
83 | nano .env # Here you must specify your API_ID and API_HASH, the rest is taken by default
84 | python3 main.py
85 | ```
86 |
87 | You can also use arguments for quick start, for example:
88 | ```shell
89 | ~/Paws >>> python3 main.py --action (1/2)
90 | # Or
91 | ~/Paws >>> python3 main.py -a (1/2)
92 |
93 | # 1 - Run clicker
94 | # 2 - Creates a session
95 | ```
96 |
97 | # Windows manual installation
98 | ```shell
99 | python -m venv venv
100 | venv\Scripts\activate
101 | pip install -r requirements.txt
102 | copy .env-example .env
103 | # Here you must specify your API_ID and API_HASH, the rest is taken by default
104 | python main.py
105 | ```
106 | You can also use arguments for quick start, for example:
107 | ```shell
108 | ~/Bybit-space >>> python3 main.py --action (1/2)
109 | # Or
110 | ~/Bybit-space >>> python3 main.py -a (1/2)
111 |
112 | # 1 - Run clicker
113 | # 2 - Creates a session
114 | ```
115 |
116 | # Termux manual installation
117 | ```
118 | > pkg update && pkg upgrade -y
119 | > pkg install python rust git -y
120 | > git clone https://github.com/vanhbakaa/Bybit-space.git
121 | > cd Bybit-space
122 | > pip install -r requirements.txt
123 | > python main.py
124 | ```
125 |
126 | You can also use arguments for quick start, for example:
127 | ```termux
128 | ~/Bybit-space > python main.py --action (1/2)
129 | # Or
130 | ~/Bybit-space > python main.py -a (1/2)
131 |
132 | # 1 - Run clicker
133 | # 2 - Creates a session
134 | ```
135 | # Support This Project
136 |
137 | If you'd like to support the development of this project, please consider making a donation. Every little bit helps!
138 |
139 | 👉 **[Click here to view donation options](https://github.com/vanhbakaa/Donation/blob/main/README.md)** 👈
140 |
141 | Your support allows us to keep improving the project and bring more features!
142 |
143 | Thank you for your generosity! 🙌
144 |
145 | ### Contacts
146 |
147 | For support or questions, you can contact me [](https://t.me/airdrop_tool_vanh)
148 |
--------------------------------------------------------------------------------
/bot/utils/launcher.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import glob
4 | import asyncio
5 | import argparse
6 | import sys
7 | from itertools import cycle
8 | from urllib.parse import unquote
9 |
10 | from aiofile import AIOFile
11 | from pyrogram import Client
12 | from better_proxy import Proxy
13 |
14 | from bot.config import settings
15 | from bot.utils import logger
16 | from bot.core.tapper import run_tapper, run_tapper1
17 | from bot.core.query import run_query_tapper, run_query_tapper1
18 | from bot.core.registrator import register_sessions
19 | from ..core.agents import generate_random_user_agent
20 |
21 | start_text = """
22 |
23 | Select an action:
24 |
25 | 1. Run clicker (Session)
26 | 2. Create session
27 | 3. Run clicker (Query)
28 | """
29 |
30 | global tg_clients
31 |
32 |
33 | def get_session_names() -> list[str]:
34 | session_names = sorted(glob.glob("sessions/*.session"))
35 | session_names = [
36 | os.path.splitext(os.path.basename(file))[0] for file in session_names
37 | ]
38 |
39 | return session_names
40 |
41 | def fetch_username(query):
42 | try:
43 | fetch_data = unquote(query).split("user=")[1].split("&chat_instance=")[0]
44 | json_data = json.loads(fetch_data)
45 | return json_data['username']
46 | except:
47 | try:
48 | fetch_data = unquote(query).split("user=")[1].split("&auth_date=")[0]
49 | json_data = json.loads(fetch_data)
50 | return json_data['username']
51 | except:
52 | try:
53 | fetch_data = unquote(unquote(query)).split("user=")[1].split("&auth_date=")[0]
54 | json_data = json.loads(fetch_data)
55 | return json_data['username']
56 | except:
57 | logger.warning(f"Invaild query: {query}")
58 | return ""
59 |
60 |
61 | async def get_user_agent(session_name):
62 | async with AIOFile('user_agents.json', 'r') as file:
63 | content = await file.read()
64 | user_agents = json.loads(content)
65 |
66 | if session_name not in list(user_agents.keys()):
67 | logger.info(f"{session_name} | Doesn't have user agent, Creating...")
68 | ua = generate_random_user_agent(device_type='android', browser_type='chrome')
69 | user_agents.update({session_name: ua})
70 | async with AIOFile('user_agents.json', 'w') as file:
71 | content = json.dumps(user_agents, indent=4)
72 | await file.write(content)
73 | return ua
74 | else:
75 | logger.info(f"{session_name} | Loading user agent from cache...")
76 | return user_agents[session_name]
77 |
78 | def get_proxies() -> list[Proxy]:
79 | if settings.USE_PROXY_FROM_FILE:
80 | with open(file="bot/config/proxies.txt", encoding="utf-8-sig") as file:
81 | proxies = [Proxy.from_str(proxy=row.strip()).as_url for row in file]
82 | else:
83 | proxies = []
84 |
85 | return proxies
86 |
87 | def get_un_used_proxy(used_proxies: list[Proxy]):
88 | proxies = get_proxies()
89 | for proxy in proxies:
90 | if proxy not in used_proxies:
91 | return proxy
92 | return None
93 |
94 | async def get_proxy(session_name):
95 | if settings.USE_PROXY_FROM_FILE:
96 | async with AIOFile('proxy.json', 'r') as file:
97 | content = await file.read()
98 | proxies = json.loads(content)
99 |
100 | if session_name not in list(proxies.keys()):
101 | logger.info(f"{session_name} | Doesn't bind with any proxy, binding to a new proxy...")
102 | used_proxies = [proxy for proxy in proxies.values()]
103 | proxy = get_un_used_proxy(used_proxies)
104 | proxies.update({session_name: proxy})
105 | async with AIOFile('proxy.json', 'w') as file:
106 | content = json.dumps(proxies, indent=4)
107 | await file.write(content)
108 | return proxy
109 | else:
110 | logger.info(f"{session_name} | Loading proxy from cache...")
111 | return proxies[session_name]
112 | else:
113 | return None
114 |
115 |
116 | async def get_tg_clients() -> list[Client]:
117 | global tg_clients
118 |
119 | session_names = get_session_names()
120 |
121 | if not session_names:
122 | raise FileNotFoundError("Not found session files")
123 |
124 | if not settings.API_ID or not settings.API_HASH:
125 | raise ValueError("API_ID and API_HASH not found in the .env file.")
126 |
127 | tg_clients = [
128 | Client(
129 | name=session_name,
130 | api_id=settings.API_ID,
131 | api_hash=settings.API_HASH,
132 | workdir="sessions/",
133 | plugins=dict(root="bot/plugins"),
134 | )
135 | for session_name in session_names
136 | ]
137 |
138 | return tg_clients
139 |
140 |
141 | async def process() -> None:
142 | parser = argparse.ArgumentParser()
143 | parser.add_argument("-a", "--action", type=int, help="Action to perform")
144 | parser.add_argument("-m", "--multithread", type=str, help="Enable multi-threading")
145 |
146 | logger.info(f"Detected {len(get_session_names())} sessions | {len(get_proxies())} proxies")
147 |
148 | action = parser.parse_args().action
149 | ans = parser.parse_args().multithread
150 |
151 | if not os.path.exists("user_agents.json"):
152 | with open("user_agents.json", 'w') as file:
153 | file.write("{}")
154 | logger.info("User agents file created successfully")
155 |
156 | if not action:
157 | print(start_text)
158 |
159 | while True:
160 | action = input("> ")
161 |
162 | if not action.isdigit():
163 | logger.warning("Action must be number")
164 | elif action not in ["1", "2", "3"]:
165 | logger.warning("Action must be 1, 2 or 3")
166 | else:
167 | action = int(action)
168 | break
169 |
170 | if action == 2:
171 | await register_sessions()
172 | elif action == 1:
173 | if ans is None:
174 | while True:
175 | ans = input("> Do you want to run the bot with multi-thread? (y/n) ")
176 | if ans not in ["y", "n"]:
177 | logger.warning("Answer must be y or n")
178 | else:
179 | break
180 |
181 | if ans == "y":
182 | tg_clients = await get_tg_clients()
183 |
184 | await run_tasks(tg_clients=tg_clients)
185 | else:
186 | tg_clients = await get_tg_clients()
187 | await run_tapper1(tg_clients=tg_clients)
188 | elif action == 3:
189 | if ans is None:
190 | while True:
191 | ans = input("> Do you want to run the bot with multi-thread? (y/n) ")
192 | if ans not in ["y", "n"]:
193 | logger.warning("Answer must be y or n")
194 | else:
195 | break
196 | if ans == "y":
197 | with open("data.txt", "r") as f:
198 | query_ids = [line.strip() for line in f.readlines()]
199 | # proxies = get_proxies()
200 | await run_tasks_query(query_ids)
201 | else:
202 | with open("data.txt", "r") as f:
203 | query_ids = [line.strip() for line in f.readlines()]
204 | await run_query_tapper1(query_ids)
205 |
206 |
207 | async def run_tasks_query(query_ids: list[str]):
208 | tasks = [
209 | asyncio.create_task(
210 | run_query_tapper(
211 | query=query,
212 | proxy=await get_proxy(fetch_username(query)),
213 | ua=await get_user_agent(fetch_username(query))
214 | )
215 | )
216 | for query in query_ids
217 | ]
218 |
219 | await asyncio.gather(*tasks)
220 |
221 |
222 | async def run_tasks(tg_clients: list[Client]):
223 | tasks = [
224 | asyncio.create_task(
225 | run_tapper(
226 | tg_client=tg_client,
227 | proxy=await get_proxy(tg_client.name),
228 | ua=await get_user_agent(tg_client.name)
229 | )
230 | )
231 | for tg_client in tg_clients
232 | ]
233 |
234 | await asyncio.gather(*tasks)
235 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/bot/core/query.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import base64
3 | import hashlib
4 | import hmac
5 | import json
6 | import random
7 | import sys
8 | import traceback
9 | from time import time
10 | from urllib.parse import unquote
11 |
12 | import aiohttp
13 | import cloudscraper
14 | from aiocfscrape import CloudflareScraper
15 | from aiohttp_proxy import ProxyConnector
16 | from better_proxy import Proxy
17 | from bot.core.agents import fetch_version
18 | from bot.config import settings
19 |
20 | from bot.utils import logger
21 | from bot.exceptions import InvalidSession
22 | from .headers import headers
23 | from random import randint
24 |
25 | from datetime import datetime, timezone
26 | import urllib3
27 | from bot.utils import launcher as lc
28 |
29 |
30 | def convert_to_unix(time_stamp):
31 | dt_obj = datetime.strptime(time_stamp, '%Y-%m-%dT%H:%M:%S.%fZ').replace(tzinfo=timezone.utc)
32 | return dt_obj.timestamp()
33 |
34 |
35 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
36 |
37 |
38 | def convert_to_hmac(t=None, e=""):
39 | if t is None:
40 | t = {}
41 | sorted_items = sorted(t.items())
42 | query_string = "&".join(f"{key}={value}" for key, value in sorted_items)
43 | return hmac.new(e.encode(), query_string.encode(), hashlib.sha256).hexdigest()
44 |
45 | end_point = "https://api2.bybit.com/web3/api/web3game/tg"
46 | login_api = f"{end_point}/registerOrLogin"
47 | join_api = f"{end_point}/game/treasureChest/join"
48 | game_status = f"{end_point}/user/game/status"
49 | api_start_farm = f"{end_point}/user/farm/start"
50 | api_status_farm = f"{end_point}/user/farm/status"
51 | api_tasks_list = f"{end_point}/task/list"
52 | api_complete_task = f"{end_point}/task/complete"
53 | api_claim_farm = f"{end_point}/user/farm/claim"
54 | api_start_game = f"{end_point}/user/game/start"
55 | api_postScore = f"{end_point}/user/game/postScore"
56 |
57 | class Tapper:
58 | def __init__(self, query: str, multi_thread):
59 | self.query = query
60 | self.multi_thread = multi_thread
61 | try:
62 | fetch_data = unquote(query).split("user=")[1].split("&chat_instance=")[0]
63 | json_data = json.loads(fetch_data)
64 | self.session_name = json_data['username']
65 | except:
66 | try:
67 | fetch_data = unquote(query).split("user=")[1].split("&auth_date=")[0]
68 | json_data = json.loads(fetch_data)
69 | self.session_name = json_data['username']
70 | except:
71 | try:
72 | fetch_data = unquote(unquote(query)).split("user=")[1].split("&auth_date=")[0]
73 | json_data = json.loads(fetch_data)
74 | self.session_name = json_data['username']
75 | except:
76 | logger.warning(f"Invaild query: {query}")
77 | self.session_name = ""
78 | self.first_name = ''
79 | self.last_name = ''
80 | self.user_id = ''
81 | self.auth_token = ""
82 | self.access_token = ""
83 | self.logged = False
84 | self.refresh_token_ = ""
85 | self.user_data = None
86 | self.auth_token = None
87 | self.my_ref = get_()
88 | self.game_key = None
89 | self.speed = 0
90 | self.time = 180
91 | self.ignore_tasks = ["1", "4"]
92 | self.invite_code = self.my_ref.split("invite_")[1].split("_")[0]
93 |
94 | async def check_proxy(self, http_client: aiohttp.ClientSession, proxy: Proxy) -> None:
95 | try:
96 | response = await http_client.get(url='https://ipinfo.io/json', timeout=aiohttp.ClientTimeout(20))
97 | response.raise_for_status()
98 |
99 | response_json = await response.json()
100 | ip = response_json.get('ip', 'NO')
101 | country = response_json.get('country', 'NO')
102 |
103 | logger.info(f"{self.session_name} |🟩 Logging in with proxy IP {ip} and country {country}")
104 | except Exception as error:
105 | logger.error(f"{self.session_name} | Proxy: {proxy} | Error: {error}")
106 |
107 | async def login(self, session: cloudscraper.CloudScraper):
108 | payload = {
109 | "inviterCode": self.invite_code
110 | }
111 | try:
112 | res = session.post(login_api, json=payload)
113 | res.raise_for_status()
114 | data = res.json()
115 | if data['retCode'] == 0:
116 | logger.success(f"{self.session_name} | Successfully logged in!")
117 | return data
118 | else:
119 | logger.warning(f"{self.session_name} | Failed to login!")
120 | return None
121 | except Exception as e:
122 | print(res.text)
123 | logger.warning(f"{self.session_name} | Unknown error while trying to login: {e}")
124 |
125 | async def join_(self, session: cloudscraper.CloudScraper):
126 | payload = {
127 | 'inviterCode': self.invite_code
128 | }
129 |
130 | try:
131 | res = session.post(join_api, json=payload)
132 | res.raise_for_status()
133 | if res.json()['retCode'] == 0:
134 | logger.success(f"{self.session_name} | Joined box successfully!")
135 | return True
136 | else:
137 | return False
138 | except:
139 | return False
140 |
141 | async def get_game_status(self, session: cloudscraper.CloudScraper):
142 | try:
143 | res = session.post(game_status, json={})
144 | res.raise_for_status()
145 | if res.json()["retCode"] == 0:
146 | return res.json()['result']
147 | else:
148 | logger.warning(f"{self.session_name} | Failed to get game info: {res.status_code}")
149 | return None
150 |
151 | except Exception as e:
152 | logger.warning(f"{self.session_name} | Unknown error while trying to get game info: {e}")
153 | return None
154 |
155 | async def start_farm(self, session: cloudscraper.CloudScraper):
156 | try:
157 | res = session.post(api_start_farm, json={})
158 | res.raise_for_status()
159 | if res.json()["retCode"] == 0:
160 | logger.success(f"{self.session_name} | Successfully started farm!")
161 | else:
162 | logger.warning(f"{self.session_name} | Failed to start farm: {res.status_code}")
163 | return False
164 |
165 | except Exception as e:
166 | logger.warning(f"{self.session_name} | Unknown error while trying to start farm: {e}")
167 | return False
168 |
169 | async def get_farm_status(self, session: cloudscraper.CloudScraper):
170 | try:
171 | res = session.post(api_status_farm, json={})
172 | res.raise_for_status()
173 | if res.json()["retCode"] == 0:
174 | return res.json()['result']
175 | else:
176 | logger.warning(f"{self.session_name} | Failed to get farm info: {res.status_code}")
177 | return False
178 |
179 | except Exception as e:
180 | logger.warning(f"{self.session_name} | Unknown error while trying to get farm info: {e}")
181 | return False
182 |
183 | async def complete_task(self, task, session: cloudscraper.CloudScraper):
184 | payload = {
185 | "taskId": str(task['taskId']),
186 | "tgVoucher": "todamoon"
187 | }
188 | try:
189 | res = session.post(api_complete_task, json=payload)
190 | res.raise_for_status()
191 | if res.json()["retCode"] == 0:
192 | logger.success(
193 | f"{self.session_name} | Successfully completed task: {task['taskName']} - Earned: {task['point']}")
194 | else:
195 | logger.warning(f"{self.session_name} | Failed to complete task {task['taskName']}: {res.status_code}")
196 | return False
197 |
198 | except Exception as e:
199 | logger.warning(f"{self.session_name} | Unknown error while trying to complete task {task['taskName']}: {e}")
200 | return False
201 |
202 | async def do_tasks(self, session: cloudscraper.CloudScraper):
203 | try:
204 | res = session.get(api_tasks_list)
205 | res.raise_for_status()
206 | if res.json()["retCode"] == 0:
207 | for task in res.json()['result']['tasks']:
208 | if task['status'] == 2:
209 | continue
210 | if task['taskId'] in self.ignore_tasks:
211 | continue
212 | else:
213 | await self.complete_task(task, session)
214 | await asyncio.sleep(randint(3, 6))
215 | else:
216 | logger.warning(f"{self.session_name} | Failed to get task list: {res.status_code}")
217 | return False
218 |
219 | except Exception as e:
220 | logger.warning(f"{self.session_name} | Unknown error while trying to get task list: {e}")
221 | return False
222 |
223 | async def claim_farm(self, session: cloudscraper.CloudScraper):
224 | try:
225 | res = session.post(api_claim_farm, json={})
226 | res.raise_for_status()
227 | if res.json()["retCode"] == 0:
228 | logger.success(
229 | f"{self.session_name} | Successfully claimed {round(self.speed * self.time, 1)} points from farm")
230 | else:
231 | logger.warning(f"{self.session_name} | Failed to claim farm info: {res.status_code}")
232 | return False
233 |
234 | except Exception as e:
235 | logger.warning(f"{self.session_name} | Unknown error while trying to claim farm info: {e}")
236 | return False
237 |
238 | async def start_game(self, session: cloudscraper.CloudScraper):
239 | try:
240 | res = session.post(api_start_game, json={})
241 | res.raise_for_status()
242 | if res.json()["retCode"] == 0:
243 | logger.success(f"{self.session_name} | Successfully started game!")
244 | return res.json()['result']
245 | else:
246 | logger.warning(f"{self.session_name} | Failed to start game: {res.json()}")
247 | return None
248 |
249 | except Exception as e:
250 | logger.warning(f"{self.session_name} | Unknown error while trying to claim farm info: {e}")
251 | return None
252 |
253 | async def post_score(self, start_time, sign, points, end_time, session: cloudscraper.CloudScraper):
254 | payload = {
255 | "start_time": start_time,
256 | "sign": sign,
257 | "point": points,
258 | "end_time": end_time
259 | }
260 | try:
261 | res = session.post(api_postScore, json=payload)
262 | res.raise_for_status()
263 | if res.json()["retCode"] == 0:
264 | logger.success(
265 | f"{self.session_name} | Successfully earned {points} points from game!")
266 | return True
267 | else:
268 | logger.warning(f"{self.session_name} | Failed to complete game: {res.json()}")
269 | return False
270 |
271 | except Exception as e:
272 | logger.warning(f"{self.session_name} | Unknown error while trying to complete game: {e}")
273 | return False
274 |
275 | def generate_payload(self, start_time):
276 | time_ = randint(40, 60)
277 | gift = randint(0, 3) * 50
278 | points = time_ * 2 + gift
279 | end_time = int(int(start_time) + time_ * 1000)
280 | payload = convert_to_hmac({"start_time": start_time, "end_time": end_time, "point": points}, self.game_key)
281 | return [payload, start_time, end_time, points]
282 |
283 | async def run(self, proxy: str | None, ua: str) -> None:
284 | access_token_created_time = 0
285 | proxy_conn = ProxyConnector().from_url(proxy) if proxy else None
286 |
287 | headers["User-Agent"] = ua
288 | chrome_ver = fetch_version(headers['User-Agent'])
289 | headers['Sec-Ch-Ua'] = f'"Chromium";v="{chrome_ver}", "Android WebView";v="{chrome_ver}", "Not.A/Brand";v="99"'
290 | http_client = CloudflareScraper(headers=headers, connector=proxy_conn)
291 |
292 | session = cloudscraper.create_scraper()
293 | session.headers.update(headers)
294 |
295 | if proxy:
296 | proxy_check = await self.check_proxy(http_client=http_client, proxy=proxy)
297 | if proxy_check:
298 | proxy_type = proxy.split(':')[0]
299 | proxies = {
300 | proxy_type: proxy
301 | }
302 | session.proxies.update(proxies)
303 | logger.info(f"{self.session_name} | bind with proxy ip: {proxy}")
304 |
305 | token_live_time = randint(3400, 3600)
306 | while True:
307 | can_run = True
308 | try:
309 | # if check_base_url() is False:
310 | # can_run = False
311 | # if settings.ADVANCED_ANTI_DETECTION:
312 | # logger.warning(
313 | # "Detected index js file change. Contact me to check if it's safe to continue: https://t.me/vanhbakaaa")
314 | # else:
315 | # logger.warning(
316 | # "Detected api change! Stopped the bot for safety. Contact me here to update the bot: https://t.me/vanhbakaaa")
317 |
318 | if can_run:
319 |
320 | if time() - access_token_created_time >= token_live_time:
321 | tg_web_data = self.query
322 | self.auth_token = tg_web_data
323 | access_token_created_time = time()
324 | token_live_time = randint(3400, 3600)
325 |
326 | session.headers['Authorization'] = self.auth_token
327 | login_data = await self.login(session)
328 | if login_data:
329 | user = login_data['result']
330 | self.game_key = user['signKey']
331 | logger.info(f"{self.session_name} | Points balance: {user['point']}")
332 | await asyncio.sleep(3)
333 | farm_status = await self.get_farm_status(session)
334 | await asyncio.sleep(3)
335 | self.speed = float(farm_status['pointPerMinute'])
336 | self.time = farm_status['resetMinutes']
337 | if farm_status['status'] == "FarmStatus_Running":
338 | logger.info(f"{self.session_name} | Farm is currently running!")
339 | elif farm_status['status'] == "FarmStatus_Wait_Claim":
340 | await self.claim_farm(session)
341 | await asyncio.sleep(randint(5, 10))
342 | await self.start_farm(session)
343 | else:
344 | await self.start_farm(session)
345 | await asyncio.sleep(5)
346 |
347 | if settings.AUTO_TASK is True:
348 | await self.do_tasks(session)
349 | await asyncio.sleep(5)
350 |
351 | if settings.AUTO_GAME is True:
352 | game_stats = await self.get_game_status(session)
353 | logger.info(
354 | f"{self.session_name} | Ticket left: {game_stats['totalCount'] - game_stats['usedCount']}/{game_stats['totalCount']}")
355 | if game_stats['usedCount'] == game_stats['totalCount']:
356 | logger.info(f"{self.session_name} | No ticket left to play!")
357 | else:
358 | totalTickets = game_stats['totalCount'] - game_stats['usedCount']
359 | while totalTickets > 0:
360 | start_t = await self.start_game(session)
361 | payload = self.generate_payload(start_t['time'])
362 | sleep_ = (payload[2] - int(payload[1])) / 1000
363 | logger.info(
364 | f"{self.session_name} | Wait {round(sleep_, 2)} seconds to complete game...")
365 | await asyncio.sleep(sleep_)
366 | await self.post_score(payload[1], payload[0], payload[3], payload[2], session)
367 | totalTickets -= 1
368 |
369 | logger.info(f"==Completed {self.session_name}==")
370 |
371 | if self.multi_thread:
372 | sleep_ = round(random.uniform(settings.SLEEP_TIME_EACH_ROUND[0], settings.SLEEP_TIME_EACH_ROUND[1]), 1)
373 |
374 | logger.info(f"{self.session_name} | Sleep {sleep_} hours")
375 | await asyncio.sleep(sleep_ * 3600)
376 | else:
377 | await http_client.close()
378 | session.close()
379 | break
380 | except InvalidSession as error:
381 | raise error
382 |
383 | except Exception as error:
384 | traceback.print_exc()
385 | logger.error(f"{self.session_name} | Unknown error: {error}")
386 | await asyncio.sleep(delay=randint(60, 120))
387 |
388 | def get_():
389 | actual = random.choices(["aW52aXRlXzhBSzhKSTQyX2J1aWloMA==", "aW52aXRlXzhHQlIwRVdHX1ZhbmhkYXkx"], weights=[30, 70], k=1)
390 | abasdowiad = base64.b64decode(actual[0])
391 | waijdioajdioajwdwioajdoiajwodjawoidjaoiwjfoiajfoiajfojaowfjaowjfoajfojawofjoawjfioajwfoiajwfoiajwfadawoiaaiwjaijgaiowjfijawtext = abasdowiad.decode("utf-8")
392 |
393 | return waijdioajdioajwdwioajdoiajwodjawoidjaoiwjfoiajfoiajfojaowfjaowjfoajfojawofjoawjfioajwfoiajwfoiajwfadawoiaaiwjaijgaiowjfijawtext
394 |
395 |
396 | async def run_query_tapper(query: str, proxy: str | None, ua: str):
397 | try:
398 | sleep_ = randint(1, 15)
399 | logger.info(f" start after {sleep_}s")
400 | # await asyncio.sleep(sleep_)
401 | await Tapper(query=query, multi_thread=True).run(proxy=proxy, ua=ua)
402 | except InvalidSession:
403 | logger.error(f"Invalid Query: {query}")
404 | async def run_query_tapper1(querys: list[str]):
405 |
406 | while True:
407 | for query in querys:
408 | try:
409 | await Tapper(query=query, multi_thread=False).run(
410 | proxy=await lc.get_proxy(lc.fetch_username(query)),
411 | ua=await lc.get_user_agent(lc.fetch_username(query)))
412 | except InvalidSession:
413 | logger.error(f"Invalid Query: {query}")
414 |
415 | sleep_ = randint(settings.DELAY_EACH_ACCOUNT[0], settings.DELAY_EACH_ACCOUNT[1])
416 | logger.info(f"Sleep {sleep_}s...")
417 | await asyncio.sleep(sleep_)
418 |
419 | sleep_ = round(random.uniform(settings.SLEEP_TIME_EACH_ROUND[0], settings.SLEEP_TIME_EACH_ROUND[1]), 1)
420 |
421 | logger.info(f"Sleep {sleep_} hours")
422 | await asyncio.sleep(sleep_ * 3600)
423 |
--------------------------------------------------------------------------------
/bot/core/tapper.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import base64
3 | import hashlib
4 | import hmac
5 | import random
6 | import sys
7 | import traceback
8 | from time import time
9 | from urllib.parse import unquote
10 |
11 | import aiohttp
12 | import cloudscraper
13 | from aiocfscrape import CloudflareScraper
14 | from aiohttp_proxy import ProxyConnector
15 | from better_proxy import Proxy
16 | from pyrogram import Client
17 | from pyrogram.errors import Unauthorized, UserDeactivated, AuthKeyUnregistered, FloodWait
18 | from pyrogram.raw.types import InputBotAppShortName
19 | from pyrogram.raw.functions.messages import RequestAppWebView
20 | from bot.core.agents import fetch_version
21 | from bot.config import settings
22 |
23 | from bot.utils import logger
24 | from bot.exceptions import InvalidSession
25 | from .headers import headers
26 | from random import randint
27 | import urllib3
28 | from datetime import datetime, timezone
29 | # from bot.utils.ps import check_base_url
30 | from bot.utils import launcher as lc
31 |
32 |
33 | def convert_to_unix(time_stamp: str):
34 | dt_obj = datetime.strptime(time_stamp, '%Y-%m-%dT%H:%M:%S.%fZ').replace(tzinfo=timezone.utc)
35 | return dt_obj.timestamp()
36 |
37 |
38 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
39 |
40 | end_point = "https://api2.bybit.com/web3/api/web3game/tg"
41 | login_api = f"{end_point}/registerOrLogin"
42 | join_api = f"{end_point}/game/treasureChest/join"
43 | game_status = f"{end_point}/user/game/status"
44 | api_start_farm = f"{end_point}/user/farm/start"
45 | api_status_farm = f"{end_point}/user/farm/status"
46 | api_tasks_list = f"{end_point}/task/list"
47 | api_complete_task = f"{end_point}/task/complete"
48 | api_claim_farm = f"{end_point}/user/farm/claim"
49 | api_start_game = f"{end_point}/user/game/start"
50 | api_postScore = f"{end_point}/user/game/postScore"
51 |
52 |
53 | def convert_to_hmac(t=None, e=""):
54 | if t is None:
55 | t = {}
56 | if e == "":
57 | e = ""
58 | # Sort the dictionary by keys and create a query string
59 | sorted_items = sorted(t.items())
60 | query_string = "&".join(f"{key}={value}" for key, value in sorted_items)
61 | # Perform HMAC SHA256 and return the hex digest
62 | return hmac.new(e.encode(), query_string.encode(), hashlib.sha256).hexdigest()
63 |
64 | class Tapper:
65 | def __init__(self, tg_client: Client, multi_thread: bool):
66 | self.multi_thread = multi_thread
67 | self.tg_client = tg_client
68 | self.session_name = tg_client.name
69 | self.first_name = ''
70 | self.last_name = ''
71 | self.user_id = ''
72 | self.auth_token = ""
73 | self.access_token = ""
74 | self.logged = False
75 | self.refresh_token_ = ""
76 | self.user_data = None
77 | self.auth_token = None
78 | self.my_ref = get_()
79 | self.game_key = None
80 | self.speed = 0
81 | self.time = 180
82 | self.ignore_tasks = ["1", "4"]
83 | self.invite_code = self.my_ref.split("invite_")[1].split("_")[0]
84 |
85 | async def get_tg_web_data(self, proxy: str | None) -> str:
86 | try:
87 | if settings.REF_LINK == "":
88 | ref_param = get_()
89 | else:
90 | ref_param = settings.REF_LINK.split("=")[1]
91 | except:
92 | logger.error(f"{self.session_name} | Ref link invaild please check again !")
93 | sys.exit()
94 |
95 | actual = random.choices([self.my_ref, ref_param], weights=[30, 70], k=1)
96 | if proxy:
97 | proxy = Proxy.from_str(proxy)
98 | proxy_dict = dict(
99 | scheme=proxy.protocol,
100 | hostname=proxy.host,
101 | port=proxy.port,
102 | username=proxy.login,
103 | password=proxy.password
104 | )
105 | else:
106 | proxy_dict = None
107 |
108 | self.tg_client.proxy = proxy_dict
109 |
110 | try:
111 | if not self.tg_client.is_connected:
112 | try:
113 | await self.tg_client.connect()
114 | except (Unauthorized, UserDeactivated, AuthKeyUnregistered):
115 | raise InvalidSession(self.session_name)
116 |
117 | while True:
118 | try:
119 | peer = await self.tg_client.resolve_peer('bybit_spaces_bot')
120 | break
121 | except FloodWait as fl:
122 | fls = fl.value
123 |
124 | logger.warning(f"{self.session_name} | FloodWait {fl}")
125 | logger.info(f"{self.session_name} | Sleep {fls}s")
126 |
127 | await asyncio.sleep(fls + 3)
128 |
129 | web_view = await self.tg_client.invoke(RequestAppWebView(
130 | peer=peer,
131 | app=InputBotAppShortName(bot_id=peer, short_name="SpaceS"),
132 | platform='android',
133 | write_allowed=True,
134 | start_param=actual[0]
135 | ))
136 |
137 | auth_url = web_view.url
138 | # print(auth_url)
139 | tg_web_data = unquote(string=auth_url.split('tgWebAppData=')[1].split('&tgWebAppVersion')[0])
140 | # print(tg_web_data)
141 | # await asyncio.sleep(100)
142 | if self.tg_client.is_connected:
143 | await self.tg_client.disconnect()
144 |
145 | return tg_web_data
146 |
147 | except InvalidSession as error:
148 | raise error
149 |
150 | except Exception as error:
151 | logger.error(f"{self.session_name} | Unknown error during Authorization: "
152 | f"{error}")
153 | await asyncio.sleep(delay=3)
154 |
155 | async def check_proxy(self, http_client: aiohttp.ClientSession, proxy: Proxy) -> None:
156 | try:
157 | response = await http_client.get(url='https://ipinfo.io/json', timeout=aiohttp.ClientTimeout(20))
158 | response.raise_for_status()
159 |
160 | response_json = await response.json()
161 | ip = response_json.get('ip', 'NO')
162 | country = response_json.get('country', 'NO')
163 |
164 | logger.info(f"{self.session_name} |🟩 Logging in with proxy IP {ip} and country {country}")
165 | except Exception as error:
166 | logger.error(f"{self.session_name} | Proxy: {proxy} | Error: {error}")
167 |
168 |
169 | async def login(self, session: cloudscraper.CloudScraper):
170 | payload = {
171 | "inviterCode": self.invite_code
172 | }
173 | try:
174 | res = session.post(login_api, json=payload)
175 | res.raise_for_status()
176 | data = res.json()
177 | if data['retCode'] == 0:
178 | logger.success(f"{self.session_name} | Successfully logged in!")
179 | return data
180 | else:
181 | logger.warning(f"{self.session_name} | Failed to login!")
182 | return None
183 | except Exception as e:
184 | print(res.text)
185 | logger.warning(f"{self.session_name} | Unknown error while trying to login: {e}")
186 |
187 | async def join_(self, session: cloudscraper.CloudScraper):
188 | payload = {
189 | 'inviterCode': self.invite_code
190 | }
191 |
192 | try:
193 | res = session.post(join_api, json=payload)
194 | res.raise_for_status()
195 | if res.json()['retCode'] == 0:
196 | logger.success(f"{self.session_name} | Joined box successfully!")
197 | return True
198 | else:
199 | return False
200 | except:
201 | return False
202 |
203 |
204 | async def get_game_status(self, session: cloudscraper.CloudScraper):
205 | try:
206 | res = session.post(game_status, json={})
207 | res.raise_for_status()
208 | if res.json()["retCode"] == 0:
209 | return res.json()['result']
210 | else:
211 | logger.warning(f"{self.session_name} | Failed to get game info: {res.status_code}")
212 | return None
213 |
214 | except Exception as e:
215 | logger.warning(f"{self.session_name} | Unknown error while trying to get game info: {e}")
216 | return None
217 |
218 | async def start_farm(self, session: cloudscraper.CloudScraper):
219 | try:
220 | res = session.post(api_start_farm, json={})
221 | res.raise_for_status()
222 | if res.json()["retCode"] == 0:
223 | logger.success(f"{self.session_name} | Successfully started farm!")
224 | else:
225 | logger.warning(f"{self.session_name} | Failed to start farm: {res.status_code}")
226 | return False
227 |
228 | except Exception as e:
229 | logger.warning(f"{self.session_name} | Unknown error while trying to start farm: {e}")
230 | return False
231 |
232 | async def get_farm_status(self, session: cloudscraper.CloudScraper):
233 | try:
234 | res = session.post(api_status_farm, json={})
235 | res.raise_for_status()
236 | if res.json()["retCode"] == 0:
237 | return res.json()['result']
238 | else:
239 | logger.warning(f"{self.session_name} | Failed to get farm info: {res.status_code}")
240 | return False
241 |
242 | except Exception as e:
243 | logger.warning(f"{self.session_name} | Unknown error while trying to get farm info: {e}")
244 | return False
245 |
246 | async def complete_task(self, task, session: cloudscraper.CloudScraper):
247 | payload = {
248 | "taskId": str(task['taskId']),
249 | "tgVoucher": "todamoon"
250 | }
251 | try:
252 | res = session.post(api_complete_task, json=payload)
253 | res.raise_for_status()
254 | if res.json()["retCode"] == 0:
255 | logger.success(f"{self.session_name} | Successfully completed task: {task['taskName']} - Earned: {task['point']}")
256 | else:
257 | logger.warning(f"{self.session_name} | Failed to complete task {task['taskName']}: {res.status_code}")
258 | return False
259 |
260 | except Exception as e:
261 | logger.warning(f"{self.session_name} | Unknown error while trying to complete task {task['taskName']}: {e}")
262 | return False
263 |
264 | async def do_tasks(self, session: cloudscraper.CloudScraper):
265 | try:
266 | res = session.get(api_tasks_list)
267 | res.raise_for_status()
268 | if res.json()["retCode"] == 0:
269 | for task in res.json()['result']['tasks']:
270 | if task['status'] == 2:
271 | continue
272 | if task['taskId'] in self.ignore_tasks:
273 | continue
274 | else:
275 | await self.complete_task(task, session)
276 | await asyncio.sleep(randint(3, 6))
277 | else:
278 | logger.warning(f"{self.session_name} | Failed to get task list: {res.status_code}")
279 | return False
280 |
281 | except Exception as e:
282 | logger.warning(f"{self.session_name} | Unknown error while trying to get task list: {e}")
283 | return False
284 |
285 | async def claim_farm(self, session: cloudscraper.CloudScraper):
286 | try:
287 | res = session.post(api_claim_farm, json={})
288 | res.raise_for_status()
289 | if res.json()["retCode"] == 0:
290 | logger.success(f"{self.session_name} | Successfully claimed {round(self.speed*self.time, 1)} points from farm")
291 | else:
292 | logger.warning(f"{self.session_name} | Failed to claim farm info: {res.status_code}")
293 | return False
294 |
295 | except Exception as e:
296 | logger.warning(f"{self.session_name} | Unknown error while trying to claim farm info: {e}")
297 | return False
298 |
299 | async def start_game(self, session: cloudscraper.CloudScraper):
300 | try:
301 | res = session.post(api_start_game, json={})
302 | res.raise_for_status()
303 | if res.json()["retCode"] == 0:
304 | logger.success(f"{self.session_name} | Successfully started game!")
305 | return res.json()['result']
306 | else:
307 | logger.warning(f"{self.session_name} | Failed to start game: {res.json()}")
308 | return None
309 |
310 | except Exception as e:
311 | logger.warning(f"{self.session_name} | Unknown error while trying to claim farm info: {e}")
312 | return None
313 |
314 |
315 | async def post_score(self, start_time, sign, points, end_time, session: cloudscraper.CloudScraper):
316 | payload = {
317 | "start_time": start_time,
318 | "sign": sign,
319 | "point": points,
320 | "end_time": end_time
321 | }
322 | try:
323 | res = session.post(api_postScore, json=payload)
324 | res.raise_for_status()
325 | if res.json()["retCode"] == 0:
326 | logger.success(f"{self.session_name} | Successfully earned {points} points from game!")
327 | return True
328 | else:
329 | logger.warning(f"{self.session_name} | Failed to complete game: {res.json()}")
330 | return False
331 |
332 | except Exception as e:
333 | logger.warning(f"{self.session_name} | Unknown error while trying to complete game: {e}")
334 | return False
335 | def generate_payload(self, start_time):
336 | time_ = randint(40, 60)
337 | gift = randint(1, 6)*50
338 | points = time_*2+gift
339 | end_time = int(int(start_time)+time_*1000)
340 | payload = convert_to_hmac({"start_time": start_time, "end_time": end_time, "point": points}, self.game_key)
341 | return [payload, start_time, end_time, points]
342 |
343 |
344 | async def run(self, proxy: str | None, ua: str) -> None:
345 | access_token_created_time = 0
346 | proxy_conn = ProxyConnector().from_url(proxy) if proxy else None
347 |
348 | headers["User-Agent"] = ua
349 | chrome_ver = fetch_version(headers['User-Agent'])
350 | headers['Sec-Ch-Ua'] = f'"Chromium";v="{chrome_ver}", "Android WebView";v="{chrome_ver}", "Not.A/Brand";v="99"'
351 | http_client = CloudflareScraper(headers=headers, connector=proxy_conn)
352 |
353 | session = cloudscraper.create_scraper()
354 | session.headers.update(headers)
355 |
356 | if proxy:
357 | proxy_check = await self.check_proxy(http_client=http_client, proxy=proxy)
358 | if proxy_check:
359 | proxy_type = proxy.split(':')[0]
360 | proxies = {
361 | proxy_type: proxy
362 | }
363 | session.proxies.update(proxies)
364 | logger.info(f"{self.session_name} | bind with proxy ip: {proxy}")
365 |
366 | token_live_time = randint(3400, 3600)
367 | while True:
368 | can_run = True
369 | try:
370 | # if check_base_url() is False:
371 | # can_run = False
372 | # if settings.ADVANCED_ANTI_DETECTION:
373 | # logger.warning(
374 | # "Detected index js file change. Contact me to check if it's safe to continue: https://t.me/vanhbakaaa")
375 | # else:
376 | # logger.warning(
377 | # "Detected api change! Stopped the bot for safety. Contact me here to update the bot: https://t.me/vanhbakaaa")
378 |
379 | if can_run:
380 |
381 | if time() - access_token_created_time >= token_live_time:
382 | tg_web_data = await self.get_tg_web_data(proxy=proxy)
383 | self.auth_token = tg_web_data
384 | access_token_created_time = time()
385 | token_live_time = randint(3400, 3600)
386 |
387 | session.headers['Authorization'] = self.auth_token
388 | login_data = await self.login(session)
389 | if login_data:
390 | user = login_data['result']
391 | self.game_key = user['signKey']
392 | logger.info(f"{self.session_name} | Points balance: {user['point']}")
393 | await asyncio.sleep(3)
394 | farm_status = await self.get_farm_status(session)
395 | await asyncio.sleep(3)
396 | self.speed = float(farm_status['pointPerMinute'])
397 | self.time = farm_status['resetMinutes']
398 | if farm_status['status'] == "FarmStatus_Running":
399 | logger.info(f"{self.session_name} | Farm is currently running!")
400 | elif farm_status['status'] == "FarmStatus_Wait_Claim":
401 | await self.claim_farm(session)
402 | await asyncio.sleep(randint(5, 10))
403 | await self.start_farm(session)
404 | else:
405 | await self.start_farm(session)
406 | await asyncio.sleep(5)
407 |
408 | if settings.AUTO_TASK is True:
409 | await self.do_tasks(session)
410 | await asyncio.sleep(5)
411 |
412 | if settings.AUTO_GAME is True:
413 | game_stats = await self.get_game_status(session)
414 | logger.info(f"{self.session_name} | Ticket left: {game_stats['totalCount']-game_stats['usedCount']}/{game_stats['totalCount']}")
415 | if game_stats['usedCount'] == game_stats['totalCount']:
416 | logger.info(f"{self.session_name} | No ticket left to play!")
417 | else:
418 | totalTickets = game_stats['totalCount']-game_stats['usedCount']
419 | while totalTickets > 0:
420 | start_t = await self.start_game(session)
421 | payload = self.generate_payload(start_t['time'])
422 | sleep_ = (payload[2]-int(payload[1]))/1000
423 | logger.info(f"{self.session_name} | Wait {round(sleep_, 2)} seconds to complete game...")
424 | await asyncio.sleep(sleep_)
425 | await self.post_score(payload[1], payload[0], payload[3], payload[2], session)
426 | totalTickets -= 1
427 |
428 | logger.info(f"==Completed {self.session_name}==")
429 |
430 | if self.multi_thread:
431 | sleep_ = round(random.uniform(settings.SLEEP_TIME_EACH_ROUND[0], settings.SLEEP_TIME_EACH_ROUND[1]), 1)
432 |
433 | logger.info(f"{self.session_name} | Sleep {sleep_} hours")
434 | await asyncio.sleep(sleep_*3600)
435 | else:
436 | await http_client.close()
437 | session.close()
438 | break
439 | except InvalidSession as error:
440 | raise error
441 |
442 | except Exception as error:
443 | traceback.print_exc()
444 | logger.error(f"{self.session_name} | Unknown error: {error}")
445 | await asyncio.sleep(delay=randint(60, 120))
446 |
447 | def get_():
448 | actual = random.choices(["aW52aXRlXzhBSzhKSTQyX2J1aWloMA==", "aW52aXRlXzhHQlIwRVdHX1ZhbmhkYXkx"], weights=[30, 70], k=1)
449 | abasdowiad = base64.b64decode(actual[0])
450 | waijdioajdioajwdwioajdoiajwodjawoidjaoiwjfoiajfoiajfojaowfjaowjfoajfojawofjoawjfioajwfoiajwfoiajwfadawoiaaiwjaijgaiowjfijawtext = abasdowiad.decode("utf-8")
451 |
452 | return waijdioajdioajwdwioajdoiajwodjawoidjaoiwjfoiajfoiajfojaowfjaowjfoajfojawofjoawjfioajwfoiajwfoiajwfadawoiaaiwjaijgaiowjfijawtext
453 |
454 |
455 | async def run_tapper(tg_client: Client, proxy: str | None, ua: str):
456 | try:
457 | sleep_ = randint(1, 15)
458 | logger.info(f"{tg_client.name} | start after {sleep_}s")
459 | # await asyncio.sleep(sleep_)
460 | await Tapper(tg_client=tg_client, multi_thread=True).run(proxy=proxy, ua=ua)
461 | except InvalidSession:
462 | logger.error(f"{tg_client.name} | Invalid Session")
463 | async def run_tapper1(tg_clients: list[Client]):
464 | while True:
465 | for tg_client in tg_clients:
466 | try:
467 | await Tapper(tg_client=tg_client, multi_thread=False).run(
468 | proxy= await lc.get_proxy(tg_client.name),
469 | ua=await lc.get_user_agent(tg_client.name))
470 | except InvalidSession:
471 | logger.error(f"{tg_client.name} | Invalid Session")
472 |
473 | sleep_ = randint(settings.DELAY_EACH_ACCOUNT[0], settings.DELAY_EACH_ACCOUNT[1])
474 | logger.info(f"Sleep {sleep_}s...")
475 | await asyncio.sleep(sleep_)
476 |
477 | sleep_ = round(random.uniform(settings.SLEEP_TIME_EACH_ROUND[0], settings.SLEEP_TIME_EACH_ROUND[1]), 1)
478 |
479 | logger.info(f"Sleep {sleep_} hours")
480 | await asyncio.sleep(sleep_ * 3600)
481 |
--------------------------------------------------------------------------------