Skip to content

Instantly share code, notes, and snippets.

@zmanian
Created November 20, 2025 00:31
Show Gist options
  • Select an option

  • Save zmanian/557f2423cdc3fa02ac102314d7ea6d8b to your computer and use it in GitHub Desktop.

Select an option

Save zmanian/557f2423cdc3fa02ac102314d7ea6d8b to your computer and use it in GitHub Desktop.
Alpha AI Backend: Troubleshooting Zero Balance Issue - Diagnostic and Fix Sequence

Troubleshooting Guide: Zero Balance Issue

Issue

User test123@test.getpara.com expected to see 5 USDC balance on Solana at address 3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK, but the portfolio showed zero.

Diagnostic Steps

Step 1: Check User's Solana Balances via API

grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/GetSolanaBalances

Result: {} Finding: No balances returned for this user.


Step 2: Check if Solana Address is Registered

grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/GetSolanaAddress

Result: {} Finding: No Solana address registered for this user.


Step 3: Check Portfolio Value

grpcurl -d '{"user_id": "test123@test.getpara.com", "time_period": "1D"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/GetPortfolio

Result:

{
  "portfolio": {
    "id": "portfolio-test123@test.getpara.com",
    "balanceHistory": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  }
}

Finding: Portfolio shows zero value.


Step 4: Verify On-Chain Balance

curl -s -X POST "https://api.mainnet-beta.solana.com" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"getTokenAccountsByOwner",
    "params":[
      "3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK",
      {"programId":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},
      {"encoding":"jsonParsed"}
    ]
  }' | python3 -m json.tool

Result:

{
  "jsonrpc": "2.0",
  "result": {
    "value": [
      {
        "account": {
          "data": {
            "parsed": {
              "info": {
                "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
                "owner": "3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK",
                "tokenAmount": {
                  "amount": "5000000",
                  "decimals": 6,
                  "uiAmount": 5.0,
                  "uiAmountString": "5"
                }
              }
            }
          }
        }
      }
    ]
  }
}

Finding: ✅ On-chain balance confirms 5 USDC exists at the address.


Root Cause Analysis

The backend uses a background job that:

  1. Runs every 5 minutes (configurable via ALPHA_AI_SOLANA_BALANCE_REFRESH_SECS)
  2. Fetches all users with registered Solana addresses from user_blockchain_addresses table
  3. For each user, queries their token balances from Solana RPC
  4. Stores balances in the solana_token_balances database table
  5. Portfolio and balance endpoints read from this table

The issue: The user's Solana address was not registered in the backend, so the background job never fetched their balances.


Fix Steps

Step 1: Create User Account

grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/CreateUser

Result:

{
  "success": true,
  "message": "User 'test123@test.getpara.com' created successfully"
}

Step 2: Register Solana Address

grpcurl -d '{
  "user_id": "test123@test.getpara.com",
  "solana_address": "3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK"
}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/SetSolanaAddress

Result:

{
  "success": true,
  "message": "Solana address set successfully"
}

Step 3: Verify Address Registration

grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/GetAllBlockchainAddresses

Result:

{
  "addresses": [
    {
      "blockchain": "BLOCKCHAIN_TYPE_SOLANA",
      "address": "3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK"
    }
  ]
}

Step 4: Wait for Background Job (or trigger manually)

The background job runs every 5 minutes. After waiting ~1 minute for the next cycle:

grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/GetSolanaBalances

Result:

{
  "balances": [
    {
      "symbol": "USDC",
      "name": "USD Coin",
      "contractAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "balance": 5000000,
      "uiAmount": 5,
      "decimals": 6,
      "category": "Stablecoin"
    }
    // ... other tokens with zero balances
  ]
}

Step 5: Verify Portfolio Calculation

grpcurl -d '{"user_id": "test123@test.getpara.com", "time_period": "1D"}' \
  alpha-ai-backend-665016120277.us-central1.run.app:443 \
  iqlusion.ai.app.IqlusionAiAppService/GetPortfolio

Result:

{
  "portfolio": {
    "id": "portfolio-test123@test.getpara.com",
    "portfolioValue": 5,
    "cashValue": 5,
    "balanceHistory": [3.5, 3.74, ..., 4.76]
  }
}

Issue Resolved: Portfolio now shows $5 total value, $5 cash value.


Key Takeaways

  1. User must be created first - CreateUser must be called before any other operations
  2. Address must be registered - SetSolanaAddress or SetBlockchainAddress must be called to link wallet
  3. Background job required - Balances are not fetched in real-time; the background job must run
  4. Background job interval - Default is 5 minutes, configurable via ALPHA_AI_SOLANA_BALANCE_REFRESH_SECS environment variable
  5. USDC is cash - Stablecoins (USDC, USDT, PYUSD, DAI, BUSD) count toward cashValue in portfolio

Prevention in Production

The iOS app should ensure:

  1. User is created on first login via CreateUser
  2. Wallet addresses are registered immediately after Para SDK authentication
  3. Clear UX message when balances are being indexed (e.g., "Syncing balances...")
  4. Retry logic if address registration fails

Future Improvements

  1. Manual Refresh Endpoint - Add RefreshUserBalances RPC to trigger immediate indexing
  2. Webhook on Address Registration - Trigger immediate balance fetch when address is registered
  3. Real-time Balance Query - Option to bypass cache and query RPC directly for fresh data
  4. Status Indicator - Add last_indexed_at timestamp to balance responses

Related Files

  • backend/src/service.rs:442-480 - GetSolanaBalances implementation
  • backend/src/storage.rs:1622-1660 - get_solana_token_balances database query
  • backend/src/background.rs:133-222 - spawn_solana_balance_refresh background job
  • backend/src/storage.rs:2542-2600 - calculate_portfolio_value logic
  • config/ai-stocks.json:97-108 - USDC token configuration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment