Skip to content

Wallet balance is hardcoded to Horizon testnet: mainnet wallets always display a zero balance #8

Description

@ibrahimmosouf-png

Labels / Complexity: bug,dx · High — 13## Problem

store/walletStore.ts fetches balances from a hardcoded testnet endpoint regardless of the configured network:

// store/walletStore.ts
const res = await fetch(`https://horizon-testnet.stellar.org/accounts/${address}`);

The repo already has network-aware infrastructure that this bypasses: lib/stellar/config.ts defines HORIZON_URLS and getStellarConfig, and lib/env.ts validates NEXT_PUBLIC_STELLAR_NETWORK and NEXT_PUBLIC_STELLAR_HORIZON_URL.

  • Mainnet wallets always show zero: with NEXT_PUBLIC_STELLAR_NETWORK=mainnet (per .env.example), the balance lookup still hits testnet Horizon, which either returns a 404 (rendered as '0.0000000') or a testnet balance unrelated to the user's mainnet account.
  • Balance never refreshes: fetchBalance is called from connect without being awaited and never runs again, so a donation or funding event is not reflected until a full reconnect.
  • Account-not-found is indistinguishable from zero: a 404 from Horizon is silently shown as a zero balance, so users cannot tell an empty account from a lookup failure.

Root cause

// store/walletStore.ts
const fetchBalance = async (address: string, set: any) => {
  // hardcoded testnet URL ignores NEXT_PUBLIC_STELLAR_NETWORK / HORIZON_URLS
  const res = await fetch(`https://horizon-testnet.stellar.org/accounts/${address}`);

Why this is architecturally hard

  1. The balance lookup must resolve the Horizon URL through getStellarConfig() (or the env value) per network, which means the store cannot keep a literal URL and must import from lib/stellar/ without creating a client/server split.
  2. Account-not-found must be distinguishable from a zero balance, which requires parsing Horizon's 404 response rather than collapsing every failure into '0.0000000'.
  3. The refresh lifecycle is a design decision: refresh on connect, on network change, and periodically, without fighting the fire-and-forget call in connect or causing the global loading overlay in lib/api/interceptors.ts to flash on background polls.
  4. Native balance parsing must stay robust across Horizon response shapes (asset_type === 'native'), which the current find already assumes but never tests.

Acceptance criteria

  • A connected wallet's balance is fetched from the Horizon URL of the configured network, not a hardcoded URL.
  • On mainnet configuration the balance reflects the mainnet account; switching NEXT_PUBLIC_STELLAR_NETWORK changes the lookup target.
  • A brand-new account shows zero with no error; a Horizon failure surfaces as an error rather than a silently wrong balance.
  • Balance refreshes on reconnect and at least once after connect without user action.
  • Tests cover the fetch with mocked responses: native balance, no native asset, 404, network error, and mainnet vs testnet URL selection.

Out of scope

Multi-asset balance display and trustline management; only the native balance lookup is in scope.

Getting started

  • Read store/walletStore.ts, lib/stellar/config.ts, lib/env.ts, and components/WalletDropdown.tsx for how the balance is displayed.
  • Verify with npm run type-check and npm run lint.

Good first files to read: store/walletStore.ts, lib/stellar/config.ts, lib/env.ts.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignbugSomething isn't workingdxDeveloper experience

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions