├── .gitignore ├── LICENSE ├── README.md ├── alien.ico ├── alien.py ├── doc └── demo1.png ├── install_dependencies.bat ├── main.py ├── nonce.py ├── requirements.txt ├── settings.py ├── user.bat └── user.yml /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .idea 3 | /*build 4 | /*dist 5 | /pack.bat 6 | /logs 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 encoderlee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAlien 2 | ![version](https://img.shields.io/badge/version-1.1.2-blue) 3 | ![license](https://img.shields.io/badge/license-MIT-brightgreen) 4 | ![python_version](https://img.shields.io/badge/python-%3E%3D%203.6-brightgreen) 5 | ![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen) 6 | [![](https://img.shields.io/badge/blog-@encoderlee-red)](https://encoderlee.blog.csdn.net) 7 | ### 一个免费开源的外星世界(Alien Worlds)自动化挂机合约脚本 8 | ![](https://raw.githubusercontent.com/encoderlee/OpenAlien/main/doc/demo1.png) 9 | ## 说明 10 | 外星世界(Alien Worlds)官网: [https://alienworlds.io](https://alienworlds.io) 11 | 12 | 之前我们推出过免费开源的农民世界(FarmersWorld)合约脚本: 13 | [https://github.com/encoderlee/OpenFarmer](https://github.com/encoderlee/OpenFarmer) 14 | 15 | 本次推出外星世界(Alien Worlds)的合约脚本: 16 | [https://github.com/encoderlee/OpenAlien](https://github.com/encoderlee/OpenAlien) 17 | 18 | 老用户都懂,无需多言 19 | 20 | 和之前的 OpenFarmer 相比,本次开源的 OpenAlien 彻底脱离了Chrome浏览器运行 21 | 22 | 底层的 EOSIO SDK 由原来的 [【eospy】](https://github.com/eosnewyork/eospy) 换成了我们自己开发的 [【eosapi】](https://github.com/encoderlee/eosapi) , 23 | 提高了稳定性和单台电脑的多开数量 24 | 25 | 欢迎关注我的博客:[https://encoderlee.blog.csdn.net](https://encoderlee.blog.csdn.net) 26 | 27 | ### 欢迎加入我们的QQ群交流讨论:568229631 28 | 29 | # 用法 30 | 31 | ### 视频教程: 32 | 33 | [https://www.bilibili.com/video/BV1da4115757](https://www.bilibili.com/video/BV1da4115757) 34 | 35 | [https://www.youtube.com/watch?v=hZSl-2QyJys](https://www.youtube.com/watch?v=hZSl-2QyJys) 36 | 37 | ### 使用方法一: 38 | 39 | 直接点下面链接下载最新版打包版本(或在github页面右侧的【Releases】里找),打包版本只支持Win10或更高版本的操作系统。 40 | 41 | [【点我下载】](https://github.com/encoderlee/OpenAlien/releases/download/v1.1.2/OpenAlien_1.1.2.zip) 42 | 43 | 把压缩包里的文件解压出来,先修改配置文件【user.yml】,再双击运行【user.bat】 44 | 45 | 多开第二个账号,复制【user.yml】为【user2.yml】,复制【user.bat】为【user2.bat】 46 | 47 | 修改配置文件【user2.yml】为第二个账户的信息,修改【user2.bat】文件,把里面的字符串“user.yml”改为“user2.yml”,然后双击运行【user2.bat】 48 | 49 | 多开更多账号,以此类推 50 | 51 | ### 使用方法二: 52 | 53 | 1.从源码运行,先安装 Python 环境,推荐安装 Python 3.9.13 版本,因为这是我们测试过的版本 54 | 55 | 下载地址:[https://www.python.org/ftp/python/3.9.13/python-3.9.13-amd64.exe](https://www.python.org/ftp/python/3.9.13/python-3.9.13-amd64.exe) 56 | 57 | 安装时记得勾选“Add Python 3.9 to PATH” 58 | 59 | 2.下载源码,在 github 项目页面上点击绿色按钮【Code】,【Download ZIP】,下载后解压出来 60 | 61 | 3.双击运行【install_dependencies.bat】安装依赖包,这个步骤每台电脑只需做一次 62 | 63 | 【注意】安装依赖包前请关闭梯子之类的代理,以免下载出错 64 | 65 | 4.先修改配置文件【user.yml】,再双击运行【user.bat】 66 | 67 | 5.多开方法和上面一样,就是复制这两个文件,修改后运行 68 | 69 | ### 配置文件说明 70 | 71 | ```yaml 72 | #注意,每个参数名的冒号后面,都有一个空格,修改参数不要丢了空格 73 | 74 | # wax节点地址,使用公共节点,有时候会网络不通,或者访问太频繁被限制,出现429错误,可以换节点,或者搭建私有节点 75 | # 公共节点列表:https://wax.eosio.online/endpoints 76 | 77 | rpc_domain: https://wax.pink.gg 78 | 79 | # cpu代付号,cpu_key填写该代付号私钥,不需要代付则留空 80 | # 注意,由于外星世界官方于2022年10月更新了智能合约,阻止代付行为,所以代付功能失效 81 | cpu_account: 82 | cpu_key: 83 | 84 | # 即使可挖时间到了,也延迟20-60秒再挖 85 | delay1: 20 86 | delay2: 60 87 | 88 | # 挖多少次获取一次收益,0为不自动获取 89 | claimmines: 10 90 | 91 | # http代理(比如127.0.0.1:10808) 92 | # 给脚本设置HTTP代理,这样可以在一定程度上解决公共节点限制访问的问题,不需要则留空 93 | proxy: 94 | proxy_username: 95 | proxy_password: 96 | 97 | # 下面三项改为你的账号信息 98 | # account是wax云钱包账号名 99 | # token是什么,先在chrome浏览器中手工登录WAX云钱包 https://wallet.wax.io/dashboard 100 | # 然后在chrome浏览器中输入地址导航到: https://all-access.wax.io/api/session 101 | # 把token复制出来填到下面 102 | # charge_time是采矿间隔,单位秒,登录alienworlds官网,打开工具页面,就可以看到,按实际情况填写 103 | 104 | account: gts3c.c.wam 105 | token: EHuyFHPcLpSNUJ4BLSUnPxxxxxxxxxxxx 106 | charge_time: 336 107 | 108 | ``` 109 | 110 | 公共节点列表:[https://wax.eosio.online/endpoints](https://wax.eosio.online/endpoints) 111 | 112 | 注意,从 Chrome 浏览器中复制出 token 后,浏览器可以点右上角叉叉关闭,但不要点退出登录该账号,也不要直接重新登录另外一个账号,不然之前的账号会掉线。 113 | 114 | 如果需要在 Chrome 中登录第二个账号,请使用 Chrome 的多用户功能登录 115 | 116 | Chrome 多用户相关文章:[https://www.chensnotes.com/chrome-profile.html](https://www.chensnotes.com/chrome-profile.html) 117 | 118 | ### 常用工具 119 | 120 | 【nodepad++】[https://notepad-plus-plus.org/downloads/v8.4.2](https://notepad-plus-plus.org/downloads/v8.4.2) 121 | 122 | 文本编辑器,编辑修改【user.yml】配置文件更愉快 123 | 124 | 【cmder】[https://cmder.net](https://cmder.net) 125 | 126 | 替代 windows 自带的 cmd 命令行工具,防止脚本假死 127 | 128 | 系统自带的 cmd 命令行工具,默认开启快速编辑模式,有时候因为鼠标键盘意外操作, 129 | 130 | 日志会留在一个地方,处于假死状态,导致脚本不能持续运行,换用【cmder】解决该问题 131 | 132 | ### 常见错误 133 | 1.交易错误 134 | 135 | 交易错误的原因有很多种,比如智能合约报错,CPU不足,秘钥不对,WAX节点限制等 136 | 137 | 连续出现5次交易出错,脚本将停止,此时需要手工检查问题或更换节点 138 | 139 | 为什么不一直继续反复重试?因为反复提交错误的交易,公共节点就会把你拉黑,需要24小时之后才能使用该节点了 140 | 141 | 自行架设 WAX 私有节点,会在一定程度上改善此问题 142 | 143 | 2.节点错误 144 | 145 | 节点错误,尤其是 429 错误,主要是因为你一个IP下面同时跑的号太多了,请求频繁,被节点拉黑 146 | 147 | 公共节点毕竟是面向全球的免费服务,为了防止滥用,做了很多限制 148 | 149 | 每N个号设置一个代理IP,或者自行架设 WAX 私有节点,会在一定程度上改善此问题 150 | 151 | ### 欢迎打赏 152 | 153 | wax钱包地址: 154 | 155 | m45yy.wam 156 | 157 | ### 更新记录 158 | v1.1 (2022年11月8日) 159 | 1. 优化logger,允许每个账号的日志输出到不同的文件 160 | 2. 从代码中移除 eosapi 源文件,直接从 pip 下载该库 161 | 3. 增加账户可用的CPU资源判断,如果CPU不足则不会冒然尝试提交交易,减少因频繁提交错误交易被节点拉黑的概率 162 | 4. 注意,由于外星世界官方于2022年10月更新了智能合约,阻止代付行为,所以代付功能失效 163 | 164 | v1.1.2 (2022年12月8日) 165 | 1. 游戏玩法改变,挖矿不再即时获得收益,而是需要点击获取收益TLM才会到账 166 | 2. 脚本更新,支持每挖N次,自动获取一次收益 167 | 3. 移除logger.py,直接从 pip 下载该库 168 | -------------------------------------------------------------------------------- /alien.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encoderlee/OpenAlien/6d9279b9d4bf12352d250dc0018e2ced8d6ccf97/alien.ico -------------------------------------------------------------------------------- /alien.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timezone, timedelta 2 | import time 3 | from bestlog import logger 4 | import logging 5 | import requests 6 | import functools 7 | from eosapi import NodeException, TransactionException, EosApiException, Transaction 8 | from nonce import Nonce, generate_nonce 9 | from eosapi import EosApi 10 | from typing import List, Dict, Union, Tuple 11 | import random 12 | from settings import user_param, interval 13 | from requests.adapters import HTTPAdapter 14 | from requests.packages.urllib3.util.ssl_ import create_urllib3_context 15 | import tenacity 16 | from tenacity import wait_fixed, RetryCallState, retry_if_not_exception_type 17 | from requests import RequestException 18 | from dataclasses import dataclass 19 | 20 | 21 | class CipherAdapter(HTTPAdapter): 22 | def init_poolmanager(self, *args, **kwargs): 23 | context = create_urllib3_context(ciphers='DEFAULT:@SECLEVEL=2') 24 | kwargs['ssl_context'] = context 25 | return super(CipherAdapter, self).init_poolmanager(*args, **kwargs) 26 | 27 | def proxy_manager_for(self, *args, **kwargs): 28 | context = create_urllib3_context(ciphers='DEFAULT:@SECLEVEL=2') 29 | kwargs['ssl_context'] = context 30 | return super(CipherAdapter, self).proxy_manager_for(*args, **kwargs) 31 | 32 | 33 | class StopException(Exception): 34 | def __init__(self, msg: str): 35 | super().__init__(msg) 36 | 37 | 38 | 39 | @dataclass 40 | class HttpProxy: 41 | proxy: str 42 | user_name: str = None 43 | password: str = None 44 | 45 | def to_proxies(self) -> Dict: 46 | if self.user_name and self.password: 47 | proxies = { 48 | "http": "http://{0}:{1}@{2}".format(self.user_name, self.password, self.proxy), 49 | "https": "http://{0}:{1}@{2}".format(self.user_name, self.password, self.proxy), 50 | } 51 | else: 52 | proxies = { 53 | "http": "http://{0}".format(self.proxy), 54 | "https": "http://{0}".format(self.proxy), 55 | } 56 | return proxies 57 | 58 | 59 | 60 | class Alien: 61 | # alien_host = "https://aw-guard.yeomen.ai" 62 | 63 | def __init__(self, wax_account: str, token: str, charge_time: int, proxy: HttpProxy = None): 64 | self.wax_account: str = wax_account 65 | self.token: str = token 66 | self.log: logging.LoggerAdapter = logger.get(self.wax_account, self.wax_account) 67 | self.http = requests.Session() 68 | self.http.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, " \ 69 | "like Gecko) Chrome/101.0.4951.54 Safari/537.36 " 70 | self.http.trust_env = False 71 | self.http.request = functools.partial(self.http.request, timeout=60) 72 | self.http.mount('https://public-wax-on.wax.io', CipherAdapter()) 73 | self.rpc_host = user_param.rpc_domain 74 | self.eosapi = EosApi(self.rpc_host, timeout=60) 75 | if user_param.cpu_account and user_param.cpu_key: 76 | self.eosapi.set_cpu_payer(user_param.cpu_account, user_param.cpu_key) 77 | 78 | if proxy: 79 | proxies = proxy.to_proxies() 80 | self.http.proxies = proxies 81 | self.eosapi.session.proxies = proxies 82 | 83 | retry = tenacity.retry(retry = retry_if_not_exception_type(StopException), wait=self.wait_retry, reraise=False) 84 | self.mine = retry(self.mine) 85 | self.query_last_mine = retry(self.query_last_mine) 86 | 87 | self.charge_time: int = charge_time 88 | self.next_mine_time: datetime = None 89 | self.check_cpu: bool = False 90 | 91 | self.count_mine = 0 92 | self.trx_error_count = 0 93 | 94 | def wait_retry(self, retry_state: RetryCallState) -> float: 95 | exp = retry_state.outcome.exception() 96 | wait_seconds = interval.transact 97 | if isinstance(exp, RequestException): 98 | self.log.info("网络错误: {0}".format(exp)) 99 | wait_seconds = interval.net_error 100 | elif isinstance(exp, NodeException): 101 | self.log.info((str(exp))) 102 | self.log.info("节点错误,状态码【{0}】".format(exp.resp.status_code)) 103 | wait_seconds = interval.transact 104 | elif isinstance(exp, TransactionException): 105 | self.trx_error_count += 1 106 | self.log.info("交易失败: {0}".format(exp.resp.text)) 107 | if "is greater than the maximum billable" in exp.resp.text: 108 | self.log.error("CPU资源不足,可能需要质押更多WAX,稍后重试 [{0}]".format(self.trx_error_count)) 109 | wait_seconds = interval.cpu_insufficient 110 | self.check_cpu = True 111 | elif "is not less than the maximum billable CPU time" in exp.resp.text: 112 | self.log.error("交易被限制,可能被该节点拉黑 [{0}]".format(self.trx_error_count)) 113 | wait_seconds = interval.transact 114 | elif "NOTHING_TO_MINE" in exp.resp.text: 115 | self.log.error("账号可能被封,请手动检查 ERR::NOTHING_TO_MINE") 116 | raise StopException("账号可能被封") 117 | else: 118 | if exp: 119 | self.log.info("常规错误: {0}".format(exp), exc_info=exp) 120 | else: 121 | self.log.info("常规错误") 122 | if self.trx_error_count >= interval.max_trx_error: 123 | self.log.info("交易连续出错[{0}]次,为避免被节点拉黑,脚本停止,请手动检查问题或更换节点".format(self.trx_error_count)) 124 | raise StopException("交易连续出错") 125 | self.log.info("{0}秒后重试: [{1}]".format(wait_seconds, retry_state.attempt_number)) 126 | return float(wait_seconds) 127 | 128 | 129 | def get_table_rows(self, table: str): 130 | post_data = { 131 | "json": True, 132 | "code": "m.federation", 133 | "scope": "m.federation", 134 | "table": table, 135 | "lower_bound": self.wax_account, 136 | "upper_bound": self.wax_account, 137 | "index_position": 1, 138 | "key_type": "", 139 | "limit": 10, 140 | "reverse": False, 141 | "show_payer": False 142 | } 143 | return self.eosapi.get_table_rows(post_data) 144 | 145 | # 获取收益 146 | 147 | def claim_mines(self): 148 | self.log.info("正在获取收益") 149 | trx = { 150 | "actions": [{ 151 | "account": "m.federation", 152 | "name": "claimmines", 153 | "authorization": [{ 154 | "actor": self.wax_account, 155 | "permission": "active", 156 | }], 157 | "data": { 158 | "receiver": self.wax_account, 159 | }, 160 | }] 161 | } 162 | trx = self.eosapi.make_transaction(trx) 163 | serialized_trx = list(trx.pack()) 164 | 165 | # wax云钱包签名 166 | signatures = self.wax_sign(serialized_trx) 167 | time.sleep(interval.req) 168 | trx.signatures.extend(signatures) 169 | self.push_transaction(trx) 170 | return True 171 | 172 | # 采矿 173 | def mine(self) -> bool: 174 | if self.check_cpu: 175 | if not self.check_cpu_net(): 176 | self.log.info("CPU/NET资源不足,暂时不采矿,60秒后再试") 177 | self.next_mine_time = datetime.now() + timedelta(seconds = 60) 178 | return False 179 | # 查询上次采矿的信息 180 | last_mine_time, last_mine_tx = self.query_last_mine() 181 | 182 | ready_mine_time = last_mine_time + timedelta(seconds=self.charge_time) 183 | if datetime.now() < ready_mine_time: 184 | interval_seconds = self.charge_time + random.randint(user_param.delay1, user_param.delay2) 185 | self.next_mine_time = last_mine_time + timedelta(seconds=interval_seconds) 186 | self.log.info("时间不到,下次采矿时间: {0}".format(self.next_mine_time)) 187 | return False 188 | 189 | time.sleep(interval.req) 190 | self.log.info("开始采矿") 191 | # 生成nonce 192 | nonce = generate_nonce(self.wax_account, last_mine_tx) 193 | nonce = nonce.random_string 194 | 195 | self.log.info("生成 nonce: {0}".format(nonce)) 196 | 197 | # 调用合约,序列化交易 198 | trx = { 199 | "actions": [{ 200 | "account": "m.federation", 201 | "name": "mine", 202 | "authorization": [{ 203 | "actor": self.wax_account, 204 | "permission": "active", 205 | }], 206 | "data": { 207 | "miner": self.wax_account, 208 | "nonce": nonce, 209 | }, 210 | }] 211 | } 212 | trx = self.eosapi.make_transaction(trx) 213 | serialized_trx = list(trx.pack()) 214 | 215 | # wax云钱包签名 216 | signatures = self.wax_sign(serialized_trx) 217 | time.sleep(interval.req) 218 | trx.signatures.extend(signatures) 219 | self.push_transaction(trx) 220 | 221 | self.count_mine += 1 222 | if user_param.claimmines > 0 and self.count_mine % user_param.claimmines == 0: 223 | time.sleep(1) 224 | self.claim_mines() 225 | 226 | interval_seconds = self.charge_time + random.randint(user_param.delay1, user_param.delay2) 227 | self.next_mine_time = datetime.now() + timedelta(seconds=interval_seconds) 228 | self.log.info("下次采矿时间: {0}".format(self.next_mine_time)) 229 | 230 | return True 231 | 232 | 233 | def push_transaction(self, trx: Union[Dict, Transaction]): 234 | self.log.info("开始交易: {0}".format(trx)) 235 | resp = self.eosapi.push_transaction(trx) 236 | self.log.info("交易成功, transaction_id: [{0}]".format(resp["transaction_id"])) 237 | self.trx_error_count = 0 238 | self.check_cpu = False 239 | 240 | 241 | def wax_sign(self, serialized_trx: str) -> List[str]: 242 | self.log.info("正在通过云钱包签名") 243 | url = "https://public-wax-on.wax.io/wam/sign" 244 | post_data = { 245 | "serializedTransaction": serialized_trx, 246 | "description": "jwt is insecure", 247 | "freeBandwidth": False, 248 | "website": "play.alienworlds.io", 249 | } 250 | headers = {"x-access-token": self.token} 251 | resp = self.http.post(url, json=post_data, headers=headers) 252 | if resp.status_code != 200: 253 | self.log.info("签名失败: {0}".format(resp.text)) 254 | if "Session Token is invalid" in resp.text: 255 | self.log.info("token失效,请重新获取") 256 | raise StopException("token失效") 257 | else: 258 | raise NodeException("wax server error: {0}".format 259 | (resp.text), resp) 260 | 261 | resp = resp.json() 262 | self.log.info("签名成功: {0}".format(resp["signatures"])) 263 | return resp["signatures"] 264 | 265 | 266 | def query_last_mine(self) -> Tuple[datetime, str]: 267 | self.log.info("正在查询上次采矿信息") 268 | resp = self.get_table_rows("miners") 269 | resp = resp["rows"][0] 270 | self.log.info("上次采矿信息: {0}".format(resp)) 271 | last_mine_time = datetime.fromisoformat(resp["last_mine"]) 272 | last_mine_time = last_mine_time.replace(tzinfo=timezone.utc) 273 | last_mine_time = last_mine_time.astimezone() 274 | last_mine_time = last_mine_time.replace(tzinfo=None) 275 | self.log.info("上次采矿时间: {0}".format(last_mine_time)) 276 | return last_mine_time, resp["last_mine_tx"] 277 | 278 | 279 | def check_cpu_net(self) -> bool: 280 | self.log.info("正在查询可用CPU/NET资源") 281 | url = self.rpc_host + "/v1/chain/get_account" 282 | if user_param.cpu_account: 283 | account_name = user_param.cpu_account 284 | else: 285 | account_name = self.wax_account 286 | post_data = {"account_name": account_name} 287 | resp = self.http.post(url, json = post_data) 288 | if resp.status_code != 200: 289 | raise NodeException("wax rpc error: {0}".format(resp.text), resp) 290 | resp = resp.json() 291 | cpu_available = resp["cpu_limit"]["available"] 292 | net_available = resp["net_limit"]["available"] 293 | self.log.info("CPU可用:{0}us NET可用:{1}bytes".format(cpu_available, net_available)) 294 | if cpu_available < 600 or net_available < 180: 295 | return False 296 | else: 297 | return True 298 | 299 | 300 | def run(self): 301 | try: 302 | self.mine() 303 | while True: 304 | if datetime.now() > self.next_mine_time: 305 | self.mine() 306 | time.sleep(1) 307 | except StopException as e: 308 | self.log.info("采矿停止") 309 | except Exception as e: 310 | self.log.exception("采矿异常: {0}".format(str(e))) 311 | -------------------------------------------------------------------------------- /doc/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encoderlee/OpenAlien/6d9279b9d4bf12352d250dc0018e2ced8d6ccf97/doc/demo1.png -------------------------------------------------------------------------------- /install_dependencies.bat: -------------------------------------------------------------------------------- 1 | python -m pip install -r requirements.txt 2 | @pause 3 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from bestlog import logger 2 | import ruamel.yaml 3 | yaml = ruamel.yaml.YAML() 4 | from ruamel.yaml.comments import CommentedMap 5 | from settings import user_param, load_param 6 | from alien import Alien, HttpProxy 7 | import traceback 8 | import sys 9 | 10 | def start(): 11 | user_yml = "user.yml" 12 | if len(sys.argv) == 2: 13 | user_yml = sys.argv[1] 14 | 15 | with open(user_yml, "r", encoding="utf8") as file: 16 | data: CommentedMap = yaml.load(file) 17 | file.close() 18 | load_param(data) 19 | 20 | logger.init(user_param.account, tag = True) 21 | log = logger.get(user_param.account) 22 | 23 | proxy = None 24 | if user_param.proxy: 25 | proxy = HttpProxy(user_param.proxy, user_param.proxy_username, user_param.proxy_password) 26 | 27 | log.info("正在加载配置文件: {0}".format(user_yml)) 28 | log.info("=============开始采矿=============") 29 | alien = Alien(user_param.account, user_param.token, user_param.charge_time, proxy) 30 | alien.run() 31 | log.info("=============采矿停止=============") 32 | 33 | 34 | 35 | def main(): 36 | print(">>>>>>>>>>>>> OpenAlien 开源版:v1.1.2 <<<<<<<<<<<<") 37 | print(">>>>>>>>>>>>> 交流QQ群:568229631 <<<<<<<<<<<<") 38 | print(">>>>>>>>>>>>> 项目地址:https://github.com/encoderlee/OpenAlien <<<<<<<<<<<<\n") 39 | try: 40 | start() 41 | except Exception as e: 42 | traceback.print_exc() 43 | input("按回车键退出") 44 | 45 | 46 | if __name__ == '__main__': 47 | main() 48 | 49 | -------------------------------------------------------------------------------- /nonce.py: -------------------------------------------------------------------------------- 1 | import random 2 | import hashlib 3 | from dataclasses import dataclass 4 | import time 5 | from binascii import hexlify 6 | 7 | @dataclass() 8 | class Nonce: 9 | random_string: str 10 | hex_digest: str 11 | 12 | 13 | def random_bytes(count: int): 14 | return bytes([random.getrandbits(8) for i in range(0, count)]) 15 | 16 | 17 | def str_to_hex(c): 18 | hex_data = hexlify(bytearray(c, 'ascii')).decode() 19 | return int(hex_data, 16) 20 | 21 | 22 | def char_subtraction(a, b, add): 23 | x = str_to_hex(a) 24 | y = str_to_hex(b) 25 | ans = str((x - y) + add) 26 | if len(ans) % 2 == 1: 27 | ans = '0' + ans 28 | return int(ans) 29 | 30 | def char_to_symbol(c): 31 | if 'a' <= c <= 'z': 32 | return char_subtraction(c, 'a', 6) 33 | if '1' <= c <= '5': 34 | return char_subtraction(c, '1', 1) 35 | return 0 36 | 37 | def string_to_name(s): 38 | i = 0 39 | name = 0 40 | while i < len(s): 41 | name += (char_to_symbol(s[i]) & 0x1F) << (64 - 5 * (i + 1)) 42 | i += 1 43 | if i > 12: 44 | name |= char_to_symbol(s[11]) & 0x0F 45 | return name 46 | 47 | 48 | def generate_nonce(account_name: str, last_mine_trx: str, difficulty=0) -> Nonce: 49 | account_arr = string_to_name(account_name).to_bytes(8, "little") 50 | last_mine_arr = bytes.fromhex(last_mine_trx)[:8] 51 | zeroes = 4 if account_name[-4:] == ".wam" else 6 52 | while True: 53 | random_arr = random_bytes(8) 54 | temp_arr = bytearray(account_arr + last_mine_arr + random_arr) 55 | hash256 = hashlib.sha256(temp_arr).hexdigest() 56 | if hash256[:zeroes] != "0" * zeroes: 57 | continue 58 | if int(hash256[zeroes: zeroes+1], 16) <= difficulty: 59 | break 60 | return Nonce(random_arr.hex(), hash256) 61 | 62 | 63 | def test(): 64 | account_name = "m45yy.wam" 65 | last_mine_trx = "41aaf836170e3a72994d658707162f825bf5e27ed786e4f76acaad844ce5da09" 66 | t1 = time.time() 67 | ret = generate_nonce(account_name, last_mine_trx) 68 | print(ret) 69 | print(time.time() - t1) 70 | 71 | 72 | if __name__ == '__main__': 73 | test() 74 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | cryptos 3 | tenacity 4 | dacite 5 | base58 6 | eosapi 7 | ruamel.yaml 8 | bestlog 9 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict, Optional 2 | from dataclasses import dataclass 3 | from dacite import from_dict, Config 4 | 5 | 6 | class interval: 7 | req: int = 2 8 | net_error: int = 5 9 | transact: int = 20 10 | cpu_insufficient: int = 60 11 | max_trx_error: int = 10 12 | 13 | @dataclass 14 | class UserParam: 15 | rpc_domain: str = "https://wax.pink.gg" 16 | cpu_account: Optional[str] = None 17 | cpu_key: Optional[str] = None 18 | delay1: int = 30 19 | delay2: int = 90 20 | claimmines: int = 10 21 | 22 | proxy: Optional[str] = None 23 | proxy_username: Optional[str] = None 24 | proxy_password: Optional[str] = None 25 | 26 | account: str = None 27 | token: str = None 28 | charge_time: int = None 29 | 30 | 31 | user_param: UserParam = UserParam() 32 | 33 | 34 | def load_param(data: Dict) -> UserParam: 35 | user = from_dict(UserParam, data, config = Config(type_hooks={str: str})) 36 | user_param.__dict__ = user.__dict__ 37 | -------------------------------------------------------------------------------- /user.bat: -------------------------------------------------------------------------------- 1 | python main.py user.yml 2 | -------------------------------------------------------------------------------- /user.yml: -------------------------------------------------------------------------------- 1 | #注意,每个参数名的冒号后面,都有一个空格,修改参数不要丢了空格 2 | 3 | # wax节点地址,使用公共节点,有时候会网络不通,或者访问太频繁被限制,出现429错误,可以换节点,或者搭建私有节点 4 | # 公共节点列表:https://wax.eosio.online/endpoints 5 | 6 | rpc_domain: https://wax.greymass.com 7 | 8 | # cpu代付号,cpu_key填写该代付号私钥,不需要代付则留空 9 | # 注意,由于外星世界官方于2022年10月更新了智能合约,阻止代付行为,所以代付功能失效 10 | cpu_account: 11 | cpu_key: 12 | 13 | # 即使可挖时间到了,也延迟20-60秒再挖 14 | delay1: 20 15 | delay2: 60 16 | 17 | # 挖多少次获取一次收益,0为不自动获取 18 | claimmines: 10 19 | 20 | # http代理(比如127.0.0.1:10808) 21 | # 给脚本设置HTTP代理,这样可以在一定程度上解决公共节点限制访问的问题,不需要则留空 22 | proxy: 23 | proxy_username: 24 | proxy_password: 25 | 26 | # 下面三项改为你的账号信息 27 | # account是wax云钱包账号名 28 | # token是什么,先在chrome浏览器中手工登录WAX云钱包 https://wallet.wax.io/dashboard 29 | # 然后在chrome浏览器中输入地址导航到: https://all-access.wax.io/api/session 30 | # 把token复制出来填到下面 31 | # charge_time是采矿间隔,单位秒,登录alienworlds官网,打开工具页面,就可以看到,按实际情况填写 32 | 33 | account: gts3c.c.wam 34 | token: 9Ejaq6Q06vaxxxxxxxxxxxxxxxxxxxxx 35 | charge_time: 480 36 | --------------------------------------------------------------------------------