Trireme commited on
Commit
ffdcfe5
·
verified ·
1 Parent(s): 10eebfd

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +3 -9
  2. app.py +242 -0
  3. requirements.txt +7 -0
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Vice Balances
3
- emoji: 🦀
4
- colorFrom: red
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.49.0
8
  app_file: app.py
9
- pinned: false
 
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: vice_balances
 
 
 
 
 
3
  app_file: app.py
4
+ sdk: gradio
5
+ sdk_version: 5.31.0
6
  ---
 
 
app.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import asyncio
3
+ import aiohttp
4
+ import pandas as pd
5
+ import urllib
6
+ import gradio as gr
7
+ import os
8
+ import numpy as np
9
+
10
+ base_addresses = ["0x45e7035499bc860dA0b5666A93B97AFc51F3cD3F",'0x8Ff84fa392340d4683C57A602AC400C3D2fF5cdD','0xA6bbEFBB13BBbcA0022a270c734674146DCcf668','0x43D04107E14C19DCDd2C0D0afC33cDa458b349A3','0xA19f7F0643FF7f655D3E39D0689caa3D53944AAE']
11
+
12
+ lp_wallets = ["0x45e7035499bc860dA0b5666A93B97AFc51F3cD3F"]
13
+
14
+ def chunk_addresses(addresses, size):
15
+ return [addresses[i:i + size] for i in range(0, len(addresses), size)]
16
+
17
+ API_URL = "https://api.g.alchemy.com/data/v1/yhe6L3PXmiENzS1sP9Fu4_T5E3l0QyeB/assets/tokens/by-address"
18
+
19
+ async def fetch_batch(session, batch,chain):
20
+ json_payload = {
21
+ "addresses": [{"address": addr, "networks": [chain]} for addr in batch],
22
+ "withMetadata": True,
23
+ "withPrices": True,
24
+ "includeNativeTokens": True
25
+ }
26
+ async with session.post(API_URL, json=json_payload) as response:
27
+ response = await response.json()
28
+ return response['data']['tokens']
29
+
30
+ async def get_wallet_base_balances(addresses):
31
+ async with aiohttp.ClientSession() as session:
32
+ batches = chunk_addresses(addresses, 3)
33
+ tasks = [fetch_batch(session, batch,"eth-mainnet") for batch in batches]
34
+ responses = await asyncio.gather(*tasks)
35
+ first_parts = []
36
+ rest_parts = []
37
+
38
+ for res in responses:
39
+ first_parts.extend(res[:3])
40
+ rest_parts.extend(res[3:])
41
+
42
+ responses = first_parts + rest_parts
43
+ df = pd.DataFrame(responses)
44
+ print(df)
45
+ for i in range(len(addresses)):
46
+ df.at[i,'tokenMetadata'] = {}
47
+
48
+ vice_data = {
49
+ "decimals": 18,
50
+ "logo": 'null',
51
+ "name": "",
52
+ "symbol": "VICE"
53
+ }
54
+ df['tokenMetadata'] = np.where(df['tokenAddress'] == '0xfd409bc96d126bc8a56479d4c7672015d539f96c',vice_data,df['tokenMetadata'])
55
+
56
+ df['tokenBalance'] = df['tokenBalance'].apply(lambda x : int(x,16))
57
+ df['decimals'] = df['tokenMetadata'].apply(lambda x : x.get('decimals',0))
58
+ df['tokenBalance'] = df['tokenBalance']/(10**df['decimals'])
59
+ for i in range(len(addresses)):
60
+ df.at[i, 'tokenBalance'] = df.at[i, 'tokenBalance'] / (10**18)
61
+ df['symbol'] = df['tokenMetadata'].apply(lambda x : x.get('symbol',''))
62
+ for i in range(len(addresses)):
63
+ df.at[i,'symbol'] = 'ETH'
64
+ df['currentPrice'] = df['tokenPrices'].apply(lambda x : x[0].get('value',0) if len(x) > 0 else 0)
65
+ df.drop(columns=['tokenPrices','tokenMetadata','network','tokenAddress'], inplace=True)
66
+
67
+ df = df.dropna()
68
+ df['tokenBalance'] = pd.to_numeric(df['tokenBalance'], errors='coerce')
69
+ df = df[df['tokenBalance'] != 0]
70
+ df['tokenBalance'] = pd.to_numeric(df['tokenBalance'], errors='coerce')
71
+ df['currentPrice'] = pd.to_numeric(df['currentPrice'], errors='coerce')
72
+ eth_price = df.loc[df['symbol']=='ETH','currentPrice'].values[0]
73
+ base_price = df.loc[df['symbol']=='VICE','currentPrice'].values[0]
74
+ df['value'] = df['tokenBalance'] * df['currentPrice']
75
+ df.drop(columns=['address','decimals'],inplace=True)
76
+
77
+ df = df[df['symbol'].isin(['VICE', 'ETH', 'USDT', 'USDC'])]
78
+ df= df[['symbol','tokenBalance','value']]
79
+ df = df.rename(columns={'tokenBalance':'amount','value':'usd_value'})
80
+
81
+ df = df.groupby("symbol", as_index=False).sum()
82
+
83
+ return df, df['usd_value'].sum(), eth_price, base_price
84
+
85
+ async def fetch_lp():
86
+ url = "https://public.zapper.xyz/graphql"
87
+ headers = {
88
+ "Content-Type": "application/json",
89
+ "x-zapper-api-key": "8fe2c210-66e0-4ef9-9505-96a901c9b042"
90
+ }
91
+
92
+ query = """
93
+ query AppBalances($addresses: [Address!]!, $first: Int = 10) {
94
+ portfolioV2(addresses: $addresses) {
95
+ appBalances {
96
+ totalBalanceUSD
97
+ byApp(first: $first) {
98
+ totalCount
99
+ edges {
100
+ node {
101
+ balanceUSD
102
+ app {
103
+ displayName
104
+ imgUrl
105
+ description
106
+ category { name }
107
+ }
108
+ network {
109
+ name
110
+ chainId
111
+ }
112
+ positionBalances(first: 10) {
113
+ edges {
114
+ node {
115
+ ... on AppTokenPositionBalance {
116
+ type
117
+ symbol
118
+ balance
119
+ balanceUSD
120
+ price
121
+ groupLabel
122
+ displayProps {
123
+ label
124
+ images
125
+ }
126
+ }
127
+ ... on ContractPositionBalance {
128
+ type
129
+ balanceUSD
130
+ groupLabel
131
+ tokens {
132
+ metaType
133
+ token {
134
+ ... on BaseTokenPositionBalance {
135
+ symbol
136
+ balance
137
+ balanceUSD
138
+ }
139
+ }
140
+ }
141
+ displayProps {
142
+ label
143
+ images
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+ """
156
+
157
+ variables = {
158
+ "addresses": lp_wallets,
159
+ "first": 5
160
+ }
161
+
162
+ payload = {
163
+ "query": query,
164
+ "variables": variables
165
+ }
166
+
167
+ response = requests.post(url, json=payload, headers=headers)
168
+ response = response.json()
169
+ df = pd.json_normalize(response['data']['portfolioV2']['appBalances']['byApp']['edges'])
170
+ def agg_balances(lp):
171
+ lps = []
172
+ for i in range(len(lp)):
173
+ two = lp['node.tokens'].iloc[i]
174
+ more_lp = pd.json_normalize(two)
175
+ more_lp['token.balance'] = more_lp['token.balance'].apply(pd.to_numeric,errors='coerce')
176
+ more_lp['token.balanceUSD'] = more_lp['token.balanceUSD'].apply(pd.to_numeric,errors='coerce')
177
+ x = more_lp.groupby('token.symbol')[['token.balance','token.balanceUSD']].sum().reset_index()
178
+ #x.columns = x.iloc[0] # Set first row as column headers
179
+ #x = x.drop(x.index[0]).reset_index(drop=True) # Drop the row that became header
180
+ #x = x.apply(pd.to_numeric, errors='coerce') # Convert all to numeric
181
+ lps.append(x)
182
+ bals_df = pd.concat(lps, ignore_index=True)
183
+ bals_df['token.balance'] = bals_df['token.balance'].apply(pd.to_numeric,errors='coerce')
184
+ bals_df['token.balanceUSD'] = bals_df['token.balanceUSD'].apply(pd.to_numeric,errors='coerce')
185
+
186
+ bals_df.fillna(0, inplace=True)
187
+ bals_df = bals_df.groupby('token.symbol').sum().reset_index()
188
+ return bals_df
189
+ def get_dex_balances(df):
190
+ balances = []
191
+ if df.empty:
192
+ return
193
+ for i in range(len(pd.json_normalize(df['node.positionBalances.edges']))):
194
+ balances.append((df['node.app.displayName'].iloc[i],agg_balances(pd.json_normalize(df['node.positionBalances.edges'].iloc[i]))))
195
+
196
+ final_balances = []
197
+ for i in range(len(balances)):
198
+ df = balances[i]
199
+ dex_name = df[0] # or extract from your grouped index
200
+ df_pivot = df[1].pivot_table(index=None, columns='token.symbol', values='token.balance')
201
+ # Add DEX column and reorder
202
+ df_pivot.insert(0,'DEX', dex_name)
203
+ # Remove the first level of row index (e.g., 'token.symbol')
204
+ df_pivot = df_pivot.reset_index(drop=True)
205
+ df_pivot.columns.name = None
206
+ final_balances.append(df_pivot)
207
+
208
+ final_balances = pd.concat(final_balances, ignore_index=True)
209
+ final_balances.fillna(0, inplace=True)
210
+ return final_balances
211
+ final_balances = get_dex_balances(df)
212
+ return final_balances.T.drop('DEX').reset_index().rename(columns={'index':'symbol',0:'amount'}) if final_balances else pd.DataFrame([{}])
213
+
214
+
215
+ async def get_all_dfs():
216
+ #starting_df = pd.DataFrame([{"symbol":"AIQ","amount":3000000.00,"usd_value":3000000.00*0.05},{"symbol":"ETH","amount":55.5309,"usd_value":55.5309*4486.62}])
217
+ df, total, eth_price, base_price = await get_wallet_base_balances(base_addresses)
218
+ symbols = {"VICE":base_price,"WETH":eth_price}
219
+ lp_df = await fetch_lp()
220
+ if not lp_df.empty:
221
+ lp_df['price'] = lp_df['symbol'].map(symbols)
222
+ lp_df['price'] = lp_df['price'] * lp_df['amount']
223
+ lp_df.rename(columns={"price":"usd_value"},inplace=True)
224
+ for col in ['amount','usd_value']:
225
+ df[col] = pd.to_numeric(df[col], errors='coerce')
226
+ df[col] = df[col].apply(lambda x: f"{x:,.2f}")
227
+ return df,lp_df
228
+
229
+ with gr.Blocks() as demo:
230
+ gr.Markdown("## VICE Balances & PnL")
231
+
232
+ df1_out = gr.Dataframe(label="Current Balances")
233
+ df2_out = gr.Dataframe(label="LP Balances")
234
+
235
+ demo.load(
236
+ fn= get_all_dfs,
237
+ inputs = [],
238
+ outputs=[df1_out,df2_out]
239
+ )
240
+
241
+
242
+ demo.launch(debug=True, share=True)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ aiohttp
2
+ nest_asyncio
3
+ pandas
4
+ requests
5
+ gradio
6
+ web3
7
+ numpy