Skip to content

Fix Stellar wallet refresh error handling and transaction history mapping - #135

Merged
memplethee-lab merged 5 commits into
LintError:mainfrom
ykargeee-bit:feature/stellar-wallet-history-and-refresh-errors
Oct 12, 2026
Merged

memplethee-lab merged 5 commits into
LintError:mainfrom
ykargeee-bit:feature/stellar-wallet-history-and-refresh-errors

Conversation

@ykargeee-bit

Copy link
Copy Markdown
Contributor

Stellar Wallet: refresh errors & transaction history

Summary

Two Stellar wallet bugs, both rooted in StellarWallet.tsx and utils/stellar.ts.

#17 - Failed refreshes were silent, leaving stale balances

loadAccountData() caught every error, console.error'd it and returned. The 30s poll and the manual Refresh button both swallowed failures, so users saw old balances with no indication anything went wrong - and handleRefresh() always showed a Balances refreshed success toast even when nothing was refreshed.

  • The failure is now exposed through refreshError state and a once-per-outage toastError('Failed to refresh balances'), so a persistent outage does not stack identical toasts.
  • Previous balances are kept (not blanked), and the balance card shows Stale data - refresh failed; after a good refresh it shows Last updated <time>.
  • The error is re-thrown so useAccountPolling() reports failure and handleRefresh() only shows success when it truly succeeded.
  • A failed post-creation refresh no longer turns a successful account creation into Failed to create account.

#16 - Every history row showed "unknown / 0 XLM"

getTransactionHistory() fetched /accounts/{id}/transactions, whose records do not embed operations. The wallet then read tx.operations?.records?.[0], which was always undefined, defaulting to unknown / 0.

  • Now queries /accounts/{id}/payments, which returns the counterparty and amount inline (no per-transaction operations round-trip).
  • New mapPaymentToHistoryEntry() normalizes payment, create_account, account_merge and path_payment_* records into a flat TransactionHistoryEntry.
  • Rows render the real amount + asset and the destination; non-payment operations render a readable label.
  • The section shows explicit No transactions yet. / Could not load transactions. states instead of stale rows.

Files changed

  • src/utils/stellar.ts - payments endpoint + TransactionHistoryEntry / mapPaymentToHistoryEntry()
  • src/components/stellar/StellarWallet.tsx - error/stale state, toasts, history rendering
  • docs/stellar-wallet-qa.md - manual QA notes for the failure path

Testing

Manual QA steps are documented in docs/stellar-wallet-qa.md (refresh failure via DevTools offline, history mapping). This repo has no component test harness yet.

Notes

  • No new dependencies.
  • HORIZON_URL remains the existing constant (extracting network config is tracked separately).

Closes #16
Closes #17

getTransactionHistory() requested /accounts/{id}/transactions, whose
records do not embed operations. The wallet then read
tx.operations?.records?.[0], so every row fell back to 'unknown / 0 XLM'
and the Recent Transactions list was effectively broken.

- Query /accounts/{id}/payments, which returns the counterparty and amount
  inline, instead of fetching operations per transaction
- Add TransactionHistoryEntry and mapPaymentToHistoryEntry() to normalize
  payment, create_account, account_merge and path-payment records
- Label non-payment operations instead of inventing a destination

Related to LintError#16
loadAccountData() caught every error, logged it, and returned, so a failed
refresh left stale balances on screen with no signal to the user.

- Keep the previous balances but expose the failure via refreshError state
- Show toastError('Failed to refresh balances') once per outage so the 30s
  poll does not stack identical toasts on every tick
- Re-throw so useAccountPolling() can report the failure, and only show the
  'Balances refreshed' toast in handleRefresh() when it actually succeeded
- Stop a failed post-creation refresh from turning account creation into a
  'Failed to create account' error

Closes LintError#17
Users had no way to tell whether the balance on screen was fresh. Add a
small status line under the balance:

- 'Last updated <time>' after a successful load
- 'Stale data - refresh failed' (with an icon, aria-live polite) when the
  most recent refresh failed

Refs LintError#17
…states

The Recent Transactions list now renders the normalized history entries:

- Payment rows show the real amount plus asset (e.g. '2.5 XLM' or '10 USDC')
  and the destination instead of the previous 'unknown / 0 XLM'
- Non-payment operations (account created/merged, path payments) render a
  readable label
- The section is always shown with an explicit 'No transactions yet.' empty
  state, or 'Could not load transactions.' when the last refresh failed, so
  stale rows are never presented as live data

Closes LintError#16
Document the failure-path checks the issues ask for, since there is no
component-test harness yet:

- Refresh failure with DevTools offline: error toast, stale indicator,
  previous balance retained, no toast spam
- Transaction history shows real destination/amount and empty/error states

Refs LintError#16
Refs LintError#17
@memplethee-lab
memplethee-lab merged commit 02b4266 into LintError:main Oct 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

loadAccountData() swallows errors leaving stale balances after failed refresh Transaction history mapping assumes every tx has payment operations

2 participants