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.
- getsourcecode/__init__.py +74 -0
- getsourcecode/check.py +22 -0
- getsourcecode/common.py +69 -0
- getsourcecode/config.py +175 -0
- getsourcecode/filter.py +169 -0
- getsourcecode/handle.py +427 -0
- getsourcecode/keys.py +28 -0
- getsourcecode/menu.py +43 -0
- getsourcecode-2.1.0.dist-info/LICENSE +201 -0
- getsourcecode-2.1.0.dist-info/METADATA +234 -0
- getsourcecode-2.1.0.dist-info/RECORD +14 -0
- getsourcecode-2.1.0.dist-info/WHEEL +5 -0
- getsourcecode-2.1.0.dist-info/entry_points.txt +2 -0
- getsourcecode-2.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from getsourcecode.check import *
|
|
3
|
+
from getsourcecode.filter import *
|
|
4
|
+
from getsourcecode.config import *
|
|
5
|
+
from getsourcecode.keys import *
|
|
6
|
+
from getsourcecode.common import *
|
|
7
|
+
import getsourcecode.menu
|
|
8
|
+
import urllib3
|
|
9
|
+
|
|
10
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
11
|
+
# Load config
|
|
12
|
+
parser = menu.argparse_menu()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_code(input_file, output_folder, address, network, api_key):
|
|
16
|
+
try:
|
|
17
|
+
if network.lower() == "Tron".lower():
|
|
18
|
+
addresses = get_addresses_by_file_or_string(input_file, True, address)
|
|
19
|
+
send_tron(addresses, output_folder)
|
|
20
|
+
elif network.lower() == "okt" or network.lower() == "okt-testnet" or network.lower() == "okb":
|
|
21
|
+
if parser.apikey == "":
|
|
22
|
+
print_okex_api_key_explain()
|
|
23
|
+
return
|
|
24
|
+
addresses = get_addresses_by_file_or_string(input_file, False, address)
|
|
25
|
+
send_okex(addresses, output_folder, parser.apikey, network.lower())
|
|
26
|
+
elif network.lower() == "klaytn" or network.lower() == "baobab":
|
|
27
|
+
addresses = get_addresses_by_file_or_string(input_file, False, address)
|
|
28
|
+
send_klaytn(addresses, output_folder, network)
|
|
29
|
+
elif network.lower() == "ronin" or network.lower() == "ronin-testnet":
|
|
30
|
+
addresses = get_addresses_by_file_or_string(input_file, False, address)
|
|
31
|
+
send_ronin(addresses, output_folder, network)
|
|
32
|
+
elif network.lower() == "zksyncera" or network.lower() == "zksyncera-testnet":
|
|
33
|
+
addresses = get_addresses_by_file_or_string(input_file, False, address)
|
|
34
|
+
send_zksync_era(addresses, output_folder, network)
|
|
35
|
+
else:
|
|
36
|
+
if network in paid_only_set and api_key == "":
|
|
37
|
+
raise ValueError("Invalid api key, please privide paid api key")
|
|
38
|
+
addresses = get_addresses_by_file_or_string(input_file, False, address)
|
|
39
|
+
if addresses:
|
|
40
|
+
send_request(addresses, output_folder, network, api_key)
|
|
41
|
+
else:
|
|
42
|
+
raise ValueError("Error address")
|
|
43
|
+
except Exception as e:
|
|
44
|
+
handle_exception(e)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def main():
|
|
48
|
+
try:
|
|
49
|
+
if parser.proxy:
|
|
50
|
+
set_configs(parser.proxy)
|
|
51
|
+
if parser.update:
|
|
52
|
+
check_update(name, current_version)
|
|
53
|
+
sys.exit(0)
|
|
54
|
+
elif parser.inputFile != "" or parser.address != "":
|
|
55
|
+
get_code(parser.inputFile, parser.outputFolder, parser.address, parser.network.lower(), parser.key)
|
|
56
|
+
elif parser.txhash != "":
|
|
57
|
+
get_addresses_by_tx(parser.txhash, parser.network.lower(), parser.outputFolder)
|
|
58
|
+
else:
|
|
59
|
+
print("Invalid command")
|
|
60
|
+
if contract_info != {}:
|
|
61
|
+
print("\nAddress => ContractName:")
|
|
62
|
+
for key in contract_info.keys():
|
|
63
|
+
print(f"{key}\t{contract_info[key]}")
|
|
64
|
+
if proxy_contract != {}:
|
|
65
|
+
print("\nProxy => Implementation:")
|
|
66
|
+
for key in proxy_contract.keys():
|
|
67
|
+
print(f"{key}\t{proxy_contract[key]}")
|
|
68
|
+
print('\nSuccess.')
|
|
69
|
+
except Exception as e:
|
|
70
|
+
handle_exception(e)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if __name__ == '__main__':
|
|
74
|
+
main()
|
getsourcecode/check.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import certifi
|
|
3
|
+
from distutils.version import StrictVersion
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def check_update(package_name, current_version):
|
|
7
|
+
try:
|
|
8
|
+
url = f"https://pypi.org/pypi/{package_name}/json"
|
|
9
|
+
response = requests.get(url, verify=False)
|
|
10
|
+
response.raise_for_status()
|
|
11
|
+
data = response.json()
|
|
12
|
+
latest_version = data["info"]["version"]
|
|
13
|
+
if StrictVersion(current_version) < StrictVersion(latest_version):
|
|
14
|
+
print(f"A new version of {package_name} is available: {latest_version}")
|
|
15
|
+
else:
|
|
16
|
+
print(f"You are using the latest version ({current_version}) of {package_name}.")
|
|
17
|
+
except requests.exceptions.RequestException as e:
|
|
18
|
+
print("Failed to check for updates:", str(e))
|
|
19
|
+
except KeyError:
|
|
20
|
+
print("Failed to parse response data.")
|
|
21
|
+
except Exception as e:
|
|
22
|
+
print("An error occurred:", str(e))
|
getsourcecode/common.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import time
|
|
4
|
+
import hashlib
|
|
5
|
+
import traceback
|
|
6
|
+
|
|
7
|
+
# Package base info
|
|
8
|
+
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"
|
|
9
|
+
current_version = "2.0.11"
|
|
10
|
+
name = "getsourcecode"
|
|
11
|
+
proxy_contract = {}
|
|
12
|
+
contract_index = 0
|
|
13
|
+
contract_info = {}
|
|
14
|
+
EXIT_CODE = 0
|
|
15
|
+
temp_contract_name = ""
|
|
16
|
+
find_duplicate_file = False
|
|
17
|
+
proxy = ""
|
|
18
|
+
deal_addresses = []
|
|
19
|
+
|
|
20
|
+
def print_okex_api_key_explain():
|
|
21
|
+
print("If you want to get the contract code of the okex link, you need to manually enter the api key.\nVisit this link: \n1. okt: https://www.oklink.com/cn/oktc/address/0x38AB5022BEa07AA8966A9bEB5EF7759b715e4BEE\n2. okb: https://www.oklink.com/cn/okbc-test/address/0x6BC26C28130e7634fFa1330969f34e98DC4d0019\n3. okt-testnet: https://www.oklink.com/cn/oktc-test/address/0x7c3ebCB6c4Ae99964980006C61d7eb032eDcb06B\n\nFollow the steps below:\n1. Open the above link\n2. Open the browser developer tool\n3. Click the contract tab page on the browser\n4. Find the request \"contract?t=\"\n5. X-Apikey in the request header of the request is the required apikey\n\nFor example:\ngetCode -p 127.0.0.1:7890 -n okt -a 0x38AB5022BEa07AA8966A9bEB5EF7759b715e4BEE --apikey LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI4MDQzNDU3Mjc2NjY0OTI=")
|
|
22
|
+
sys.exit(EXIT_CODE)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def set_configs(input_proxy):
|
|
26
|
+
global proxy
|
|
27
|
+
proxy = input_proxy
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_proxies():
|
|
31
|
+
proxies = {}
|
|
32
|
+
if proxy != "":
|
|
33
|
+
proxies = {
|
|
34
|
+
"https": "http://" + proxy,
|
|
35
|
+
"http": "http://" + proxy
|
|
36
|
+
}
|
|
37
|
+
return proxies
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def handle_exception(e):
|
|
41
|
+
print("--------------------------------------")
|
|
42
|
+
traceback.print_exc()
|
|
43
|
+
print("--------------------------------------")
|
|
44
|
+
sys.exit(EXIT_CODE)
|
|
45
|
+
|
|
46
|
+
def hash_file(file_path, algorithm='sha256'):
|
|
47
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
48
|
+
text = f.read()
|
|
49
|
+
hash_result = hash_string(text, algorithm)
|
|
50
|
+
return hash_result
|
|
51
|
+
|
|
52
|
+
def hash_string(text, algorithm='sha256'):
|
|
53
|
+
h = hashlib.new(algorithm)
|
|
54
|
+
h.update(text.encode('utf-8'))
|
|
55
|
+
return h.hexdigest()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def make_dir(path):
|
|
60
|
+
path = path.strip()
|
|
61
|
+
path = path.rstrip("\\")
|
|
62
|
+
if not os.path.exists(path):
|
|
63
|
+
try:
|
|
64
|
+
os.makedirs(path)
|
|
65
|
+
return True
|
|
66
|
+
except OSError:
|
|
67
|
+
return False
|
|
68
|
+
else:
|
|
69
|
+
return False
|
getsourcecode/config.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
class CaseInsensitiveDict(dict):
|
|
2
|
+
def __init__(self, data=None):
|
|
3
|
+
super().__init__()
|
|
4
|
+
if data:
|
|
5
|
+
for key, value in data.items():
|
|
6
|
+
self[key] = value # 走重写的 __setitem__
|
|
7
|
+
|
|
8
|
+
def __setitem__(self, key, value):
|
|
9
|
+
super().__setitem__(key.lower(), value)
|
|
10
|
+
|
|
11
|
+
def __getitem__(self, key):
|
|
12
|
+
return super().__getitem__(key.lower())
|
|
13
|
+
|
|
14
|
+
def __contains__(self, key):
|
|
15
|
+
return super().__contains__(key.lower())
|
|
16
|
+
|
|
17
|
+
def get(self, key, default=None):
|
|
18
|
+
return super().get(key.lower(), default)
|
|
19
|
+
|
|
20
|
+
api_keys = [
|
|
21
|
+
"B69GNP1IXCXJUGTWVCZPW4PS6KFDQ9MNJ1",
|
|
22
|
+
"TRUHXX8K4D5E4665M22FUYZ6F4ZP4SC6UQ",
|
|
23
|
+
"373ZPPAM1QZYS55Q5AW24BKW124BGPMPIA",
|
|
24
|
+
"75FE5RHNXQJPRY6A4EGXTWJKE4M7783W6F",
|
|
25
|
+
"TRUHXX8K4D5E4665M22FUYZ6F4ZP4SC6UQ",
|
|
26
|
+
"Q8K1J5WIXHVQWV1XHVFF1INTPHWFZP5AZV",
|
|
27
|
+
"KWPEX5CZ437P2JRB2U7WZ37VQFAVZFXXP6"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
req_url = "https://api.etherscan.io/v2/api?module=contract&action=getsourcecode&address="
|
|
31
|
+
|
|
32
|
+
tx_hash_scan_config = {
|
|
33
|
+
'eth': {
|
|
34
|
+
"url": "https://etherscan.io/vmtrace?txhash={}&type=parity#raw",
|
|
35
|
+
"re": r"<preid=\"editor\"class=\"ms-3\">(.*?)</pre>"
|
|
36
|
+
},
|
|
37
|
+
'bsc': {
|
|
38
|
+
"url": "https://www.bscscan.com/vmtrace?txhash={}&type=gethtrace2",
|
|
39
|
+
"re": r"<preid=\"editor\"class=\"ms-3\">(.*?)</pre>"
|
|
40
|
+
},
|
|
41
|
+
'heco': {
|
|
42
|
+
"url": "https://www.hecoinfo.com/api/v1/chain/txs/detail?txHash={}&chainId=HECO",
|
|
43
|
+
"re": ""
|
|
44
|
+
},
|
|
45
|
+
'arbi': {
|
|
46
|
+
"url": "https://arbiscan.io/vmtrace?txhash={}&type=gethtrace2",
|
|
47
|
+
"re": r"<preid='editor'>(.*?)</pre>"
|
|
48
|
+
},
|
|
49
|
+
'boba': {
|
|
50
|
+
"url": "https://bobascan.com/vmtrace?txhash={}&type=gethtrace2",
|
|
51
|
+
"re": r"<preid='editor'>(.*?)</pre>"
|
|
52
|
+
},
|
|
53
|
+
'arbi-nova': {
|
|
54
|
+
"url": "https://nova.arbiscan.io/vmtrace?txhash={}&type=gethtrace2",
|
|
55
|
+
"re": r"<preid='editor'>(.*?)</pre>"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
tenderly_chain_id_list = {
|
|
60
|
+
"arbi": 42161,
|
|
61
|
+
"arbi-testnet": 421613,
|
|
62
|
+
"bsc": 56,
|
|
63
|
+
"bsc-testnet": 97,
|
|
64
|
+
"avax": 43114,
|
|
65
|
+
"avax-testnet": 43113,
|
|
66
|
+
"fantom": 250,
|
|
67
|
+
"ftm-testnet": 25,
|
|
68
|
+
"moonbeam": 1284,
|
|
69
|
+
"moonriver": 1285,
|
|
70
|
+
"cronos": 25,
|
|
71
|
+
"cronos-testnet": 338,
|
|
72
|
+
"boba-testnet": 2888,
|
|
73
|
+
"gnosis": 100,
|
|
74
|
+
"eth": 1,
|
|
75
|
+
"sepolia": 11155111,
|
|
76
|
+
"goerli": 5,
|
|
77
|
+
"poly": 137,
|
|
78
|
+
"poly-testnet": 80001,
|
|
79
|
+
"opt": 10,
|
|
80
|
+
"opt-testnet": 420,
|
|
81
|
+
"base": 8453,
|
|
82
|
+
"base-testnet": 84531,
|
|
83
|
+
"boba": 288
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
special_trace_api = {
|
|
87
|
+
"klaytn": {},
|
|
88
|
+
'ronin': {}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
chain_to_id = CaseInsensitiveDict({
|
|
92
|
+
"Ethereum Mainnet": 1,
|
|
93
|
+
"Sepolia Testnet": 11155111,
|
|
94
|
+
"Hoodi Testnet": 560048,
|
|
95
|
+
"BNB Smart Chain Mainnet": 56,
|
|
96
|
+
"BNB Smart Chain Testnet": 97,
|
|
97
|
+
"Polygon Mainnet": 137,
|
|
98
|
+
"Polygon Amoy Testnet": 80002,
|
|
99
|
+
"Base Mainnet": 8453,
|
|
100
|
+
"Base Sepolia Testnet": 84532,
|
|
101
|
+
"Arbitrum One Mainnet": 42161,
|
|
102
|
+
"Arbitrum Sepolia Testnet": 421614,
|
|
103
|
+
"Linea Mainnet": 59144,
|
|
104
|
+
"Linea Sepolia Testnet": 59141,
|
|
105
|
+
"Blast Mainnet": 81457,
|
|
106
|
+
"Blast Sepolia Testnet": 168587773,
|
|
107
|
+
"OP Mainnet": 10,
|
|
108
|
+
"OP Sepolia Testnet": 11155420,
|
|
109
|
+
"Avalanche C-Chain": 43114,
|
|
110
|
+
"Avalanche Fuji Testnet": 43113,
|
|
111
|
+
"BitTorrent Chain Mainnet": 199,
|
|
112
|
+
"BitTorrent Chain Testnet": 1029,
|
|
113
|
+
"Celo Mainnet": 42220,
|
|
114
|
+
"Celo Sepolia Testnet": 11142220,
|
|
115
|
+
"Fraxtal Mainnet": 252,
|
|
116
|
+
"Fraxtal Hoodi Testnet": 2523,
|
|
117
|
+
"Gnosis": 100,
|
|
118
|
+
"Mantle Mainnet": 5000,
|
|
119
|
+
"Mantle Sepolia Testnet": 5003,
|
|
120
|
+
"Memecore Mainnet": 4352,
|
|
121
|
+
"Memecore Testnet": 43521,
|
|
122
|
+
"Moonbeam Mainnet": 1284,
|
|
123
|
+
"Moonriver Mainnet": 1285,
|
|
124
|
+
"Moonbase Alpha Testnet": 1287,
|
|
125
|
+
"opBNB Mainnet": 204,
|
|
126
|
+
"opBNB Testnet": 5611,
|
|
127
|
+
"Scroll Mainnet": 534352,
|
|
128
|
+
"Scroll Sepolia Testnet": 534351,
|
|
129
|
+
"Taiko Mainnet": 167000,
|
|
130
|
+
"Taiko Hoodi": 167013,
|
|
131
|
+
"XDC Mainnet": 50,
|
|
132
|
+
"XDC Apothem Testnet": 51,
|
|
133
|
+
"ApeChain Mainnet": 33139,
|
|
134
|
+
"ApeChain Curtis Testnet": 33111,
|
|
135
|
+
"World Mainnet": 480,
|
|
136
|
+
"World Sepolia Testnet": 4801,
|
|
137
|
+
"Sonic Mainnet": 146,
|
|
138
|
+
"Sonic Testnet": 14601,
|
|
139
|
+
"Unichain Mainnet": 130,
|
|
140
|
+
"Unichain Sepolia Testnet": 1301,
|
|
141
|
+
"Abstract Mainnet": 2741,
|
|
142
|
+
"Abstract Sepolia Testnet": 11124,
|
|
143
|
+
"Berachain Mainnet": 80094,
|
|
144
|
+
"Berachain Bepolia Testnet": 80069,
|
|
145
|
+
"Swellchain Mainnet": 1923,
|
|
146
|
+
"Swellchain Testnet": 1924,
|
|
147
|
+
"Monad Mainnet": 143,
|
|
148
|
+
"Monad Testnet": 10143,
|
|
149
|
+
"HyperEVM Mainnet": 999,
|
|
150
|
+
"Katana Mainnet": 747474,
|
|
151
|
+
"Katana Bokuto": 737373,
|
|
152
|
+
"Sei Mainnet": 1329,
|
|
153
|
+
"Sei Testnet": 1328,
|
|
154
|
+
"Stable Mainnet": 988,
|
|
155
|
+
"Stable Testnet": 2201,
|
|
156
|
+
"Plasma Mainnet": 9745,
|
|
157
|
+
"Plasma Testnet": 9746,
|
|
158
|
+
"MegaETH Mainnet": 4326,
|
|
159
|
+
"MegaETH Testnet": 6342,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
paid_only_chains = [
|
|
163
|
+
"BNB Smart Chain Mainnet",
|
|
164
|
+
"BNB Smart Chain Testnet",
|
|
165
|
+
"Base Mainnet",
|
|
166
|
+
"Base Sepolia Testnet",
|
|
167
|
+
"OP Mainnet",
|
|
168
|
+
"OP Sepolia Testnet",
|
|
169
|
+
"Avalanche C-Chain",
|
|
170
|
+
"Avalanche Fuji Testnet",
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
paid_only_set = {c.lower() for c in paid_only_chains}
|
|
174
|
+
|
|
175
|
+
chain_id_to_name = {v: k for k, v in chain_to_id.items()}
|
getsourcecode/filter.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from getsourcecode.handle import *
|
|
3
|
+
from getsourcecode.config import *
|
|
4
|
+
from retrying import retry
|
|
5
|
+
import certifi
|
|
6
|
+
|
|
7
|
+
current_path = os.getcwd()
|
|
8
|
+
ADDRESS_PATTERN = r'[\'\"]{1}[\s]{0,5}:[\s]{0,5}[\'\"]{1}(0x[a-zA-Z0-9)]{40})[\'\"]{1}'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_address(json_data):
|
|
12
|
+
try:
|
|
13
|
+
address_list = list(set(re.findall(ADDRESS_PATTERN, json_data)))
|
|
14
|
+
return address_list
|
|
15
|
+
except Exception as e:
|
|
16
|
+
handle_exception(e)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def read_file(file_path):
|
|
20
|
+
if os.path.isfile(file_path):
|
|
21
|
+
with open(file_path, 'r', encoding='utf-8') as fr:
|
|
22
|
+
return fr.read().replace('\n', ' ')
|
|
23
|
+
else:
|
|
24
|
+
raise FileNotFoundError("File not found: {}".format(file_path))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_addresses_from_input(input_file, add_string):
|
|
28
|
+
if input_file:
|
|
29
|
+
file_path = os.path.join(current_path, input_file)
|
|
30
|
+
add_str = read_file(file_path)
|
|
31
|
+
elif add_string:
|
|
32
|
+
add_str = add_string
|
|
33
|
+
else:
|
|
34
|
+
return None
|
|
35
|
+
return add_str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_addresses_by_file_or_string(input_file, is_tron, add_string,):
|
|
39
|
+
try:
|
|
40
|
+
add_str = get_addresses_from_input(input_file, add_string)
|
|
41
|
+
if add_str is None:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
if is_tron:
|
|
45
|
+
pattern = r'T[a-zA-Z\d]{33}'
|
|
46
|
+
else:
|
|
47
|
+
pattern = r'0x[a-zA-Z\d]{40}'
|
|
48
|
+
|
|
49
|
+
addresses = re.findall(pattern, add_str)
|
|
50
|
+
return addresses
|
|
51
|
+
except Exception as e:
|
|
52
|
+
handle_exception(e)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@retry(stop_max_attempt_number=5, wait_fixed=2000)
|
|
56
|
+
def get_by_tenderly_api_use_retry(tx_hash, proxies, network):
|
|
57
|
+
tenderly_api = f'https://api.tenderly.co/api/v1/public-contract/{tenderly_chain_id_list[network]}/tx/{tx_hash}'
|
|
58
|
+
tenderly_req = requests.get(tenderly_api, proxies=proxies, verify=False)
|
|
59
|
+
return tenderly_req.json()['addresses']
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@retry(stop_max_attempt_number=5, wait_fixed=2000)
|
|
63
|
+
def get_by_scan_use_re_use_retry(url, proxies):
|
|
64
|
+
header = {
|
|
65
|
+
"User-Agent": USER_AGENT
|
|
66
|
+
}
|
|
67
|
+
scan_req = requests.get(url, headers=header, proxies=proxies, verify=False)
|
|
68
|
+
return scan_req
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_by_scan_use_re(tx_hash, proxies, network):
|
|
72
|
+
try:
|
|
73
|
+
url = tx_hash_scan_config[network]['url'].format(tx_hash)
|
|
74
|
+
scan_req = get_by_scan_use_re_use_retry(url, proxies)
|
|
75
|
+
if tx_hash_scan_config[network]['re'] != "":
|
|
76
|
+
data = scan_req.text.replace("\r\n", "").replace(' ', '').replace('\n', '')
|
|
77
|
+
result = re.findall(r"{}".format(tx_hash_scan_config[network]['re']), data)[0]
|
|
78
|
+
else:
|
|
79
|
+
result = "{}".format(scan_req.json()["data"]["overview"]["internalTxns"])
|
|
80
|
+
if network == 'eth':
|
|
81
|
+
result = "[" + result + "]"
|
|
82
|
+
scan_address_list = get_address(result)
|
|
83
|
+
return scan_address_list
|
|
84
|
+
except Exception as e:
|
|
85
|
+
handle_exception(e)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@retry(stop_max_attempt_number=5, wait_fixed=2000)
|
|
89
|
+
def get_ronin_info_by_api_use_retry(tx_hash, start_index, size, header, proxies):
|
|
90
|
+
ronin_api = f'https://explorerv3-api.roninchain.com/tx/{tx_hash}/internal?from={start_index}&size={size}'
|
|
91
|
+
ronin_req = requests.get(ronin_api, headers=header, proxies=proxies, verify=False)
|
|
92
|
+
return ronin_req
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_by_special_way_ronin(tx_hash, proxies):
|
|
96
|
+
special_way_ronin_address_list = []
|
|
97
|
+
header = {
|
|
98
|
+
"User-Agent": USER_AGENT,
|
|
99
|
+
"Content-Type": "application/json"
|
|
100
|
+
}
|
|
101
|
+
try:
|
|
102
|
+
start_index = 0
|
|
103
|
+
size = 25
|
|
104
|
+
while True:
|
|
105
|
+
ronin_req = get_ronin_info_by_api_use_retry(tx_hash, start_index, size, header, proxies)
|
|
106
|
+
for ronin_item in ronin_req.json()['results']:
|
|
107
|
+
special_way_ronin_address_list.append(ronin_item['from'])
|
|
108
|
+
special_way_ronin_address_list.append(ronin_item['to'])
|
|
109
|
+
total = ronin_req.json()["total"]
|
|
110
|
+
rest = total - (start_index + 1) * 25
|
|
111
|
+
if rest <= 0:
|
|
112
|
+
break
|
|
113
|
+
start_index = start_index + size
|
|
114
|
+
return special_way_ronin_address_list
|
|
115
|
+
except Exception as e:
|
|
116
|
+
handle_exception(e)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@retry(stop_max_attempt_number=5, wait_fixed=2000)
|
|
120
|
+
def get_klaytn_block_by_api_use_retry(tx_hash, proxies):
|
|
121
|
+
klaytn_block_api = f"https://api-cypress.klaytnscope.com/v2/txs/{tx_hash}"
|
|
122
|
+
klaytn_block_req = requests.get(klaytn_block_api, proxies=proxies, verify=False)
|
|
123
|
+
return klaytn_block_req.json()["result"]["blockNumber"]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@retry(stop_max_attempt_number=5, wait_fixed=2000)
|
|
127
|
+
def get_klaytn_trance_by_api_use_retry(tx_hash, proxies, klaytn_block):
|
|
128
|
+
klaytn_trance_api = f"https://api-cypress.klaytnscope.com/v2/blocks/{klaytn_block}/itxDetail?txHash={tx_hash}"
|
|
129
|
+
klaytn_trance_req = requests.get(klaytn_trance_api, proxies=proxies, verify=False)
|
|
130
|
+
return klaytn_trance_req
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def get_by_special_way_klaytn(tx_hash, proxies):
|
|
134
|
+
special_way_klaytn_address_list = []
|
|
135
|
+
try:
|
|
136
|
+
klaytn_block = get_klaytn_block_by_api_use_retry(tx_hash, proxies)
|
|
137
|
+
klaytn_trance_req = get_klaytn_trance_by_api_use_retry(tx_hash, proxies, klaytn_block)
|
|
138
|
+
for klaytn_item in klaytn_trance_req.json()["result"]:
|
|
139
|
+
special_way_klaytn_address_list.append(klaytn_item['fromAddress'])
|
|
140
|
+
special_way_klaytn_address_list.append(klaytn_item['toAddress'])
|
|
141
|
+
return special_way_klaytn_address_list
|
|
142
|
+
except Exception as e:
|
|
143
|
+
handle_exception(e)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_by_special_way(tx_hash, proxies, network):
|
|
147
|
+
special_address_list = []
|
|
148
|
+
if network == "ronin":
|
|
149
|
+
special_address_list = get_by_special_way_ronin(tx_hash, proxies)
|
|
150
|
+
elif network == "klaytn":
|
|
151
|
+
special_address_list = get_by_special_way_klaytn(tx_hash, proxies)
|
|
152
|
+
return special_address_list
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def get_addresses_by_tx(tx_hash, network, output_folder):
|
|
156
|
+
temp_addresses_list = []
|
|
157
|
+
proxies = get_proxies()
|
|
158
|
+
if network in tenderly_chain_id_list.keys():
|
|
159
|
+
temp_addresses_list = get_by_tenderly_api_use_retry(tx_hash, proxies, network)
|
|
160
|
+
elif network in tx_hash_scan_config.keys():
|
|
161
|
+
temp_addresses_list = get_by_scan_use_re(tx_hash, proxies, network)
|
|
162
|
+
elif network in special_trace_api.keys():
|
|
163
|
+
temp_addresses_list = get_by_special_way(tx_hash, proxies, network)
|
|
164
|
+
|
|
165
|
+
if temp_addresses_list:
|
|
166
|
+
temp_addresses_list = list(set(temp_addresses_list))
|
|
167
|
+
send_request(temp_addresses_list, output_folder, network)
|
|
168
|
+
else:
|
|
169
|
+
print(f"{network} is not supported (at least for now).")
|