├── .gitignore ├── README.md ├── __pycache__ └── main.cpython-311.pyc ├── abi.json ├── erc721.json ├── favicon.ico ├── go.py └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | checkin_account.txt 3 | test.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Skygate

2 | 3 |

注册推荐小号Skygate

4 |

5 | 6 |

7 | 8 | ## ⚡ 安装 9 | + 安装 [python](https://www.google.com/search?client=opera&q=how+install+python) 10 | + [下载项目](https://sites.northwestern.edu/researchcomputing/resources/downloading-from-github) 并解压 11 | + 安装依赖包: 12 | ```python 13 | pip install web3 14 | pip install pyuseragents 15 | ``` 16 | 17 | ## 💻 第一次跑 18 | ```python 19 | proxy = {} 20 | # 代理 21 | # proxy = { 22 | # 'http': '127.0.0.1:10809', 23 | # 'https': '127.0.0.1:10809', 24 | # } 25 | 26 | 27 | 28 | # 生成主钱包地址数 29 | main_account_num = 100 30 | # 每个主钱包邀请的小号数 31 | invite_num = 20 32 | for i in range(main_account_num): 33 | main_account_pk = Skygate.get_random_account_pk() 34 | main_sg = Skygate(pk=main_account_pk, proxy=proxy) 35 | try: 36 | main_sg.checkin() 37 | except Exception as e: 38 | print(str(e)) 39 | continue 40 | invite_code = str(main_sg.account.address) 41 | for z in range(invite_num): 42 | sub_account_pk = Skygate.get_random_account_pk() 43 | sub_sg = Skygate(pk=sub_account_pk, invite_code=invite_code, proxy=proxy) 44 | try: 45 | sub_sg.checkin() 46 | except Exception as e: 47 | print(str(e)) 48 | continue 49 | ``` 50 | 51 | ## ✔️ 日常签到 52 | ```python 53 | proxy = {} 54 | # 代理 55 | # proxy = { 56 | # 'http': '127.0.0.1:10809', 57 | # 'https': '127.0.0.1:10809', 58 | # } 59 | Skygate.daily_checkin(proxy) 60 | ``` 61 | 62 | ## ✔️ 日常探索,收集宝藏,探险 63 | ```python 64 | Skygate.daily_explore_treasure_adventure() 65 | ``` 66 | **第一次跑,会把主号和小号保存在当前文件夹下的 ```checkin_account.txt``` 文件内** 67 | 68 | **日常签到,自动把 ```checkin_account.txt``` 文件内的账号跑一遍签到,无需gas** 69 | 70 | **日常```探索(每日1次),收集宝藏(每日6次),探险(每日6次)```,自动把 ```checkin_account.txt``` 文件内的账号跑一遍, 三种任务需要钱包有在opbnb链有bnb作为gas,其中```收集宝藏,探险```需要账户有史莱姆nft,自动检测是否满足条件,不符合条件的会跳过** 71 | 72 | + [史莱姆nft购买](https://element.market/collections/skygate) 73 | 74 | 75 | ## 其他 76 | **接口经常502,可能是刷的人太多了** 77 | 78 | **已经优化加入自动重试机制** 79 | 80 | ## 操作页面 81 | 82 | + 会python的直接看main.py即可 83 | 84 | + 不会的看下面 85 | 86 | ```python 87 | pip install pypubsub 88 | pip install wxpython 89 | 执行 python go.py 90 | ``` 91 | image 92 | 93 | + 输入框填入自己的大号以太坊地址,前20个小号会用大号的邀请码作为邀请人注册 94 | 95 | + 每日手动点击,安逸~~~ 96 | 97 | ## 📧 Contacts 98 | + 推特 - [@shawngmy](https://twitter.com/shawngmy) 99 | + tks for following,if u want get more info 100 | -------------------------------------------------------------------------------- /__pycache__/main.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satisfywithmylife/skygate/bd37df25a98ea4088fbff2663755bf3f73cee0a9/__pycache__/main.cpython-311.pyc -------------------------------------------------------------------------------- /abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type":"constructor", 4 | "inputs":[ 5 | { 6 | "name":"_nftAddr", 7 | "type":"address", 8 | "internalType":"address" 9 | } 10 | ], 11 | "stateMutability":"nonpayable" 12 | }, 13 | { 14 | "name":"OwnershipTransferred", 15 | "type":"event", 16 | "inputs":[ 17 | { 18 | "name":"previousOwner", 19 | "type":"address", 20 | "indexed":true, 21 | "internalType":"address" 22 | }, 23 | { 24 | "name":"newOwner", 25 | "type":"address", 26 | "indexed":true, 27 | "internalType":"address" 28 | } 29 | ], 30 | "anonymous":false, 31 | "signature":"0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0" 32 | }, 33 | { 34 | "name":"Signin", 35 | "type":"event", 36 | "inputs":[ 37 | { 38 | "name":"_type", 39 | "type":"uint256", 40 | "indexed":true, 41 | "internalType":"uint256" 42 | }, 43 | { 44 | "name":"_from", 45 | "type":"address", 46 | "indexed":true, 47 | "internalType":"address" 48 | }, 49 | { 50 | "name":"_timestamp", 51 | "type":"uint256", 52 | "indexed":false, 53 | "internalType":"uint256" 54 | } 55 | ], 56 | "anonymous":false, 57 | "signature":"0xa39e61b7c88ca891c872fbc7e541f7e480a8f8f2d0895a858c9c31eff654ecd5" 58 | }, 59 | { 60 | "name":"isHoldNft", 61 | "type":"function", 62 | "inputs":[ 63 | 64 | ], 65 | "outputs":[ 66 | { 67 | "name":"", 68 | "type":"bool", 69 | "value":false, 70 | "internalType":"bool" 71 | } 72 | ], 73 | "constant":true, 74 | "signature":"0x40f39c9e", 75 | "stateMutability":"view" 76 | }, 77 | { 78 | "name":"nftAddr", 79 | "type":"function", 80 | "inputs":[ 81 | 82 | ], 83 | "outputs":[ 84 | { 85 | "name":"", 86 | "type":"address", 87 | "value":"0x961A98999F14e8C5e69bDD4eE0826d6e0C556A0D", 88 | "internalType":"address" 89 | } 90 | ], 91 | "constant":true, 92 | "signature":"0x740f1e18", 93 | "stateMutability":"view" 94 | }, 95 | { 96 | "name":"owner", 97 | "type":"function", 98 | "inputs":[ 99 | 100 | ], 101 | "outputs":[ 102 | { 103 | "name":"", 104 | "type":"address", 105 | "value":"0xf49c3Af1f2d751Ed016735AD5459EDC4fF1c75EC", 106 | "internalType":"address" 107 | } 108 | ], 109 | "constant":true, 110 | "signature":"0x8da5cb5b", 111 | "stateMutability":"view" 112 | }, 113 | { 114 | "name":"renounceOwnership", 115 | "type":"function", 116 | "inputs":[ 117 | 118 | ], 119 | "outputs":[ 120 | 121 | ], 122 | "signature":"0x715018a6", 123 | "stateMutability":"nonpayable" 124 | }, 125 | { 126 | "name":"signin", 127 | "type":"function", 128 | "inputs":[ 129 | { 130 | "name":"_type", 131 | "type":"uint256", 132 | "internalType":"uint256" 133 | } 134 | ], 135 | "outputs":[ 136 | 137 | ], 138 | "signature":"0x9b7d30dd", 139 | "stateMutability":"nonpayable" 140 | }, 141 | { 142 | "name":"transferOwnership", 143 | "type":"function", 144 | "inputs":[ 145 | { 146 | "name":"newOwner", 147 | "type":"address", 148 | "internalType":"address" 149 | } 150 | ], 151 | "outputs":[ 152 | 153 | ], 154 | "signature":"0xf2fde38b", 155 | "stateMutability":"nonpayable" 156 | }, 157 | { 158 | "name":"updateIsHoldNft", 159 | "type":"function", 160 | "inputs":[ 161 | { 162 | "name":"_isHoldNft", 163 | "type":"bool", 164 | "internalType":"bool" 165 | } 166 | ], 167 | "outputs":[ 168 | 169 | ], 170 | "signature":"0xdaff5cc4", 171 | "stateMutability":"nonpayable" 172 | }, 173 | { 174 | "name":"updateNFTAddr", 175 | "type":"function", 176 | "inputs":[ 177 | { 178 | "name":"_addr", 179 | "type":"address", 180 | "internalType":"address" 181 | } 182 | ], 183 | "outputs":[ 184 | 185 | ], 186 | "signature":"0x84235611", 187 | "stateMutability":"nonpayable" 188 | }, 189 | { 190 | "name":"withdrawToken", 191 | "type":"function", 192 | "inputs":[ 193 | { 194 | "name":"token", 195 | "type":"address", 196 | "internalType":"address" 197 | }, 198 | { 199 | "name":"to", 200 | "type":"address", 201 | "internalType":"address" 202 | }, 203 | { 204 | "name":"amount", 205 | "type":"uint256", 206 | "internalType":"uint256" 207 | } 208 | ], 209 | "outputs":[ 210 | 211 | ], 212 | "signature":"0x01e33667", 213 | "stateMutability":"nonpayable" 214 | } 215 | ] -------------------------------------------------------------------------------- /erc721.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "owner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "approved", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": true, 19 | "internalType": "uint256", 20 | "name": "tokenId", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "Approval", 25 | "type": "event" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "address", 33 | "name": "owner", 34 | "type": "address" 35 | }, 36 | { 37 | "indexed": true, 38 | "internalType": "address", 39 | "name": "operator", 40 | "type": "address" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "bool", 45 | "name": "approved", 46 | "type": "bool" 47 | } 48 | ], 49 | "name": "ApprovalForAll", 50 | "type": "event" 51 | }, 52 | { 53 | "anonymous": false, 54 | "inputs": [ 55 | { 56 | "indexed": true, 57 | "internalType": "address", 58 | "name": "from", 59 | "type": "address" 60 | }, 61 | { 62 | "indexed": true, 63 | "internalType": "address", 64 | "name": "to", 65 | "type": "address" 66 | }, 67 | { 68 | "indexed": true, 69 | "internalType": "uint256", 70 | "name": "tokenId", 71 | "type": "uint256" 72 | } 73 | ], 74 | "name": "Transfer", 75 | "type": "event" 76 | }, 77 | { 78 | "inputs": [ 79 | { 80 | "internalType": "address", 81 | "name": "to", 82 | "type": "address" 83 | }, 84 | { 85 | "internalType": "uint256", 86 | "name": "tokenId", 87 | "type": "uint256" 88 | } 89 | ], 90 | "name": "approve", 91 | "outputs": [], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "constant": true, 97 | "inputs": [], 98 | "name": "totalSupply", 99 | "outputs": [ 100 | { 101 | "name": "", 102 | "type": "uint256" 103 | } 104 | ], 105 | "payable": false, 106 | "stateMutability": "view", 107 | "type": "function" 108 | }, 109 | { 110 | "inputs": [ 111 | { 112 | "internalType": "address", 113 | "name": "owner", 114 | "type": "address" 115 | } 116 | ], 117 | "name": "balanceOf", 118 | "outputs": [ 119 | { 120 | "internalType": "uint256", 121 | "name": "balance", 122 | "type": "uint256" 123 | } 124 | ], 125 | "stateMutability": "view", 126 | "type": "function" 127 | }, 128 | { 129 | "inputs": [ 130 | { 131 | "internalType": "uint256", 132 | "name": "tokenId", 133 | "type": "uint256" 134 | } 135 | ], 136 | "name": "getApproved", 137 | "outputs": [ 138 | { 139 | "internalType": "address", 140 | "name": "operator", 141 | "type": "address" 142 | } 143 | ], 144 | "stateMutability": "view", 145 | "type": "function" 146 | }, 147 | { 148 | "inputs": [ 149 | { 150 | "internalType": "address", 151 | "name": "owner", 152 | "type": "address" 153 | }, 154 | { 155 | "internalType": "address", 156 | "name": "operator", 157 | "type": "address" 158 | } 159 | ], 160 | "name": "isApprovedForAll", 161 | "outputs": [ 162 | { 163 | "internalType": "bool", 164 | "name": "", 165 | "type": "bool" 166 | } 167 | ], 168 | "stateMutability": "view", 169 | "type": "function" 170 | }, 171 | { 172 | "inputs": [], 173 | "name": "name", 174 | "outputs": [ 175 | { 176 | "internalType": "string", 177 | "name": "", 178 | "type": "string" 179 | } 180 | ], 181 | "stateMutability": "view", 182 | "type": "function" 183 | }, 184 | { 185 | "inputs": [ 186 | { 187 | "internalType": "uint256", 188 | "name": "tokenId", 189 | "type": "uint256" 190 | } 191 | ], 192 | "name": "ownerOf", 193 | "outputs": [ 194 | { 195 | "internalType": "address", 196 | "name": "owner", 197 | "type": "address" 198 | } 199 | ], 200 | "stateMutability": "view", 201 | "type": "function" 202 | }, 203 | { 204 | "inputs": [ 205 | { 206 | "internalType": "address", 207 | "name": "from", 208 | "type": "address" 209 | }, 210 | { 211 | "internalType": "address", 212 | "name": "to", 213 | "type": "address" 214 | }, 215 | { 216 | "internalType": "uint256", 217 | "name": "tokenId", 218 | "type": "uint256" 219 | } 220 | ], 221 | "name": "safeTransferFrom", 222 | "outputs": [], 223 | "stateMutability": "nonpayable", 224 | "type": "function" 225 | }, 226 | { 227 | "inputs": [ 228 | { 229 | "internalType": "address", 230 | "name": "from", 231 | "type": "address" 232 | }, 233 | { 234 | "internalType": "address", 235 | "name": "to", 236 | "type": "address" 237 | }, 238 | { 239 | "internalType": "uint256", 240 | "name": "tokenId", 241 | "type": "uint256" 242 | }, 243 | { 244 | "internalType": "bytes", 245 | "name": "data", 246 | "type": "bytes" 247 | } 248 | ], 249 | "name": "safeTransferFrom", 250 | "outputs": [], 251 | "stateMutability": "nonpayable", 252 | "type": "function" 253 | }, 254 | { 255 | "inputs": [ 256 | { 257 | "internalType": "address", 258 | "name": "operator", 259 | "type": "address" 260 | }, 261 | { 262 | "internalType": "bool", 263 | "name": "_approved", 264 | "type": "bool" 265 | } 266 | ], 267 | "name": "setApprovalForAll", 268 | "outputs": [], 269 | "stateMutability": "nonpayable", 270 | "type": "function" 271 | }, 272 | { 273 | "inputs": [ 274 | { 275 | "internalType": "bytes4", 276 | "name": "interfaceId", 277 | "type": "bytes4" 278 | } 279 | ], 280 | "name": "supportsInterface", 281 | "outputs": [ 282 | { 283 | "internalType": "bool", 284 | "name": "", 285 | "type": "bool" 286 | } 287 | ], 288 | "stateMutability": "view", 289 | "type": "function" 290 | }, 291 | { 292 | "inputs": [], 293 | "name": "symbol", 294 | "outputs": [ 295 | { 296 | "internalType": "string", 297 | "name": "", 298 | "type": "string" 299 | } 300 | ], 301 | "stateMutability": "view", 302 | "type": "function" 303 | }, 304 | { 305 | "inputs": [ 306 | { 307 | "internalType": "uint256", 308 | "name": "tokenId", 309 | "type": "uint256" 310 | } 311 | ], 312 | "name": "tokenURI", 313 | "outputs": [ 314 | { 315 | "internalType": "string", 316 | "name": "", 317 | "type": "string" 318 | } 319 | ], 320 | "stateMutability": "view", 321 | "type": "function" 322 | }, 323 | { 324 | "inputs": [ 325 | { 326 | "internalType": "address", 327 | "name": "from", 328 | "type": "address" 329 | }, 330 | { 331 | "internalType": "address", 332 | "name": "to", 333 | "type": "address" 334 | }, 335 | { 336 | "internalType": "uint256", 337 | "name": "tokenId", 338 | "type": "uint256" 339 | } 340 | ], 341 | "name": "transferFrom", 342 | "outputs": [], 343 | "stateMutability": "nonpayable", 344 | "type": "function" 345 | } 346 | ] -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satisfywithmylife/skygate/bd37df25a98ea4088fbff2663755bf3f73cee0a9/favicon.ico -------------------------------------------------------------------------------- /go.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | #from dotenv import load_dotenv 3 | import sys,os 4 | sys.path.append(os.path.join(sys.path[0], '../')) 5 | 6 | from wx import grid 7 | import wx 8 | from pubsub import pub 9 | import threading 10 | import time 11 | import requests 12 | from eth_account import Account 13 | from eth_account.messages import encode_defunct 14 | from web3 import Web3, HTTPProvider 15 | from pyuseragents import random as random_ua 16 | from functools import wraps 17 | import json 18 | 19 | def retry(max_retries=3, wait_time=1): 20 | def decorator(func): 21 | @wraps(func) 22 | def wrapper(*args, **kwargs): 23 | retries = 0 24 | while retries < max_retries: 25 | try: 26 | return func(*args, **kwargs) 27 | except Exception as e: 28 | e_msg = f"错误 {e}, {wait_time} 秒后重试" 29 | pub.sendMessage("update_log", msg=e_msg) 30 | print(f"{e_msg}") 31 | retries += 1 32 | time.sleep(wait_time) 33 | raise Exception(f"到达最大重试次数 ({max_retries}),跳过") 34 | 35 | return wrapper 36 | return decorator 37 | 38 | class Skygate(): 39 | 40 | log_file_name = 'checkin_account.txt' 41 | 42 | def __init__(self, pk, invite_code='', jwt='', is_daily=False, proxy={}): 43 | self.web3 = Web3(HTTPProvider('https://opbnb.publicnode.com')) 44 | self.host = 'https://apisky.ntoken.bwtechnology.net/api/{}' 45 | self.invite_code = invite_code # 邀请码(邀请人钱包地址) 46 | self.pk = pk # 签到账号私钥 47 | self.account:Account = self.web3.eth.account.from_key(pk) 48 | self.sign_str = 'skygate' # personal_sign 签名字符串 49 | self.jwt = jwt # jwt 50 | self.is_daily = is_daily 51 | self.proxy = proxy 52 | self.block_scan_tx_url = 'https://opbnbscan.com/tx/{}' # 区块浏览器 53 | 54 | 55 | def check_balance(self): 56 | opbnb_balance = self.web3.eth.get_balance(self.account.address) 57 | return opbnb_balance 58 | 59 | def check_has_slime_nft(self): 60 | nft_contract_address = Web3.to_checksum_address('0x961a98999f14e8c5e69bdd4ee0826d6e0c556a0d') 61 | nft_contract = self.web3.eth.contract(address=nft_contract_address, abi=self.load_abi('erc721.json')) 62 | return nft_contract.functions.balanceOf(owner=self.account.address).call() 63 | 64 | def dispatch_squead(self, data): 65 | address = Web3.to_checksum_address('0x9465fe0e8cdf4e425e0c59b7caeccc1777dc6695') 66 | tx = self.web3.eth.contract(address=address, abi=self.load_abi('abi.json')).functions.signin(data) 67 | tx_hash = self.make_tx(tx) 68 | return tx_hash 69 | 70 | def adventure(self): 71 | data = 2 72 | tx_hash = self.dispatch_squead(data) 73 | self.pop_log(f'{self.account.address} 冒险成功 ! | Tx: {self.block_scan_tx_url.format(tx_hash)}') 74 | 75 | def treasure(self): 76 | data = 1 77 | tx_hash = self.dispatch_squead(data) 78 | self.pop_log(f'{self.account.address} 寻宝成功 ! | Tx: {self.block_scan_tx_url.format(tx_hash)}') 79 | 80 | def explore(self): 81 | address = Web3.to_checksum_address('0xd42126d46813472f83104811533c03c807e65435') 82 | tx = self.web3.eth.contract(address=address, abi=self.load_abi('abi.json')).functions.signin(1) 83 | tx_hash = self.make_tx(tx) 84 | self.pop_log(f'{self.account.address} 探索成功 ! | Tx: {self.block_scan_tx_url.format(tx_hash)}') 85 | 86 | def make_tx(self, tx): 87 | tx = tx.build_transaction({ 88 | 'value': 0, 89 | 'nonce': self.web3.eth.get_transaction_count(self.account.address), 90 | 'from': self.account.address, 91 | 'gas': 0, 92 | 'maxFeePerGas': 0, 93 | 'maxPriorityFeePerGas': 0 94 | }) 95 | tx.update({'maxFeePerGas': self.web3.eth.gas_price}) 96 | tx.update({'maxPriorityFeePerGas': self.web3.eth.gas_price}) 97 | tx.update({'gas': self.web3.eth.estimate_gas(tx)}) 98 | signed_tx = self.account.sign_transaction(tx) 99 | tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction) 100 | tx_receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash) 101 | while tx_receipt is None or tx_receipt['status'] is None: 102 | time.sleep(1) 103 | tx_receipt = self.web3.eth.get_transaction_receipt(tx_hash) 104 | 105 | tx_hash = Web3.to_hex(tx_hash) 106 | return tx_hash 107 | 108 | 109 | def load_abi(self, abi_name): 110 | with open(abi_name, 'r') as f: 111 | json_data = json.load(f) 112 | return json_data 113 | 114 | @retry(max_retries=30, wait_time=5) 115 | def get_info(self): 116 | # 根据jwt获取账号信息 117 | url = self.host.format('get_skyGate_coin.php') 118 | payload = { 119 | 'api_id': 'skyark_react_api', 120 | 'api_token': '3C2D36F79AFB3D5374A49BE767A17C6A3AEF91635BF7A3FB25CEA8D4DD', 121 | 'jwt': self.login() 122 | } 123 | res = requests.post(url=url, data=payload, timeout=30, proxies=self.proxy, headers=self.get_headers()) 124 | if res.status_code != 200: 125 | raise Exception(f'get_info error, status code {res.status_code}') 126 | 127 | res = res.json() 128 | 129 | if res['err'] != 0: 130 | raise Exception(f'get_info error, error code {res["err"]}, error message {res["0"]}') 131 | 132 | # {"err":0,"uName":"0x1ad453068d1808e213b46ce415a51d38b8419e57","gateWalletAddr":"9aPW9RhQ9c9eWBK","uWalletAddr":"0x1ad453068d1808e213b46ce415a51d38b8419e57","coin":"100","participationTime":"","week":"","scheduleStart":1700179200,"scheduleEnd":1734393599,"joinAmount":"100","additionalCost":"0","winAnnDate":1702857600,"advName":"31thadvanture","inviteCode":"9aPW9","uId":"21244085","userLevel":"1"} 133 | return res 134 | 135 | def get_headers(self): 136 | headers = { 137 | 'Accept': 'application/json, text/plain, */*', 138 | 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', 139 | 'Origin': 'https://skygate.skyarkchronicles.com', 140 | 'Referer': 'https://skygate.skyarkchronicles.com/', 141 | 'User-Agent': random_ua(), 142 | 'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 143 | 'Sec-Ch-Ua-Mobile': '?0', 144 | 'Sec-Ch-Ua-Platform': '"Windows"', 145 | 'Sec-Fetch-Dest': 'empty', 146 | 'Sec-Fetch-Mode': 'cors', 147 | 'Sec-Fetch-Site': 'cross-site', 148 | } 149 | 150 | return headers 151 | 152 | @retry(max_retries=30, wait_time=3) 153 | def login(self): 154 | # 获取登录态jwt 155 | if self.jwt: 156 | return self.jwt 157 | 158 | msghash = encode_defunct(text=self.sign_str) 159 | sign = Account.sign_message(msghash, self.pk) 160 | 161 | url = self.host.format('wallet_signin.php') 162 | payload = { 163 | 'api_id': 'skyark_react_api', 164 | 'api_token': '3C2D36F79AFB3D5374A49BE767A17C6A3AEF91635BF7A3FB25CEA8D4DD', 165 | 'uWalletAddr': str(self.account.address), 166 | 'sign': str(sign.signature.hex()) 167 | } 168 | if self.invite_code: 169 | payload['inviter'] = self.invite_code 170 | 171 | res = requests.post(url=url, data=payload, timeout=30, proxies=self.proxy, headers=self.get_headers()) 172 | if res.status_code != 200: 173 | raise Exception(f'登录错误, 错误状态码 {res.status_code}') 174 | 175 | res = res.json() 176 | if res['err'] != 0: 177 | raise Exception(f'登录错误, 错误状态码 {res["err"]}, 错误信息 {res["0"]}') 178 | 179 | self.jwt = res['jwt'] 180 | if not self.is_daily: 181 | self.save() 182 | #{"err":0,"msg":"verify_success","jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1SWQiOiIyMTI0NDA4NSIsInVXYWxsZXRBZGRyIjoiMHgxYWQ0NTMwNjhkMTgwOGUyMTNiNDZjZTQxNWE1MWQzOGI4NDE5ZTU3In0.shwMdrnWwqQJy3taJxhT2_mIsPsCF3e8CsWsmm_oTG4xhZsh_WOEqQlWC7AULffc1hj3xrx6btwEcXBO_MXu8yPqkDF6LN1rPtVNLEK3ISOCpbzfHMcMOpodZgmsPsd3YkDkqAnklQIO6rW3wAKhWgbZO1HHW5fhQM8sN-7cWXo","uWalletAddr":"0x1ad453068d1808e213b46ce415a51d38b8419e57"} 183 | return self.jwt 184 | 185 | @retry(max_retries=30, wait_time=3) 186 | def checkin(self): 187 | # 签到 188 | url = self.host.format('checkIn_skyGate_member.php') 189 | payload = { 190 | 'api_id': 'skyark_react_api', 191 | 'api_token': '3C2D36F79AFB3D5374A49BE767A17C6A3AEF91635BF7A3FB25CEA8D4DD', 192 | 'jwt': self.login() 193 | } 194 | 195 | res = requests.post(url=url, data=payload, timeout=30, proxies=self.proxy, headers=self.get_headers()) 196 | if res.status_code != 200: 197 | raise Exception(f'{self.account.address} 签到错误, 错误状态码: {res.status_code}') 198 | 199 | res = res.json() 200 | if res['err'] != 0: 201 | if res["0"] == "already rewarded the daily points": 202 | self.pop_log(f'{self.account.address} 当日已签到,跳过') 203 | return True 204 | raise Exception(f'{self.account.address} 签到错误, 错误状态码 {res["err"]}, 错误原因 {res["0"]}') 205 | self.pop_log(f'{self.account.address} 当日签到成功') 206 | # {"err":1,"0":"already rewarded the daily points"} 207 | # {"err":0,"dailyGift":50,"SlimeGift":0,"fullCost":150,"dailyclaimInWeek":[{"Time":1704267789,"Amount":"50"},{"Time":1704422086,"Amount":"50"}],"indicator":1} 208 | 209 | return res 210 | 211 | 212 | def save(self): 213 | # 保存账号到当前文件夹的checkin_account.txt文件, 格式: 地址----私钥----jwt----邀请人地址(邀请码) 214 | log_str = f'{self.account.address}----{self.pk}----{self.jwt}----{self.invite_code}\n' 215 | self.pop_log(f'{self.account.address} 注册账号成功,保存在 {self.log_file_name} 中') 216 | with open(self.log_file_name, 'a') as f: 217 | f.write(log_str) 218 | 219 | @staticmethod 220 | def iter_file(file_name): 221 | # 迭代文件 222 | with open(file_name, encoding='utf-8') as f: 223 | for line in f: 224 | the_line = line.strip() 225 | yield the_line 226 | 227 | def pop_log(self, log_str): 228 | pub.sendMessage(topicName=f'update_log', msg=log_str) 229 | 230 | @staticmethod 231 | def daily_checkin(proxy): 232 | for log_str in Skygate.iter_file(Skygate.log_file_name): 233 | tmp = log_str.split('----') 234 | _, pk, jwt, invite_code = tmp[0], tmp[1], tmp[2], tmp[3] 235 | sg = Skygate(pk=pk, jwt=jwt, invite_code=invite_code, is_daily=True, proxy=proxy) 236 | try: 237 | sg.checkin() 238 | except Exception as e: 239 | sg.pop_log(f'{sg.account.address} 签到错误,跳过, 错误信息:{e}') 240 | time.sleep(3) 241 | continue 242 | 243 | @staticmethod 244 | def daily_explore_treasure_adventure(): 245 | # 每日冒险和收集宝藏可以获得积分的次数,各6次 246 | daily_treasure_adventure_times = 6 247 | for log_str in Skygate.iter_file(Skygate.log_file_name): 248 | tmp = log_str.split('----') 249 | _, pk, jwt, invite_code = tmp[0], tmp[1], tmp[2], tmp[3] 250 | sg = Skygate(pk=pk, jwt=jwt, invite_code=invite_code, is_daily=True, proxy={}) 251 | if not sg.check_balance(): 252 | sg.pop_log(f'{sg.account.address} 在opbnb链没有bnb余额作为gas, 跳过gas任务') 253 | continue 254 | 255 | sg.pop_log(f'========================={sg.account.address} 日常gas任务开始============================') 256 | # 每日探索1次,10积分 257 | sg.explore() 258 | # 检查账户是否有史莱姆nft 259 | slime_nft_num = sg.check_has_slime_nft() 260 | if not slime_nft_num: 261 | sg.pop_log(f'{sg.account.address} 没有史莱姆nft,跳过探险和寻宝') 262 | sg.pop_log(f'========================={sg.account.address} 日常探险寻宝结束============================') 263 | continue 264 | else: 265 | sg.pop_log(f'{sg.account.address} 有 {slime_nft_num} 史莱姆 nft, 开始日常探险寻宝') 266 | 267 | 268 | # 每日探险6次,每次获得积分随机 269 | for i in range(daily_treasure_adventure_times): 270 | sg.pop_log(f'{sg.account.address}第 {str(i+1)} 次探险开始') 271 | try: 272 | sg.adventure() 273 | except Exception as e: 274 | sg.pop_log(f'{sg.account.address} 探险错误 , 原因 {e}, 跳过探险') 275 | break 276 | 277 | # 每日收集宝藏6次,每次获得积分随机 278 | for i in range(daily_treasure_adventure_times): 279 | sg.pop_log(f'{sg.account.address}第 {str(i+1)} 次寻宝开始') 280 | try: 281 | sg.treasure() 282 | except Exception as e: 283 | sg.pop_log(f'{sg.account.address} 寻宝错误, 原因 {e}, 跳过寻宝') 284 | break 285 | sg.pop_log(f'========================={sg.account.address} 日常探险寻宝结束============================') 286 | 287 | 288 | 289 | @staticmethod 290 | def get_random_account_pk(): 291 | # 随机生成以太坊地址私钥 292 | return Account.create().key.hex() 293 | 294 | 295 | 296 | class MyFileDropTarget(wx.FileDropTarget): 297 | def __init__(self, handle): 298 | super().__init__() 299 | self.handle: BaseBatchWx = handle 300 | 301 | def OnDropFiles(self, x, y, filenames): 302 | self.handle.file_drop_handle(filenames) 303 | 304 | 305 | 306 | 307 | class BaseBatchWx(): 308 | 309 | def __init__(self): 310 | self.loads_tks = [] 311 | self.scale = 1 # 比例尺,改变这个,就能等比放大/缩小gui的尺寸 312 | self.border = 7 * self.scale 313 | self.height = 0 314 | 315 | icon = 'favicon.ico' 316 | self.icon_type = wx.BITMAP_TYPE_ICO 317 | self.icon = f'{icon}' 318 | self.wx_config = { 319 | 'title': '交互脚本-skyark', 320 | 'size': (600*self.scale, 200*self.scale) # 第一个是控件宽度,第二个是日志控件的高度 321 | } 322 | self.app: wx.App = wx.App() 323 | self.wx: wx = wx 324 | 325 | self.frame = self.wx.Frame(None, title=self.wx_config['title'], style=self.wx.DEFAULT_FRAME_STYLE) 326 | self.frame.Centre() 327 | 328 | icon = self.wx.Icon(self.icon, self.icon_type) 329 | self.frame.SetIcon(icon) 330 | self.panel = self.wx.Panel(self.frame) 331 | # 动态高度控件 332 | self.sizer = self.wx.GridBagSizer(10, 10) 333 | # 日志控件 334 | self.log_box = self.wx.TextCtrl(self.panel, size=(-1, self.wx_config['size'][1]), value='', style=self.wx.TE_MULTILINE|self.wx.HSCROLL) 335 | self.sizer.Add(self.log_box, pos=(self.height, 0), span=(0, 11), flag=self.wx.EXPAND | self.wx.ALL, border=7*self.scale) 336 | self.height += 1 337 | self.frame.SetDropTarget(MyFileDropTarget(self)) 338 | self.log_box.SetDropTarget(MyFileDropTarget(self)) 339 | 340 | # 初始化日志 341 | self.topic_name = 'update_log' 342 | pub.subscribe(self.log_add, self.topic_name) 343 | for msg in self.init_log(): 344 | pub.sendMessage(self.topic_name, msg=msg) 345 | #pub.sendMessage(self.topic_name, msg=f'----------------------------------------------------------') 346 | 347 | 348 | def get_now_time(self, format='%Y-%m-%d %H:%M:%S'): 349 | return time.strftime(format, time.localtime(time.time())) 350 | 351 | 352 | def init_log(self)->list: 353 | return [ 354 | #'撸毛工具 合作v:a17682157736, 推:@shawngmy', 355 | '撸毛工具嘀嘀嘀', 356 | ] 357 | 358 | def file_drop_handle(self, filenames): 359 | for file in filenames: 360 | self.log_add(f'读取文件:{file}') 361 | return True 362 | 363 | # 具体的组件 364 | def init(self): 365 | self.labelName = self.wx.StaticText(self.panel, label="大号邀请码(evm钱包地址)") # Name 366 | self.sizer.Add(self.labelName, pos=(self.height, 0), flag=self.wx.LEFT, border=self.border) 367 | 368 | self.tcName = self.wx.TextCtrl(self.panel) 369 | self.sizer.Add(self.tcName, pos=(self.height, 1), span=(1, 9), flag=self.wx.EXPAND | self.wx.LEFT, border=self.border) 370 | self.height += 1 371 | 372 | 373 | def task1(self, *args): 374 | value = self.tcName.GetValue() 375 | self.wx.CallAfter(pub.sendMessage, self.topic_name, msg=f'大号邀请码:{value}') 376 | proxy = {} 377 | main_account_num = 100 378 | # 每个主钱包邀请的小号数 379 | invite_num = 20 380 | 381 | for i in range(main_account_num): 382 | main_account_pk = Skygate.get_random_account_pk() 383 | main_sg = Skygate(pk=main_account_pk, proxy=proxy) 384 | try: 385 | main_sg.checkin() 386 | except Exception as e: 387 | self.wx.CallAfter(pub.sendMessage, self.topic_name, msg=f'{e}') 388 | continue 389 | invite_code = value if value else str(main_sg.account.address) 390 | for z in range(invite_num): 391 | sub_account_pk = Skygate.get_random_account_pk() 392 | sub_sg = Skygate(pk=sub_account_pk, invite_code=invite_code, proxy=proxy) 393 | try: 394 | sub_sg.checkin() 395 | except Exception as e: 396 | self.wx.CallAfter(pub.sendMessage, self.topic_name, msg=f'{e}') 397 | continue 398 | value = '' 399 | 400 | def task2(self, *args): 401 | Skygate.daily_checkin({}) 402 | 403 | def task3(self, *args): 404 | Skygate.daily_explore_treasure_adventure() 405 | 406 | def get_args(self): 407 | return () 408 | 409 | def start_button_click(self, event): 410 | self.wx.CallAfter(pub.sendMessage, self.topic_name, msg='第一次跑') 411 | threading.Thread(target=self.task1, args=self.get_args(), daemon=False).start() 412 | 413 | def stop_button_click(self, event): 414 | self.wx.CallAfter(pub.sendMessage, self.topic_name, msg='每日签到') 415 | threading.Thread(target=self.task2, args=self.get_args(), daemon=False).start() 416 | 417 | def gas_button_click(self, event): 418 | self.wx.CallAfter(pub.sendMessage, self.topic_name, msg='gas任务') 419 | threading.Thread(target=self.task3, args=self.get_args(), daemon=False).start() 420 | 421 | def help_button_click(self, event): 422 | dg = self.wx.MessageDialog(self.frame, "这是一个嘀嘀嘀", "提示", self.wx.OK) 423 | dg.ShowModal() 424 | 425 | def log_add(self, msg): 426 | self.log_box.AppendText(f'[{self.get_now_time(format="%H:%M:%S")}]{msg}\n') 427 | 428 | 429 | def run(self): 430 | 431 | # labelName = self.wx.StaticText(self.panel, label="名称") # Name 432 | # self.sizer.Add(labelName, pos=(self.height, 0), flag=self.wx.LEFT, border=7*self.scale) 433 | # 434 | # tcName = self.wx.TextCtrl(self.panel) 435 | # self.sizer.Add(tcName, pos=(self.height, 1), span=(1, 9), flag=self.wx.EXPAND | self.wx.LEFT, border=2*self.scale) 436 | # self.height += 1 437 | 438 | # line = self.wx.StaticLine(self.panel) 439 | # self.sizer.Add(line, pos=(self.height, 0), span=(1, 9), flag=self.wx.EXPAND | self.wx.BOTTOM, 440 | # border=7 * self.scale) 441 | # self.height += 1 442 | 443 | #================ 下面是通用按钮的处理 ================# 444 | # 帮助按钮 445 | self.help_button = self.wx.Button(self.panel, label='帮助', name='button') 446 | self.help_button.Bind(self.wx.EVT_BUTTON, self.help_button_click) 447 | self.sizer.Add(self.help_button, pos=(self.height, 0), flag=self.wx.LEFT, border=self.border) 448 | # 开始按钮 449 | self.start_button = self.wx.Button(self.panel, label='第一次跑', name='button') 450 | self.start_button.Bind(self.wx.EVT_BUTTON, self.start_button_click) 451 | self.sizer.Add(self.start_button, pos=(self.height, 7), flag=self.wx.LEFT, border=self.border) 452 | # 停止按钮 453 | self.stop_button = self.wx.Button(self.panel, label='每日签到', name='button') 454 | self.stop_button.Bind(self.wx.EVT_BUTTON, self.stop_button_click) 455 | self.sizer.Add(self.stop_button, pos=(self.height, 8), flag=self.wx.LEFT, border=self.border) 456 | 457 | # 停止按钮 458 | self.stop_button = self.wx.Button(self.panel, label='gas任务', name='button') 459 | self.stop_button.Bind(self.wx.EVT_BUTTON, self.gas_button_click) 460 | self.sizer.Add(self.stop_button, pos=(self.height, 9), flag=self.wx.LEFT, border=self.border) 461 | self.height += 1 462 | 463 | # 最后 加一条线,仅做美观用 464 | # line = self.wx.StaticLine(self.panel) 465 | # self.sizer.Add(line, pos=(self.height, 0), span=(0, 10), flag=self.wx.EXPAND | self.wx.BOTTOM, 466 | # border=0) 467 | # self.height += 1 468 | 469 | self.sizer.AddGrowableCol(2) 470 | 471 | self.panel.SetSizer(self.sizer) 472 | 473 | self.sizer.Fit(self.frame) 474 | 475 | # 自适应高度后,限制死控件宽高,防止用户拖拽resize控件大小 476 | height = self.frame.GetSize()[1] + self.border 477 | self.frame.SetSizeHints(self.wx_config['size'][0], height, self.wx_config['size'][0], height) # 设置最小和最大宽度为 300,高度为自适应 478 | self.frame.SetSize(self.wx_config['size'][0], height) 479 | # 展示控件 480 | self.frame.Show() 481 | self.app.MainLoop() 482 | 483 | class BatchSkygate(BaseBatchWx): 484 | def __init__(self) -> None: 485 | BaseBatchWx.__init__(self) 486 | 487 | def init(self): 488 | super().init() 489 | 490 | line = self.wx.StaticLine(self.panel) 491 | self.sizer.Add(line, pos=(self.height, 0), span=(0, 10), flag=self.wx.EXPAND | self.wx.BOTTOM, 492 | border=0) 493 | self.height += 1 494 | 495 | def task(self, *args): 496 | pass 497 | 498 | 499 | 500 | # async for data in asyncio.run(ah.wss_block_data()): 501 | # print(data) 502 | 503 | if __name__ == '__main__': 504 | wx = BatchSkygate() 505 | wx.init() 506 | wx.run() 507 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from eth_account import Account 3 | from eth_account.messages import encode_defunct 4 | import time 5 | from web3 import Web3, HTTPProvider 6 | from pyuseragents import random as random_ua 7 | from functools import wraps 8 | import json 9 | 10 | def retry(max_retries=3, wait_time=1): 11 | def decorator(func): 12 | @wraps(func) 13 | def wrapper(*args, **kwargs): 14 | retries = 0 15 | while retries < max_retries: 16 | try: 17 | return func(*args, **kwargs) 18 | except Exception as e: 19 | print(f"Caught exception {e}, retrying in {wait_time} seconds...") 20 | retries += 1 21 | time.sleep(wait_time) 22 | raise Exception(f"Max retries exceeded ({max_retries})") 23 | 24 | return wrapper 25 | return decorator 26 | 27 | class Skygate(): 28 | 29 | log_file_name = 'checkin_account.txt' 30 | 31 | def __init__(self, pk, invite_code='', jwt='', is_daily=False, proxy={}): 32 | self.web3 = Web3(HTTPProvider('https://opbnb.publicnode.com')) 33 | self.host = 'https://apisky.ntoken.bwtechnology.net/api/{}' 34 | self.invite_code = invite_code # 邀请码(邀请人钱包地址) 35 | self.pk = pk # 签到账号私钥 36 | self.account:Account = self.web3.eth.account.from_key(pk) 37 | self.sign_str = 'skygate' # personal_sign 签名字符串 38 | self.jwt = jwt # jwt 39 | self.is_daily = is_daily 40 | self.proxy = proxy 41 | self.block_scan_tx_url = 'https://opbnbscan.com/tx/{}' # 区块浏览器 42 | 43 | 44 | def check_balance(self): 45 | opbnb_balance = self.web3.eth.get_balance(self.account.address) 46 | return opbnb_balance 47 | 48 | def check_has_slime_nft(self): 49 | nft_contract_address = Web3.to_checksum_address('0x961a98999f14e8c5e69bdd4ee0826d6e0c556a0d') 50 | nft_contract = self.web3.eth.contract(address=nft_contract_address, abi=self.load_abi('erc721.json')) 51 | return nft_contract.functions.balanceOf(owner=self.account.address).call() 52 | 53 | def dispatch_squead(self, data): 54 | address = Web3.to_checksum_address('0x9465fe0e8cdf4e425e0c59b7caeccc1777dc6695') 55 | tx = self.web3.eth.contract(address=address, abi=self.load_abi('abi.json')).functions.signin(data) 56 | tx_hash = self.make_tx(tx) 57 | return tx_hash 58 | 59 | def adventure(self): 60 | data = 2 61 | tx_hash = self.dispatch_squead(data) 62 | print(f'adventure success ! | Tx: {self.block_scan_tx_url.format(tx_hash)}') 63 | 64 | def treasure(self): 65 | data = 1 66 | tx_hash = self.dispatch_squead(data) 67 | print(f'collect treasure success ! | Tx: {self.block_scan_tx_url.format(tx_hash)}') 68 | 69 | def explore(self): 70 | address = Web3.to_checksum_address('0xd42126d46813472f83104811533c03c807e65435') 71 | tx = self.web3.eth.contract(address=address, abi=self.load_abi('abi.json')).functions.signin(1) 72 | tx_hash = self.make_tx(tx) 73 | print(f'explore success ! | Tx: {self.block_scan_tx_url.format(tx_hash)}') 74 | 75 | def make_tx(self, tx): 76 | tx = tx.build_transaction({ 77 | 'value': 0, 78 | 'nonce': self.web3.eth.get_transaction_count(self.account.address), 79 | 'from': self.account.address, 80 | 'gas': 0, 81 | 'maxFeePerGas': 0, 82 | 'maxPriorityFeePerGas': 0 83 | }) 84 | tx.update({'maxFeePerGas': self.web3.eth.gas_price}) 85 | tx.update({'maxPriorityFeePerGas': self.web3.eth.gas_price}) 86 | tx.update({'gas': self.web3.eth.estimate_gas(tx)}) 87 | signed_tx = self.account.sign_transaction(tx) 88 | tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction) 89 | tx_receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash) 90 | while tx_receipt is None or tx_receipt['status'] is None: 91 | time.sleep(1) 92 | tx_receipt = self.web3.eth.get_transaction_receipt(tx_hash) 93 | 94 | tx_hash = Web3.to_hex(tx_hash) 95 | return tx_hash 96 | 97 | 98 | def load_abi(self, abi_name): 99 | with open(abi_name, 'r') as f: 100 | json_data = json.load(f) 101 | return json_data 102 | 103 | @retry(max_retries=30, wait_time=5) 104 | def get_info(self): 105 | # 根据jwt获取账号信息 106 | url = self.host.format('get_skyGate_coin.php') 107 | payload = { 108 | 'api_id': 'skyark_react_api', 109 | 'api_token': '3C2D36F79AFB3D5374A49BE767A17C6A3AEF91635BF7A3FB25CEA8D4DD', 110 | 'jwt': self.login() 111 | } 112 | res = requests.post(url=url, data=payload, timeout=30, proxies=self.proxy, headers=self.get_headers()) 113 | if res.status_code != 200: 114 | raise Exception(f'get_info error, status code {res.status_code}') 115 | 116 | res = res.json() 117 | 118 | if res['err'] != 0: 119 | raise Exception(f'get_info error, error code {res["err"]}, error message {res["0"]}') 120 | 121 | # {"err":0,"uName":"0x1ad453068d1808e213b46ce415a51d38b8419e57","gateWalletAddr":"9aPW9RhQ9c9eWBK","uWalletAddr":"0x1ad453068d1808e213b46ce415a51d38b8419e57","coin":"100","participationTime":"","week":"","scheduleStart":1700179200,"scheduleEnd":1734393599,"joinAmount":"100","additionalCost":"0","winAnnDate":1702857600,"advName":"31thadvanture","inviteCode":"9aPW9","uId":"21244085","userLevel":"1"} 122 | return res 123 | 124 | def get_headers(self): 125 | headers = { 126 | 'Accept': 'application/json, text/plain, */*', 127 | 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', 128 | 'Origin': 'https://skygate.skyarkchronicles.com', 129 | 'Referer': 'https://skygate.skyarkchronicles.com/', 130 | 'User-Agent': random_ua(), 131 | 'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 132 | 'Sec-Ch-Ua-Mobile': '?0', 133 | 'Sec-Ch-Ua-Platform': '"Windows"', 134 | 'Sec-Fetch-Dest': 'empty', 135 | 'Sec-Fetch-Mode': 'cors', 136 | 'Sec-Fetch-Site': 'cross-site', 137 | } 138 | 139 | return headers 140 | 141 | @retry(max_retries=30, wait_time=5) 142 | def login(self): 143 | # 获取登录态jwt 144 | if self.jwt: 145 | return self.jwt 146 | 147 | msghash = encode_defunct(text=self.sign_str) 148 | sign = Account.sign_message(msghash, self.pk) 149 | 150 | url = self.host.format('wallet_signin.php') 151 | payload = { 152 | 'api_id': 'skyark_react_api', 153 | 'api_token': '3C2D36F79AFB3D5374A49BE767A17C6A3AEF91635BF7A3FB25CEA8D4DD', 154 | 'uWalletAddr': str(self.account.address), 155 | 'sign': str(sign.signature.hex()) 156 | } 157 | if self.invite_code: 158 | payload['inviter'] = self.invite_code 159 | 160 | res = requests.post(url=url, data=payload, timeout=30, proxies=self.proxy, headers=self.get_headers()) 161 | if res.status_code != 200: 162 | raise Exception(f'login error, status code {res.status_code}') 163 | 164 | res = res.json() 165 | if res['err'] != 0: 166 | raise Exception(f'login error, error code {res["err"]}, error message {res["0"]}') 167 | 168 | self.jwt = res['jwt'] 169 | if not self.is_daily: 170 | self.save() 171 | #{"err":0,"msg":"verify_success","jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1SWQiOiIyMTI0NDA4NSIsInVXYWxsZXRBZGRyIjoiMHgxYWQ0NTMwNjhkMTgwOGUyMTNiNDZjZTQxNWE1MWQzOGI4NDE5ZTU3In0.shwMdrnWwqQJy3taJxhT2_mIsPsCF3e8CsWsmm_oTG4xhZsh_WOEqQlWC7AULffc1hj3xrx6btwEcXBO_MXu8yPqkDF6LN1rPtVNLEK3ISOCpbzfHMcMOpodZgmsPsd3YkDkqAnklQIO6rW3wAKhWgbZO1HHW5fhQM8sN-7cWXo","uWalletAddr":"0x1ad453068d1808e213b46ce415a51d38b8419e57"} 172 | return self.jwt 173 | 174 | @retry(max_retries=30, wait_time=5) 175 | def checkin(self): 176 | # 签到 177 | url = self.host.format('checkIn_skyGate_member.php') 178 | payload = { 179 | 'api_id': 'skyark_react_api', 180 | 'api_token': '3C2D36F79AFB3D5374A49BE767A17C6A3AEF91635BF7A3FB25CEA8D4DD', 181 | 'jwt': self.login() 182 | } 183 | 184 | res = requests.post(url=url, data=payload, timeout=30, proxies=self.proxy, headers=self.get_headers()) 185 | if res.status_code != 200: 186 | raise Exception(f'{self.account.address} checkin error, status code: {res.status_code}') 187 | 188 | res = res.json() 189 | if res['err'] != 0: 190 | if res["0"] == "already rewarded the daily points": 191 | print(f'{self.account.address} has checkin today') 192 | return True 193 | raise Exception(f'{self.account.address} checkin error, error code {res["err"]}, error message {res["0"]}') 194 | 195 | # {"err":1,"0":"already rewarded the daily points"} 196 | # {"err":0,"dailyGift":50,"SlimeGift":0,"fullCost":150,"dailyclaimInWeek":[{"Time":1704267789,"Amount":"50"},{"Time":1704422086,"Amount":"50"}],"indicator":1} 197 | 198 | return res 199 | 200 | 201 | def save(self): 202 | # 保存账号到当前文件夹的checkin_account.txt文件, 格式: 地址----私钥----jwt----邀请人地址(邀请码) 203 | log_str = f'{self.account.address}----{self.pk}----{self.jwt}----{self.invite_code}\n' 204 | 205 | with open(self.log_file_name, 'a') as f: 206 | f.write(log_str) 207 | 208 | @staticmethod 209 | def iter_file(file_name): 210 | # 迭代文件 211 | with open(file_name, encoding='utf-8') as f: 212 | for line in f: 213 | the_line = line.strip() 214 | yield the_line 215 | 216 | @staticmethod 217 | def daily_checkin(proxy): 218 | for log_str in Skygate.iter_file(Skygate.log_file_name): 219 | tmp = log_str.split('----') 220 | _, pk, jwt, invite_code = tmp[0], tmp[1], tmp[2], tmp[3] 221 | sg = Skygate(pk=pk, jwt=jwt, invite_code=invite_code, is_daily=True, proxy=proxy) 222 | try: 223 | sg.checkin() 224 | except Exception as e: 225 | print(str(e)) 226 | time.sleep(3) 227 | continue 228 | 229 | @staticmethod 230 | def daily_explore_treasure_adventure(): 231 | # 每日冒险和收集宝藏可以获得积分的次数,各6次 232 | daily_treasure_adventure_times = 6 233 | for log_str in Skygate.iter_file(Skygate.log_file_name): 234 | tmp = log_str.split('----') 235 | _, pk, jwt, invite_code = tmp[0], tmp[1], tmp[2], tmp[3] 236 | sg = Skygate(pk=pk, jwt=jwt, invite_code=invite_code, is_daily=True, proxy={}) 237 | if not sg.check_balance(): 238 | print(f'{sg.account.address} have no opbnb balance as gas fee, skip this account daily explore,treasure,adventure') 239 | continue 240 | 241 | print(f'========================={sg.account.address} daily explore_treasure_adventure start============================') 242 | # 每日探索1次,10积分 243 | sg.explore() 244 | # 检查账户是否有史莱姆nft 245 | slime_nft_num = sg.check_has_slime_nft() 246 | if not slime_nft_num: 247 | print(f'{sg.account.address} don‘t have slime nft, skip this account daily treasure,adventure') 248 | print(f'========================={sg.account.address} daily explore_treasure_adventure end============================') 249 | continue 250 | else: 251 | print(f'{sg.account.address} have {slime_nft_num} slime nft, start daily treasure,adventure') 252 | 253 | 254 | # 每日探险6次,每次获得积分随机 255 | for i in range(daily_treasure_adventure_times): 256 | print(f'{str(i+1)}th adventure start') 257 | try: 258 | sg.adventure() 259 | except Exception as e: 260 | print(f'{sg.account.address} adventure error , reason {e}, skip adventure') 261 | break 262 | 263 | # 每日收集宝藏6次,每次获得积分随机 264 | for i in range(daily_treasure_adventure_times): 265 | print(f'{str(i+1)}th treasure start') 266 | try: 267 | sg.treasure() 268 | except Exception as e: 269 | print(f'{sg.account.address} treasure error, reason {e}, skip collect treasure') 270 | break 271 | print(f'========================={sg.account.address} daily explore_treasure_adventure end============================') 272 | 273 | 274 | 275 | @staticmethod 276 | def get_random_account_pk(): 277 | # 随机生成以太坊地址私钥 278 | return Account.create().key.hex() 279 | 280 | 281 | proxy = {} 282 | # 代理 283 | # proxy = { 284 | # 'http': '127.0.0.1:10809', 285 | # 'https': '127.0.0.1:10809', 286 | # } 287 | 288 | 289 | 290 | # ================================第一次跑==================================== 291 | # # 生成主钱包地址数 292 | # main_account_num = 100 293 | # # 每个主钱包邀请的小号数 294 | # invite_num = 20 295 | # for i in range(main_account_num): 296 | # main_account_pk = Skygate.get_random_account_pk() 297 | # main_sg = Skygate(pk=main_account_pk, proxy=proxy) 298 | # try: 299 | # main_sg.checkin() 300 | # except Exception as e: 301 | # print(str(e)) 302 | # time.sleep(3) 303 | # continue 304 | # invite_code = str(main_sg.account.address) 305 | # for z in range(invite_num): 306 | # sub_account_pk = Skygate.get_random_account_pk() 307 | # sub_sg = Skygate(pk=sub_account_pk, invite_code=invite_code, proxy=proxy) 308 | # try: 309 | # sub_sg.checkin() 310 | # except Exception as e: 311 | # print(str(e)) 312 | # time.sleep(3) 313 | # continue 314 | # ==================================每日签到================================== 315 | # Skygate.daily_checkin(proxy) 316 | 317 | # ==================================每日explore,collect treasure, adventure================================== 318 | # Skygate.daily_explore_treasure_adventure() --------------------------------------------------------------------------------