Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't open the wallet window after closing deposit flow #877

Merged
merged 8 commits into from
Dec 2, 2024
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useCallback } from "react"
import React, { useCallback, useRef } from "react"
import {
useActionFlowPause,
useActionFlowTokenAmount,
useAppDispatch,
useCancelPromise,
useDepositBTCTransaction,
useInvalidateQueries,
useStakeFlowContext,
Expand All @@ -28,6 +29,12 @@ export default function DepositBTCModal() {
queryKey: userKeys.balance(),
})

const sessionId = useRef(Math.random())
const { cancel, resolve, sessionIdToPromise } = useCancelPromise(
sessionId.current,
"Deposit cancelled",
)

Comment on lines +32 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can generate sessionId inside useCancelPromise hook?

Copy link
Contributor Author

@kkosiorowska kkosiorowska Nov 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously I used this solution but had the problem that shouldOpenErrorModal was not returning the correct value for the right session.

Steps to reproduce:

  1. Reject the withdrawal request.
  2. Try again to do the withdrawal.

The problem was that the wallet window appeared and the dApp displayed a modal error. This happened because shouldOpenErrorModal was true. Hook didn't return the right value for the session.

Screenshot 2024-11-26 at 15 13 29 Screenshot 2024-11-26 at 15 24 42

I decided to pass sessionId to the hook to make sure we get the right value for shouldOpenErrorModal. This solution solved the problem.

const onStakeBTCSuccess = useCallback(() => {
handleBitcoinBalanceInvalidation()
dispatch(setStatus(PROCESS_STATUSES.SUCCEEDED))
Expand Down Expand Up @@ -58,13 +65,15 @@ export default function DepositBTCModal() {

const onDepositBTCError = useCallback(
(error: unknown) => {
if (!sessionIdToPromise[sessionId.current].shouldOpenErrorModal) return

if (eip1193.didUserRejectRequest(error)) {
handlePause()
} else {
onError(error)
}
},
[onError, handlePause],
[sessionIdToPromise, handlePause, onError],
)

const { mutate: sendBitcoinTransaction, status } = useDepositBTCTransaction({
Expand All @@ -79,6 +88,8 @@ export default function DepositBTCModal() {
btcAddress,
)

await resolve()

if (verificationStatus === "valid") {
sendBitcoinTransaction({
recipient: btcAddress,
Expand All @@ -92,6 +103,7 @@ export default function DepositBTCModal() {
btcAddress,
depositReceipt,
verifyDepositAddress,
resolve,
sendBitcoinTransaction,
onError,
])
Expand All @@ -105,5 +117,5 @@ export default function DepositBTCModal() {
if (status === "pending" || status === "success")
return <WalletInteractionModal step="awaiting-transaction" />

return <WalletInteractionModal step="opening-wallet" />
return <WalletInteractionModal step="opening-wallet" onClose={cancel} />
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useCallback, useEffect, useRef, useState } from "react"
import React, { useCallback, useRef, useState } from "react"
import {
useActionFlowPause,
useActionFlowTokenAmount,
useAppDispatch,
useCancelPromise,
useInvalidateQueries,
useModal,
useTimeout,
Expand All @@ -22,15 +23,6 @@ const { userKeys } = queryKeysFactory

type WithdrawalStatus = "building-data" | "built-data" | "signature"

const sessionIdToPromise: Record<
number,
{
promise: Promise<void>
cancel: (reason: Error) => void
shouldOpenErrorModal: boolean
}
> = {}

export default function SignMessageModal() {
const [status, setWaitingStatus] = useState<WithdrawalStatus>("building-data")

Expand All @@ -44,36 +36,24 @@ export default function SignMessageModal() {
queryKey: userKeys.position(),
})
const sessionId = useRef(Math.random())
const { cancel, resolve, sessionIdToPromise } = useCancelPromise(
sessionId.current,
"Withdrawal cancelled",
)
const { transactionFee } = useTransactionDetails(
amount,
ACTION_FLOW_TYPES.UNSTAKE,
)

useEffect(() => {
let cancel = (_: Error) => {}
const promise: Promise<void> = new Promise((_, reject) => {
cancel = reject
})

sessionIdToPromise[sessionId.current] = {
cancel,
promise,
shouldOpenErrorModal: true,
}
}, [])

const dataBuiltStepCallback = useCallback(() => {
setWaitingStatus("built-data")
return Promise.resolve()
}, [])

const onSignMessageCallback = useCallback(async () => {
setWaitingStatus("signature")
return Promise.race([
sessionIdToPromise[sessionId.current].promise,
Promise.resolve(),
])
}, [])
return resolve()
}, [resolve])

const onSignMessageSuccess = useCallback(() => {
handleBitcoinPositionInvalidation()
Expand All @@ -98,7 +78,7 @@ export default function SignMessageModal() {
onSignMessageError(error)
}
},
[onSignMessageError, handlePause],
[sessionIdToPromise, handlePause, onSignMessageError],
)

const { mutate: handleSignMessage } = useMutation({
Expand Down Expand Up @@ -151,16 +131,7 @@ export default function SignMessageModal() {
})

const onClose = () => {
const currentSessionId = sessionId.current
const sessionData = sessionIdToPromise[currentSessionId]
sessionIdToPromise[currentSessionId] = {
...sessionData,
shouldOpenErrorModal: false,
}

sessionIdToPromise[currentSessionId].cancel(
new Error("Withdrawal cancelled"),
)
cancel()
closeModal()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ const DATA: Record<

export default function WalletInteractionModal({
step,
onClose,
}: {
step: WalletInteractionStep
onClose?: () => void
}) {
const actionType = useActionFlowType()
const connector = useConnector()
Expand All @@ -60,7 +62,7 @@ export default function WalletInteractionModal({

return (
<>
{step === "opening-wallet" && <ModalCloseButton />}
{step === "opening-wallet" && <ModalCloseButton onClick={onClose} />}
<ModalHeader textAlign="center" pt={{ sm: 16 }} pb={{ base: 4, sm: 12 }}>
{header}
</ModalHeader>
Expand Down
1 change: 1 addition & 0 deletions dapp/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ export { default as useScrollbarVisibility } from "./useScrollbarVisibility"
export { default as useAccessCode } from "./useAccessCode"
export { default as useFormField } from "./useFormField"
export { default as useDepositBTCTransaction } from "./useDepositBTCTransaction"
export { default as useCancelPromise } from "./useCancelPromise"
50 changes: 50 additions & 0 deletions dapp/src/hooks/useCancelPromise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useCallback, useEffect } from "react"

const sessionIdToPromise: Record<
number,
{
promise: Promise<void>
cancel: (reason: Error) => void
shouldOpenErrorModal: boolean
}
> = {}

export default function useCancelPromise(
sessionId: number,
errorMsgText: string,
) {
useEffect(() => {
let cancel = (_: Error) => {}
const promise: Promise<void> = new Promise((_, reject) => {
cancel = reject
})

sessionIdToPromise[sessionId] = {
cancel,
promise,
shouldOpenErrorModal: true,
}
}, [sessionId])

const cancel = useCallback(() => {
const sessionData = sessionIdToPromise[sessionId]
sessionIdToPromise[sessionId] = {
...sessionData,
shouldOpenErrorModal: false,
}

sessionIdToPromise[sessionId].cancel(new Error(errorMsgText))
}, [errorMsgText, sessionId])

const resolve = useCallback(
() =>
Promise.race([sessionIdToPromise[sessionId].promise, Promise.resolve()]),
[sessionId],
)

return {
cancel,
resolve,
sessionIdToPromise,
}
}
4 changes: 2 additions & 2 deletions dapp/src/hooks/useTransactionModal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ACTION_FLOW_TYPES, ActionFlowType, MODAL_TYPES } from "#/types"
import { ActionFlowType, MODAL_TYPES } from "#/types"
import { useCallback } from "react"
import { useModal } from "./useModal"

Expand All @@ -8,7 +8,7 @@ export function useTransactionModal(type: ActionFlowType) {
return useCallback(() => {
openModal(MODAL_TYPES[type], {
type,
closeOnEsc: type !== ACTION_FLOW_TYPES.UNSTAKE,
closeOnEsc: false,
})
}, [openModal, type])
}
Loading