gxurxv commited on
Commit
e06912b
·
verified ·
1 Parent(s): b8d3277

update daily tnxs and DAA for mode

Browse files
Files changed (1) hide show
  1. app_trans_new.py +140 -45
app_trans_new.py CHANGED
@@ -14,17 +14,22 @@ from itertools import product
14
  OPTIMISM_RPC_URL = os.getenv('OPTIMISM_RPC_URL')
15
  BASE_RPC_URL = os.getenv('BASE_RPC_URL')
16
  ETH_RPC_URL = os.getenv('ETH_RPC_URL')
 
 
 
17
 
18
  # Initialize Web3 instances
19
  print("Initializing Web3 instances...")
20
  web3_optimism = Web3(Web3.HTTPProvider(OPTIMISM_RPC_URL))
21
  web3_base = Web3(Web3.HTTPProvider(BASE_RPC_URL))
22
  web3_eth = Web3(Web3.HTTPProvider(ETH_RPC_URL))
 
23
 
24
  # Contract addresses for service registries
25
  contract_address_optimism = '0x3d77596beb0f130a4415df3D2D8232B3d3D31e44'
26
  contract_address_base = '0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE'
27
  contract_address_eth = '0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA'
 
28
 
29
  # Load the ABI from a local JSON file
30
  with open('./contracts/service_registry_abi.json', 'r') as abi_file:
@@ -34,6 +39,7 @@ with open('./contracts/service_registry_abi.json', 'r') as abi_file:
34
  service_registry_optimism = web3_optimism.eth.contract(address=contract_address_optimism, abi=contract_abi)
35
  service_registry_base = web3_base.eth.contract(address=contract_address_base, abi=contract_abi)
36
  service_registry_eth = web3_eth.eth.contract(address=contract_address_eth, abi=contract_abi)
 
37
  print("Service registry contracts loaded.")
38
 
39
  # Check if connection is successful
@@ -43,37 +49,50 @@ if not web3_base.is_connected():
43
  raise Exception("Failed to connect to the Base network.")
44
  if not web3_eth.is_connected():
45
  raise Exception("Failed to connect to the ETH network.")
46
- print("Successfully connected to Ethereum, Optimism, and Base networks.")
 
 
 
47
 
48
 
49
  def fetch_service_safes(web3, registry_contract):
50
  print("\nFetching service safes...")
51
  total_services = registry_contract.functions.totalSupply().call()
52
  print(f"Total services: {total_services}")
53
- service_safes = set()
54
-
 
55
  for service_id in range(1, total_services + 1):
56
  print(f"Processing service ID: {service_id}")
57
  service = registry_contract.functions.getService(service_id).call()
58
  agent_ids = service[-1] # Assuming the last element is the list of agent IDs
59
  print(f"Agent IDs: {agent_ids}")
60
 
61
- if 40 in agent_ids:
62
- agent_address = registry_contract.functions.getAgentInstances(service_id).call()
63
  service_safe = service[1]
64
- print(f"Found agent_address: {agent_address}")
65
- print(f"Found service safe: {service_safe}")
66
- service_safes.add(service_safe)
 
 
 
 
 
 
 
 
67
 
68
- print(f"Total service safes found: {len(service_safes)}")
69
- return service_safes
70
 
71
  # Fetch service safes for each network
72
  service_safes_optimism = fetch_service_safes(web3_optimism, service_registry_optimism)
73
  service_safes_base = fetch_service_safes(web3_base, service_registry_base)
74
  service_safes_eth = fetch_service_safes(web3_eth, service_registry_eth)
75
- service_safes_eth = {safe for safe in service_safes_eth if safe.lower() != '0x0000000000000000000000000000000000000000'}
76
-
 
77
  def get_block_range_for_date(chain_id, date_str, api_key, base_url):
78
  """Get the block range for a specific date."""
79
  target_date = datetime.strptime(date_str, "%Y-%m-%d").date()
@@ -122,12 +141,22 @@ def get_block_range_for_date(chain_id, date_str, api_key, base_url):
122
 
