| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- # -*- coding: utf-8 -*-
- import asyncio
- from loguru import logger
- import random
- import hashlib
- from eth_account import Account
- from pynocaptcha import CloudFlareCracker, TlsV1Cracker
- from curl_cffi.requests import AsyncSession
- SETTINGS = {
- "ATTEMPTS": 3,
- "RANDOM_PAUSE_BETWEEN_ACTIONS": [1, 5],
- }
- FAUCET = {
- "USE_CAPSOLVER_FOR_CLOUDFLARE": False,
- "CAPSOLVER_API_KEY": "your_capsolver_api_key",
- "NOCAPTCHA_API_KEY": "your_nocaptcha_api_key",
- }
- async def faucet(
- session: AsyncSession,
- account_index: int,
- wallet: Account,
- proxy: str,
- ) -> bool:
- for retry in range(SETTINGS["ATTEMPTS"]):
- try:
- logger.info(f"[{account_index}] | Starting faucet for account {wallet.address}...")
- user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
- href = "https://testnet.monad.xyz/"
- # Solve Cloudflare challenge
- if FAUCET["USE_CAPSOLVER_FOR_CLOUDFLARE"]:
- logger.info(f"[{account_index}] | Solving Cloudflare challenge with Capsolver...")
- # 这里假设Capsolver类已经定义并且可用
- capsolver = Capsolver(api_key=FAUCET["CAPSOLVER_API_KEY"], proxy=proxy, session=session)
- cf_result = await capsolver.solve_turnstile("0x4AAAAAAA-3X4Nd7hf3mNGx", href)
- else:
- logger.info(f"[{account_index}] | Solving Cloudflare challenge with Nocaptcha...")
- # 这里假设CloudFlareCracker类已经定义并且可用
- cracker = CloudFlareCracker(
- internal_host=True,
- user_token=FAUCET["NOCAPTCHA_API_KEY"],
- href=href,
- sitekey="0x4AAAAAAA-3X4Nd7hf3mNGx",
- proxy=proxy,
- debug=False,
- show_ad=False,
- timeout=60,
- )
- cf_result = cracker.crack()
- cf_result = cf_result["token"]
- if not cf_result:
- raise Exception("Failed to solve Cloudflare challenge")
- logger.success(f"[{account_index}] | Cloudflare challenge solved")
- # Generate visitor ID
- visitor_id = hashlib.md5(str(random.random()).encode()).hexdigest()
- json_data = {
- "address": wallet.address,
- "visitorId": visitor_id,
- "cloudFlareResponseToken": cf_result,
- }
- headers = {
- "sec-ch-ua-platform": '"Windows"',
- "user-agent": user_agent,
- "sec-ch-ua": '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
- "content-type": "application/json",
- "sec-ch-ua-mobile": "?0",
- "accept": "*/*",
- "origin": href,
- "sec-fetch-site": "same-origin",
- "sec-fetch-mode": "cors",
- "sec-fetch-dest": "empty",
- "referer": href,
- "accept-language": "en-GB,en;q=0.9",
- "priority": "u=1, i",
- }
- response = await session.post(
- f"{href}api/faucet/claim", headers=headers, json=json_data
- )
- response_text = response.text
- if not response_text:
- raise Exception("Failed to send claim request")
- if '"Success"' in response_text or '"message":"Success"' in response_text:
- logger.success(f"[{account_index}] | Successfully got tokens from faucet")
- return True
- if "Claimed already" in response_text:
- logger.success(f"[{account_index}] | Already claimed tokens from faucet")
- return True
- error_messages = {
- "FUNCTION_INVOCATION_TIMEOUT": "Server is not responding, wait...",
- "Vercel Security Checkpoint": "Failed to solve Vercel challenge, trying again...",
- "Server error on QuickNode API": "FAUCET DOES NOT WORK, QUICKNODE IS DOWN",
- "Over Enterprise free quota": "MONAD IS SHIT, FAUCET DOES NOT WORK, TRY LATER",
- "invalid-keys": "PLEASE UPDATE THE BOT USING GITHUB",
- }
- for key, message in error_messages.items():
- if key in response_text:
- logger.error(f"[{account_index}] | {message}")
- if key == "Over Enterprise free quota" or key == "invalid-keys":
- return False
- break
- else:
- logger.error(f"[{account_index}] | Failed to get tokens from faucet: {response_text}")
- await asyncio.sleep(3)
- except Exception as e:
- random_pause = random.randint(*SETTINGS["RANDOM_PAUSE_BETWEEN_ACTIONS"])
- if "operation timed out" in str(e):
- logger.error(
- f"[{account_index}] | Error faucet to monad.xyz ({retry + 1}/{SETTINGS['ATTEMPTS']}): Connection timed out. Next faucet in {random_pause} seconds")
- else:
- logger.error(
- f"[{account_index}] | Error faucet to monad.xyz ({retry + 1}/{SETTINGS['ATTEMPTS']}): {e}. Next faucet in {random_pause} seconds")
- await asyncio.sleep(random_pause)
- continue
- return False
|