# -*- coding: utf-8 -*- """ Monad 测试网 talentum 批量签到脚本 网址: monad.talentum.id 2. checkIn() → 0x9E1DDC2a90bc0bec6325dF48Cbb3125Ce2879F7C 方法 0x9e4cda43 """ import asyncio import os import random from typing import List from web3 import Web3 from web3.types import TxReceipt from eth_account import Account # ------------------------ 用户配置区 ------------------------ RPC_URL = "https://testnet-rpc.monad.xyz" CHECK_IN_CONTRACT = "0x9E1DDC2a90bc0bec6325dF48Cbb3125Ce2879F7C" KEY_FILE = "AccountList.txt" MIN_KEEP_BALANCE = 0.02 MIN_DELAY = 15 MAX_DELAY = 30 CHECK_IN_ABI = [{ "inputs": [], "name": "checkIn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }] # ----------------------------------------------------------- w3 = Web3(Web3.HTTPProvider(RPC_URL)) if not w3.is_connected(): raise RuntimeError("无法连接 RPC") CHECK_IN_SELECTOR = "0x9e4cda43" def load_private_keys(path: str) -> List[str]: if not os.path.isfile(path): raise FileNotFoundError(f"找不到私钥文件: {path}") with open(path, "r", encoding="utf-8") as f: return [line.strip() for line in f if line.strip()] def random_gas_limit(base: int = 100_000) -> int: return base + random.randint(-5_000, 10_000) async def wait_tx(tx_hash: str) -> TxReceipt: print(f"⏳ 等待交易确认: {tx_hash}") receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120) if receipt.status == 1: print("✅ 成功") else: print("❌ 失败") return receipt async def send_contract_call(private_key: str, contract_addr: str, contract_abi: list, desc: str): acct = Account.from_key(private_key) addr = acct.address balance = w3.eth.get_balance(addr) if w3.from_wei(balance, "ether") < MIN_KEEP_BALANCE: print(f"⚠️ {addr} 余额不足,跳过") return nonce = w3.eth.get_transaction_count(addr) contract = w3.eth.contract(address=Web3.to_checksum_address(contract_addr), abi=contract_abi) data = contract.encodeABI(fn_name='checkIn') tx = { "to": Web3.to_checksum_address(contract_addr), "value": 0, "data": data, "gas": random_gas_limit(), "gasPrice": w3.eth.gas_price, "nonce": nonce, "chainId": w3.eth.chain_id, } signed = Account.sign_transaction(tx, private_key) tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction).hex() print(f"{desc} tx_hash: {tx_hash}") await wait_tx(tx_hash) async def process_account(private_key: str): acct = Account.from_key(private_key) print(f"\n========== 开始处理 {acct.address} ==========") try: await send_contract_call( private_key, CHECK_IN_CONTRACT, CHECK_IN_ABI, "SignIn" ) except Exception as e: print(f"执行出错: {e}") async def main(): keys = load_private_keys(KEY_FILE) if not keys: print("私钥文件为空") return print(f"共读取到 {len(keys)} 个钱包") for pk in keys: await process_account(pk) if pk != keys[-1]: await asyncio.sleep(random.uniform(MIN_DELAY, MAX_DELAY)) if __name__ == "__main__": asyncio.run(main())