Skip to content

Commit 0a10457

Browse files
committed
Prevent swap KYC terms modal from stacking and dismiss abuse
Defer the quote auto-refresh timer while the terms modal is pending so a scene remount cannot stack a second modal. Track deferred timer expiry and replay it after the modal resolves to ensure fresh quotes. Make the terms modal non-dismissable (no backdrop tap, swipe, or X button) so the user must explicitly accept or reject. This prevents accidental dismissal from silently disabling the swap provider.
1 parent 5fdf884 commit 0a10457

3 files changed

Lines changed: 17 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- fixed: Swap quote timeout error interrupting user after cancelling a slow swap search
1717
- fixed: Disable "Migrate Wallets" button when no assets are available to migrate
1818
- fixed: Contacts permission prompt no longer appears on first receive and only shows from transaction-list or payee edit flows
19+
- fixed: Swap KYC terms modal stacking on auto-refresh and accidental dismissal disabling providers
1920

2021
## 4.45.0 (2026-03-10)
2122

src/components/modals/SwapVerifyTermsModal.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ const SwapVerifyTermsModal: React.FC<Props> = props => {
111111
<ModalTitle>{displayName}</ModalTitle>
112112
</View>
113113
}
114-
onCancel={() => {
115-
bridge.resolve(false)
116-
}}
117114
>
118115
<Paragraph>{lstrings.swap_terms_statement}</Paragraph>
119116
<ModalButtons

src/components/scenes/SwapConfirmationScene.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ export const SwapConfirmationScene: React.FC<Props> = (props: Props) => {
9898

9999
const isFocused = useIsFocused()
100100

101+
const termsCheckPending = React.useRef(false)
102+
const timerExpiredDuringTerms = React.useRef(false)
103+
101104
const pickBestQuoteWithPreference = (
102105
allQuotes: EdgeSwapQuote[]
103106
): EdgeSwapQuote => {
@@ -206,6 +209,10 @@ export const SwapConfirmationScene: React.FC<Props> = (props: Props) => {
206209

207210
const handleExchangeTimerExpired = useHandler(() => {
208211
if (!isFocused) return
212+
if (termsCheckPending.current) {
213+
timerExpiredDuringTerms.current = true
214+
return
215+
}
209216

210217
navigation.replace('swapProcessing', {
211218
swapRequest: selectedQuote.request,
@@ -227,12 +234,20 @@ export const SwapConfirmationScene: React.FC<Props> = (props: Props) => {
227234
const swapConfig = account.swapConfig[pluginId]
228235

229236
dispatch(logEvent('Exchange_Shift_Quote'))
237+
termsCheckPending.current = true
230238
swapVerifyTerms(swapConfig)
231239
.then(async result => {
232-
if (!result) handleExchangeTimerExpired()
240+
termsCheckPending.current = false
241+
if (!result || timerExpiredDuringTerms.current) {
242+
handleExchangeTimerExpired()
243+
}
233244
})
234245
.catch((err: unknown) => {
246+
termsCheckPending.current = false
235247
showError(err)
248+
if (timerExpiredDuringTerms.current) {
249+
handleExchangeTimerExpired()
250+
}
236251
})
237252
})
238253

0 commit comments

Comments
 (0)