123
  return start_block, end_block
124
 
 
 
 
 
 
 
 
 
 
125
  def get_transactions(api_keys, wallet_address, chain_name, start_block, end_block):
126
  """Retrieve transactions for the given wallet address, chain, and block range using the Etherscan or similar API."""
127
  base_url = {
128
  'optimism': "https://api-optimistic.etherscan.io/api",
129
  'base': "https://api.basescan.org/api",
130
- 'ethereum': "https://api.etherscan.io/api"
 
131
  }.get(chain_name)
132
 
133
  if not base_url:
@@ -157,6 +186,34 @@ def get_transactions(api_keys, wallet_address, chain_name, start_block, end_bloc
157
 
158
  return valid_transactions
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  def date_range(start_date, end_date):
161
  """Generates a range of dates from start_date to end_date inclusive."""
162
  start_dt = datetime.strptime(start_date, "%Y-%m-%d")
@@ -171,13 +228,15 @@ def fetch_transactions():
171
  api_keys = {
172
  'optimism': 'XQ72JA5XZ51QC7TG1W295AAIF4KTV92K1K',
173
  'base': '4BFQMVW1QUKEPVDA4VW711CF4462682CY8',
174
- 'ethereum': '3GRYJGX55W3QWCEKGREF4H53AFHCAIVVR7'
 
175
  }
176
 
177
  base_urls = {
178
  10: "https://api-optimistic.etherscan.io/api",
179
  8453: "https://api.basescan.org/api",
180
- 1: "https://api.etherscan.io/api"
 
181
  }
182
 
183
  current_date = datetime.today().strftime("%Y-%m-%d")
@@ -199,7 +258,8 @@ def fetch_transactions():
199
  chains = {
200
  10: ('optimism', service_safes_optimism),
201
  8453: ('base', service_safes_base),
202
- 1: ('ethereum', service_safes_eth)
 
203
  }
204
 
205
  all_transactions = df_existing.to_dict('records') if not df_existing.empty else []
@@ -208,36 +268,60 @@ def fetch_transactions():
208
  base_url = base_urls[chain_id]
209
  api_key = api_keys[chain_name]
210
 
211
- for safe_address in service_safes:
212
- print(f"\nProcessing {chain_name.capitalize()} for safe address {safe_address}...")
 
 
 
213
  for single_date in date_range(start_date, current_date):
214
- start_block, end_block = get_block_range_for_date(chain_id, single_date, api_key, base_url)
215
- if start_block is None or end_block is None:
216
- print(f"Skipping date {single_date} for chain {chain_name} due to missing block data.")
217
- continue
218
-
219
- print(f"Start Block: {start_block}, End Block: {end_block} for date {single_date}")
220
-
221
- transactions = get_transactions(api_keys, safe_address, chain_name, start_block, end_block)
222
-
 
 
 
 
223
  if transactions:
224
  print(f"Found {len(transactions)} transactions on {single_date} for {chain_name.capitalize()} safe address {safe_address}:")
225
  for tx in transactions:
226
- tx_time = datetime.fromtimestamp(int(tx['timeStamp']))
227
- all_transactions.append({
228
- 'chain': chain_name,
229
- 'safe_address': safe_address,
230
- 'date': single_date,
231
- 'transaction_hash': tx['hash'],
232
- 'timestamp': tx_time,
233
- 'from': tx['from'],
234
- 'to': tx['to'],
235
- 'value_eth': int(tx['value']) / 1e18 # Convert value to ETH
236
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  else:
238
- print(f"No transactions found for safe address {safe_address} on {single_date} on {chain_name.capitalize()}.")
239
 
240
  df_transactions_new = pd.DataFrame(all_transactions)
 
241
  df_transactions_new.to_csv(csv_filename, index=False)
242
  return df_transactions_new
243
 
@@ -250,7 +334,7 @@ def create_transcation_visualizations():
250
  daily_counts = df_transactions_new.groupby([df_transactions_new['timestamp'].dt.date, 'chain']).size().unstack(fill_value=0)
251
 
252
  # Ensure required chains are present
253
- chains = ['optimism', 'base', 'ethereum']
254
  for chain in chains:
255
  if chain not in daily_counts.columns:
256
  daily_counts[chain] = 0
@@ -288,7 +372,7 @@ def create_transcation_visualizations():
288
  new_rows.extend([slot1])
289
  slot2 = row.copy()
290
  if slot2['timestamp'].dayofweek == 6: # 6 represents Sunday
291
- slot2[['optimism', 'base', 'ethereum']] = 0
292
  slot2['timestamp'] = row['timestamp'].replace(hour=12)
293
  new_rows.extend([slot2])
294
 
@@ -299,7 +383,7 @@ def create_transcation_visualizations():
299
 
300
  # Prepare data for plotting
301
  dates = hourly_counts['timestamp'].tolist()
302
- values = hourly_counts[['optimism', 'base', 'ethereum']].to_numpy()
303
 
304
  # Create the figure
305
  fig = go.Figure()
@@ -354,6 +438,17 @@ def create_transcation_visualizations():
354
  textposition='none',
355
  ))
356
 
 
 
 
 
 
 
 
 
 
 
 
357
  # Update layout with numeric x-axis
358
  fig.update_layout(
359
  title='Chain Daily Activity : Transactions',
@@ -397,7 +492,7 @@ def create_active_agents_visualizations():
397
  df_transactions_new['weekday'] = df_transactions_new['timestamp'].dt.weekday
398
 
399
  # Count unique agents per day
400
- daily_agents = df_transactions_new.groupby(['week_start', 'weekday'])['from'].nunique().reset_index()
401
 
402
  # Generate all possible combinations of week_start and weekday up to today
403
  today = datetime.today()
@@ -410,8 +505,8 @@ def create_active_agents_visualizations():
410
  daily_agents = all_combinations.merge(daily_agents, on=['week_start', 'weekday'], how='left').fillna(0)
411
 
412
  # Compute average unique agents per week
413
- weekly_avg_agents = daily_agents.groupby('week_start')['from'].mean().reset_index()
414
- weekly_avg_agents.rename(columns={'from': 'avg_daily_active_agents'}, inplace=True)
415
 
416
  # Prepare data for plotting
417
  weeks = weekly_avg_agents['week_start'].unique()
 
14
  OPTIMISM_RPC_URL = os.getenv('OPTIMISM_RPC_URL')
15
  BASE_RPC_URL = os.getenv('BASE_RPC_URL')
16
  ETH_RPC_URL = os.getenv('ETH_RPC_URL')
17
+ MODE_RPC_URL = os.getenv('MODE_RPC_URL')
18
+
19
+
20
 
21
  # Initialize Web3 instances
22
  print("Initializing Web3 instances...")
23
  web3_optimism = Web3(Web3.HTTPProvider(OPTIMISM_RPC_URL))
24
  web3_base = Web3(Web3.HTTPProvider(BASE_RPC_URL))
25
  web3_eth = Web3(Web3.HTTPProvider(ETH_RPC_URL))
26
+ web3_mode = Web3(Web3.HTTPProvider(MODE_RPC_URL)) # New chain
27
 
28
  # Contract addresses for service registries
29
  contract_address_optimism = '0x3d77596beb0f130a4415df3D2D8232B3d3D31e44'
30
  contract_address_base = '0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE'
31
  contract_address_eth = '0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA'
32
+ contract_address_mode = '0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE' # New chain
33
 
34
  # Load the ABI from a local JSON file
35
  with open('./contracts/service_registry_abi.json', 'r') as abi_file:
 
39
  service_registry_optimism = web3_optimism.eth.contract(address=contract_address_optimism, abi=contract_abi)
40
  service_registry_base = web3_base.eth.contract(address=contract_address_base, abi=contract_abi)
41
  service_registry_eth = web3_eth.eth.contract(address=contract_address_eth, abi=contract_abi)
42
+ service_registry_mode = web3_mode.eth.contract(address=contract_address_mode, abi=contract_abi) # New chain
43
  print("Service registry contracts loaded.")
44
 
45
  # Check if connection is successful
 
49
  raise Exception("Failed to connect to the Base network.")
50
  if not web3_eth.is_connected():
51
  raise Exception("Failed to connect to the ETH network.")
52
+ if not web3_mode.is_connected():
53
+ raise Exception("Failed to connect to the Mode network.") # New chain
54
+ print("Successfully connected to Ethereum, Optimism, Base, and Mode networks.")
55
+
56
 
57
 
58
  def fetch_service_safes(web3, registry_contract):
59
  print("\nFetching service safes...")
60
  total_services = registry_contract.functions.totalSupply().call()
61
  print(f"Total services: {total_services}")
62
+ service_safes_dict = {}
63
+ zero_address = '0x0000000000000000000000000000000000000000'
64
+
65
  for service_id in range(1, total_services + 1):
66
  print(f"Processing service ID: {service_id}")
67
  service = registry_contract.functions.getService(service_id).call()
68
  agent_ids = service[-1] # Assuming the last element is the list of agent IDs
69
  print(f"Agent IDs: {agent_ids}")
70
 
71
+ if 40 in agent_ids or 25 in agent_ids:
72
+ agent_instance_data = registry_contract.functions.getAgentInstances(service_id).call()
73
  service_safe = service[1]
74
+ agent_addresses = agent_instance_data[1]
75
+ if agent_addresses:
76
+ agent_address = agent_addresses[0]
77
+ if service_safe != zero_address:
78
+ print(f"Found agent_address: {agent_address}")
79
+ print(f"Found service safe: {service_safe}")
80
+ service_safes_dict[agent_address] = service_safe
81
+ else:
82
+ print(f"Found zero address for service safe, skipping for agent: {agent_address}")
83
+ else:
84
+ print(f"No agent address found for service ID: {service_id}")
85
 
86
+ print(f"Total unique agent addresses found (excluding zero safe addresses): {len(service_safes_dict)}")
87
+ return service_safes_dict
88
 
89
  # Fetch service safes for each network
90
  service_safes_optimism = fetch_service_safes(web3_optimism, service_registry_optimism)
91
  service_safes_base = fetch_service_safes(web3_base, service_registry_base)
92
  service_safes_eth = fetch_service_safes(web3_eth, service_registry_eth)
93
+ service_safes_mode = fetch_service_safes(web3_mode, service_registry_mode)
94
+ # service_safes_eth = {safe for safe in service_safes_eth if safe.lower() != '0x0000000000000000000000000000000000000000'}
95
+ print(f"Service safes for Mode: {service_safes_mode}")
96
  def get_block_range_for_date(chain_id, date_str, api_key, base_url):
97
  """Get the block range for a specific date."""
98
  target_date = datetime.strptime(date_str, "%Y-%m-%d").date()
 
141
 
142
  return start_block, end_block
143
 
144
+ def get_transactions_mode_all(address):
145
+ url = f'https://explorer.mode.network/api/v2/addresses/{address}/transactions'
146
+ headers = {
147
+ 'accept': 'application/json'
148
+ }
149
+
150
+ response = requests.get(url, headers=headers)
151
+ return response.json()['items']
152
+
153
  def get_transactions(api_keys, wallet_address, chain_name, start_block, end_block):
154
  """Retrieve transactions for the given wallet address, chain, and block range using the Etherscan or similar API."""
155
  base_url = {
156
  'optimism': "https://api-optimistic.etherscan.io/api",
157
  'base': "https://api.basescan.org/api",
158
+ 'ethereum': "https://api.etherscan.io/api",
159
+ 'mode': "https://eth-sepolia.blockscout.com/api"
160
  }.get(chain_name)
161
 
162
  if not base_url:
 
186
 
187
  return valid_transactions
188
 
189
+ def get_mode_transactions(transactions_all_base,date_str):
190
+ target_date = datetime.strptime(date_str, "%Y-%m-%d").date()
191
+ start_of_day = datetime.combine(target_date, datetime.min.time())
192
+
193
+ if target_date == datetime.now().date():
194
+ end_of_day = datetime.now() # Use the current time if the target date is today
195
+ else:
196
+ end_of_day = datetime.combine(target_date, datetime.max.time())
197
+
198
+ start_timestamp = start_of_day.isoformat()
199
+ end_timestamp = end_of_day.isoformat()
200
+ processed_list = []
201
+ for transaction in transactions_all_base:
202
+ # Filter transactions based on the timestamp
203
+ if start_timestamp <= transaction['timestamp'] <= end_timestamp:
204
+ transaction_timestamp = datetime.strptime(transaction['timestamp'], "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S")
205
+ processed_transaction = {
206
+ 'hash': transaction['hash'],
207
+ 'timeStamp': transaction_timestamp,
208
+ 'from': transaction['from']['hash'],
209
+ 'to': transaction['to']['hash'],
210
+ 'value': transaction['value']
211
+ }
212
+ processed_list.append(processed_transaction)
213
+
214
+ return processed_list
215
+
216
+
217
  def date_range(start_date, end_date):
218
  """Generates a range of dates from start_date to end_date inclusive."""
219
  start_dt = datetime.strptime(start_date, "%Y-%m-%d")
 
228
  api_keys = {
229
  'optimism': 'XQ72JA5XZ51QC7TG1W295AAIF4KTV92K1K',
230
  'base': '4BFQMVW1QUKEPVDA4VW711CF4462682CY8',
231
+ 'ethereum': '3GRYJGX55W3QWCEKGREF4H53AFHCAIVVR7',
232
+ 'mode': 'f651444d-2916-4f37-bfd8-e70cc8232eb7'
233
  }
234
 
235
  base_urls = {
236
  10: "https://api-optimistic.etherscan.io/api",
237
  8453: "https://api.basescan.org/api",
238
+ 1: "https://api.etherscan.io/api",
239
+ 3443: "https://eth-sepolia.blockscout.com/api"
240
  }
241
 
242
  current_date = datetime.today().strftime("%Y-%m-%d")
 
258
  chains = {
259
  10: ('optimism', service_safes_optimism),
260
  8453: ('base', service_safes_base),
261
+ 1: ('ethereum', service_safes_eth),
262
+ 3443: ('mode', service_safes_mode)
263
  }
264
 
265
  all_transactions = df_existing.to_dict('records') if not df_existing.empty else []
 
268
  base_url = base_urls[chain_id]
269
  api_key = api_keys[chain_name]
270
 
271
+ for agent_address, safe_address in service_safes.items():
272
+ print(f"\nProcessing {chain_name.capitalize()} for agent address {agent_address} (safe address {safe_address})...")
273
+ if chain_name == 'mode':
274
+ transactions_all_base = get_transactions_mode_all(safe_address)
275
+
276
  for single_date in date_range(start_date, current_date):
277
+ if chain_name == 'mode':
278
+ print(f"Processing date {single_date} for chain {chain_name}...")
279
+ transactions = get_mode_transactions(transactions_all_base,single_date)
280
+
281
+ else:
282
+ print(f"Processing date {single_date} for chain {chain_name}...")
283
+ start_block, end_block = get_block_range_for_date(chain_id, single_date, api_key, base_url)
284
+ if start_block is None or end_block is None:
285
+ print(f"Skipping date {single_date} for chain {chain_name} due to missing block data.")
286
+ continue
287
+ print(f"Start Block: {start_block}, End Block: {end_block} for date {single_date}")
288
+ transactions = get_transactions(api_keys, safe_address, chain_name, start_block, end_block)
289
+
290
  if transactions:
291
  print(f"Found {len(transactions)} transactions on {single_date} for {chain_name.capitalize()} safe address {safe_address}:")
292
  for tx in transactions:
293
+ if chain_name != 'mode':
294
+ print(f"Transaction Hash: {tx['hash']} on {chain_name.capitalize()} at {tx['timeStamp']}")
295
+ tx_time = datetime.fromtimestamp(int(tx['timeStamp']))
296
+ all_transactions.append({
297
+ 'chain': chain_name,
298
+ 'agent_address': agent_address,
299
+ 'safe_address': safe_address,
300
+ 'date': single_date,
301
+ 'transaction_hash': tx['hash'],
302
+ 'timestamp': tx_time,
303
+ 'from': tx['from'],
304
+ 'to': tx['to'],
305
+ 'value_eth': int(tx['value']) / 1e18 # Convert value to ETH
306
+ })
307
+ else:
308
+ all_transactions.append({
309
+ 'chain': chain_name,
310
+ 'agent_address': agent_address,
311
+ 'safe_address': safe_address,
312
+ 'date': single_date,
313
+ 'transaction_hash': tx['hash'],
314
+ 'timestamp': tx['timeStamp'],
315
+ 'from': tx['from'],
316
+ 'to': tx['to'],
317
+ 'value_eth': int(tx['value']) / 1e18 # Convert value to ETH
318
+ })
319
+
320
  else:
321
+ print(f"No transactions found for agent address {agent_address} (safe address {safe_address}) on {single_date} on {chain_name.capitalize()}.")
322
 
323
  df_transactions_new = pd.DataFrame(all_transactions)
324
+ df_transactions_new = df_transactions_new[df_transactions_new['date'] != '2024-11-20']
325
  df_transactions_new.to_csv(csv_filename, index=False)
326
  return df_transactions_new
327
 
 
334
  daily_counts = df_transactions_new.groupby([df_transactions_new['timestamp'].dt.date, 'chain']).size().unstack(fill_value=0)
335
 
336
  # Ensure required chains are present
337
+ chains = ['optimism', 'base', 'ethereum', 'mode']
338
  for chain in chains:
339
  if chain not in daily_counts.columns:
340
  daily_counts[chain] = 0
 
372
  new_rows.extend([slot1])
373
  slot2 = row.copy()
374
  if slot2['timestamp'].dayofweek == 6: # 6 represents Sunday
375
+ slot2[chains] = 0
376
  slot2['timestamp'] = row['timestamp'].replace(hour=12)
377
  new_rows.extend([slot2])
378
 
 
383
 
384
  # Prepare data for plotting
385
  dates = hourly_counts['timestamp'].tolist()
386
+ values = hourly_counts[chains].to_numpy()
387
 
388
  # Create the figure
389
  fig = go.Figure()
 
438
  textposition='none',
439
  ))
