Skip to content

Commit 34548b1

Browse files
committed
Fix ramp quotes not refetching when plugins change
Include plugin IDs in React Query key so quotes refetch when region/currency/wallet changes affect available plugins. Simplify queryFn to always check current plugins while reusing valid cached quotes.
1 parent 5ae8416 commit 34548b1

File tree

3 files changed

+32
-109
lines changed

3 files changed

+32
-109
lines changed

src/components/scenes/TradeCreateScene.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,7 @@ export const TradeCreateScene: React.FC<Props> = (props: Props) => {
382382
}
383383

384384
navigation.navigate('rampSelectOption', {
385-
rampQuoteRequest,
386-
quotes: sortedQuotes // Pass the sorted quotes
385+
rampQuoteRequest
387386
})
388387
})
389388

src/components/scenes/TradeOptionSelectScene.tsx

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@ import { EdgeText } from '../themed/EdgeText'
3434

3535
export interface RampSelectOptionParams {
3636
rampQuoteRequest: RampQuoteRequest
37-
quotes?: RampQuoteResult[]
3837
}
3938

4039
interface Props extends BuyTabSceneProps<'rampSelectOption'> {}
4140

4241
export const TradeOptionSelectScene: React.FC<Props> = (props: Props) => {
4342
const { route } = props
44-
const { rampQuoteRequest, quotes: precomputedQuotes } = route.params
43+
const { rampQuoteRequest } = route.params
4544

4645
const theme = useTheme()
4746
const account = useSelector(state => state.core.account)
@@ -56,7 +55,7 @@ export const TradeOptionSelectScene: React.FC<Props> = (props: Props) => {
5655
return map
5756
}, [rampPluginArray])
5857

