fix(bridge): refresh and requote stale routes#159
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds dynamic route refresh intervals (Layer1/L2/default), wires refreshMs into route queries, refetches latest route before submit, surfaces refresh errors and route warnings, tracks quoteVerifiedAt and requiresReconfirm state, refreshes stale routes via route API, and clears route caches after successful submission. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant BridgePreviewFooter
participant RouteAPI as Route API (v2/fungible/route)
participant BridgeTx as Bridge Tx Mutation
participant Navigation
User->>BridgePreviewFooter: Click Confirm
activate BridgePreviewFooter
alt route age > ROUTE_MAX_AGE_MS
BridgePreviewFooter->>BridgePreviewFooter: set isRefreshing = true
BridgePreviewFooter->>RouteAPI: POST current inputs (refresh)
activate RouteAPI
RouteAPI-->>BridgePreviewFooter: updated route
deactivate RouteAPI
alt route signature changed
BridgePreviewFooter-->>User: show "Confirm updated route" (requiresReconfirm)
deactivate BridgePreviewFooter
User->>BridgePreviewFooter: Click Confirm again
activate BridgePreviewFooter
end
BridgePreviewFooter->>BridgePreviewFooter: set isRefreshing = false
end
BridgePreviewFooter->>BridgeTx: Call mutate()
activate BridgeTx
BridgeTx-->>BridgePreviewFooter: Transaction submitted
deactivate BridgeTx
BridgePreviewFooter->>Navigation: Navigate to result
deactivate BridgePreviewFooter
sequenceDiagram
participant User
participant BridgeFields
participant RouteQuery as useRouteQuery
participant API as Route API (skip.post)
participant Modal as Confirmation Modal
participant Navigation
User->>BridgeFields: Submit form
activate BridgeFields
BridgeFields->>BridgeFields: compute routeRefreshMs (Layer1/L2/default)
BridgeFields->>RouteQuery: refetch latest route with refreshMs
activate RouteQuery
RouteQuery->>API: request latest route
activate API
API-->>RouteQuery: route data (with warnings?)
deactivate API
deactivate RouteQuery
alt route contains warning
BridgeFields->>Modal: open with latest route + quoteVerifiedAt
activate Modal
Modal->>User: show warning
User->>Modal: Confirm to proceed
deactivate Modal
end
BridgeFields->>BridgeFields: set quoteVerifiedAt
BridgeFields->>Navigation: navigate to preview (latestRoute, quoteVerifiedAt)
deactivate BridgeFields
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
Comment |
Deploying interwovenkit-staging with
|
| Latest commit: |
e65e5cb
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c6c48bbb.interwovenkit-staging.pages.dev |
| Branch Preview URL: | https://fix-bridge-route-quote-fresh.interwovenkit-staging.pages.dev |
Deploying interwovenkit-testnet with
|
| Latest commit: |
e65e5cb
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c2969b57.interwovenkit-testnet.pages.dev |
| Branch Preview URL: | https://fix-bridge-route-quote-fresh.interwovenkit-testnet.pages.dev |
Deploying interwovenkit with
|
| Latest commit: |
e65e5cb
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://cc374dc4.interwovenkit.pages.dev |
| Branch Preview URL: | https://fix-bridge-route-quote-fresh.interwovenkit.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx`:
- Around line 58-101: The refreshRouteIfNeeded function currently falls back to
{ decimals: 0 } when
queryClient.getQueryData<RouterAsset>(skipQueryKeys.asset(...)) returns
undefined, which can under-scale toBaseUnit(values.quantity, { decimals:
srcDecimals }); update refreshRouteIfNeeded to detect missing asset metadata
(i.e., when queryClient.getQueryData returns undefined or decimals is
null/undefined) and fail fast or fetch the asset before computing amount_in:
either setRefreshError and return true (or block refresh) when decimals are
unavailable, or call the existing asset-fetch path to populate decimals, then
proceed to call toBaseUnit and post the route; ensure you reference
skipQueryKeys.asset, queryClient.getQueryData, toBaseUnit, and navigate in your
change so the code path handles missing decimals consistently.
packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx
Outdated
Show resolved
Hide resolved
packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx
Outdated
Show resolved
Hide resolved
packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx
Outdated
Show resolved
Hide resolved
packages/interwovenkit-react/src/pages/deposit/TransferFields.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx (1)
27-29: Consider memoizing the JSON keys individually.
JSON.stringifyruns on every render foraddressList,route.operations, andsignedOpHook. Ifroute.operationsis a large array, this adds serialization overhead on each render even when values haven't changed.♻️ Optional: memoize stringification
- const addressListKey = JSON.stringify(addressList) - const operationsKey = JSON.stringify(route.operations) - const signedOpHookKey = JSON.stringify(signedOpHook ?? null) + const addressListKey = useMemo(() => JSON.stringify(addressList), [addressList]) + const operationsKey = useMemo(() => JSON.stringify(route.operations), [route.operations]) + const signedOpHookKey = useMemo(() => JSON.stringify(signedOpHook ?? null), [signedOpHook])This still re-stringifies when references change, but avoids redundant work when references are stable across renders.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx` around lines 27 - 29, The three JSON.stringify calls (addressListKey, operationsKey, signedOpHookKey) run on every render and should be memoized: wrap each JSON.stringify in a React.useMemo so you only re-stringify when its specific dependency changes (use addressList for addressListKey, route.operations for operationsKey, and signedOpHook for signedOpHookKey), and ensure React.useMemo is imported; this avoids repeated serialization work when references are stable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx`:
- Around line 27-29: The three JSON.stringify calls (addressListKey,
operationsKey, signedOpHookKey) run on every render and should be memoized: wrap
each JSON.stringify in a React.useMemo so you only re-stringify when its
specific dependency changes (use addressList for addressListKey,
route.operations for operationsKey, and signedOpHook for signedOpHookKey), and
ensure React.useMemo is imported; this avoids repeated serialization work when
references are stable.
There was a problem hiding this comment.
🧹 Nitpick comments (3)
packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx (2)
62-111: Consider aborting refresh on component unmount.The
refreshRouteIfNeededasync function can complete after the component unmounts (e.g., user navigates away), potentially causing state updates on an unmounted component. While React 18+ generally handles this gracefully, it's good practice to abort in-flight requests.💡 Add abort handling
const abortControllerRef = useRef<AbortController | null>(null) useEffect(() => { return () => { abortControllerRef.current?.abort() } }, []) const refreshRouteIfNeeded = async () => { // ... existing checks ... abortControllerRef.current = new AbortController() try { const refreshedRoute = await skip .post("v2/fungible/route", { json: { /* ... */ }, signal: abortControllerRef.current.signal, }) .json<RouterRouteResponseJson>() // ... } catch (error) { if (error instanceof DOMException && error.name === "AbortError") return true setRefreshError((await normalizeError(error)).message) return true } // ... }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx` around lines 62 - 111, refreshRouteIfNeeded can complete after the component unmounts and set state; add abort handling by creating an abortControllerRef (useRef<AbortController | null>) and a useEffect cleanup that calls abortControllerRef.current?.abort(), then in refreshRouteIfNeeded assign abortControllerRef.current = new AbortController() and pass abortControllerRef.current.signal into the skip.post call; in the catch, detect an AbortError (DOMException name === "AbortError") and return early without calling setRefreshError or other state setters, and in finally clear abortControllerRef.current = null to avoid stale references while still calling setIsRefreshing(false) only when not aborted. Ensure you reference refreshRouteIfNeeded, abortControllerRef, skip.post, setRefreshError and setIsRefreshing when making these changes.
32-46: Potential false positives from JSON.stringify key ordering.
JSON.stringifydoesn't guarantee consistent property ordering for objects. If the API returns properties in different order between calls (even with identical values),getRouteSignaturemay incorrectly detect a route change, triggering unnecessary reconfirmation prompts.💡 Consider a deterministic comparison
function getRouteSignature(route: RouterRouteResponseJson) { - return JSON.stringify({ + // Sort keys for deterministic comparison + return JSON.stringify({ amount_in: route.amount_in, amount_out: route.amount_out, usd_amount_in: route.usd_amount_in, usd_amount_out: route.usd_amount_out, - operations: route.operations, + operations: route.operations, // Array order is preserved estimated_fees: route.estimated_fees, estimated_route_duration_seconds: route.estimated_route_duration_seconds, warning: route.warning, extra_infos: route.extra_infos, extra_warnings: route.extra_warnings, required_op_hook: route.required_op_hook, - }) + }, Object.keys(route).sort()) }Alternatively, compare individual fields or use a library like
fast-deep-equalfor reliable deep comparison.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx` around lines 32 - 46, getRouteSignature currently uses JSON.stringify which can produce false positives due to non-deterministic object key ordering; update the comparison logic so route changes are detected deterministically by either: 1) replacing getRouteSignature with a deterministic serializer that sorts keys (or builds a canonical string by reading the known fields in a fixed order) for RouterRouteResponseJson, or 2) replace usage of getRouteSignature with a proper deep equality check (e.g., fast-deep-equal) or explicit field-by-field comparison of the listed properties (amount_in, amount_out, usd_amount_in, usd_amount_out, operations, estimated_fees, estimated_route_duration_seconds, warning, extra_infos, extra_warnings, required_op_hook) to avoid ordering issues.packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx (1)
27-56: Unnecessary JSON roundtrip in memoization.The pattern of
JSON.stringify→JSON.parseis wasteful. The stringified keys are useful for stable dependency comparison, but there's no need to parse them back when the original values are available.♻️ Suggested simplification
const addressListKey = useMemo(() => JSON.stringify(addressList), [addressList]) const operationsKey = useMemo(() => JSON.stringify(route.operations), [route.operations]) const signedOpHookKey = useMemo(() => JSON.stringify(signedOpHook ?? null), [signedOpHook]) const params = useMemo( () => ({ - address_list: JSON.parse(addressListKey) as string[], + address_list: addressList, amount_in: route.amount_in, amount_out: route.amount_out, source_asset_chain_id: route.source_asset_chain_id, source_asset_denom: route.source_asset_denom, dest_asset_chain_id: route.dest_asset_chain_id, dest_asset_denom: route.dest_asset_denom, slippage_tolerance_percent: values.slippagePercent, - operations: JSON.parse(operationsKey) as RouterRouteResponseJson["operations"], - signed_op_hook: (JSON.parse(signedOpHookKey) as SignedOpHook | null) ?? undefined, + operations: route.operations, + signed_op_hook: signedOpHook, }), [ addressListKey, operationsKey, + signedOpHookKey, route.amount_in, route.amount_out, route.source_asset_chain_id, route.source_asset_denom, route.dest_asset_chain_id, route.dest_asset_denom, values.slippagePercent, - signedOpHookKey, ], )The stringified keys already serve as stable dependency markers—use the original values in the object construction.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx` around lines 27 - 56, The JSON.stringify → JSON.parse roundtrip inside the params useMemo is unnecessary; update the params factory (the useMemo that produces params) to use the original values (addressList, route.operations, and signedOpHook) instead of parsing addressListKey/operationsKey/signedOpHookKey, while keeping the stringified keys (addressListKey, operationsKey, signedOpHookKey) in the dependency array for stable comparisons; adjust the signed_op_hook expression to use signedOpHook (or signedOpHook ?? undefined) and keep other route/value fields as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx`:
- Around line 62-111: refreshRouteIfNeeded can complete after the component
unmounts and set state; add abort handling by creating an abortControllerRef
(useRef<AbortController | null>) and a useEffect cleanup that calls
abortControllerRef.current?.abort(), then in refreshRouteIfNeeded assign
abortControllerRef.current = new AbortController() and pass
abortControllerRef.current.signal into the skip.post call; in the catch, detect
an AbortError (DOMException name === "AbortError") and return early without
calling setRefreshError or other state setters, and in finally clear
abortControllerRef.current = null to avoid stale references while still calling
setIsRefreshing(false) only when not aborted. Ensure you reference
refreshRouteIfNeeded, abortControllerRef, skip.post, setRefreshError and
setIsRefreshing when making these changes.
- Around line 32-46: getRouteSignature currently uses JSON.stringify which can
produce false positives due to non-deterministic object key ordering; update the
comparison logic so route changes are detected deterministically by either: 1)
replacing getRouteSignature with a deterministic serializer that sorts keys (or
builds a canonical string by reading the known fields in a fixed order) for
RouterRouteResponseJson, or 2) replace usage of getRouteSignature with a proper
deep equality check (e.g., fast-deep-equal) or explicit field-by-field
comparison of the listed properties (amount_in, amount_out, usd_amount_in,
usd_amount_out, operations, estimated_fees, estimated_route_duration_seconds,
warning, extra_infos, extra_warnings, required_op_hook) to avoid ordering
issues.
In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx`:
- Around line 27-56: The JSON.stringify → JSON.parse roundtrip inside the params
useMemo is unnecessary; update the params factory (the useMemo that produces
params) to use the original values (addressList, route.operations, and
signedOpHook) instead of parsing addressListKey/operationsKey/signedOpHookKey,
while keeping the stringified keys (addressListKey, operationsKey,
signedOpHookKey) in the dependency array for stable comparisons; adjust the
signed_op_hook expression to use signedOpHook (or signedOpHook ?? undefined) and
keep other route/value fields as-is.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx (2)
44-58: Redundant dependencies: both original values and their stringified keys are included.The dependency array lists both
addressListandaddressListKey,route.operationsandoperationsKey, etc. Since each*Keymemo already depends on its source value, including both is redundant—whenaddressListchanges,addressListKeywill recompute, triggering this memo anyway. Consider keeping only the stringified keys if you want stable reference detection, or only the original values if not:♻️ Simplified dependency array
}, [ addressList, - addressListKey, route.operations, - operationsKey, - signedOpHookKey, signedOpHook, route.amount_in, ... ])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx` around lines 44 - 58, The dependency array for the memo includes both raw values and their derived string keys (e.g., addressList + addressListKey, route.operations + operationsKey, signedOpHook + signedOpHookKey), which is redundant; update the dependency list inside the useMemo in FooterWithMsgs.tsx to remove the original raw values and keep only the stable stringified keys (addressListKey, operationsKey, signedOpHookKey) plus the other primitive route fields and values.slippagePercent so the memo relies on the canonical stable dependencies.
26-42:hasStableKeysis always truthy, making the conditional ineffective.The
*Keyvariables are always non-empty strings sinceJSON.stringifyreturns"[]","{}", or"null"for empty/null values—all truthy. ThushasStableKeyswill always betrue, and the ternary at line 42 will always evaluate tosignedOpHook ?? undefined.If this is intentional (i.e., you're only using the keys for referential stability in the dependency array), consider simplifying:
♻️ Suggested simplification
const params = useMemo(() => { - const hasStableKeys = !!addressListKey && !!operationsKey && !!signedOpHookKey return { address_list: addressList, amount_in: route.amount_in, ... - signed_op_hook: hasStableKeys ? (signedOpHook ?? undefined) : undefined, + signed_op_hook: signedOpHook ?? undefined, } }, [🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx` around lines 26 - 42, hasStableKeys is always truthy because addressListKey/operationsKey/signedOpHookKey are JSON.stringify results, so replace that ineffective check by using explicit null/emptiness checks: remove addressListKey/operationsKey/signedOpHookKey usage for truthiness, change hasStableKeys to something like (signedOpHook !== null && signedOpHook !== undefined) or include explicit checks for addressList.length and route.operations.length, and then set signed_op_hook: signedOpHook ?? undefined (or only include it when the explicit check passes) inside the params object so the conditional actually reflects presence/absence of the underlying values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/interwovenkit-react/src/pages/bridge/FooterWithMsgs.tsx`:
- Around line 44-58: The dependency array for the memo includes both raw values
and their derived string keys (e.g., addressList + addressListKey,
route.operations + operationsKey, signedOpHook + signedOpHookKey), which is
redundant; update the dependency list inside the useMemo in FooterWithMsgs.tsx
to remove the original raw values and keep only the stable stringified keys
(addressListKey, operationsKey, signedOpHookKey) plus the other primitive route
fields and values.slippagePercent so the memo relies on the canonical stable
dependencies.
- Around line 26-42: hasStableKeys is always truthy because
addressListKey/operationsKey/signedOpHookKey are JSON.stringify results, so
replace that ineffective check by using explicit null/emptiness checks: remove
addressListKey/operationsKey/signedOpHookKey usage for truthiness, change
hasStableKeys to something like (signedOpHook !== null && signedOpHook !==
undefined) or include explicit checks for addressList.length and
route.operations.length, and then set signed_op_hook: signedOpHook ?? undefined
(or only include it when the explicit check passes) inside the params object so
the conditional actually reflects presence/absence of the underlying values.
|
packages/interwovenkit-react/src/pages/bridge/data/useRouteRefresh.ts
Outdated
Show resolved
Hide resolved
packages/interwovenkit-react/src/pages/bridge/BridgePreviewFooter.tsx
Outdated
Show resolved
Hide resolved
b66ea97 to
efa190e
Compare
- Extract fetchRoute() from useRouteQuery for reuse - Move refresh logic from BridgePreviewFooter to useRouteRefresh hook - Add previewRefreshing state to show "Refreshing route..." on button - Stabilize reference-type deps individually in FooterWithMsgs - Drop quoteVerifiedAt from TransferFields effect deps
The shared fetchRoute silently fell back to decimals: 0 when source asset metadata was unavailable, which would send a wrong amount to the API. Restore the explicit error that the old inline code had.
Co-authored-by: Sawit Trisirisatayawong <tansawit@users.noreply.github.com>
Co-authored-by: Sawit Trisirisatayawong <tansawit@users.noreply.github.com>
- fetchRoute: explain why missing asset metadata throws - BridgePreviewFooter: clarify Date.now() fallback rationale - TransferFields: document quoteVerifiedAt exclusion from useEffect deps to avoid 10s refetch re-navigation
Co-authored-by: Sawit Trisirisatayawong <tansawit@users.noreply.github.com>
Co-authored-by: Sawit Trisirisatayawong <tansawit@users.noreply.github.com>
Co-authored-by: Sawit Trisirisatayawong <tansawit@users.noreply.github.com>
Co-authored-by: Sawit Trisirisatayawong <tansawit@users.noreply.github.com>
efa190e to
cd54727
Compare
|
I think it'd be better to merge #157 first. |
…e-freshness # Conflicts: # packages/interwovenkit-react/src/pages/deposit/TransferFields.tsx
…e-freshness # Conflicts: # packages/interwovenkit-react/src/pages/bridge/data/simulate.ts
Code reviewFound 2 issues:
interwovenkit/packages/interwovenkit-react/src/pages/bridge/BridgeFields.tsx Lines 148 to 156 in 53d5e1c
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
- remove track() from queryFn to prevent firing on every poll - add cancelled guard in FooterWithMsgs useEffect cleanup
Code reviewFound 2 issues — both fixed in e65e5cb.
🤖 Generated with Claude Code |
| extra_infos: route.extra_infos, | ||
| extra_warnings: route.extra_warnings, | ||
| required_op_hook: route.required_op_hook, | ||
| }) |
There was a problem hiding this comment.
USD amounts in route signature cause spurious reconfirmation
Medium Severity
getRouteSignature includes usd_amount_in and usd_amount_out in the comparison used to detect whether a route has "changed." These USD valuations are derived from live market prices and can fluctuate between API calls even when the actual swap terms (amount_in, amount_out, operations, estimated_fees) are identical. This means a confirm-time requote can trigger a "Route updated — please review and confirm again" reconfirmation prompt even though nothing material about the swap has changed, leading to unnecessary friction and potentially repeated reconfirm cycles.


Summary
This change fixes inconsistent bridge quote behavior after returning to the swap form and attempting a second swap. Users could sometimes see conversion values derived from stale route data, and in some paths proceed with outdated preview information.
User impact
When a user performs one swap, comes back, and enters a new amount, route and conversion data now refresh deterministically instead of depending on incidental react-query cache state. At confirm time, stale preview data is actively refreshed and requires explicit reconfirmation if the route changed.
Root cause
The bridge route query did not have a short, route-specific freshness policy and could reuse cached route data after navigation. The preview flow also lacked a strict freshness check at confirm time, so a previously previewed route could remain in state longer than intended.
What changed
staleTimetied to refresh windowrefetchIntervalPreview route, force a fresh route refetch before navigating to preview and storequoteVerifiedAttimestamp.Why this fix
This approach keeps preview data responsive during input while still enforcing execution-time freshness. It reduces stale quote exposure without adding unnecessary requotes for every click.
Note
Medium Risk
Touches routing/quoting and transaction confirmation flow, so regressions could block swaps or require extra reconfirmation, but changes are localized and add explicit UI/error handling.
Overview
Fixes stale bridge quotes by making route simulation actively refresh and by enforcing quote freshness at preview/confirm time.
On the form,
useRouteQuerynow supports configurable refresh windows (2s/5s/10s), uses them asstaleTime, and polls viarefetchIntervalwith refetch-on-mount/focus/reconnect; clicking Preview route forces arefetch(), recordsquoteVerifiedAt, and shows a dedicated refresh loading/error state.On the preview screen, a new
useRouteRefreshhook requotes if the saved quote is older than 10s and, if the route materially changed, updates location state to require an explicit reconfirm (with updated confirm button label + status messaging). After a successful bridge tx, route-related react-query caches are cleared to prevent reuse across subsequent swaps; deposit transfer flow now also preservesquoteVerifiedAtand recipient state via a newbuildTransferLocationStatehelper.Written by Cursor Bugbot for commit e65e5cb. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes