| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- # -*- coding: utf-8 -*-
- """
- Monad 测试网 talentum 批量签到脚本
- 网址: monad.talentum.id
- 2. checkIn() → 0x703e753E9a2aCa1194DED65833EAec17dcFeAc1b 方法 0x183ff085
- """
- 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 = "0xcBE623D259261FFa0CFAff44484bFF46c1b7D6c2"
- KEY_FILE = "AccountList.txt"
- MIN_KEEP_BALANCE = 0.02
- MIN_DELAY = 15
- MAX_DELAY = 30
- # -----------------------------------------------------------
- w3 = Web3(Web3.HTTPProvider(RPC_URL))
- if not w3.is_connected():
- raise RuntimeError("无法连接 RPC")
- CHECK_IN_SELECTOR = "0x7ab71841"
- 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,
- selector: str,
- 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)
- tx = {
- "to": Web3.to_checksum_address(contract_addr),
- "value": 0,
- "data": selector,
- "gas": random_gas_limit(),
- "gasPrice": w3.eth.gas_price,
- "nonce": nonce,
- "chainId": w3.eth.chain_id,
- }
- signed = Account.sign_transaction(tx, private_key)
- # 注意新版为 raw_transaction,不是 rawTransaction
- tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction).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_SELECTOR,
- "0x7ab71841"
- )
- 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())
|