Skip to content

Optimize portfolio state: Only fetch balances from defaultNetworks #103

@fengtality

Description

@fengtality

Problem

The /portfolio/state endpoint is extremely slow because _update_gateway_balances() queries all configured networks for each chain, even if the user only uses a subset of networks.

Current Behavior

When fetching Gateway wallet balances, the code iterates through ALL available networks:

# accounts_service.py:1469-1477
for network in networks:  # ALL 9 ethereum networks, 2 solana networks
    chain_network_key = f"{chain}-{network}"
    balance_tasks.append(self.get_gateway_balances(chain, address, network=network))

This results in:

  • 9 Ethereum network RPC calls (mainnet, polygon, optimism, base, celo, arbitrum, avalanche, bnb, etc.)
  • 2 Solana network RPC calls

Many EVM RPC calls timeout (2s per token), causing massive delays:

2025-12-26 16:00:11 | warn | Error getting balance for WETH: Token balance request timed out
2025-12-26 16:00:11 | warn | Error getting balance for DAI: Token balance request timed out
2025-12-26 16:00:11 | warn | Error getting balance for ETH: Token balance request timed out
...
2025-12-26 16:04:09 | error | Error getting balances: timeout (url="https://celo-mainnet.infura.io/...")

Expected Behavior

Only query networks that the user has explicitly configured as active.

Proposed Solution

Reference a new defaultNetworks list from Gateway's chain config files (ethereum.yml, solana.yml).

Gateway Config Structure (after gateway PR)

Current config:

# ethereum.yml
defaultNetwork: mainnet
defaultWallet: "0x..."
rpcProvider: infura

New config with defaultNetworks:

# ethereum.yml  
defaultNetwork: mainnet          # Keep for backwards compatibility
defaultNetworks:                 # NEW: Networks to query for balances
  - mainnet
  - base
defaultWallet: "0x..."
rpcProvider: infura

Implementation Changes

  1. Modify _update_gateway_balances() to fetch defaultNetworks from Gateway config:
async def _update_gateway_balances(self, chain_networks: Optional[List[str]] = None):
    # ... existing code ...
    
    for wallet_info in wallets:
        chain = wallet_info.get("chain")
        
        # Get defaultNetworks from chain config (NEW)
        chain_config = await self.gateway_client.get_config(chain)
        default_networks = chain_config.get("defaultNetworks")
        
        # Fallback to all networks if defaultNetworks not configured
        if default_networks:
            networks = default_networks
        else:
            networks = chain_networks_map.get(chain, [])
        
        for network in networks:
            # ... existing balance fetching code ...
  1. Add helper method to fetch chain config with caching:
async def _get_chain_default_networks(self, chain: str) -> Optional[List[str]]:
    """Get defaultNetworks from Gateway chain config."""
    config = await self.gateway_client.get_config(chain)
    return config.get("defaultNetworks") if config else None

Benefits

  • Performance: Only query networks user actually uses (e.g., 2 instead of 9 for Ethereum)
  • Reliability: Avoid timeouts from unused network RPCs
  • User Control: Users can configure exactly which networks to monitor
  • Backwards Compatible: Falls back to querying all networks if defaultNetworks not set

Dependencies

Affected Files

  • services/accounts_service.py - _update_gateway_balances() method
  • services/gateway_client.py - May need config caching

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions