This PR implements live NOVA token balance display in the application header, replacing hardcoded placeholder values with real on-chain data from the Stellar network. The balance is fetched from the authenticated /api/wallet/balance endpoint and updates dynamically after transactions.
The header was displaying a hardcoded placeholder balance instead of the user's actual NOVA token balance from the Stellar network. This is the most visible data point in the app and must reflect real on-chain data to provide users with accurate account information.
Implemented a complete balance display system with:
- Backend API endpoint for authenticated balance retrieval
- Frontend component with loading, error, and success states
- Automatic balance refresh after transactions
- Proper decimal formatting (7 places for Stellar)
- New Endpoint:
GET /api/wallet/balance- Requires authentication via JWT Bearer token
- Uses
authenticateUsermiddleware to validate user - Retrieves live NOVA balance from Stellar network via
walletService.getBalances() - Returns formatted balance with 7 decimal places
- Handles errors gracefully (no wallet linked, server errors)
- Displays authenticated user's live NOVA token balance
- Three States:
- Loading: Shows skeleton animation while fetching
- Error: Displays "—" with tooltip explaining the failure
- Success: Shows formatted balance with 7 decimal places
- Automatically fetches balance when wallet connects
- Integrates with Zustand store for state management
- Imports and renders
BalanceDisplaycomponent - Positioned next to wallet connection button
- Displays balance only when wallet is connected
- Calls
fetchBalanceFromAPI()after successful transfer - Ensures balance updates immediately after transaction
- Calls
fetchBalanceFromAPI()after successful redemption - Ensures balance updates immediately after transaction
- New State Properties:
balanceLoading: Boolean flag for loading statebalanceError: Error message string
- New Method:
fetchBalanceFromAPI()- Fetches balance from
/api/wallet/balanceendpoint - Handles loading and error states
- Updates store with formatted balance
- Provides user-friendly error messages
- Fetches balance from
-
Header fetches and displays authenticated user's live NOVA balance
- BalanceDisplay component fetches from
/api/wallet/balanceon mount - Balance updates when wallet connects
- BalanceDisplay component fetches from
-
Balance updates on every successful transaction
- TransferForm calls
fetchBalanceFromAPI()after successful transfer - RedeemForm calls
fetchBalanceFromAPI()after successful redemption - Balance reflects new on-chain state immediately
- TransferForm calls
-
Loading state shows skeleton while first fetch completes
- BalanceDisplay shows animated skeleton with two lines
- Skeleton matches balance display dimensions
- Smooth transition to actual balance
-
Error state shows — with tooltip explaining fetch failure
- Displays "—" when balance fetch fails
- Tooltip appears on hover with error message
- User-friendly error messages from ERROR_MESSAGES object
-
Balance formatted with correct decimal precision (7 places for Stellar)
- Backend formats to 7 decimal places using
.toFixed(7) - Frontend uses
toLocaleString()withminimumFractionDigits: 7 - Consistent formatting across all displays
- Backend formats to 7 decimal places using
GET /api/wallet/balance
Authorization: Bearer {token}
Response (Success):
{
"success": true,
"balance": "1234.5678901",
"raw": "1234.5678901",
"stellarPublicKey": "GXXXXXX..."
}
Response (Error):
{
"success": false,
"error": "no_wallet_linked",
"message": "User has no linked Stellar wallet"
}
- BalanceDisplay is rendered in Header.js next to WalletConnectButton
- Uses Zustand store for state management
- Integrates with existing authentication system
- Follows existing error handling patterns
- User connects wallet →
publicKeyset in store - BalanceDisplay mounts → calls
fetchBalanceFromAPI() balanceLoadingset to true → skeleton displays- API returns balance →
balanceupdated,balanceLoadingset to false - User performs transaction → form calls
fetchBalanceFromAPI() - Balance refreshes with new on-chain value
-
Connection Flow
- Connect wallet and verify balance displays
- Verify skeleton shows during initial fetch
- Verify balance updates after connection
-
Transaction Flow
- Perform transfer and verify balance updates
- Perform redemption and verify balance updates
- Verify balance reflects correct on-chain value
-
Error Handling
- Disconnect wallet and verify balance hides
- Simulate API failure and verify error state
- Verify tooltip displays on error hover
-
Formatting
- Verify balance displays with 7 decimal places
- Test with various balance amounts
- Verify formatting on different locales
-
Network States
- Test on mainnet and testnet
- Verify network badge displays correctly
- Verify balance updates on network switch
novaRewards/backend/routes/wallet.js(+42 lines)novaRewards/frontend/components/BalanceDisplay.js(+84 lines, new)novaRewards/frontend/components/layout/Header.js(+2 lines)novaRewards/frontend/components/TransferForm.js(+6 lines)novaRewards/frontend/components/RedeemForm.js(+8 lines)novaRewards/frontend/store/walletStore.js(+25 lines)
Total: 6 files changed, 165 insertions(+), 2 deletions(-)
None. This is a backward-compatible enhancement.
No new dependencies added. Uses existing:
- Zustand for state management
- Axios for API calls
- Lucide React for icons
- Tailwind CSS for styling
- No database migrations required
- No environment variable changes required
- API endpoint requires existing authentication middleware
- Frontend changes are client-side only
Closes #[issue-number] - Live NOVA balance header display
- Code follows project style guidelines
- All acceptance criteria met
- Error handling implemented
- Loading states implemented
- Responsive design maintained
- Dark mode support included
- Accessibility considerations addressed
- No console errors or warnings