Skip to content

Commit

Permalink
fix: WC signatures + subsequent transactions (#2650)
Browse files Browse the repository at this point in the history
* fix: reject requests on flow change

* fix: success doesn't quit + unsubscriptions

* refactor: cleanup code

* fix: change event payload + use callback syntax
  • Loading branch information
iamacook authored Oct 18, 2023
1 parent ea2ad6a commit aa6b049
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 20 deletions.
24 changes: 18 additions & 6 deletions src/components/tx-flow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { createContext, type ReactElement, type ReactNode, useState, useEffect,
import TxModalDialog from '@/components/common/TxModalDialog'
import { usePathname } from 'next/navigation'
import useSafeInfo from '@/hooks/useSafeInfo'
import { txDispatch, TxEvent } from '@/services/tx/txEvents'
import { SuccessScreen } from './flows/SuccessScreen'

const noop = () => {}

Expand Down Expand Up @@ -41,18 +43,28 @@ export const TxModalProvider = ({ children }: { children: ReactNode }): ReactEle
}

const ok = confirm('Closing this window will discard your current progress.')
if (ok) {
handleModalClose()
}
if (!ok) return

// Reject if the flow is closed
txDispatch(TxEvent.USER_QUIT, {})

handleModalClose()
}, [shouldWarn, handleModalClose])

const setTxFlow = useCallback(
(txFlow: TxModalContextType['txFlow'], onClose?: () => void, shouldWarn?: boolean) => {
setFlow(txFlow)
(newTxFlow: TxModalContextType['txFlow'], onClose?: () => void, shouldWarn?: boolean) => {
setFlow((prevFlow) => {
// Reject if a flow is open and the user changes to a different one
if (prevFlow && prevFlow !== newTxFlow && newTxFlow?.type !== SuccessScreen) {
txDispatch(TxEvent.USER_QUIT, {})
}

return newTxFlow
})
setOnClose(() => onClose ?? noop)
setShouldWarn(shouldWarn ?? true)
},
[setFlow, setOnClose],
[],
)

// Show the confirmation dialog if user navigates
Expand Down
2 changes: 1 addition & 1 deletion src/services/safe-wallet-provider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface RpcRequest {
params?: unknown[]
}

enum RpcErrorCode {
export enum RpcErrorCode {
INVALID_PARAMS = -32602,
USER_REJECTED = 4001,
UNSUPPORTED_METHOD = 4200,
Expand Down
59 changes: 46 additions & 13 deletions src/services/safe-wallet-provider/useSafeWalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useContext, useEffect, useMemo, useRef } from 'react'
import { BigNumber } from 'ethers'
import { useRouter } from 'next/router'

import { RpcErrorCode } from '.'
import type { AppInfo, WalletSDK } from '.'
import { SafeWalletProvider } from '.'
import useSafeInfo from '@/hooks/useSafeInfo'
Expand Down Expand Up @@ -51,12 +52,28 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK |
const { title, options } = NotificationMessages.SIGNATURE_REQUEST(appInfo)
showNotification(title, options)

return new Promise((resolve) => {
const unsubscribe = safeMsgSubscribe(SafeMsgEvent.SIGNATURE_PREPARED, ({ requestId, signature }) => {
if (requestId === id) {
resolve({ signature })
unsubscribe()
}
return new Promise((resolve, reject) => {
const unsubscribe = () => {
unsubscribeSignaturePrepared()
unsubscribeUserQuit()
}

const unsubscribeSignaturePrepared = safeMsgSubscribe(
SafeMsgEvent.SIGNATURE_PREPARED,
({ requestId, signature }) => {
if (requestId === id) {
resolve({ signature })
unsubscribe()
}
},
)

const unsubscribeUserQuit = txSubscribe(TxEvent.USER_QUIT, () => {
reject({
code: RpcErrorCode.USER_REJECTED,
message: 'User rejected signature request',
})
unsubscribe()
})
})
}
Expand Down Expand Up @@ -101,13 +118,29 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK |
const { title, options } = NotificationMessages.TRANSACTION_REQUEST(appInfo)
showNotification(title, options)

return new Promise((resolve) => {
const unsubscribe = txSubscribe(TxEvent.SAFE_APPS_REQUEST, async ({ safeAppRequestId, safeTxHash, txId }) => {
if (safeAppRequestId === id) {
const txHash = txId ? pendingTxs.current[txId] : undefined
resolve({ safeTxHash, txHash })
unsubscribe()
}
return new Promise((resolve, reject) => {
const unsubscribe = () => {
unsubscribeSignaturePrepared()
unsubscribeUserQuit()
}

const unsubscribeSignaturePrepared = txSubscribe(
TxEvent.SAFE_APPS_REQUEST,
async ({ safeAppRequestId, safeTxHash, txId }) => {
if (safeAppRequestId === id) {
const txHash = txId ? pendingTxs.current[txId] : undefined
resolve({ safeTxHash, txHash })
unsubscribe()
}
},
)

const unsubscribeUserQuit = txSubscribe(TxEvent.USER_QUIT, () => {
reject({
code: RpcErrorCode.USER_REJECTED,
message: 'User rejected transaction',
})
unsubscribe()
})
})
},
Expand Down
2 changes: 2 additions & 0 deletions src/services/tx/txEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import EventBus from '@/services/EventBus'
import type { RequestId } from '@safe-global/safe-apps-sdk'

export enum TxEvent {
USER_QUIT = 'USER_QUIT',
SIGNED = 'SIGNED',
SIGN_FAILED = 'SIGN_FAILED',
PROPOSED = 'PROPOSED',
Expand All @@ -27,6 +28,7 @@ type Id = { txId: string; groupKey?: string } | { txId?: string; groupKey: strin
type HumanDescription = { humanDescription?: string }

interface TxEvents {
[TxEvent.USER_QUIT]: {}
[TxEvent.SIGNED]: { txId?: string }
[TxEvent.SIGN_FAILED]: HumanDescription & { txId?: string; error: Error }
[TxEvent.PROPOSE_FAILED]: HumanDescription & { error: Error }
Expand Down

0 comments on commit aa6b049

Please sign in to comment.