440
 
441
+ fig.add_trace(go.Bar(
442
+ name='Mode',
443
+ x=x_numeric,
444
+ y=values[:,3],
445
+ marker_color='orange',
446
+ opacity=0.7,
447
+ text=None,
448
+ width=width_array,
449
+ textposition='none',
450
+ ))
451
+
452
  # Update layout with numeric x-axis
453
  fig.update_layout(
454
  title='Chain Daily Activity : Transactions',
 
492
  df_transactions_new['weekday'] = df_transactions_new['timestamp'].dt.weekday
493
 
494
  # Count unique agents per day
495
+ daily_agents = df_transactions_new.groupby(['week_start', 'weekday'])['agent_address'].nunique().reset_index()
496
 
497
  # Generate all possible combinations of week_start and weekday up to today
498
  today = datetime.today()
 
505
  daily_agents = all_combinations.merge(daily_agents, on=['week_start', 'weekday'], how='left').fillna(0)
506
 
507
  # Compute average unique agents per week
508
+ weekly_avg_agents = daily_agents.groupby('week_start')['agent_address'].mean().reset_index()
509
+ weekly_avg_agents.rename(columns={'agent_address': 'avg_daily_active_agents'}, inplace=True)
510
 
511
  # Prepare data for plotting
512
  weeks = weekly_avg_agents['week_start'].unique()