import requests import asyncio import aiohttp import pandas as pd import urllib import gradio as gr import os from pymongo import MongoClient addresses = [ "0x46dae11e3ab74C417d370FB0d467364397178f5d", "0x2B3cb7D697Dd5224f3AcfC1b7EbDe77F468Dd539", "0x7B04395AF49caf8C4Fd5FF716698D97f394d0d41", "0x4dAFdbdB45947AB8666411AFc07F95b39Ab3841B", "0xa2ebb53A922E8fe9E6949316b0018F95f0956Ce7", "0x0FCc5f7845F3B2188918495f60F6294a15dc772b", "0xefa59c4aE5BaBA2c1017Ce2Fc9c1E0E080e5F448", "0x1C2A2D1b1A95a252AD4f9E8c9055885a1721c252", "0xfCb81D6a2678D9f0798124BD3E46bA0E1Ff0C32c", "0xdF04384C3AE43bD08E04692139C6B6C6Eb308B76", "0xA734C747E53171261568DbBB1BCd699EDF01925c", "0xC6347a0924aAbBA5E655397fbD18cb702066304b", "0xc6300201821CB7026E0e73cC10dC9Ca5C623Ff15", "0x2777698A53410C344e98267dB672a432c77C6Ed9", "0xCCc07e973c04c607381b96eCBe3e426cc7c17B88", "0xE813553077d0bfdd9615465D8A974F63bbf33aD4", "0x0a045118cDb3fB0FDb50D2f91f04c56B28F5fD07", "0x0bC67eE9A36f5bc8e05282E538FDe119C372a222", "0x1ca7bCe8A7c4F62a3575279688D9E9ad337f6b3d", "0x940665c733acBcA198306F8881c1d268E2F92DFA", "0x6393613ca5a87Cc2BEe2eC3610EcAcD279FcBcD6", "0xAB851cA6F8e5329Dcf9B164d312f7d5C9D41eE01", "0xe2Db92758567D1D67A861F0645F850ddb6e216E8", "0x4a7F42021C71Be21D3c21717743449620Abb3D25", "0x2Bd99Ac1dCa390A543BD06F7712ece7B787752a5", "0x8c27aa11FF3562c807C5A40e0512bDC043B39Bb0", "0xB4e6dEa305a1A84FA0B2185F36de31bcE2c22005", "0xA89f812f26ef2f6D89c81371A89787240c63D524", "0xF7a54082215D4508CD674b270ECc37Bd281FD92d", "0xc419410F5B29cdd4343013210ac194B872cF5a4B" ] # Chunk into groups of 3 def chunk_addresses(addresses, size): return [addresses[i:i + size] for i in range(0, len(addresses), size)] API_URL = "https://api.g.alchemy.com/data/v1/yhe6L3PXmiENzS1sP9Fu4_T5E3l0QyeB/assets/tokens/by-address" async def fetch_batch(session, batch): json_payload = { "addresses": [{"address": addr, "networks": ["arb-mainnet"]} for addr in batch], "withMetadata": True, "withPrices": True, "includeNativeTokens": True } async with session.post(API_URL, json=json_payload) as response: response = await response.json() return response['data']['tokens'] async def get_wallet_balances(addresses): async with aiohttp.ClientSession() as session: batches = chunk_addresses(addresses, 3) tasks = [fetch_batch(session, batch) for batch in batches] responses = await asyncio.gather(*tasks) first_parts = [] rest_parts = [] for res in responses: first_parts.extend(res[:3]) rest_parts.extend(res[3:]) responses = first_parts + rest_parts df = pd.DataFrame(responses) for i in range(len(addresses)): df.at[i,'tokenMetadata'] = {} df['tokenBalance'] = df['tokenBalance'].apply(lambda x : int(x,16)) df['decimals'] = df['tokenMetadata'].apply(lambda x : x.get('decimals',0)) df['tokenBalance'] = df['tokenBalance']/(10**df['decimals']) for i in range(len(addresses)): df.at[i, 'tokenBalance'] = df.at[i, 'tokenBalance'] / (10**18) df['symbol'] = df['tokenMetadata'].apply(lambda x : x.get('symbol','')) for i in range(len(addresses)): df.at[i,'symbol'] = 'ETH' df['currentPrice'] = df['tokenPrices'].apply(lambda x : x[0].get('value',None) if len(x) > 0 else None) df.drop(columns=['tokenPrices','tokenMetadata','network','tokenAddress'], inplace=True) df = df.dropna() df['tokenBalance'] = pd.to_numeric(df['tokenBalance'], errors='coerce') df = df[df['tokenBalance'] != 0] df['tokenBalance'] = pd.to_numeric(df['tokenBalance'], errors='coerce') df['currentPrice'] = pd.to_numeric(df['currentPrice'], errors='coerce') df['value'] = df['tokenBalance'] * df['currentPrice'] df.drop(columns=['decimals'],inplace=True) df = df[df['symbol'].isin(['BLUP', 'ETH', 'USDT', 'USDC'])] df= df[['address','symbol','tokenBalance','value']] df = df.rename(columns={'tokenBalance':'amount','value':'usd_value'}) df = df.sort_values(['address', 'symbol']) df['address'] = df['address'].mask(df['address'].duplicated()).fillna('') #df = df.groupby("symbol", as_index=False).sum() return df, df['usd_value'].sum() async def get_lp_balances(): client = MongoClient(os.getenv('MONGO_DB_URI')) db = client["debank_tokens"] token_collection = db["debank"] token_list = token_collection.find_one(sort=[("timestamp", -1)]) del token_list["_id"] del token_list["timestamp"] url = "https://api.debank.com/user?id=0x275c7f2781db0b78228029f85735059c9bdd4f35" SCRAPE_DO_TOKEN = os.getenv('SCRAPE_DO_KEY') headers = token_list encoded_url = urllib.parse.quote(url) proxy_url = f"http://api.scrape.do/?token={SCRAPE_DO_TOKEN}&url={encoded_url}&forwardHeaders=True&super=True" response = requests.get(proxy_url, headers=headers) response = response.json()['data']['user']['stats'] top_coins = response['top_coins'] top_tokens = response['top_tokens'] coins = pd.DataFrame(top_coins) tokens = pd.DataFrame(top_tokens) balances = pd.concat([coins, tokens], axis=0) balances.drop(columns=['id','logo_url','percent','price','chain_id'],inplace=True) balances = balances[['symbol','amount','usd_value']] return balances, balances['usd_value'].sum() async def get_all_dfs(): wallet_df, wallet_total = await get_wallet_balances(addresses) lp_df, lp_total = await get_lp_balances() final_df = pd.concat([wallet_df,lp_df],axis=0) final_df.drop(columns=['address'],inplace=True) final_df = final_df.groupby("symbol", as_index=False).sum() starting_df = pd.DataFrame([{"symbol":"ETH","amount":24,"usd_value":1613*24}]) pnl = final_df['usd_value'].sum() - starting_df['usd_value'].sum() return wallet_df, wallet_total, lp_df, lp_total, final_df, final_df['usd_value'].sum(),starting_df,starting_df['usd_value'].sum(),pnl with gr.Blocks() as demo: gr.Markdown("## BLUP Balances and PnL") df3_out = gr.Dataframe(label="Starting Balances") txt3_out = gr.Textbox(label="Total Value") df0_out = gr.Dataframe(label="Wallet Balances") txt0_out = gr.Textbox(label="Total Value") df1_out = gr.Dataframe(label="LP Balances") txt1_out = gr.Textbox(label="Total Value") df2_out = gr.Dataframe(label="Total Balances") txt2_out = gr.Textbox(label="Total Value") pnl_out = gr.Textbox(label="PNL (AUM Model)") # Load from MongoDB on app load (sync function) demo.load( fn= get_all_dfs, inputs = [], outputs=[df0_out, txt0_out, df1_out, txt1_out, df2_out, txt2_out,df3_out,txt3_out,pnl_out] ) demo.launch(debug=True, share=True)