Spaces:
Runtime error
Runtime error
gauravlochab
commited on
Commit
·
fd97ba6
1
Parent(s):
07ba1e6
Add agent/service metrics
Browse files
app.py
CHANGED
@@ -2,109 +2,156 @@ import requests
|
|
2 |
import pandas as pd
|
3 |
import gradio as gr
|
4 |
import plotly.express as px
|
5 |
-
from datetime import datetime
|
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 |
return df
|
52 |
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
# 2. Number of Opportunities Taken per Agent per Day
|
68 |
-
opportunities_per_agent = df.groupby(["date", "from_address"]).size().reset_index(name="opportunities_taken")
|
69 |
-
fig_opportunities_agent = px.bar(opportunities_per_agent, x="date", y="opportunities_taken", color="from_address",
|
70 |
-
title="Number of Opportunities Taken per Agent per Day")
|
71 |
-
|
72 |
-
# 3. Amount of Investment in Pools Daily per Agent (Note: Assuming sending_amount_usd as investment)
|
73 |
-
# Since we might not have explicit data about pool investments, we'll use sending_amount_usd
|
74 |
-
investment_per_agent = df.groupby(["date", "from_address"])["sending_amount_usd"].sum().reset_index()
|
75 |
-
fig_investment_agent = px.bar(investment_per_agent, x="date", y="sending_amount_usd", color="from_address",
|
76 |
-
title="Amount of Investment (USD) per Agent per Day")
|
77 |
-
|
78 |
-
# 4. Number of Swaps per Day
|
79 |
-
# Assuming each transaction is a swap if sending and receiving tokens are different
|
80 |
-
df["is_swap"] = df.apply(lambda x: x["sending_token_symbol"] != x["receiving_token_symbol"], axis=1)
|
81 |
-
swaps_per_day = df[df["is_swap"]].groupby("date").size().reset_index(name="swap_count")
|
82 |
-
fig_swaps_per_day = px.bar(swaps_per_day, x="date", y="swap_count", title="Number of Swaps per Day")
|
83 |
-
|
84 |
-
# 5. Aggregated Metrics over All Traders
|
85 |
-
amount_usd = df["sending_amount_usd"]
|
86 |
-
stats = {
|
87 |
-
"Total": amount_usd.sum(),
|
88 |
-
"Average": amount_usd.mean(),
|
89 |
-
"Min": amount_usd.min(),
|
90 |
-
"Max": amount_usd.max(),
|
91 |
-
"25th Percentile": amount_usd.quantile(0.25),
|
92 |
-
"50th Percentile (Median)": amount_usd.median(),
|
93 |
-
"75th Percentile": amount_usd.quantile(0.75),
|
94 |
-
}
|
95 |
-
stats_df = pd.DataFrame(list(stats.items()), columns=["Metric", "Value"])
|
96 |
-
|
97 |
-
# Visualization for Aggregated Metrics
|
98 |
-
fig_stats = px.bar(stats_df, x="Metric", y="Value", title="Aggregated Transaction Amount Metrics (USD)")
|
99 |
-
|
100 |
-
return fig_tx_chain_agent, fig_opportunities_agent, fig_investment_agent, fig_swaps_per_day, fig_stats
|
101 |
-
|
102 |
-
# Gradio interface
|
103 |
def dashboard():
|
104 |
with gr.Blocks() as demo:
|
105 |
gr.Markdown("# Valory Transactions Dashboard")
|
106 |
|
107 |
-
#
|
108 |
with gr.Tab("Transactions per Chain per Agent"):
|
109 |
fig_tx_chain_agent, _, _, _, _ = create_visualizations()
|
110 |
gr.Plot(fig_tx_chain_agent)
|
@@ -124,10 +171,20 @@ def dashboard():
|
|
124 |
with gr.Tab("Aggregated Metrics"):
|
125 |
_, _, _, _, fig_stats = create_visualizations()
|
126 |
gr.Plot(fig_stats)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
|
128 |
return demo
|
129 |
|
130 |
-
# Launch the dashboard
|
131 |
if __name__ == "__main__":
|
132 |
dashboard().launch()
|
133 |
-
|
|
|
2 |
import pandas as pd
|
3 |
import gradio as gr
|
4 |
import plotly.express as px
|
5 |
+
from datetime import datetime, timedelta
|
6 |
+
from web3 import Web3
|
7 |
+
from web3.middleware import geth_poa_middleware
|
8 |
+
|
9 |
+
# Optimism RPC endpoint (you can use Infura, Alchemy, or any other provider)
|
10 |
+
OPTIMISM_RPC = "https://mainnet.optimism.io"
|
11 |
+
|
12 |
+
# ServiceRegistry contract address and ABI
|
13 |
+
SERVICE_REGISTRY_ADDRESS = "0x3d77596beb0f130a4415df3D2D8232B3d3D31e44"
|
14 |
+
SERVICE_REGISTRY_ABI = [
|
15 |
+
# Include the ABI for the functions you need
|
16 |
+
# totalSupply() and getService(uint256)
|
17 |
+
{
|
18 |
+
"constant": True,
|
19 |
+
"inputs": [],
|
20 |
+
"name": "totalSupply",
|
21 |
+
"outputs": [{"name": "", "type": "uint256"}],
|
22 |
+
"type": "function",
|
23 |
+
},
|
24 |
+
{
|
25 |
+
"constant": True,
|
26 |
+
"inputs": [{"name": "serviceId", "type": "uint256"}],
|
27 |
+
"name": "getService",
|
28 |
+
"outputs": [
|
29 |
+
{"name": "owner", "type": "address"},
|
30 |
+
{"name": "multisig", "type": "address"},
|
31 |
+
{"name": "agentInstances", "type": "address[]"},
|
32 |
+
{"name": "threshold", "type": "uint32"},
|
33 |
+
{"name": "bonds", "type": "uint256[]"},
|
34 |
+
{"name": "agentIds", "type": "uint256[]"},
|
35 |
+
{"name": "state", "type": "uint8"},
|
36 |
+
],
|
37 |
+
"type": "function",
|
38 |
+
},
|
39 |
+
]
|
40 |
+
|
41 |
+
# Gnosis Safe ABI (for getting the nonce)
|
42 |
+
SAFE_ABI = [
|
43 |
+
{
|
44 |
+
"constant": True,
|
45 |
+
"inputs": [],
|
46 |
+
"name": "nonce",
|
47 |
+
"outputs": [{"name": "", "type": "uint256"}],
|
48 |
+
"type": "function",
|
49 |
+
},
|
50 |
+
]
|
51 |
+
|
52 |
+
def fetch_services():
|
53 |
+
w3 = Web3(Web3.HTTPProvider(OPTIMISM_RPC))
|
54 |
+
w3.middleware_onion.inject(geth_poa_middleware, layer=0) # For Optimism
|
55 |
+
|
56 |
+
service_registry = w3.eth.contract(
|
57 |
+
address=Web3.toChecksumAddress(SERVICE_REGISTRY_ADDRESS),
|
58 |
+
abi=SERVICE_REGISTRY_ABI,
|
59 |
+
)
|
60 |
+
|
61 |
+
total_services = service_registry.functions.totalSupply().call()
|
62 |
+
print(f"Total services: {total_services}")
|
63 |
+
|
64 |
+
services_data = []
|
65 |
+
for service_id in range(1, total_services + 1):
|
66 |
+
service = service_registry.functions.getService(service_id).call()
|
67 |
+
owner = service[0]
|
68 |
+
multisig = service[1]
|
69 |
+
agent_ids = service[5] # List of agent IDs
|
70 |
+
state = service[6]
|
71 |
+
|
72 |
+
# Filter for Optimus services (agentId == 25)
|
73 |
+
if 25 in agent_ids:
|
74 |
+
# Get the registration block number (we need to get the block number of the transaction that created the service)
|
75 |
+
# Since we don't have a subgraph, we'll approximate by using the block number of the latest transaction involving the service multisig
|
76 |
+
# Note: This is a simplification and may not be accurate
|
77 |
+
# For accurate results, a subgraph or indexed data is recommended
|
78 |
+
services_data.append({
|
79 |
+
"service_id": service_id,
|
80 |
+
"owner": owner,
|
81 |
+
"multisig": multisig,
|
82 |
+
"agent_ids": agent_ids,
|
83 |
+
"state": state,
|
84 |
+
})
|
85 |
+
|
86 |
+
return services_data
|
87 |
+
|
88 |
+
def fetch_service_creation_dates(services_data):
|
89 |
+
w3 = Web3(Web3.HTTPProvider(OPTIMISM_RPC))
|
90 |
+
w3.middleware_onion.inject(geth_poa_middleware, layer=0) # For Optimism
|
91 |
+
|
92 |
+
# Since we don't have direct access to service creation dates, we'll need to fetch historical logs
|
93 |
+
# Unfortunately, without a subgraph or an indexer, this is impractical for a large number of services
|
94 |
+
# As an alternative, we can skip this step or set approximate dates
|
95 |
+
|
96 |
+
# For demonstration, we'll set all registration dates to today
|
97 |
+
for service in services_data:
|
98 |
+
service["registration_date"] = datetime.utcnow().date()
|
99 |
+
|
100 |
+
return services_data
|
101 |
+
|
102 |
+
def check_service_transactions(services_data):
|
103 |
+
w3 = Web3(Web3.HTTPProvider(OPTIMISM_RPC))
|
104 |
+
w3.middleware_onion.inject(geth_poa_middleware, layer=0) # For Optimism
|
105 |
+
|
106 |
+
for service in services_data:
|
107 |
+
multisig_address = service["multisig"]
|
108 |
+
safe_contract = w3.eth.contract(
|
109 |
+
address=multisig_address,
|
110 |
+
abi=SAFE_ABI,
|
111 |
+
)
|
112 |
+
try:
|
113 |
+
nonce = safe_contract.functions.nonce().call()
|
114 |
+
service["nonce"] = nonce
|
115 |
+
except Exception as e:
|
116 |
+
# If the multisig is not a Gnosis Safe or the call fails
|
117 |
+
service["nonce"] = 0
|
118 |
+
|
119 |
+
return services_data
|
120 |
+
|
121 |
+
def process_services_data(services_data):
|
122 |
+
# Convert to DataFrame
|
123 |
+
df = pd.DataFrame(services_data)
|
124 |
+
|
125 |
+
# Convert registration_date to datetime
|
126 |
+
df["registration_date"] = pd.to_datetime(df["registration_date"])
|
127 |
+
|
128 |
+
# Add week number
|
129 |
+
df["week"] = df["registration_date"].dt.strftime('%Y-%W')
|
130 |
+
|
131 |
+
# Determine if service has made at least one transaction
|
132 |
+
df["has_transaction"] = df["nonce"] > 0
|
133 |
+
|
134 |
return df
|
135 |
|
136 |
+
def create_services_visualizations(df):
|
137 |
+
# 1) Number of services registered WoW
|
138 |
+
services_registered = df.groupby("week").size().reset_index(name="services_registered")
|
139 |
+
fig_services_registered = px.bar(services_registered, x="week", y="services_registered",
|
140 |
+
title="Number of Services Registered WoW")
|
141 |
+
|
142 |
+
# 2) Number of services making at least one transaction WoW
|
143 |
+
services_with_tx = df[df["has_transaction"]].groupby("week").size().reset_index(name="services_with_transaction")
|
144 |
+
fig_services_with_tx = px.bar(services_with_tx, x="week", y="services_with_transaction",
|
145 |
+
title="Number of Services with at Least One Transaction WoW")
|
146 |
+
|
147 |
+
return fig_services_registered, fig_services_with_tx
|
148 |
+
|
149 |
+
# Integrate with the existing dashboard
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
def dashboard():
|
151 |
with gr.Blocks() as demo:
|
152 |
gr.Markdown("# Valory Transactions Dashboard")
|
153 |
|
154 |
+
# Existing visualizations
|
155 |
with gr.Tab("Transactions per Chain per Agent"):
|
156 |
fig_tx_chain_agent, _, _, _, _ = create_visualizations()
|
157 |
gr.Plot(fig_tx_chain_agent)
|
|
|
171 |
with gr.Tab("Aggregated Metrics"):
|
172 |
_, _, _, _, fig_stats = create_visualizations()
|
173 |
gr.Plot(fig_stats)
|
174 |
+
|
175 |
+
# New visualizations for services
|
176 |
+
with gr.Tab("Services Registered WoW"):
|
177 |
+
services_data = fetch_services()
|
178 |
+
services_data = fetch_service_creation_dates(services_data)
|
179 |
+
services_data = check_service_transactions(services_data)
|
180 |
+
df_services = process_services_data(services_data)
|
181 |
+
fig_services_registered, fig_services_with_tx = create_services_visualizations(df_services)
|
182 |
+
gr.Plot(fig_services_registered)
|
183 |
+
|
184 |
+
with gr.Tab("Services with Transactions WoW"):
|
185 |
+
gr.Plot(fig_services_with_tx)
|
186 |
|
187 |
return demo
|
188 |
|
|
|
189 |
if __name__ == "__main__":
|
190 |
dashboard().launch()
|
|