Skip to content

Settings page: autoRefreshInterval, slippageTolerance, defaultMemo, and showTestnetWarning are all saved but never actually applied anywhere — only network works #46

Description

@abayomicornelius

Problem

The Settings page (src/pages/Settings.tsx) lets a user configure five preferences, shows a "Settings Saved!" confirmation, and persists them to localStorage — but four of the five silently have no effect on the app's actual behavior. Only network is genuinely wired end to end.

autoRefreshInterval is read from a localStorage key that nothing ever writes. Settings.tsx's useSettings() hook persists the entire settings object as one JSON blob under a single key:

// src/pages/Settings.tsx:36-38
const save = (next: AppSettings) => {
  setSettings(next)
  localStorage.setItem('stellarsend_settings', JSON.stringify(next))
}

But WalletContext.tsx's account-refresh interval reads a completely different, flat key that is never written anywhere in the codebase:

// src/context/WalletContext.tsx:154-159
const interval = parseInt(
  localStorage.getItem('stellarsend_refresh_interval') || '30',
  10,
)
refreshTimerRef.current = setInterval(refreshAccount, interval * 1_000)
$ grep -rn "stellarsend_refresh_interval" src --include="*.tsx" --include="*.ts"
src/context/WalletContext.tsx:156:      localStorage.getItem('stellarsend_refresh_interval') || '30',

That's the only occurrence in the whole codebase. Whatever the user picks in the "Auto-Refresh Interval" dropdown (10s / 30s / 1 min / 5 min), WalletContext always falls back to the hardcoded default of 30, forever.

slippageTolerance is saved but never read by the quote/payment pipeline. QuoteRequest (src/types/index.ts:130-138) — what actually gets sent to quoteApi.getQuote — has no slippageTolerance field at all; the slippage value used everywhere in the send flow (QuoteCard.tsx, buildTransactionFromQuote in lib/stellar.ts) comes from quote.slippageTolerance, a field the backend returns on the quote response, not from the user's Settings selection:

$ grep -rn "slippageTolerance" src --include="*.tsx" --include="*.ts" | grep -v types/index.ts
src/components/send/QuoteCard.tsx:167,171   # uses quote.slippageTolerance (from the backend quote)
src/lib/stellar.ts:204                       # uses quote.slippageTolerance
src/pages/Settings.tsx:265-266               # reads/writes localSettings.slippageTolerance
src/lib/api.ts:121                           # slippageTolerance?: string — an unused field on an unused buildTransaction params type
src/pages/Send.tsx:177                       # hardcodes '0.5' in an unrelated placeholder quote object

The user's configured tolerance is round-tripped to and from localStorage purely for its own sake.

defaultMemo is never read outside Settings.tsx itself. Send.tsx seeds SendForm's defaultValues from state.formValues only (src/pages/Send.tsx:145), never from settings.defaultMemo — so the memo field is never pre-filled despite the setting existing specifically to do that (per its own hint text: "Will be pre-filled on the send form").

showTestnetWarning is never read outside Settings.tsx either. The testnet banner in Layout.tsx is shown unconditionally whenever network === 'testnet', with no reference to the setting meant to control it:

// src/components/layout/Layout.tsx:13-20
{network === 'testnet' && (
  <div className="bg-warning-500/15 ...">
    <p>You are on <strong>Testnet</strong> — ...</p>
  </div>
)}

Toggling "Show testnet banner" off in Settings has no observable effect anywhere.

Why it matters

This isn't a cosmetic gap in one setting — it's four out of five controls on the entire Settings page silently doing nothing, while the page actively tells the user otherwise: the "Saved!" confirmation, the descriptive hint text under each control ("Maximum price deviation before transaction reverts", "Will be pre-filled on the send form", "Display a warning banner when using testnet"), and the very existence of a form with a save button all signal that these are live, meaningful preferences. A user who deliberately sets a tighter slippage tolerance to protect themselves from a bad path-payment fill, for example, gets no such protection — the number they typed is inert.

Reproduction

  • Set "Auto-Refresh Interval" to "5 minutes", save, reload, connect a wallet, and watch network requests — refreshAccount() still fires every 30 seconds (grep above confirms nothing ever writes stellarsend_refresh_interval).
  • Set "Default Memo" to some text, save, navigate to Send — the memo field on SendForm is empty, not pre-filled.
  • Turn off "Show testnet banner" while connected to testnet — the banner in Layout.tsx remains visible.
  • Set "Slippage Tolerance" to 5, then send a path payment — buildTransactionFromQuote's destMin calculation uses quote.slippageTolerance from the backend's quote response, not the 5 just configured.

Suggested fix

  • autoRefreshInterval: either write it under the key WalletContext actually reads (stellarsend_refresh_interval) when saving settings, or — better — have WalletContext read autoRefreshInterval out of the same stellarsend_settings blob Settings.tsx already writes, so there's one source of truth.
  • defaultMemo: thread settings.defaultMemo into SendForm's defaultValues in Send.tsx when there's no in-progress state.formValues yet.
  • showTestnetWarning: gate Layout.tsx's banner on the setting, not just network === 'testnet'.
  • slippageTolerance: either add it to QuoteRequest and have the backend honor it when computing the quote's own slippageTolerance/destMin, or remove the control from Settings if slippage is intentionally always server-determined, to stop presenting it as a working client-side control.

Additional Notes

  • src/pages/Settings.tsx:25-44 (useSettings), src/context/WalletContext.tsx:154-159, src/components/layout/Layout.tsx:13-20, src/pages/Send.tsx:145, src/types/index.ts:130-138,216-230 (QuoteRequest, AppSettings/DEFAULT_SETTINGS).
  • Testing strategy: an integration test that saves a non-default AppSettings object and asserts observable effects — WalletContext's refresh timer interval, SendForm's initial memo value, and Layout's banner visibility — currently none of the three would pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Third CampaignCampaign: Third CampaignbugSomething isn't workingvery hardVery difficult / senior-level bounty issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions