getsourcecode 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,427 @@
1
+ from audioop import add
2
+ import json
3
+ import base64
4
+ import requests
5
+ from getsourcecode.common import *
6
+ from getsourcecode.config import *
7
+ from getsourcecode.keys import get_key
8
+ from retrying import retry
9
+ import certifi
10
+
11
+ def check_is_duplicate_file(file_path, contract_code):
12
+ if hash_file(file_path) == hash_string(contract_code):
13
+ return True
14
+ return False
15
+
16
+ def save_info(address, contract_name):
17
+ try:
18
+ if address not in contract_info.keys():
19
+ contract_info[address] = contract_name
20
+ except Exception as e:
21
+ handle_exception(e)
22
+
23
+
24
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
25
+ def tron_requests(address, api_url):
26
+ data = {
27
+ "contractAddress": address
28
+ }
29
+ tron_req = requests.post(api_url, data=data, verify=False)
30
+ return tron_req
31
+
32
+
33
+ def send_tron(addresses, output_folder):
34
+ global contract_index
35
+ global temp_contract_name
36
+ try:
37
+ api_url = "https://apiasia.tronscan.io:5566/api/solidity/contract/info"
38
+ for address in addresses:
39
+ req = tron_requests(address, api_url)
40
+ if json.loads(req.text)["code"] == 200:
41
+ contract_code = json.loads(req.text)["data"]["contract_code"]
42
+ contract_folder = json.loads(req.text)["data"][
43
+ "contract_name"] if output_folder == "" else output_folder
44
+ make_dir(contract_folder)
45
+ sub_index = 0
46
+ save_info(address, json.loads(req.text)["data"]["contract_name"])
47
+ for code in contract_code:
48
+ index = 0
49
+ contract_name = code['name']
50
+ temp_contract_name = contract_name
51
+ code_temp = str(base64.b64decode(code['code']), 'utf-8').replace('\r\n', '\n')
52
+ exist_file =False
53
+ while os.path.exists(contract_folder + "//" + contract_name):
54
+ exist_file = True
55
+ if contract_name.find("_")!= -1:
56
+ contract_name = code['name'].split('_')[0] + "_{}".format(index) + ".sol"
57
+ else:
58
+ contract_name = code['name'].split('.')[0] + "_{}".format(index) + ".sol"
59
+ index += 1
60
+ # Do not process files with duplicate content
61
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
62
+ continue
63
+ make_dir(os.path.split(contract_folder + "//" + contract_name)[0])
64
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
65
+ fw.write(code_temp)
66
+
67
+ print(f'{contract_index}-{sub_index}: {contract_folder + "/" + contract_name}'.replace(
68
+ '//', '/'))
69
+ sub_index += 1
70
+ contract_index += 1
71
+ except Exception as e:
72
+ handle_exception(e)
73
+
74
+
75
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
76
+ def okex_requests(api_url, apikey, proxies):
77
+ head = {
78
+ "X-Apikey": apikey
79
+ }
80
+ okex_req = requests.get(api_url, headers=head, proxies=proxies, verify=False)
81
+ return okex_req
82
+
83
+
84
+ def send_okex(addresses, output_folder, apikey, network):
85
+ okex_network_api = {
86
+ "okt": "okexchain",
87
+ "okb": "okbc_test",
88
+ "okt-testnet": "okexchain_test"
89
+ }
90
+ global contract_index
91
+ global proxy_contract
92
+ global temp_contract_name
93
+ proxies = get_proxies()
94
+ try:
95
+ for address in addresses:
96
+ api_url = f"https://www.oklink.com/api/explorer/v1/{okex_network_api[network]}/addresses/{address}/contract"
97
+ req = okex_requests(api_url, apikey, proxies)
98
+ if json.loads(req.text)["code"] == 0:
99
+ contractSourceList = json.loads(req.text)["data"]["contractSourceList"]
100
+ contract_main_name = json.loads(req.text)["data"]["name"] if "name" in json.loads(req.text)[
101
+ "data"].keys() else "not_open_source"
102
+ if contractSourceList != []:
103
+ contract_code_list = json.loads(req.text)["data"]["contractSourceList"]
104
+ else:
105
+ contract_code_list = [{
106
+ "name": contract_main_name,
107
+ "source_code": json.loads(req.text)["data"]["contractSource"],
108
+ }]
109
+ contract_folder = contract_main_name if output_folder == "" else output_folder
110
+ make_dir(contract_folder)
111
+ save_info(address, contract_main_name)
112
+ sub_index = 0
113
+ for code in contract_code_list:
114
+ index = 0
115
+ contract_name = code['name'] + ".sol"
116
+ temp_contract_name = contract_name
117
+ code_temp = code['source_code'].replace('\r\n', '\n')
118
+ exist_file = False
119
+ while os.path.exists(contract_folder + "//" + contract_name):
120
+ exist_file = True
121
+ if contract_name.find("_")!= -1:
122
+ contract_name = code['name'].split('_')[0] + "_{}".format(index) + ".sol"
123
+ else:
124
+ contract_name = code['name'].split('.')[0] + "_{}".format(index) + ".sol"
125
+ index += 1
126
+ # Do not process files with duplicate content
127
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
128
+ continue
129
+ make_dir(os.path.split(contract_folder + "//" + contract_name)[0])
130
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
131
+ fw.write(code_temp)
132
+ print(f'{contract_index}-{sub_index}: {contract_folder + "/" + contract_name}'.replace('//', '/'))
133
+ sub_index += 1
134
+ contract_index += 1
135
+ impl = ""
136
+ if "implContractAddress" in json.loads(req.text)["data"].keys():
137
+ impl = json.loads(req.text)["data"]["implContractAddress"]
138
+ if impl != "":
139
+ addresses = [impl]
140
+ proxy_contract[address] = impl
141
+ send_okex(addresses, "impl_contract", apikey, network)
142
+ except Exception as e:
143
+ handle_exception(e)
144
+
145
+
146
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
147
+ def klaytn_requests(real_url, proxies):
148
+ klaytn_req = requests.get(real_url, proxies=proxies, verify=False)
149
+ return klaytn_req
150
+
151
+
152
+ def send_klaytn(addresses, output_folder, network):
153
+ global contract_index
154
+ global temp_contract_name
155
+ try:
156
+ proxies = get_proxies()
157
+ for address in addresses:
158
+ if network == "klaytn":
159
+ klaytn_url = f"https://api-cypress.klaytnscope.com/v2/accounts/{address}"
160
+ else:
161
+ klaytn_url = f"https://api-baobab.klaytnscope.com/v2/accounts/{address}"
162
+ req = klaytn_requests(klaytn_url, proxies)
163
+ code = json.loads(req.text)['result']['matchedContract']
164
+ contract_name = code['contractName'] + ".sol"
165
+ temp_contract_name = contract_name
166
+ code_temp = code["contractSource"].replace('\r\n', '\n')
167
+ exist_file = False
168
+ save_info(address, code['contractName'])
169
+ contract_folder = code['contractName'] if output_folder == "" else output_folder
170
+ index = 0
171
+ while os.path.exists(contract_folder + "//" + contract_name):
172
+ exist_file = True
173
+ if contract_name.find("_")!= -1:
174
+ contract_name = code['contractName'].split('_')[0] + "_{}".format(index) + ".sol"
175
+ else:
176
+ contract_name = code['contractName'].split('.')[0] + "_{}".format(index) + ".sol"
177
+ index += 1
178
+ # Do not process files with duplicate content
179
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
180
+ continue
181
+ make_dir(os.path.split(contract_folder + "//" + contract_name)[0])
182
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
183
+ fw.write(code_temp)
184
+ print(f'{contract_index}: {contract_folder + "/" + contract_name}'.replace('//', '/'))
185
+ contract_index += 1
186
+ except Exception as e:
187
+ handle_exception(e)
188
+
189
+
190
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
191
+ def check_ronin_is_proxy(address, proxies, network):
192
+ header = {
193
+ "User-Agent": USER_AGENT,
194
+ "Content-Type": "application/json"
195
+ }
196
+ if network == "ronin":
197
+ check_proxy_url = f"https://explorer-kintsugi.roninchain.com/v2/2020/contract/{address}"
198
+ else:
199
+ check_proxy_url = f"https://explorer-kintsugi.roninchain.com/v2/2021/contract/{address}"
200
+ check_proxy_req = requests.get(check_proxy_url, proxies=proxies, headers=header, verify=False)
201
+ return check_proxy_req.json()['result']
202
+
203
+
204
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
205
+ def ronin_request(url, proxies):
206
+ header = {
207
+ "User-Agent": USER_AGENT,
208
+ "Content-Type": "application/json"
209
+ }
210
+ ronin_req = requests.get(url, proxies=proxies, headers=header, verify=False)
211
+ return ronin_req.json()
212
+
213
+
214
+ def send_ronin(addresses, output_folder, network):
215
+ global contract_index
216
+ global proxy_contract
217
+ global temp_contract_name
218
+ try:
219
+ proxies = get_proxies()
220
+ for address in addresses:
221
+ address_info = check_ronin_is_proxy(address, proxies, network)
222
+ proxy_address = address_info["proxy_to"]
223
+ contract_name = address_info["contract_name"]
224
+ temp_contract_name = contract_name
225
+ if network == "ronin":
226
+ url = f"https://explorer-kintsugi.roninchain.com/v2/2020/contract/{address}/src"
227
+ else:
228
+ url = f"https://explorer-kintsugi.roninchain.com/v2/2021/contract/{address}/src"
229
+ ronin_req = ronin_request(url, proxies)
230
+ save_info(address, contract_name)
231
+ contract_folder = contract_name if output_folder == "" else output_folder
232
+ index = 0
233
+ sub_index = 0
234
+ for code in ronin_req['result']:
235
+ exist_file = False
236
+ code_temp = code['content'].replace('\r\n', '\n')
237
+ while os.path.exists(contract_folder + "//" + contract_name):
238
+ exist_file = True
239
+ if contract_name.find("_")!= -1:
240
+ contract_name = contract_name.split('_')[0] + "_{}".format(index) + ".sol"
241
+ else:
242
+ contract_name = contract_name.split('.')[0] + "_{}".format(index) + ".sol"
243
+ index += 1
244
+ make_dir(os.path.split(contract_folder + "//" + address_info["contract_name"])[0])
245
+ # Do not process files with duplicate content
246
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
247
+ continue
248
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
249
+ fw.write(code_temp)
250
+ sub_index += 1
251
+ print(f'{contract_index}-{sub_index}: {contract_folder + "/" + contract_name}'.replace('//', '/'))
252
+ contract_index += 1
253
+ if proxy_address != "":
254
+ addresses = [proxy_address]
255
+ proxy_contract[address] = proxy_address
256
+ send_ronin(addresses, output_folder, network)
257
+ except Exception as e:
258
+ handle_exception(e)
259
+
260
+
261
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
262
+ def zksync_request(url, proxies):
263
+ header = {
264
+ "User-Agent": USER_AGENT,
265
+ "Content-Type": "application/json"
266
+ }
267
+ zksync_req = requests.get(url, proxies=proxies, headers=header, verify=False)
268
+ return zksync_req.json()
269
+
270
+
271
+ def send_zksync_era(addresses, output_folder, network):
272
+ global contract_index
273
+ global proxy_contract
274
+ global temp_contract_name
275
+ try:
276
+ proxies = get_proxies()
277
+ for address in addresses:
278
+ if network == "zksyncera":
279
+ url = f"https://zksync2-mainnet-explorer.zksync.io/contract_verification/info/{address}"
280
+ else:
281
+ url = f"https://zksync2-testnet-explorer.zksync.dev/contract_verification/info/{address}"
282
+ zksync_req = zksync_request(url, proxies)
283
+ contract_name = zksync_req['request']['contractName'].split(".sol:")[1]
284
+ save_info(address, contract_name)
285
+ contract_folder = contract_name if output_folder == "" else output_folder
286
+ index = 0
287
+ sub_index = 0
288
+ for contract_name in zksync_req['request']['sourceCode']['sources'].keys():
289
+ temp_contract_name = contract_name
290
+ code_temp = zksync_req['request']['sourceCode']['sources'][contract_name]['content'].replace('\r\n', '\n')
291
+ exist_file = False
292
+ while os.path.exists(contract_folder + "//" + contract_name):
293
+ exist_file = True
294
+ if contract_name.find("_")!= -1:
295
+ contract_name = contract_name.split('_')[0] + "_{}".format(index) + ".sol"
296
+ else:
297
+ contract_name = contract_name.split('.')[0] + "_{}".format(index) + ".sol"
298
+ index += 1
299
+ # Do not process files with duplicate content
300
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
301
+ continue
302
+ make_dir(os.path.split(contract_folder + "//" + contract_name)[0])
303
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
304
+ fw.write(code_temp)
305
+ sub_index += 1
306
+ print(f'{contract_index}-{sub_index}: {contract_folder + "/" + contract_name}'.replace('//', '/'))
307
+ contract_index += 1
308
+ except Exception as e:
309
+ handle_exception(e)
310
+
311
+
312
+ @retry(stop_max_attempt_number=5, wait_fixed=2000)
313
+ def common_requests(real_url, proxies, headers):
314
+ common_req = requests.get(real_url, proxies=proxies, headers=headers, verify=False)
315
+ return common_req
316
+
317
+
318
+ def send_request(addresses, output_folder, network, api_key):
319
+ try:
320
+ proxies = get_proxies()
321
+ headers = {
322
+ 'user-agent': USER_AGENT
323
+ }
324
+ for address in addresses:
325
+ if address in deal_addresses:
326
+ continue
327
+ deal_addresses.append(address)
328
+ output_data = ""
329
+ api_key = get_key() if api_key == "" else api_key
330
+ real_url = req_url + address + "&apikey=" + api_key + f"&chainid={chain_to_id.get(network)}"
331
+ req = common_requests(real_url, proxies, headers)
332
+ results = json.loads(req.text)['result']
333
+ if isinstance(results, dict):
334
+ output_data = results
335
+ elif isinstance(results, list):
336
+ output_data = results[0]
337
+ export_result(output_data, output_folder, network, address, api_key)
338
+ except Exception as e:
339
+ handle_exception(e)
340
+
341
+
342
+ def export_result(result, output_folder, network, address, api_key):
343
+ global contract_index
344
+ global proxy_contract
345
+ global temp_contract_name
346
+ if "ContractName" not in result.keys():
347
+ return
348
+ try:
349
+ contract_suffix = ".sol"
350
+ if result['CompilerVersion'].find("vyper") != -1:
351
+ contract_suffix = ".vy"
352
+ index = 0
353
+ sub_index = 0
354
+ is_multi_file = False
355
+ contract_name = result['ContractName']
356
+ save_info(address, contract_name)
357
+ source_code = result['SourceCode'].replace("\r\n", "\n")
358
+ if source_code.find(contract_suffix + '":{"content":') != -1:
359
+ is_multi_file = True
360
+ if "\"language\":" in source_code or is_multi_file:
361
+ contract_folder = contract_name if output_folder == "" else output_folder
362
+ make_dir(contract_folder)
363
+ if not is_multi_file:
364
+ source_code = json.loads(source_code[1:-1])['sources']
365
+ else:
366
+ source_code = json.loads(source_code)
367
+ for key in source_code.keys():
368
+ contract_name = key + contract_suffix if key.find(contract_suffix) == -1 else key
369
+ temp_contract_name = contract_name
370
+ code_temp = source_code[key]["content"].replace('\r\n', '\n')
371
+ exist_file = False
372
+ while os.path.exists(contract_folder + "//" + contract_name):
373
+ exist_file = True
374
+ if contract_name.find("_")!= -1:
375
+ contract_name = contract_name.split('_')[0] + "_{}".format(index) + ".sol"
376
+ else:
377
+ contract_name = contract_name.split('.')[0] + "_{}".format(index) + ".sol"
378
+ index += 1
379
+ index = 0
380
+ # Do not process files with duplicate content
381
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
382
+ continue
383
+ make_dir(os.path.split(contract_folder + "//" + contract_name)[0])
384
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
385
+ fw.write(code_temp)
386
+ print(f'{contract_index}-{sub_index}: {contract_folder + "/" + contract_name}'.replace('//', '/'))
387
+ sub_index += 1
388
+ contract_index += 1
389
+ else:
390
+ if contract_name == "":
391
+ return
392
+ contract_folder = contract_name if output_folder == "" else output_folder
393
+ contract_name = contract_name + contract_suffix if contract_name.find(contract_suffix) == -1 else contract_name
394
+ temp_contract_name = contract_name
395
+ code_temp = source_code.replace('\r\n', '\n')
396
+ exist_file = False
397
+ while os.path.exists(contract_folder + "//" + contract_name):
398
+ exist_file = True
399
+ if contract_name.find("_")!= -1:
400
+ contract_name = contract_name.split('_')[0] + "_{}".format(index) + ".sol"
401
+ else:
402
+ contract_name = contract_name.split('.')[0] + "_{}".format(index) + ".sol"
403
+ index += 1
404
+ # Do not process files with duplicate content
405
+ if exist_file and check_is_duplicate_file(contract_folder + "//" + temp_contract_name, code_temp):
406
+ return
407
+ make_dir(os.path.split(contract_folder + "//" + contract_name)[0])
408
+ with open(contract_folder + "//" + contract_name, "w+", encoding='utf-8') as fw:
409
+ fw.write(code_temp)
410
+ print(f'{contract_index}-{sub_index}: {contract_folder + "/" + contract_name}'.replace('//', '/'))
411
+ contract_index += 1
412
+ addresses = []
413
+ if network == "cronos":
414
+ if "ImplementationAddress" in result.keys():
415
+ if result['ImplementationAddress'] != "":
416
+ proxy_contract[address] = result['ImplementationAddress']
417
+ addresses.append(result['ImplementationAddress'])
418
+ send_request(addresses, "Implementation", network, api_key)
419
+ elif result['Implementation'] != "":
420
+ # Handle block explorer API exception returns to avoid infinite loops
421
+ if result['Implementation'].lower() == address.lower():
422
+ return
423
+ proxy_contract[address] = result['Implementation']
424
+ addresses.append(result['Implementation'])
425
+ send_request(addresses, "Implementation", network, api_key)
426
+ except Exception as e:
427
+ handle_exception(e)
getsourcecode/keys.py ADDED
@@ -0,0 +1,28 @@
1
+ from random import randint
2
+ from getsourcecode.common import handle_exception
3
+ from getsourcecode.config import api_keys
4
+
5
+ def get_keys():
6
+ try:
7
+ return api_keys
8
+ except KeyError as e:
9
+ handle_exception(e)
10
+
11
+
12
+ def get_key():
13
+ try:
14
+ keys = get_keys()
15
+ random_num = randint(0, len(keys) - 1)
16
+ return keys[random_num]
17
+ except IndexError as e:
18
+ handle_exception(e)
19
+
20
+
21
+ def print_key():
22
+ try:
23
+ keys = get_keys()
24
+ if keys:
25
+ output_keys = "\n".join(keys)
26
+ print(output_keys)
27
+ except Exception as e:
28
+ handle_exception(e)
getsourcecode/menu.py ADDED
@@ -0,0 +1,43 @@
1
+ import argparse
2
+ from argparse import RawTextHelpFormatter
3
+ from getsourcecode.common import current_version
4
+
5
+
6
+ def argparse_menu():
7
+ parser = argparse.ArgumentParser(
8
+ description="To get contract source code verified on blockchain explorer.\n\n"
9
+ "Supported Chain Platforms:\n"
10
+ " Ethereum Mainnet | Sepolia Testnet | Hoodi Testnet\n"
11
+ " BNB Smart Chain Mainnet | BNB Smart Chain Testnet\n"
12
+ " Polygon Mainnet | Polygon Amoy Testnet\n"
13
+ " Base Mainnet | Base Sepolia Testnet\n"
14
+ " Arbitrum One Mainnet | Arbitrum Sepolia Testnet\n"
15
+ " Linea Mainnet | Linea Sepolia Testnet\n"
16
+ " Blast Mainnet | Blast Sepolia Testnet\n"
17
+ " OP Mainnet | OP Sepolia Testnet\n"
18
+ " Avalanche C-Chain | Avalanche Fuji Testnet\n"
19
+ " BitTorrent Chain Mainnet | BitTorrent Chain Testnet\n"
20
+ " Celo Mainnet | Celo Sepolia Testnet\n"
21
+ " Fraxtal Mainnet | Fraxtal Hoodi Testnet\n"
22
+ " Gnosis\n"
23
+ " * Chain names are case-insensitive.\n"
24
+ " * Some chains (e.g. BNB Smart Chain, Base, OP, Avalanche) require a paid API plan.\n"
25
+ " * For the full list, visit: https://docs.etherscan.io/supported-chains\n\n"
26
+ "Some of the above networks may not be fully tested.\n"
27
+ "If you encounter any problems, please contact support@hxzy.me\n\n"
28
+ "PS: Files with exactly the same code will not be saved repeatedly.",
29
+ formatter_class=RawTextHelpFormatter)
30
+
31
+ parser.add_argument('-i', default='', dest='inputFile', help='Input file path including contract addresses.')
32
+ parser.add_argument('-o', default='', dest='outputFolder', help='Choose a folder to export.')
33
+ parser.add_argument('-a', default='', dest='address', help='A string including contract addresses.')
34
+ parser.add_argument('-n', default='', dest='network', help='Which network to get source code.')
35
+ parser.add_argument('-k', default='', dest='key', help='Provide paid api key to download paid-only network code.')
36
+ parser.add_argument('-p', default='', dest='proxy', help='Use a proxy.')
37
+ parser.add_argument('-t', default='', dest='txhash', help='Get the relevant contract source code in the specified transaction.')
38
+ parser.add_argument('-u', action="store_true", dest='update', help='Check to see if a new version is available to update.')
39
+ parser.add_argument('-v', action='version', version=current_version, help='Show current version.')
40
+ parser.add_argument('--hash', action="store_true", dest='contractHash', help='Show contract hash data.')
41
+ parser.add_argument('--apikey', default='', dest='apikey', help='The apikey required by the okex related chain.')
42
+
43
+ return parser.parse_args()