Improve Configure Fees Design - #913
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
iOS Simulator preview build is ready: https://github.com/stellar/freighter-mobile/releases/tag/untagged-5f95785a50f272c3e130 (SDF collaborators only — install instructions in the release description) |
There was a problem hiding this comment.
Pull request overview
This PR implements #413 by reworking transaction fee configuration from a free-text input into Low / Med / High / Custom tiers, and by freezing a single “network fee snapshot” across a Send / Swap / Send-Collectible flow to prevent mid-flow fee/congestion flicker.
Changes:
- Add fee priority tiers (Low/Med/High/Custom) backed by Horizon
feeStats().max_feepercentiles and persist the selected tier in settings ducks. - Freeze network fee data per-network per-flow via a cache in
useNetworkFees, with explicit cache clearing on flow exit and navigator pre-warming on flow entry. - Introduce a shared fee-details bottom sheet hook to unify the fee info affordance (classic info vs Soroban breakdown) and support previewing unsaved inclusion fee changes.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/stellar.ts | Derives fee presets from Horizon fee stats and returns { recommendedFee, networkCongestion, feePresets }. |
| src/navigators/SwapNavigator.tsx | Pre-warms cached network fees at Swap flow entry. |
| src/navigators/SendPaymentNavigator.tsx | Pre-warms cached network fees and clears flow state + fee cache on unmount. |
| src/hooks/useNetworkFees.ts | Implements frozen per-network fee snapshot + in-flight de-duping + explicit cache clear. |
| src/hooks/useInitialRecommendedFee.ts | Defaults both fee amount and tier from congestion mapping until user edits. |
| src/hooks/useFeeDetailsBottomSheet.tsx | New shared hook to render/open fee info sheets (classic vs Soroban breakdown). |
| src/config/types.ts | Adds FeePriority, FeePresets, and CONGESTION_TO_FEE_PRIORITY. |
| src/ducks/transactionSettings.ts | Persists feePriority in transaction settings store. |
| src/ducks/swapSettings.ts | Persists feePriority in swap settings store. |
| src/components/TransactionSettingsBottomSheet.tsx | Replaces fee input UX with tiered selector, locks input for presets, and integrates shared fee details sheets. |
| src/components/sds/SegmentedControl.tsx | Updates segmented control layout and adds radio-group accessibility + improved touch target. |
| src/components/screens/SwapScreen/screens/SwapAmountScreen.tsx | Uses congestion when initializing defaults and clears fee cache on unmount. |
| src/components/screens/SwapScreen/components/SwapReviewBottomSheet.tsx | Displays fee row with info icon and mounts shared fee details sheets. |
| src/components/screens/SendScreen/screens/TransactionAmountScreen.tsx | Uses congestion when initializing defaults; removes direct fee breakdown sheet wiring. |
| src/components/screens/SendScreen/screens/SendCollectibleReview.tsx | Uses congestion when initializing defaults; removes direct fee breakdown sheet wiring. |
| src/components/screens/SendScreen/components/SendReviewBottomSheet.tsx | Uses shared fee details sheets and aligns fee display with total fee logic. |
| src/components/FeeBreakdownBottomSheet.tsx | Adds inclusion-fee preview override and adjusts total fee computation accordingly. |
| src/i18n/locales/en/translations.json | Adds new transaction settings strings for network + priority tiers. |
| src/i18n/locales/pt/translations.json | Adds Portuguese strings for network + priority tiers. |
| src/helpers/testUtils.tsx | Refactors test render helper to use RTL wrapper to preserve providers across rerenders. |
| tests/services/stellar.test.ts | Adds coverage for fee presets + congestion→recommended mapping + fallback behavior. |
| tests/hooks/useNetworkFees.test.ts | Updates tests for cache freeze/clear behavior (needs mock shape alignment). |
| tests/hooks/useInitialRecommendedFee.test.tsx | Adds assertions for congestion→tier defaulting and manual override behavior. |
| tests/ducks/transactionSettings.test.ts | Adds tests for storing/resetting feePriority. |
| tests/components/TransactionSettingsBottomSheet.test.tsx | Adds integration tests for tier selection, scaling, locking, and preview behavior. |
| tests/components/screens/SwapScreen/SwapAmountScreen.test.tsx | Updates mocks for new swap settings fields and fee cache clearing. |
| tests/components/FeeBreakdownBottomSheet.test.tsx | Adds tests for inclusion fee override preview behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| feePresets = { | ||
| [FeePriority.LOW]: stroopToXlm(maxFee.p10).toFixed(), | ||
| [FeePriority.MEDIUM]: stroopToXlm(maxFee.p50).toFixed(), | ||
| [FeePriority.HIGH]: stroopToXlm(maxFee.p90).toFixed(), | ||
| }; |
| expect(first.result.current.networkCongestion).toBe(NetworkCongestion.LOW); | ||
| expect(first.result.current.recommendedFee).toBe(""); | ||
|
|
||
| // Flush the fetch promise + its setState. | ||
| await act(async () => { | ||
| await Promise.resolve(); | ||
| }); | ||
| await flushPromises(); | ||
| expect(first.result.current.networkCongestion).toBe(NetworkCongestion.HIGH); |
| const handleFeePriorityChange = useCallback( | ||
| (value: string | number) => { | ||
| feeInteractedRef.current = true; | ||
| const priority = value as FeePriority; | ||
| // Preset tiers derive their shown value automatically; switching to |
| mockGetNetworkFees.mockResolvedValue({ | ||
| recommendedFee: "0.005", | ||
| networkCongestion: NetworkCongestion.HIGH, | ||
| }); |
…/freighter-mobile into lf-improve-configure-fees-design
Code reviewFound 1 issue:
If the user taps Low/Med/High before the presets have loaded, the tap is discarded and freighter-mobile/src/components/TransactionSettingsBottomSheet.tsx Lines 429 to 441 in 7638afa The effect it disables: freighter-mobile/src/components/TransactionSettingsBottomSheet.tsx Lines 272 to 281 in 7638afa 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
# Conflicts: # src/components/sds/SegmentedControl.tsx
Closes #413
📱 - 1.19.27 (1782817626)
Reworks the transaction‑settings fee UI from a single free‑text input into a Low / Med / High / Custom priority selector, and makes the network fee data consistent and stable for the duration of a single Send / Swap / Send‑Collectible flow (no mid‑flow flicker). Presets are derived from Horizon feeStats, and the default tier follows current network congestion.
Builds on the existing FeeBreakdownBottomSheet (inclusion / resource / total) shipped earlier for this ticket.
Currently uses the API response of p10/p50 and p90 for low/med/high, instead of the mode of the recent values for the derivation
It respects the operation count from the Swap to new token, so med show as 2x fee, for example.
The network congestion is also frozen during the duration for consistency Low <> Low / Med <> Med / High <> High
ScreenRecording_06-30-2026.10-10-22_1.MP4
Small fix post recording to make the Fees show the total fee for soroban transaction, not the inclusion fee only on the SendReview sheet
Android Smoke test:
Screen.Recording.2026-06-30.at.10.47.48.mov
Checklist
PR structure
Testing
Release