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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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