59-
// Use supported plugins hook only if no precomputed quotes
58+
// Use supported plugins hook
6059
const { supportedPlugins } = useSupportedPlugins({
6160
selectedWallet: rampQuoteRequest.wallet,
6261
selectedCrypto:
@@ -76,24 +75,20 @@ export const TradeOptionSelectScene: React.FC<Props> = (props: Props) => {
7675
direction: rampQuoteRequest.direction
7776
})
7877

79-
// Use precomputed quotes if available, otherwise use supported plugins
80-
const pluginsToUse =
81-
precomputedQuotes != null
82-
? rampPlugins
83-
: Object.fromEntries(
84-
supportedPlugins.map(plugin => [plugin.pluginId, plugin])
85-
)
78+
// Use supported plugins
79+
const pluginsToUse = Object.fromEntries(
80+
supportedPlugins.map(plugin => [plugin.pluginId, plugin])
81+
)
8682

87-
// Use the new hook with precomputed quotes
83+
// Use the ramp quotes hook
8884
const {
8985
quotes: allQuotes,
9086
isLoading: isLoadingQuotes,
9187
isFetching: isFetchingQuotes,
9288
errors: failedQuotes
9389
} = useRampQuotes({
9490
rampQuoteRequest,
95-
plugins: pluginsToUse,
96-
precomputedQuotes
91+
plugins: pluginsToUse
9792
})
9893

9994
const handleQuotePress = async (quote: RampQuoteResult): Promise<void> => {

src/hooks/useRampQuotes.ts

Lines changed: 23 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ interface UseRampQuotesOptions {
1818
/** The quote request to fetch quotes for. If null, no quotes will be fetched. */
1919
rampQuoteRequest: RampQuoteRequest | null
2020
plugins: Record<string, RampPlugin>
21-
precomputedQuotes?: RampQuoteResult[]
2221
staleTime?: number
2322
}
2423

@@ -52,13 +51,13 @@ const isQuoteExpiringSoon = (
5251
export const useRampQuotes = ({
5352
rampQuoteRequest,
5453
plugins,
55-
precomputedQuotes = [],
5654
staleTime = 30000
5755
}: UseRampQuotesOptions): UseRampQuotesResult => {
5856
const queryClient = useQueryClient()
5957

6058
// Stable query key that doesn't change based on expired quotes
61-
const queryKey = ['rampQuotes', rampQuoteRequest]
59+
const pluginIds = Object.keys(plugins).sort() // Sort for stability
60+
const queryKey = ['rampQuotes', rampQuoteRequest, pluginIds]
6261

6362
const {
6463
data: quoteResults = [],
@@ -75,91 +74,38 @@ export const useRampQuotes = ({
7574
queryKey
7675
) ?? []
7776

78-
// Determine which plugins need fresh quotes
79-
const pluginsNeedingRefresh = new Set<string>()
80-
const validPrevResults = new Map<
77+
// Create a map of previous results by plugin ID
78+
const prevResultsMap = new Map<
8179
string,
8280
Result<RampQuoteResult[], QuoteError>
8381
>()
84-
85-
// Check previous results for expired quotes
8682
prevResults.forEach(result => {
87-
if (result.ok) {
88-
const pluginId = result.value[0]?.pluginId
89-
if (pluginId === '') return
90-
91-
const validQuotes = result.value.filter(
92-
quote => !isQuoteExpired(quote)
93-
)
94-
const hasExpiredQuotes = result.value.some(quote =>
95-
isQuoteExpired(quote)
96-
)
97-
98-
if (hasExpiredQuotes || validQuotes.length === 0) {
99-
pluginsNeedingRefresh.add(pluginId)
100-
} else {
101-
// Store the complete successful result with only valid quotes
102-
validPrevResults.set(pluginId, { ok: true, value: validQuotes })
103-
}
104-
} else {
105-
// Preserve error results as-is
106-
const pluginId = result.error.pluginId
107-
validPrevResults.set(pluginId, result)
108-
// Don't add to pluginsNeedingRefresh - we keep the error
109-
}
83+
const pluginId = result.ok
84+
? result.value[0]?.pluginId
85+
: result.error.pluginId
86+
if (pluginId !== '') prevResultsMap.set(pluginId, result)
11087
})
11188

112-
// If this is the first fetch (no prev results), use precomputed quotes or fetch all
113-
if (prevResults.length === 0) {
114-
if (precomputedQuotes.length > 0) {
115-
// Group precomputed quotes by plugin
116-
const groupedPrecomputed = new Map<string, RampQuoteResult[]>()
117-
118-
precomputedQuotes.forEach(quote => {
119-
const existing = groupedPrecomputed.get(quote.pluginId) ?? []
120-
groupedPrecomputed.set(quote.pluginId, [...existing, quote])
121-
})
122-
123-
// Convert to results format
124-
const initialResults: Array<Result<RampQuoteResult[], QuoteError>> =
125-
[]
126-
127-
groupedPrecomputed.forEach((quotes, pluginId) => {
128-
const validQuotes = quotes.filter(quote => !isQuoteExpired(quote))
89+
// Fetch quotes from all plugins, reusing valid cached quotes
90+
const resultPromises = Object.entries(plugins).map(
91+
async ([pluginId, plugin]): Promise<
92+
Result<RampQuoteResult[], QuoteError>
93+
> => {
94+
const prevResult = prevResultsMap.get(pluginId)
95+
96+
// If we have valid non-expired quotes, use them
97+
if (prevResult?.ok === true) {
98+
const validQuotes = prevResult.value.filter(
99+
quote => !isQuoteExpired(quote)
100+
)
129101
if (validQuotes.length > 0) {
130-
initialResults.push({ ok: true, value: validQuotes })
131-
} else {
132-
// All quotes expired for this plugin, need to fetch
133-
pluginsNeedingRefresh.add(pluginId)
102+
return { ok: true, value: validQuotes }
134103
}
135-
})
136-
137-
// If we have some valid precomputed quotes, return them
138-
if (initialResults.length > 0 && pluginsNeedingRefresh.size === 0) {
139-
return initialResults
140104
}
141-
} else {
142-
// No precomputed quotes, fetch from all plugins
143-
Object.keys(plugins).forEach(pluginId => {
144-
pluginsNeedingRefresh.add(pluginId)
145-
})
146-
}
147-
}
148-
149-
// If no plugins need refresh, return previous results
150-
if (pluginsNeedingRefresh.size === 0) {
151-
return prevResults
152-
}
153-
154-
// Fetch only from plugins that need refresh
155-
const freshResultsPromises = Array.from(pluginsNeedingRefresh).map(
156-
async (pluginId): Promise<Result<RampQuoteResult[], QuoteError>> => {
157-
const plugin = plugins[pluginId]
158-
if (plugin == null) return { ok: true, value: [] }
159105

106+
// Otherwise fetch fresh quotes
160107
try {
161108
const quotes = await plugin.fetchQuote(rampQuoteRequest)
162-
// Return quotes as-is (empty array means plugin doesn't support the request)
163109
return { ok: true, value: quotes }
164110
} catch (error) {
165111
console.warn(`Failed to get quote from ${pluginId}:`, error)
@@ -175,24 +121,7 @@ export const useRampQuotes = ({
175121
}
176122
)
177123

178-
const freshResults = await Promise.all(freshResultsPromises)
179-
180-
// Merge fresh results with valid previous results
181-
const mergedResults: Array<Result<RampQuoteResult[], QuoteError>> = []
182-
183-
// Add fresh results
184-
freshResults.forEach(result => {
185-
mergedResults.push(result)
186-
})
187-
188-
// Add valid previous results (including errors) for plugins we didn't refresh
189-
validPrevResults.forEach((result, pluginId) => {
190-
if (!pluginsNeedingRefresh.has(pluginId)) {
191-
mergedResults.push(result)
192-
}
193-
})
194-
195-
return mergedResults
124+
return await Promise.all(resultPromises)
196125
},
197126
refetchOnMount: 'always',
198127
refetchInterval: query => {

0 commit comments

Comments
 (0)