Repository navigation
Expand file tree
/
Copy pathfetch_xlend_nfts.py
More file actions
190 lines (156 loc) · 7.84 KB
/
Copy pathfetch_xlend_nfts.py
File metadata and controls
190 lines (156 loc) · 7.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/env python3
import asyncio
import aiohttp
import json
import base64
import argparse
from typing import List, Optional
from asyncio import Semaphore
from datetime import datetime
# Configuration
GATEWAY_BASE_URL = "https://gateway.multiversx.com"
MAX_CONCURRENT_REQUESTS = 5
REQUEST_DELAY = 0.1
class XLendNFTFetcher:
def __init__(self):
self.semaphore = Semaphore(MAX_CONCURRENT_REQUESTS)
async def fetch_nfts_for_address(self, session: aiohttp.ClientSession, address: str) -> Optional[str]:
"""Fetch NFTs for a specific address and look for XLEND-18dc6f collection NFTs only"""
url = f"{GATEWAY_BASE_URL}/address/{address}/registered-nfts"
async with self.semaphore:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as response:
if response.status == 200:
data = await response.json()
# Handle different response formats
nfts = []
if isinstance(data, dict):
if 'data' in data:
nfts = data['data']
elif 'nfts' in data:
nfts = data['nfts']
elif isinstance(data, list):
nfts = data
# Look specifically for XLEND-18dc6f collection NFTs
for nft in nfts:
if isinstance(nft, dict):
identifier = nft.get('identifier', '')
if identifier.startswith('XLEND-18dc6f'):
return identifier
elif isinstance(nft, str) and nft.startswith('XLEND-18dc6f'):
return nft
return None
else:
print(f"Failed to get NFTs for {address}: {response.status}")
return None
except Exception as e:
print(f"Error fetching NFTs for {address}: {e}")
return None
async def fetch_nft_details(self, session: aiohttp.ClientSession, nft_identifier: str) -> Optional[dict]:
"""Fetch detailed information about a specific NFT"""
# Extract token and nonce from identifier (e.g., "XLEND-18dc6f-456" -> token="XLEND-18dc6f", nonce="456")
parts = nft_identifier.split('-')
if len(parts) < 3:
return None
token = '-'.join(parts[:-1]) # Everything except the last part
nonce = parts[-1] # Last part is the nonce
url = f"{GATEWAY_BASE_URL}/nft/{token}/nonce/{nonce}"
async with self.semaphore:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as response:
if response.status == 200:
data = await response.json()
return data
else:
print(f"Failed to get NFT details for {nft_identifier}: {response.status}")
return None
except Exception as e:
print(f"Error fetching NFT details for {nft_identifier}: {e}")
return None
def extract_utk_info_from_nft(self, nft_details: dict) -> Optional[dict]:
"""Extract UTK supply information from NFT details"""
try:
# Check various possible locations for UTK information
attributes = nft_details.get('attributes', '')
if attributes:
# Decode base64 attributes if needed
try:
decoded_attributes = base64.b64decode(attributes).decode('utf-8')
if 'UTK' in decoded_attributes or 'utk' in decoded_attributes.lower():
return {'source': 'attributes', 'data': decoded_attributes}
except:
pass
# Check metadata
metadata = nft_details.get('metadata', {})
if metadata:
for key, value in metadata.items():
if 'utk' in str(key).lower() or 'utk' in str(value).lower():
return {'source': 'metadata', 'key': key, 'value': value}
# Check tags
tags = nft_details.get('tags', [])
if tags:
for tag in tags:
if 'utk' in str(tag).lower():
return {'source': 'tags', 'tag': tag}
return None
except Exception as e:
print(f"Error extracting UTK info from NFT: {e}")
return None
async def process_supply_data(self, input_file: str = 'xlend_supply_data.json'):
"""Process existing supply data and fetch XLEND NFTs for each address"""
print("Loading existing supply data...")
try:
with open(input_file, 'r') as f:
data = json.load(f)
except FileNotFoundError:
print(f"File {input_file} not found")
return
except json.JSONDecodeError:
print(f"Invalid JSON in {input_file}")
return
supply_data = data.get('supply_data', [])
if not supply_data:
print("No supply data found in the file")
return
print(f"Found {len(supply_data)} supply records to process")
# Get unique addresses
addresses = list(set([item['address'] for item in supply_data if item.get('address')]))
print(f"Found {len(addresses)} unique addresses")
async with aiohttp.ClientSession() as session:
for i, address in enumerate(addresses):
print(f"Processing address {i+1}/{len(addresses)}: {address}")
# Fetch XLEND NFTs for this address
xlend_nft = await self.fetch_nfts_for_address(session, address)
if xlend_nft:
print(f"Found XLEND NFT for {address}: {xlend_nft}")
# Fetch NFT details to check for UTK supply information
nft_details = await self.fetch_nft_details(session, xlend_nft)
if nft_details:
# Look for UTK supply information in NFT attributes or metadata
utk_info = self.extract_utk_info_from_nft(nft_details)
if utk_info:
print(f"Found UTK info in NFT: {utk_info}")
# Update all supply data entries for this address
for item in supply_data:
if item['address'] == address:
item['NFT'] = xlend_nft
else:
print(f"No XLEND NFT found for {address}")
# Add delay to avoid rate limiting
await asyncio.sleep(REQUEST_DELAY)
# Save updated data
data['supply_data'] = supply_data
data['timestamp'] = json.dumps(datetime.now().isoformat())
output_file = 'xlend_supply_data_with_nfts.json'
with open(output_file, 'w') as f:
json.dump(data, f, indent=2)
print(f"Updated data saved to {output_file}")
async def main():
parser = argparse.ArgumentParser(description='Fetch XLEND NFTs for addresses in supply data')
parser.add_argument('--input', default='xlend_supply_data.json',
help='Input file with supply data')
args = parser.parse_args()
fetcher = XLendNFTFetcher()
await fetcher.process_supply_data(args.input)
if __name__ == "__main__":
asyncio.run(main())