User test123@test.getpara.com expected to see 5 USDC balance on Solana at address 3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK, but the portfolio showed zero.
grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/GetSolanaBalancesResult: {}
Finding: No balances returned for this user.
grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/GetSolanaAddressResult: {}
Finding: No Solana address registered for this user.
grpcurl -d '{"user_id": "test123@test.getpara.com", "time_period": "1D"}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/GetPortfolioResult:
{
"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.
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.toolResult:
{
"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.
The backend uses a background job that:
- Runs every 5 minutes (configurable via
ALPHA_AI_SOLANA_BALANCE_REFRESH_SECS) - Fetches all users with registered Solana addresses from
user_blockchain_addressestable - For each user, queries their token balances from Solana RPC
- Stores balances in the
solana_token_balancesdatabase table - 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.
grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/CreateUserResult:
{
"success": true,
"message": "User 'test123@test.getpara.com' created successfully"
}grpcurl -d '{
"user_id": "test123@test.getpara.com",
"solana_address": "3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK"
}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/SetSolanaAddressResult:
{
"success": true,
"message": "Solana address set successfully"
}grpcurl -d '{"user_id": "test123@test.getpara.com"}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/GetAllBlockchainAddressesResult:
{
"addresses": [
{
"blockchain": "BLOCKCHAIN_TYPE_SOLANA",
"address": "3SmuXS2mwhody9ezyMi7Kyg62ymteKkTGcQJ2nKJbUgK"
}
]
}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/GetSolanaBalancesResult:
{
"balances": [
{
"symbol": "USDC",
"name": "USD Coin",
"contractAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"balance": 5000000,
"uiAmount": 5,
"decimals": 6,
"category": "Stablecoin"
}
// ... other tokens with zero balances
]
}grpcurl -d '{"user_id": "test123@test.getpara.com", "time_period": "1D"}' \
alpha-ai-backend-665016120277.us-central1.run.app:443 \
iqlusion.ai.app.IqlusionAiAppService/GetPortfolioResult:
{
"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.
- User must be created first -
CreateUsermust be called before any other operations - Address must be registered -
SetSolanaAddressorSetBlockchainAddressmust be called to link wallet - Background job required - Balances are not fetched in real-time; the background job must run
- Background job interval - Default is 5 minutes, configurable via
ALPHA_AI_SOLANA_BALANCE_REFRESH_SECSenvironment variable - USDC is cash - Stablecoins (USDC, USDT, PYUSD, DAI, BUSD) count toward
cashValuein portfolio
The iOS app should ensure:
- User is created on first login via
CreateUser - Wallet addresses are registered immediately after Para SDK authentication
- Clear UX message when balances are being indexed (e.g., "Syncing balances...")
- Retry logic if address registration fails
- Manual Refresh Endpoint - Add
RefreshUserBalancesRPC to trigger immediate indexing - Webhook on Address Registration - Trigger immediate balance fetch when address is registered
- Real-time Balance Query - Option to bypass cache and query RPC directly for fresh data
- Status Indicator - Add
last_indexed_attimestamp to balance responses
backend/src/service.rs:442-480- GetSolanaBalances implementationbackend/src/storage.rs:1622-1660- get_solana_token_balances database querybackend/src/background.rs:133-222- spawn_solana_balance_refresh background jobbackend/src/storage.rs:2542-2600- calculate_portfolio_value logicconfig/ai-stocks.json:97-108- USDC token configuration