gauravlochab commited on
Commit
5fbddca
1 Parent(s): 3893ff1

feat: Add delay between API requests for block retrieval

Browse files
Files changed (1) hide show
  1. app.py +289 -222
app.py CHANGED
@@ -5,248 +5,305 @@ import plotly.express as px
5
  from datetime import datetime, timedelta
6
  import json
7
  from web3 import Web3
8
- import time
9
- # RPC URLs
10
  OPTIMISM_RPC_URL = 'https://opt-mainnet.g.alchemy.com/v2/U5gnXPYxeyH43MJ9tP8ONBQHEDRav7H0'
11
- BASE_RPC_URL = 'https://base-mainnet.g.alchemy.com/v2/U5gnXPYxeyH43MJ9tP8ONBQHEDRav7H0'
12
- ETH_RPC_URL = 'https://eth-mainnet.g.alchemy.com/v2/U5gnXPYxeyH43MJ9tP8ONBQHEDRav7H0'
13
 
14
- # Initialize Web3 instances
15
- print("Initializing Web3 instances...")
16
- web3_optimism = Web3(Web3.HTTPProvider(OPTIMISM_RPC_URL))
17
- web3_base = Web3(Web3.HTTPProvider(BASE_RPC_URL))
18
- web3_eth = Web3(Web3.HTTPProvider(ETH_RPC_URL))
 
19
 
20
- # Contract addresses for service registries
21
- contract_address_optimism = '0x3d77596beb0f130a4415df3D2D8232B3d3D31e44'
22
- contract_address_base = '0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE'
23
- contract_address_eth = '0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA'
24
 
25
- # Load the ABI from a local JSON file
26
  with open('service_registry_abi.json', 'r') as abi_file:
27
  contract_abi = json.load(abi_file)
28
 
29
- # Create the contract instances
30
- service_registry_optimism = web3_optimism.eth.contract(address=contract_address_optimism, abi=contract_abi)
31
- service_registry_base = web3_base.eth.contract(address=contract_address_base, abi=contract_abi)
32
- service_registry_eth = web3_eth.eth.contract(address=contract_address_eth, abi=contract_abi)
33
- print("Service registry contracts loaded.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- # Check if connection is successful
36
- if not web3_optimism.is_connected():
37
- raise Exception("Failed to connect to the Optimism network.")
38
- if not web3_base.is_connected():
39
- raise Exception("Failed to connect to the Base network.")
40
- if not web3_eth.is_connected():
41
- raise Exception("Failed to connect to the ETH network.")
42
- print("Successfully connected to Ethereum, Optimism, and Base networks.")
43
 
 
 
 
 
 
44
 
45
- def fetch_service_safes(web3, registry_contract):
46
- print("\nFetching service safes...")
47
- total_services = registry_contract.functions.totalSupply().call()
48
- print(f"Total services: {total_services}")
49
- service_safes = set()
50
 
51
  for service_id in range(1, total_services + 1):
52
- print(f"Processing service ID: {service_id}")
53
- service = registry_contract.functions.getService(service_id).call()
 
54
  agent_ids = service[-1] # Assuming the last element is the list of agent IDs
55
- print(f"Agent IDs: {agent_ids}")
56
 
 
57
  if 25 in agent_ids:
58
- agent_address = registry_contract.functions.getAgentInstances(service_id).call()
59
- service_safe = service[1]
60
- print(f"Found agent_address: {agent_address}")
61
- print(f"Found service safe: {service_safe}")
62
- service_safes.add(service_safe)
63
-
64
- print(f"Total service safes found: {len(service_safes)}")
65
- return service_safes
66
-
67
- # Fetch service safes for each network
68
- service_safes_optimism = fetch_service_safes(web3_optimism, service_registry_optimism)
69
- service_safes_base = fetch_service_safes(web3_base, service_registry_base)
70
- service_safes_eth = fetch_service_safes(web3_eth, service_registry_eth)
71
- service_safes_eth = {safe for safe in service_safes_eth if safe.lower() != '0x0000000000000000000000000000000000000000'}
72
-
73
- def get_block_range_for_date(chain_id, date_str, api_key, base_url):
74
- """Get the block range for a specific date."""
75
- target_date = datetime.strptime(date_str, "%Y-%m-%d")
76
- start_of_day = datetime.combine(target_date, datetime.min.time())
77
- end_of_day = datetime.combine(target_date, datetime.max.time())
78
-
79
- start_timestamp = int(start_of_day.timestamp())
80
- end_timestamp = int(end_of_day.timestamp())
81
-
82
- # Get start block
83
-
84
- start_response = requests.get(
85
- f"{base_url}?module=block&action=getblocknobytime&timestamp={start_timestamp}&closest=before&apikey={api_key}"
86
- )
87
- if start_response.status_code == 200:
88
- start_data = start_response.json()
89
- start_block = start_data.get('result')
90
- else:
91
- print(f"Error fetching start block for {date_str} on chain {chain_id}")
92
- return None, None
93
-
94
- if start_block is None:
95
- print(f"No start block found for chain {chain_id} on {date_str}")
96
- return None, None
97
- print(f"Start block for chain {chain_id} on {date_str}: {start_block}")
98
-
99
- # Get end block
100
- time.sleep(1)
101
- end_response = requests.get(
102
- f"{base_url}?module=block&action=getblocknobytime&timestamp={end_timestamp}&closest=before&apikey={api_key}"
103
- )
104
- if end_response.status_code == 200:
105
- end_data = end_response.json()
106
- end_block = end_data.get('result')
107
- else:
108
- print(f"Error fetching end block for {date_str} on chain {chain_id}")
109
- return None, None
110
-
111
- if end_block is None:
112
- print(f"No end block found for chain {chain_id} on {date_str}")
113
- return None, None
114
- print(f"End block for chain {chain_id} on {date_str}: {end_block}")
115
-
116
- return start_block, end_block
117
-
118
- def get_transactions(api_keys, wallet_address, chain_name, start_block, end_block):
119
- """Retrieve transactions for the given wallet address, chain, and block range using the Etherscan or similar API."""
120
- base_url = {
121
- 'optimism': "https://api-optimistic.etherscan.io/api",
122
- 'base': "https://api.basescan.org/api",
123
- 'ethereum': "https://api.etherscan.io/api"
124
- }.get(chain_name)
125
-
126
- if not base_url:
127
- print(f"Invalid chain name: {chain_name}")
128
- return []
129
-
130
- params = {
131
- 'module': 'account',
132
- 'action': 'txlist',
133
- 'address': wallet_address,
134
- 'startblock': start_block,
135
- 'endblock': end_block,
136
- 'sort': 'asc',
137
- 'apikey': api_keys.get(chain_name)
138
- }
139
-
140
- response = requests.get(base_url, params=params)
141
- data = response.json()
142
-
143
- time.sleep(1)
144
 
145
- if data['status'] != '1':
146
- print(f"Error: {data['message']}")
147
- return []
148
-
149
- valid_transactions = [tx for tx in data['result'] if tx['isError'] == '0']
150
 
151
- return valid_transactions
152
-
153
- def date_range(start_date, end_date):
154
- """Generates a range of dates from start_date to end_date inclusive."""
155
- start_dt = datetime.strptime(start_date, "%Y-%m-%d")
156
- end_dt = datetime.strptime(end_date, "%Y-%m-%d")
157
- delta = timedelta(days=1)
158
- current_dt = start_dt
159
- while current_dt <= end_dt:
160
- yield current_dt.strftime("%Y-%m-%d")
161
- current_dt += delta
162
-
163
- def fetch_transactions():
164
- # User inputs
165
- api_keys = {
166
- 'optimism': 'XQ72JA5XZ51QC7TG1W295AAIF4KTV92K1K',
167
- 'base': '4BFQMVW1QUKEPVDA4VW711CF4462682CY8',
168
- 'ethereum': '3GRYJGX55W3QWCEKGREF4H53AFHCAIVVR7'
169
- }
170
-
171
- base_urls = {
172
- 10: "https://api-optimistic.etherscan.io/api",
173
- 8453: "https://api.basescan.org/api",
174
- 1: "https://api.etherscan.io/api"
175
- }
176
-
177
- start_date = '2024-09-19' # Starting date
178
- current_date = datetime.now().strftime('%Y-%m-%d') # Till present date
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
- chains = {
181
- 10: ('optimism', service_safes_optimism), # Optimism chain ID and service safes
182
- 8453: ('base', service_safes_base), # Base chain ID and service safes
183
- 1: ('ethereum', service_safes_eth) # Ethereum mainnet chain ID and service safes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
185
-
186
- all_transactions = [] # List to hold all transactions
187
-
188
- for chain_id, (chain_name, service_safes) in chains.items():
189
- base_url = base_urls[chain_id]
190
- api_key = api_keys[chain_name]
191
-
192
- for safe_address in service_safes:
193
- print(f"\nProcessing {chain_name.capitalize()} for safe address {safe_address}...")
194
- for single_date in date_range(start_date, current_date):
195
- start_block, end_block = get_block_range_for_date(chain_id, single_date, api_key, base_url)
196
- if start_block is None or end_block is None:
197
- print(f"Skipping date {single_date} for chain {chain_name} due to missing block data.")
198
- continue
199
-
200
- print(f"Start Block: {start_block}, End Block: {end_block} for date {single_date}")
201
-
202
- transactions = get_transactions(api_keys, safe_address, chain_name, start_block, end_block)
203
-
204
- if transactions:
205
- print(f"Found {len(transactions)} transactions on {single_date} for {chain_name.capitalize()} safe address {safe_address}:")
206
- for tx in transactions:
207
- tx_time = datetime.fromtimestamp(int(tx['timeStamp']))
208
- all_transactions.append({
209
- 'chain': chain_name,
210
- 'safe_address': safe_address,
211
- 'date': single_date,
212
- 'transaction_hash': tx['hash'],
213
- 'timestamp': tx_time,
214
- 'from': tx['from'],
215
- 'to': tx['to'],
216
- 'value_eth': int(tx['value']) / 1e18 # Convert value to ETH
217
- })
218
- else:
219
- print(f"No transactions found for safe address {safe_address} on {single_date} on {chain_name.capitalize()}.")
220
-
221
- # Convert the collected transactions into a DataFrame
222
- df_transactions_new = pd.DataFrame(all_transactions)
223
- return df_transactions_new
224
-
225
- def create_transcation_visualizations():
226
- df_transactions_new = fetch_transactions()
227
- df_transactions_new.to_csv('daily_transactions_new.csv', index=False)
228
-
229
- df_transactions_new['timestamp'] = pd.to_datetime(df_transactions_new['timestamp'])
230
-
231
- # Group by date and chain, count transactions
232
- daily_counts = df_transactions_new.groupby([df_transactions_new['timestamp'].dt.date, 'chain']).size().unstack(fill_value=0)
233
-
234
- # Set up the plot
235
- fig_tx_chain = px.bar(
236
- daily_counts,
 
237
  barmode="stack",
238
- title="Chain Daily Activity: Transactions"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  )
240
- fig_tx_chain.update_layout(
241
- xaxis_title="Date",
242
- yaxis_title="Daily Transaction Nr",
243
- legend_title="Transaction Chain",
244
- xaxis_tickformat="%Y-%m-%d",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  height=700,
246
  )
247
 
248
- return fig_tx_chain
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
 
 
250
 
251
  # Gradio interface
252
  def dashboard():
@@ -254,12 +311,22 @@ def dashboard():
254
  gr.Markdown("# Valory Transactions Dashboard")
255
 
256
  # Fetch and display visualizations
257
- with gr.Tab("Transactions"):
258
- fig_tx_chain = create_transcation_visualizations()
259
- gr.Plot(fig_tx_chain)
260
-
261
- # Add more tabs as needed...
 
 
262
 
 
 
 
 
 
 
 
 
263
  return demo
264
 
265
  # Launch the dashboard
 
5
  from datetime import datetime, timedelta
6
  import json
7
  from web3 import Web3
8
+
 
9
  OPTIMISM_RPC_URL = 'https://opt-mainnet.g.alchemy.com/v2/U5gnXPYxeyH43MJ9tP8ONBQHEDRav7H0'
 
 
10
 
11
+ # Initialize a Web3 instance
12
+ web3 = Web3(Web3.HTTPProvider(OPTIMISM_RPC_URL))
13
+
14
+ # Check if connection is successful
15
+ if not web3.is_connected():
16
+ raise Exception("Failed to connect to the Optimism network.")
17
 
18
+ # Contract address
19
+ contract_address = '0x3d77596beb0f130a4415df3D2D8232B3d3D31e44'
 
 
20
 
21
+ # Load the ABI from the provided JSON file
22
  with open('service_registry_abi.json', 'r') as abi_file:
23
  contract_abi = json.load(abi_file)
24
 
25
+ # Now you can create the contract
26
+ service_registry = web3.eth.contract(address=contract_address, abi=contract_abi)
27
+
28
+ def get_transfers(integrator: str, wallet: str) -> str:
29
+ url = f"https://li.quest/v1/analytics/transfers?integrator={integrator}&wallet={wallet}"
30
+ headers = {"accept": "application/json"}
31
+ response = requests.get(url, headers=headers)
32
+ return response.json()
33
+
34
+ def load_activity_checker_contract(w3, staking_token_address):
35
+ """
36
+ Loads the Staking Token and Activity Checker contracts.
37
+
38
+ :param w3: Web3 instance
39
+ :param staking_token_address: Address of the staking token contract
40
+ :return: Tuple of (Staking Token contract instance, Activity Checker contract instance)
41
+ """
42
+ try:
43
+ # Load the ABI file for the Staking Token contract
44
+ with open('./contracts/StakingToken.json', "r", encoding="utf-8") as file:
45
+ staking_token_data = json.load(file)
46
+
47
+ staking_token_abi = staking_token_data.get("abi", [])
48
+
49
+ # Create the Staking Token contract instance
50
+ staking_token_contract = w3.eth.contract(address=staking_token_address, abi=staking_token_abi)
51
+
52
+ # Get the activity checker contract address from staking_token_contract
53
+ activity_checker_address = staking_token_contract.functions.activityChecker().call()
54
+
55
+ # Load the ABI file for the Activity Checker contract
56
+ with open('./contracts/StakingActivityChecker.json', "r", encoding="utf-8") as file:
57
+ activity_checker_data = json.load(file)
58
+
59
+ activity_checker_abi = activity_checker_data.get("abi", [])
60
+
61
+ # Create the Activity Checker contract instance
62
+ activity_checker_contract = w3.eth.contract(address=activity_checker_address, abi=activity_checker_abi)
63
+
64
+ return staking_token_contract, activity_checker_contract
65
+
66
+ except Exception as e:
67
+ print(f"An error occurred while loading the contracts: {e}")
68
+ raise
69
 
 
 
 
 
 
 
 
 
70
 
71
+ def fetch_and_aggregate_transactions():
72
+ total_services = service_registry.functions.totalSupply().call()
73
+ aggregated_transactions = []
74
+ daily_agent_counts = {}
75
+ daily_agents_with_transactions = {}
76
 
77
+ _staking_token_contract, activity_checker_contract = load_activity_checker_contract(web3, '0x88996bbdE7f982D93214881756840cE2c77C4992')
 
 
 
 
78
 
79
  for service_id in range(1, total_services + 1):
80
+ service = service_registry.functions.getService(service_id).call()
81
+
82
+ # Extract the list of agent IDs from the service data
83
  agent_ids = service[-1] # Assuming the last element is the list of agent IDs
 
84
 
85
+ # Check if 25 is in the list of agent IDs
86
  if 25 in agent_ids:
87
+ agent_address = service_registry.functions.getAgentInstances(service_id).call()[1][0]
88
+ response_transfers = get_transfers("valory", agent_address)
89
+ transfers = response_transfers.get("transfers", [])
90
+ if isinstance(transfers, list):
91
+ aggregated_transactions.extend(transfers)
92
+
93
+ # Track the daily number of agents
94
+ creation_event = service_registry.events.CreateService.create_filter(
95
+ from_block=0, argument_filters={'serviceId': service_id, 'configHash': service[2]}
96
+ ).get_all_entries()
97
+
98
+ if creation_event:
99
+ block_number = creation_event[0]['blockNumber']
100
+ block = web3.eth.get_block(block_number)
101
+ creation_timestamp = datetime.fromtimestamp(block['timestamp'])
102
+ date_str = creation_timestamp.strftime('%Y-%m-%d')
103
+
104
+ if date_str not in daily_agent_counts:
105
+ daily_agent_counts[date_str] = set()
106
+ if date_str not in daily_agents_with_transactions:
107
+ daily_agents_with_transactions[date_str] = set()
108
+
109
+ for agent_id in agent_ids:
110
+ service_safe = service[1]
111
+ print("agent_address",agent_address,"service_safe",service_safe)
112
+ multisig_nonces = activity_checker_contract.functions.getMultisigNonces(service_safe).call()[0]
113
+ if multisig_nonces > 0:
114
+ daily_agents_with_transactions[date_str].add(agent_id)
115
+ daily_agent_counts[date_str].add(agent_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
+ # Convert set to count
118
+ daily_agent_counts = {date: len(agents) for date, agents in daily_agent_counts.items()}
119
+ daily_agents_with_transactions = {date: len(agents) for date, agents in daily_agents_with_transactions.items()}
 
 
120
 
121
+ return aggregated_transactions, daily_agent_counts, daily_agents_with_transactions
122
+
123
+ # Function to parse the transaction data and prepare it for visualization
124
+ def process_transactions_and_agents(data):
125
+ transactions, daily_agent_counts, daily_agents_with_transactions = data
126
+
127
+ # Convert the data into a pandas DataFrame for easy manipulation
128
+ rows = []
129
+ for tx in transactions:
130
+ # Normalize amounts
131
+ sending_amount = float(tx["sending"]["amount"]) / (10 ** tx["sending"]["token"]["decimals"])
132
+ receiving_amount = float(tx["receiving"]["amount"]) / (10 ** tx["receiving"]["token"]["decimals"])
133
+
134
+ # Convert timestamps to datetime objects
135
+ sending_timestamp = datetime.utcfromtimestamp(tx["sending"]["timestamp"])
136
+ receiving_timestamp = datetime.utcfromtimestamp(tx["receiving"]["timestamp"])
137
+
138
+ # Prepare row data
139
+ rows.append({
140
+ "transactionId": tx["transactionId"],
141
+ "from_address": tx["fromAddress"],
142
+ "to_address": tx["toAddress"],
143
+ "sending_chain": tx["sending"]["chainId"],
144
+ "receiving_chain": tx["receiving"]["chainId"],
145
+ "sending_token_symbol": tx["sending"]["token"]["symbol"],
146
+ "receiving_token_symbol": tx["receiving"]["token"]["symbol"],
147
+ "sending_amount": sending_amount,
148
+ "receiving_amount": receiving_amount,
149
+ "sending_amount_usd": float(tx["sending"]["amountUSD"]),
150
+ "receiving_amount_usd": float(tx["receiving"]["amountUSD"]),
151
+ "sending_gas_used": int(tx["sending"]["gasUsed"]),
152
+ "receiving_gas_used": int(tx["receiving"]["gasUsed"]),
153
+ "sending_timestamp": sending_timestamp,
154
+ "receiving_timestamp": receiving_timestamp,
155
+ "date": sending_timestamp.date(), # Group by day
156
+ "week": sending_timestamp.strftime('%Y-%m-%d') # Group by week
157
+ })
158
+
159
+ df_transactions = pd.DataFrame(rows)
160
+ df_agents = pd.DataFrame(list(daily_agent_counts.items()), columns=['date', 'agent_count'])
161
+ df_agents_with_transactions = pd.DataFrame(list(daily_agents_with_transactions.items()), columns=['date', 'agent_count_with_transactions'])
162
 
163
+ # Convert the date column to datetime
164
+ df_agents['date'] = pd.to_datetime(df_agents['date'])
165
+ df_agents_with_transactions['date'] = pd.to_datetime(df_agents_with_transactions['date'])
166
+
167
+ # Convert to week periods
168
+ df_agents['week'] = df_agents['date'].dt.to_period('W').apply(lambda r: r.start_time)
169
+ df_agents_with_transactions['week'] = df_agents_with_transactions['date'].dt.to_period('W').apply(lambda r: r.start_time)
170
+
171
+ # Group by week
172
+ df_agents_weekly = df_agents[['week', 'agent_count']].groupby('week').sum().reset_index()
173
+ df_agents_with_transactions_weekly = df_agents_with_transactions[['week', 'agent_count_with_transactions']].groupby('week').sum().reset_index()
174
+
175
+ return df_transactions, df_agents_weekly, df_agents_with_transactions_weekly
176
+
177
+ # Function to create visualizations based on the metrics
178
+ def create_visualizations():
179
+ transactions_data = fetch_and_aggregate_transactions()
180
+ df_transactions, df_agents_weekly, df_agents_with_transactions_weekly = process_transactions_and_agents(transactions_data)
181
+
182
+ # Map chain IDs to chain names
183
+ chain_name_map = {
184
+ 10: "Optimism",
185
+ 8453: "Base",
186
+ 1: "Ethereum"
187
  }
188
+ df_transactions["sending_chain"] = df_transactions["sending_chain"].map(chain_name_map)
189
+ df_transactions["receiving_chain"] = df_transactions["receiving_chain"].map(chain_name_map)
190
+
191
+ # Ensure that chain IDs are strings for consistent grouping
192
+ df_transactions["sending_chain"] = df_transactions["sending_chain"].astype(str)
193
+ df_transactions["receiving_chain"] = df_transactions["receiving_chain"].astype(str)
194
+ df_transactions['date'] = pd.to_datetime(df_transactions['date'])
195
+
196
+ # Identify swap transactions
197
+ df_transactions["is_swap"] = df_transactions.apply(lambda x: x["sending_token_symbol"] != x["receiving_token_symbol"], axis=1)
198
+
199
+ # Total swaps per chain per day
200
+ swaps_per_chain = df_transactions[df_transactions["is_swap"]].groupby(["date", "sending_chain"]).size().reset_index(name="swap_count")
201
+ fig_swaps_chain = px.bar(
202
+ swaps_per_chain,
203
+ x="date",
204
+ y="swap_count",
205
+ color="sending_chain",
206
+ title="Chain Daily Activity: Swaps",
207
+ labels={"sending_chain": "Transaction Chain", "swap_count": "Daily Swap Nr"},
208
+ barmode="stack",
209
+ color_discrete_map={
210
+ "Optimism": "blue",
211
+ "Ethereum": "darkgreen",
212
+ "Base": "purple"
213
+ }
214
+ )
215
+ fig_swaps_chain.update_layout(
216
+ xaxis_title=None,
217
+ yaxis=dict(tickmode='linear', tick0=0, dtick=1),
218
+ xaxis=dict(
219
+ tickmode='array',
220
+ tickvals=swaps_per_chain['date'],
221
+ ticktext=swaps_per_chain['date'].dt.strftime('%y-%m-%d'),
222
+ tickangle=0,
223
+ ),
224
+ bargap=0.8,
225
+ height=700,
226
+ )
227
+ fig_swaps_chain.update_xaxes(tickformat="%Y-%m-%d")
228
+
229
+ # Identify bridge transactions
230
+ df_transactions["is_bridge"] = df_transactions.apply(lambda x: x["sending_chain"] != x["receiving_chain"], axis=1)
231
+
232
+ # Total bridges per chain per day
233
+ bridges_per_chain = df_transactions[df_transactions["is_bridge"]].groupby(["date", "sending_chain"]).size().reset_index(name="bridge_count")
234
+ fig_bridges_chain = px.bar(
235
+ bridges_per_chain,
236
+ x="date",
237
+ y="bridge_count",
238
+ color="sending_chain",
239
+ title="Chain Daily Activity: Bridges",
240
+ labels={"sending_chain": "Transaction Chain", "bridge_count": "Daily Bridge Nr"},
241
  barmode="stack",
242
+ color_discrete_map={
243
+ "Optimism": "blue",
244
+ "Ethereum": "darkgreen",
245
+ "Base": "purple"
246
+ }
247
+ )
248
+ fig_bridges_chain.update_layout(
249
+ xaxis_title=None,
250
+ yaxis=dict(tickmode='linear', tick0=0, dtick=1),
251
+ xaxis=dict(
252
+ tickmode='array',
253
+ tickvals=bridges_per_chain['date'],
254
+ ticktext=bridges_per_chain['date'].dt.strftime('%y-%m-%d'),
255
+ tickangle=0,
256
+ ),
257
+ bargap=0.8,
258
+ height=700,
259
  )
260
+ fig_bridges_chain.update_xaxes(tickformat="%Y-%m-%d")
261
+
262
+ # Number of agents per week
263
+ fig_agents_daily = px.bar(
264
+ df_agents_weekly,
265
+ x="week",
266
+ y="agent_count",
267
+ title="Number of Agents Registered WoW",
268
+ labels={"week": "Week", "agent_count": "Number of Agents"},
269
+ color_discrete_sequence=["purple"]
270
+ )
271
+ fig_agents_daily.update_layout(
272
+ xaxis_title=None,
273
+ yaxis=dict(tickmode='linear', tick0=0, dtick=1),
274
+ xaxis=dict(
275
+ tickmode='array',
276
+ tickvals=df_agents_weekly['week'],
277
+ ticktext=df_agents_weekly['week'].dt.strftime('%y-%m-%d'),
278
+ tickangle=0
279
+ ),
280
+ bargap=0.8,
281
  height=700,
282
  )
283
 
284
+ # Number of agents with transactions per week
285
+ fig_agents_with_transactions_daily = px.bar(
286
+ df_agents_with_transactions_weekly,
287
+ x="week",
288
+ y="agent_count_with_transactions",
289
+ title="Agents With at Least 1 Transaction WoW",
290
+ labels={"week": "Week", "agent_count_with_transactions": "Number of Agents with Transactions"},
291
+ color_discrete_sequence=["darkgreen"]
292
+ )
293
+ fig_agents_with_transactions_daily.update_layout(
294
+ xaxis_title=None,
295
+ yaxis=dict(tickmode='linear', tick0=0, dtick=1),
296
+ xaxis=dict(
297
+ tickmode='array',
298
+ tickvals=df_agents_with_transactions_weekly['week'],
299
+ ticktext=df_agents_with_transactions_weekly['week'].dt.strftime('%y-%m-%d'),
300
+ tickangle=0
301
+ ),
302
+ bargap=0.8,
303
+ height=700,
304
+ )
305
 
306
+ return fig_swaps_chain, fig_bridges_chain, fig_agents_daily, fig_agents_with_transactions_daily
307
 
308
  # Gradio interface
309
  def dashboard():
 
311
  gr.Markdown("# Valory Transactions Dashboard")
312
 
313
  # Fetch and display visualizations
314
+ with gr.Tab("Swaps"):
315
+ fig_swaps_chain, fig_bridges_chain, fig_agents_daily, fig_agents_with_transactions_daily = create_visualizations()
316
+ gr.Plot(fig_swaps_chain)
317
+
318
+ with gr.Tab("Bridges"):
319
+ fig_swaps_chain, fig_bridges_chain, fig_agents_daily, fig_agents_with_transactions_daily = create_visualizations()
320
+ gr.Plot(fig_bridges_chain)
321
 
322
+ with gr.Tab("Agents Week Over Week"):
323
+ fig_swaps_chain, fig_bridges_chain, fig_agents_daily, fig_agents_with_transactions_daily = create_visualizations()
324
+ gr.Plot(fig_agents_daily)
325
+
326
+ with gr.Tab("Agents with Transactions Week Over Week"):
327
+ fig_swaps_chain, fig_bridges_chain, fig_agents_daily, fig_agents_with_transactions_daily = create_visualizations()
328
+ gr.Plot(fig_agents_with_transactions_daily)
329
+
330
  return demo
331
 
332
  # Launch the dashboard