├── README.md ├── data └── config.py ├── main.py ├── requirements.txt └── utils ├── core ├── __init__.py ├── file_manager.py ├── logger.py └── telegram.py ├── starter.py └── vertus.py /README.md: -------------------------------------------------------------------------------- 1 | # VertusBot 2 | clicker for [https://t.me/Vertus_App_bot](t.me/vertus_app_bot/app?startapp=6008239182) 3 | 4 | More crypto themes and softs in telegram: [ApeCryptor](https://t.me/+_xCNXumUNWJkYjAy "ApeCryptor") 🦧 5 | Additional soft information: https://t.me/ApeCryptorSoft/89 6 | 7 | ## Functionality 8 | | Functional | Supported | 9 | |----------------------------------------------------------------|:---------:| 10 | | Multithreading | ✅ | 11 | | Binding a proxy to a session | ✅ | 12 | | Auto-clicker; auto-reger; daily claim, | ✅ | 13 | | Auto-upgrades | ✅ | 14 | | Random sleep time between accounts | ✅ | 15 | | Support pyrogram .session | ✅ | 16 | | Get statistics for all accounts | ✅ | 17 | 18 | ## Settings data/config.py 19 | | Setting | Description | 20 | |------------------------------|------------------------------------------------------------------------------------------------| 21 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session _(stock - Android)_ | 22 | | **DELAYS-ACCOUNT** | Delay between connections to accounts (the more accounts, the longer the delay) _(eg [5, 15])_ | 23 | | **BATTLES** | settings for battles | 24 | | **PROXY_TYPES-TG** | Proxy type for telegram session _(eg 'socks5')_ | 25 | | **PROXY_TYPES-REQUESTS** | Proxy type for requests _(eg 'socks5')_ | 26 | | **WORKDIR** | directory with session _(eg "sessions/")_ | 27 | | **TIMEOUT** | timeout in seconds for checking accounts on valid _(eg 30)_ | 28 | 29 | ## Requirements 30 | - Python 3.9 (you can install it [here](https://www.python.org/downloads/release/python-390/)) 31 | - Telegram API_ID and API_HASH (you can get them [here](https://my.telegram.org/auth)) 32 | 33 | 1. Install the required dependencies: 34 | ```bash 35 | pip install -r requirements.txt 36 | ``` 37 | 38 | ## Usage 39 | 1. Run the bot: 40 | ```bash 41 | python main.py 42 | ``` 43 | -------------------------------------------------------------------------------- /data/config.py: -------------------------------------------------------------------------------- 1 | # api id, hash 2 | API_ID = 1488 3 | API_HASH = 'abcde1488' 4 | 5 | REF_LINK = "t.me/vertus_app_bot/app?startapp=14881488" 6 | 7 | DELAYS = { 8 | 'ACCOUNT': [5, 15], # delay between connections to accounts (the more accounts, the longer the delay) 9 | 'REPEAT': [300, 600], 10 | 'BUY_CARD': [2, 5] # delay before buy a upgrade cards 11 | } 12 | 13 | # need buy a cards 14 | BUY_CARD = True 15 | 16 | # need buy upgrades 17 | BUY_UPGRADE = True 18 | 19 | PROXY = { 20 | "USE_PROXY_FROM_FILE": False, # True - if use proxy from file, False - if use proxy from accounts.json 21 | "PROXY_PATH": "data/proxy.txt", # path to file proxy 22 | "TYPE": { 23 | "TG": "socks5", # proxy type for tg client. "socks4", "socks5" and "http" are supported 24 | "REQUESTS": "socks5" # proxy type for requests. "http" for https and http proxys, "socks5" for socks5 proxy. 25 | } 26 | } 27 | # session folder (do not change) 28 | WORKDIR = "sessions/" 29 | 30 | # timeout in seconds for checking accounts on valid 31 | TIMEOUT = 30 32 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from utils.core.telegram import Accounts 2 | from utils.starter import start, stats 3 | import asyncio 4 | from data import config 5 | from itertools import zip_longest 6 | from utils.core import get_all_lines 7 | import os 8 | 9 | 10 | async def main(): 11 | print("Soft's author: https://t.me/ApeCryptor\n") 12 | action = int(input("Select action:\n1. Start soft\n2. Get statistics\n3. Create sessions\n\n> ")) 13 | 14 | if not os.path.exists('sessions'): os.mkdir('sessions') 15 | 16 | if config.PROXY['USE_PROXY_FROM_FILE']: 17 | if not os.path.exists(config.PROXY['PROXY_PATH']): 18 | with open(config.PROXY['PROXY_PATH'], 'w') as f: 19 | f.write("") 20 | else: 21 | if not os.path.exists('sessions/accounts.json'): 22 | with open("sessions/accounts.json", 'w') as f: 23 | f.write("[]") 24 | 25 | if action == 3: 26 | await Accounts().create_sessions() 27 | 28 | if action == 2: 29 | await stats() 30 | 31 | if action == 1: 32 | accounts = await Accounts().get_accounts() 33 | 34 | tasks = [] 35 | 36 | for thread, account in enumerate(accounts): 37 | session_name, phone_number, proxy = account.values() 38 | tasks.append(asyncio.create_task(start(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy))) 39 | 40 | await asyncio.gather(*tasks) 41 | 42 | 43 | if __name__ == '__main__': 44 | asyncio.get_event_loop().run_until_complete(main()) 45 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrogram==2.0.106 2 | tgcrypto==1.2.5 3 | loguru==0.7.2 4 | aiohttp==3.9.5 5 | fake-useragent==1.5.1 6 | pandas==2.2.2 7 | aiohttp_socks==0.8.4 -------------------------------------------------------------------------------- /utils/core/__init__.py: -------------------------------------------------------------------------------- 1 | from .logger import logger 2 | from .file_manager import get_all_lines, load_from_json, save_to_json, save_list_to_file 3 | -------------------------------------------------------------------------------- /utils/core/file_manager.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def get_all_lines(filepath: str): 5 | with open(filepath, 'r') as file: 6 | lines = file.readlines() 7 | 8 | if not lines: 9 | return [] 10 | 11 | return [line.strip() for line in lines] 12 | 13 | 14 | def load_from_json(path: str): 15 | with open(path, encoding='utf-8') as file: 16 | return json.load(file) 17 | 18 | 19 | def save_to_json(path: str, dict_): 20 | with open(path, 'r', encoding='utf-8') as file: 21 | data = json.load(file) 22 | 23 | data.append(dict_) 24 | with open(path, 'w', encoding='utf-8') as file: 25 | json.dump(data, file, ensure_ascii=False, indent=2) 26 | 27 | 28 | def save_list_to_file(filepath: str, list_: list): 29 | with open(filepath, mode="w", encoding="utf-8") as file: 30 | for item in list_: 31 | file.write(f"{item['session_name']}.session\n") 32 | -------------------------------------------------------------------------------- /utils/core/logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | from loguru import logger 4 | 5 | 6 | def formatter(record, format_string): 7 | return format_string + record["extra"].get("end", "\n") + "{exception}" 8 | 9 | 10 | def clean_brackets(raw_str): 11 | return re.sub(r'<.*?>', '', raw_str) 12 | 13 | 14 | def logging_setup(): 15 | format_info = "{time:HH:mm:ss.SS} | {level} | {message}" 16 | format_error = "{time:HH:mm:ss.SS} | {level} | {name}:{function}:{line} | {message}" 17 | logger_path = r"logs/out.log" 18 | 19 | logger.remove() 20 | 21 | logger.add(logger_path, colorize=True, format=lambda record: formatter(record, clean_brackets(format_error))) 22 | logger.add(sys.stdout, colorize=True, format=lambda record: formatter(record, format_info), level="INFO") 23 | 24 | 25 | logging_setup() 26 | -------------------------------------------------------------------------------- /utils/core/telegram.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import random 4 | 5 | from data import config 6 | from pyrogram import Client 7 | from utils.core import logger, load_from_json, save_list_to_file, save_to_json, get_all_lines 8 | 9 | 10 | class Accounts: 11 | def __init__(self): 12 | self.workdir = config.WORKDIR 13 | self.api_id = config.API_ID 14 | self.api_hash = config.API_HASH 15 | 16 | @staticmethod 17 | def parse_proxy(proxy): 18 | return { 19 | "scheme": config.PROXY['TYPE']['TG'], 20 | "hostname": proxy.split(":")[1].split("@")[1], 21 | "port": int(proxy.split(":")[2]), 22 | "username": proxy.split(":")[0], 23 | "password": proxy.split(":")[1].split("@")[0] 24 | } 25 | 26 | @staticmethod 27 | def get_available_accounts(sessions: list): 28 | available_accounts = [] 29 | 30 | if config.PROXY['USE_PROXY_FROM_FILE']: 31 | proxys = get_all_lines(config.PROXY['PROXY_PATH']) 32 | for session in sessions: 33 | available_accounts.append({ 34 | 'session_name': session, 35 | 'phone_number': '+0', 36 | 'proxy': proxys.pop(proxys.index(random.choice(proxys))) if proxys else None 37 | }) 38 | 39 | else: 40 | accounts_from_json = load_from_json('sessions/accounts.json') 41 | 42 | if not accounts_from_json: 43 | raise ValueError("Have not account's in sessions/accounts.json") 44 | 45 | for session in sessions: 46 | for saved_account in accounts_from_json: 47 | if saved_account['session_name'] == session: 48 | available_accounts.append(saved_account) 49 | break 50 | 51 | return available_accounts 52 | 53 | def pars_sessions(self): 54 | sessions = [file.replace(".session", "") for file in os.listdir(self.workdir) if file.endswith(".session")] 55 | 56 | logger.info(f"Searched sessions: {len(sessions)}.") 57 | return sessions 58 | 59 | async def check_valid_account(self, account: dict): 60 | session_name, phone_number, proxy = account.values() 61 | 62 | try: 63 | proxy_dict = { 64 | "scheme": config.PROXY['TYPE']['TG'], 65 | "hostname": proxy.split(":")[1].split("@")[1], 66 | "port": int(proxy.split(":")[2]), 67 | "username": proxy.split(":")[0], 68 | "password": proxy.split(":")[1].split("@")[0] 69 | } if proxy else None 70 | 71 | client = Client(name=session_name, api_id=self.api_id, api_hash=self.api_hash, workdir=self.workdir, 72 | proxy=proxy_dict) 73 | 74 | connect = await asyncio.wait_for(client.connect(), timeout=config.TIMEOUT) 75 | if connect: 76 | await client.get_me() 77 | await client.disconnect() 78 | return account 79 | else: 80 | await client.disconnect() 81 | except: 82 | pass 83 | 84 | async def check_valid_accounts(self, accounts: list): 85 | logger.info(f"Checking accounts for valid...") 86 | 87 | tasks = [] 88 | for account in accounts: 89 | tasks.append(asyncio.create_task(self.check_valid_account(account))) 90 | 91 | v_accounts = await asyncio.gather(*tasks) 92 | 93 | valid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if is_valid] 94 | invalid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if not is_valid] 95 | logger.success(f"Valid accounts: {len(valid_accounts)}; Invalid: {len(invalid_accounts)}") 96 | 97 | return valid_accounts, invalid_accounts 98 | 99 | async def get_accounts(self): 100 | sessions = self.pars_sessions() 101 | available_accounts = self.get_available_accounts(sessions) 102 | 103 | if not available_accounts: 104 | raise ValueError("Have not available accounts!") 105 | else: 106 | logger.success(f"Search available accounts: {len(available_accounts)}.") 107 | 108 | valid_accounts, invalid_accounts = await self.check_valid_accounts(available_accounts) 109 | 110 | if invalid_accounts: 111 | save_list_to_file(f"{ config.WORKDIR}invalid_accounts.txt", invalid_accounts) 112 | logger.info(f"Saved {len(invalid_accounts)} invalid account(s) in { config.WORKDIR}invalid_accounts.txt") 113 | 114 | if not valid_accounts: 115 | raise ValueError("Have not valid sessions") 116 | else: 117 | return valid_accounts 118 | 119 | async def create_sessions(self): 120 | while True: 121 | session_name = input('\nInput the name of the session (press Enter to exit): ') 122 | if not session_name: return 123 | 124 | if config.PROXY['USE_PROXY_FROM_FILE']: 125 | proxys = get_all_lines(config.PROXY['PROXY_PATH']) 126 | proxy = random.choice(proxys) if proxys else None 127 | else: 128 | proxy = input("Input the proxy in the format login:password@ip:port (press Enter to use without proxy): ") 129 | 130 | dict_proxy = self.parse_proxy(proxy) if proxy else None 131 | 132 | phone_number = (input("Input the phone number of the account: ")).replace(' ', '') 133 | phone_number = '+' + phone_number if not phone_number.startswith('+') else phone_number 134 | 135 | client = Client( 136 | api_id=self.api_id, 137 | api_hash=self.api_hash, 138 | name=session_name, 139 | workdir=self.workdir, 140 | phone_number=phone_number, 141 | proxy=dict_proxy, 142 | lang_code='ru' 143 | ) 144 | 145 | async with client: 146 | me = await client.get_me() 147 | 148 | save_to_json(f'{ config.WORKDIR}accounts.json', dict_={ 149 | "session_name": session_name, 150 | "phone_number": phone_number, 151 | "proxy": proxy 152 | }) 153 | logger.success(f'Added a account {me.username} ({me.first_name}) | {me.phone_number}') -------------------------------------------------------------------------------- /utils/starter.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | from data import config 4 | from utils.vertus import Vertus 5 | from utils.core import logger 6 | import datetime 7 | import pandas as pd 8 | from utils.core.telegram import Accounts 9 | from aiohttp.client_exceptions import ContentTypeError 10 | import asyncio 11 | 12 | 13 | async def start(thread: int, session_name: str, phone_number: str, proxy: [str, None]): 14 | vertus = Vertus(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy) 15 | account = session_name + '.session' 16 | 17 | if await vertus.login(): 18 | logger.success(f"Thread {thread} | {account} | Login") 19 | while True: 20 | try: 21 | data = await vertus.get_data() 22 | 23 | if not await vertus.is_activated(data): 24 | wallet = await vertus.create_wallet() 25 | logger.success(f"Thread {thread} | {account} | Create wallet: {wallet}") 26 | 27 | if await vertus.can_collect_first(data): 28 | amount = await vertus.first_collect() 29 | logger.success(f"Thread {thread} | {account} | First collect {amount} VERT") 30 | 31 | if vertus.can_claim_daily_reward(data): 32 | status, claim_count = await vertus.claim_daily_reward() 33 | if status == 201: 34 | logger.success(f"Thread {thread} | {account} | Claim daily reward: {claim_count} VERT!") 35 | else: 36 | logger.error(f"Thread {thread} | {account} | Can't claim daily reward! Response {status}") 37 | 38 | storage = vertus.get_storage(data) 39 | 40 | if storage >= 0.003: 41 | status, balance = await vertus.collect() 42 | if status == 201: 43 | logger.success(f"Thread {thread} | {account} | Collect VERT! New balance: {balance}") 44 | else: 45 | logger.error(f"Thread {thread} | {account} | Can't collect VERT! Response {status}") 46 | continue 47 | 48 | balance = vertus.get_balance(data) 49 | farm, population = vertus.get_upgrades(data) 50 | 51 | if farm is None or farm > 10: farm = 9999 52 | if population is None or population > 10: population = 9999 53 | 54 | if farm < population and balance >= farm: 55 | upgrade = "farm" 56 | elif farm > population and balance >= population: 57 | upgrade = "population" 58 | elif farm == population and balance >= population: 59 | upgrade = "farm" 60 | else: 61 | upgrade = "" 62 | 63 | if upgrade and config.BUY_UPGRADE: 64 | status, balance = await vertus.upgrade(upgrade) 65 | if status == 201: 66 | logger.success(f"Thread {thread} | {account} | Upgrade {upgrade}! New balance: {balance}") 67 | else: 68 | logger.error(f"Thread {thread} | {account} | Can't upgrade {upgrade}! Response {status}") 69 | 70 | cards = None 71 | while config.BUY_CARD: 72 | await asyncio.sleep(random.uniform(*config.DELAYS['BUY_CARD'])) 73 | card = await vertus.get_profitable_upgrade_card(balance, cards) 74 | if not card: break 75 | 76 | status, balance, cards = await vertus.buy_upgrade_card(card['id']) 77 | if status == 201: 78 | logger.success(f"Thread {thread} | {account} | Buy card «{card['title']}» in «{card['category']}»! New balance: {balance}") 79 | else: 80 | logger.error(f"Thread {thread} | {account} | Can't buy card «{card['title']}» in «{card['category']}»! Response {status}: {balance}") 81 | 82 | await asyncio.sleep(random.uniform(*config.DELAYS['REPEAT'])) 83 | except ContentTypeError as e: 84 | logger.error(f"Thread {thread} | {account} | Error: {e}") 85 | await asyncio.sleep(15) 86 | 87 | except Exception as e: 88 | logger.error(f"Thread {thread} | {account} | Error: {e}") 89 | await asyncio.sleep(10) 90 | 91 | else: 92 | await vertus.logout() 93 | 94 | 95 | async def stats(): 96 | accounts = await Accounts().get_accounts() 97 | 98 | tasks = [] 99 | for thread, account in enumerate(accounts): 100 | session_name, phone_number, proxy = account.values() 101 | tasks.append(asyncio.create_task(Vertus(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy).stats())) 102 | 103 | data = await asyncio.gather(*tasks) 104 | 105 | path = f"statistics/statistics_{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.csv" 106 | columns = ['Registered', 'Phone number', 'Name', 'Balance', 'Referrals', 'Referral link', 'Wallet', 'Proxy (login:password@ip:port)'] 107 | 108 | if not os.path.exists('statistics'): os.mkdir('statistics') 109 | df = pd.DataFrame(data, columns=columns) 110 | df.to_csv(path, index=False, encoding='utf-8-sig') 111 | 112 | logger.success(f"Saved statistics to {path}") 113 | -------------------------------------------------------------------------------- /utils/vertus.py: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | from datetime import datetime 4 | from utils.core import logger 5 | from pyrogram import Client 6 | from pyrogram.raw.functions.messages import RequestAppWebView 7 | from pyrogram.raw.types import InputBotAppShortName 8 | import asyncio 9 | from urllib.parse import unquote, quote, unquote_plus 10 | from data import config 11 | import aiohttp 12 | from fake_useragent import UserAgent 13 | from aiohttp_socks import ProxyConnector 14 | 15 | 16 | class Vertus: 17 | def __init__(self, thread: int, session_name: str, phone_number: str, proxy: [str, None]): 18 | self.account = session_name + '.session' 19 | self.thread = thread 20 | self.proxy = f"{config.PROXY['TYPE']['REQUESTS']}://{proxy}" if proxy is not None else None 21 | connector = ProxyConnector.from_url(self.proxy) if proxy else aiohttp.TCPConnector(verify_ssl=False) 22 | 23 | if proxy: 24 | proxy = { 25 | "scheme": config.PROXY['TYPE']['TG'], 26 | "hostname": proxy.split(":")[1].split("@")[1], 27 | "port": int(proxy.split(":")[2]), 28 | "username": proxy.split(":")[0], 29 | "password": proxy.split(":")[1].split("@")[0] 30 | } 31 | 32 | self.client = Client( 33 | name=session_name, 34 | api_id=config.API_ID, 35 | api_hash=config.API_HASH, 36 | workdir=config.WORKDIR, 37 | proxy=proxy, 38 | lang_code='ru' 39 | ) 40 | 41 | headers = {'User-Agent': UserAgent(os='android').random} 42 | self.session = aiohttp.ClientSession(headers=headers, trust_env=True, connector=connector) 43 | 44 | async def buy_upgrade_card(self, card_id: str): 45 | resp = await self.session.post('https://api.thevertus.app/upgrade-cards/upgrade', json={'cardId': card_id}) 46 | resp_json = await resp.json() 47 | 48 | return resp.status, self.from_nano(resp_json.get('balance')) if resp_json.get("isSuccess") else await resp.text(), resp_json.get('cards') 49 | 50 | async def get_profitable_upgrade_card(self, balance, upgrade_cards: [dict, None] = None): 51 | if upgrade_cards: 52 | upgrade_cards = upgrade_cards.get('economyCards') + upgrade_cards.get('militaryCards') + upgrade_cards.get('scienceCards') 53 | else: 54 | upgrade_cards = await self.get_upgrades_cards() 55 | 56 | cards = [] 57 | for card in upgrade_cards: 58 | if not card['isLocked'] and card['isUpgradable'] and self.from_nano(card['levels'][card['currentLevel']]['cost']) <= balance: 59 | cards.append({ 60 | "id": card['_id'], 61 | "profitability": card['levels'][card['currentLevel']]['value'] / card['levels'][card['currentLevel']]['cost'], 62 | "title": card['cardName'], 63 | "category": card['type'] 64 | }) 65 | 66 | return max(cards, key=lambda x: x["profitability"]) if cards else None 67 | 68 | async def get_upgrades_cards(self): 69 | resp = await self.session.get('https://api.thevertus.app/upgrade-cards') 70 | r = await resp.json() 71 | 72 | return r.get('economyCards') + r.get('militaryCards') + r.get('scienceCards') 73 | 74 | async def stats(self): 75 | await self.login() 76 | data = await self.get_data() 77 | 78 | registered = '✅' if data.get('activated') else '❌' 79 | balance = self.from_nano(data.get('balance')) 80 | wallet = data.get('walletAddress') 81 | referral_link = 'https://t.me/vertus_app_bot/app?startapp=' + str(data.get('telegramId')) 82 | 83 | referrals = (await (await self.session.post('https://api.thevertus.app/users/get-referrals/1', json={})).json()).get('total') 84 | 85 | await self.logout() 86 | 87 | await self.client.connect() 88 | me = await self.client.get_me() 89 | phone_number, name = "'" + me.phone_number, f"{me.first_name} {me.last_name if me.last_name is not None else ''}" 90 | await self.client.disconnect() 91 | 92 | proxy = self.proxy.replace(f'{config.PROXY_TYPES["REQUESTS"]}://', "") if self.proxy is not None else '-' 93 | return [registered, phone_number, name, str(balance), str(referrals), referral_link, wallet, proxy] 94 | 95 | def can_claim_daily_reward(self, data): 96 | if data.get("dailyRewards").get('lastRewardClaimed') is None: return True 97 | return self.iso_to_unix_time(data.get("dailyRewards").get('lastRewardClaimed')) + 86400 < self.current_time() 98 | 99 | async def claim_daily_reward(self): 100 | resp = await self.session.post("https://api.thevertus.app/users/claim-daily", json={}) 101 | resp_json = await resp.json() 102 | 103 | return resp.status, self.from_nano(resp_json.get('claimed')) if resp_json.get("success") else await resp.text() 104 | 105 | async def upgrade(self, upgrade): 106 | json_data = {"upgrade": upgrade} 107 | resp = await self.session.post('https://api.thevertus.app/users/upgrade', json=json_data) 108 | resp_json = await resp.json() 109 | 110 | return resp.status, self.from_nano(resp_json.get('newBalance')) if resp_json.get("success") else await resp.text() 111 | 112 | async def collect(self): 113 | resp = await self.session.post('https://api.thevertus.app/game-service/collect', json={}) 114 | return resp.status, self.from_nano((await resp.json()).get('newBalance')) if resp.status == 201 else await resp.text() 115 | 116 | def get_storage(self, data): 117 | return self.from_nano(data.get('vertStorage')) 118 | 119 | def get_balance(self, data): 120 | return self.from_nano(data.get('balance')) 121 | 122 | async def first_collect(self): 123 | resp = await self.session.post('https://api.thevertus.app/game-service/collect-first', json={}) 124 | return self.from_nano((await resp.json()).get('newBalance')) 125 | 126 | async def get_data(self): 127 | resp = await self.session.post('https://api.thevertus.app/users/get-data', json={}) 128 | return (await resp.json()).get('user') 129 | 130 | async def create_wallet(self): 131 | resp = await self.session.post('https://api.thevertus.app/users/create-wallet', json={}) 132 | return (await resp.json()).get('walletAddress') 133 | 134 | @staticmethod 135 | def get_offline_profit(data): 136 | return data.get('earnedOffline') 137 | 138 | @staticmethod 139 | def get_upgrades(data): 140 | return data.get('abilities').get('farm').get('priceToLevelUp'), data.get('abilities').get('population').get('priceToLevelUp') 141 | 142 | @staticmethod 143 | def iso_to_unix_time(iso_time: str): 144 | return int(datetime.strptime(iso_time, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()) + 1 145 | 146 | @staticmethod 147 | def current_time(): 148 | return int(time.time()) 149 | 150 | @staticmethod 151 | async def can_collect_first(data): 152 | return not data.get('storage') and not data.get('balance') 153 | 154 | @staticmethod 155 | async def is_activated(data): 156 | return data.get('activated') 157 | 158 | @staticmethod 159 | def from_nano(amount: int): 160 | return amount/1e18 161 | 162 | @staticmethod 163 | def to_nano(amount: int): 164 | return amount*1e18 165 | 166 | async def logout(self): 167 | await self.session.close() 168 | 169 | async def login(self): 170 | await asyncio.sleep(random.uniform(*config.DELAYS['ACCOUNT'])) 171 | query = await self.get_tg_web_data() 172 | 173 | if query is None: 174 | logger.error(f"Thread {self.thread} | {self.account} | Session {self.account} invalid") 175 | await self.logout() 176 | return None 177 | 178 | self.session.headers['Authorization'] = 'Bearer ' + query 179 | return True 180 | 181 | async def get_tg_web_data(self): 182 | try: 183 | await self.client.connect() 184 | web_view = await self.client.invoke(RequestAppWebView( 185 | peer=await self.client.resolve_peer('Vertus_App_bot'), 186 | app=InputBotAppShortName(bot_id=await self.client.resolve_peer('Vertus_App_bot'), short_name="app"), 187 | platform='android', 188 | write_allowed=True, 189 | start_param='6008239182' if random.random() <= 0.4 else config.REF_LINK.split('startapp=')[1] 190 | )) 191 | 192 | await self.client.disconnect() 193 | auth_url = web_view.url 194 | 195 | return unquote_plus(string=auth_url.split('tgWebAppData=')[1].split('&tgWebAppVersion')[0]) 196 | except: 197 | return None 198 | --------------------------------------------------------------------------------