├── .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 |
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()
--------------------------------------------------------------------------------