diff --git a/apps/web/src/components/SendFlow/Beacon/useSignWithBeacon.tsx b/apps/web/src/components/SendFlow/Beacon/useSignWithBeacon.tsx index 80ca2bf2ab..23f4bbf80d 100644 --- a/apps/web/src/components/SendFlow/Beacon/useSignWithBeacon.tsx +++ b/apps/web/src/components/SendFlow/Beacon/useSignWithBeacon.tsx @@ -1,8 +1,9 @@ -import { BeaconMessageType, type OperationResponseInput } from "@airgap/beacon-wallet"; +import { BeaconErrorType, BeaconMessageType, type OperationResponseInput } from "@airgap/beacon-wallet"; import { type TezosToolkit } from "@taquito/taquito"; import { useDynamicModalContext } from "@umami/components"; import { executeOperations, totalFee } from "@umami/core"; import { WalletClient, useAsyncActionHandler } from "@umami/state"; +import { getErrorContext } from "@umami/utils"; import { useForm } from "react-hook-form"; import { SuccessStep } from "../SuccessStep"; @@ -34,9 +35,15 @@ export const useSignWithBeacon = ({ return openWith(); }, - error => ({ - description: `Failed to confirm Beacon operation: ${error.message}`, - }) + error => { + const context = getErrorContext(error); + void WalletClient.respond({ + id: headerProps.requestId.id.toString(), + type: BeaconMessageType.Error, + errorType: BeaconErrorType.UNKNOWN_ERROR, + }); + return { description: `Failed to confirm Beacon operation: ${context.description}` }; + } ); return { diff --git a/apps/web/src/components/beacon/useHandleBeaconMessage.tsx b/apps/web/src/components/beacon/useHandleBeaconMessage.tsx index 01a0bf5ad0..b11aa7bdde 100644 --- a/apps/web/src/components/beacon/useHandleBeaconMessage.tsx +++ b/apps/web/src/components/beacon/useHandleBeaconMessage.tsx @@ -15,7 +15,7 @@ import { useRemoveBeaconPeerBySenderId, } from "@umami/state"; import { type Network } from "@umami/tezos"; -import { CustomError } from "@umami/utils"; +import { CustomError, getErrorContext } from "@umami/utils"; import { PermissionRequestModal } from "./PermissionRequestModal"; import { SignPayloadRequestModal } from "../common/SignPayloadRequestModal"; @@ -41,6 +41,20 @@ export const useHandleBeaconMessage = () => { const findNetwork = useFindNetwork(); const removePeer = useRemoveBeaconPeerBySenderId(); + // Beacon SDK expects errorData for TRANSACTION_INVALID_ERROR only and as an array of RPC errors + const respondWithError = async ( + messageId: string, + errorType: BeaconErrorType, + errorData?: any + ) => { + await WalletClient.respond({ + id: messageId, + type: BeaconMessageType.Error, + errorType, + errorData, + }); + }; + // we should confirm that we support the network that the beacon request is coming from const checkNetwork = ({ id: messageId, @@ -52,11 +66,7 @@ export const useHandleBeaconMessage = () => { const network = findNetwork(beaconNetwork.type); if (!network) { - void WalletClient.respond({ - id: messageId, - type: BeaconMessageType.Error, - errorType: BeaconErrorType.NETWORK_NOT_SUPPORTED, - }); + void respondWithError(messageId, BeaconErrorType.NETWORK_NOT_SUPPORTED); throw new CustomError( `Got Beacon request from an unknown network: ${JSON.stringify( beaconNetwork @@ -79,11 +89,7 @@ export const useHandleBeaconMessage = () => { checkNetwork(message); modal = ; onClose = async () => { - await WalletClient.respond({ - id: message.id, - type: BeaconMessageType.Error, - errorType: BeaconErrorType.NOT_GRANTED_ERROR, - }); + await respondWithError(message.id, BeaconErrorType.NOT_GRANTED_ERROR); await removePeer(message.senderId); }; break; @@ -100,11 +106,7 @@ export const useHandleBeaconMessage = () => { }; modal = ; onClose = async () => { - await WalletClient.respond({ - id: message.id, - type: BeaconMessageType.Error, - errorType: BeaconErrorType.ABORTED_ERROR, - }); + await respondWithError(message.id, BeaconErrorType.ABORTED_ERROR); }; break; } @@ -112,11 +114,7 @@ export const useHandleBeaconMessage = () => { const network = checkNetwork(message); const signer = getAccount(message.sourceAddress); if (!signer) { - void WalletClient.respond({ - id: message.id, - type: BeaconMessageType.Error, - errorType: BeaconErrorType.NO_PRIVATE_KEY_FOUND_ERROR, - }); + void respondWithError(message.id, BeaconErrorType.NO_PRIVATE_KEY_FOUND_ERROR); throw new CustomError(`Unknown account: ${message.sourceAddress}`); } @@ -141,23 +139,14 @@ export const useHandleBeaconMessage = () => { } else { modal = ; } - onClose = () => - WalletClient.respond({ - id: message.id, - type: BeaconMessageType.Error, - errorType: BeaconErrorType.ABORTED_ERROR, - }); + onClose = () => respondWithError(message.id, BeaconErrorType.ABORTED_ERROR); break; } default: { // TODO: Open a modal with an unknown operation instead - void WalletClient.respond({ - id: message.id, - type: BeaconMessageType.Error, - errorType: BeaconErrorType.UNKNOWN_ERROR, - }); + void respondWithError(message.id, BeaconErrorType.UNKNOWN_ERROR); throw new CustomError(`Unknown Beacon message type: ${message.type}`); } @@ -165,9 +154,11 @@ export const useHandleBeaconMessage = () => { return openWith(modal, { onClose }); }, - error => ({ - description: `Error while processing Beacon request: ${error.message}`, - }) + error => { + const context = getErrorContext(error); + void respondWithError(message.id, BeaconErrorType.UNKNOWN_ERROR); + return { description: `Error while processing Beacon request: ${context.description}` }; + } ); }; }; diff --git a/packages/test-utils/src/setupTests.ts b/packages/test-utils/src/setupTests.ts new file mode 100644 index 0000000000..63776d3784 --- /dev/null +++ b/packages/test-utils/src/setupTests.ts @@ -0,0 +1,12 @@ +jest.mock("@walletconnect/core", () => ({ + Core: jest.fn().mockImplementation(config => ({ + projectId: config.projectId, + })), + })); + jest.mock("@reown/walletkit", () => ({ + WalletKit: jest.fn(), + })); + jest.mock("@walletconnect/utils", () => ({ + WalletConnect: jest.fn(), + })); + \ No newline at end of file diff --git a/packages/utils/src/ErrorContext.ts b/packages/utils/src/ErrorContext.ts index 098055e3b5..31b5e6f394 100644 --- a/packages/utils/src/ErrorContext.ts +++ b/packages/utils/src/ErrorContext.ts @@ -132,7 +132,7 @@ export const getErrorContext = (error: any, silent: boolean = false): ErrorConte "Something went wrong. Please try again. Contact support if the issue persists."; let description = defaultDescription; let technicalDetails: any = undefined; - let code: number = WcErrorCode.INTERNAL_ERROR; + let code: WcErrorCode | number = WcErrorCode.INTERNAL_ERROR; const errorMessage = typeof error === "string" ? error : error.message; let stacktrace = ""; @@ -175,7 +175,6 @@ export const getErrorContext = (error: any, silent: boolean = false): ErrorConte const plainMessage = stripHtmlTags(error.message); description = `HTTP request failed for ${error.url} (${error.status}) ${httpError}`; code = error.status; - console.log("HTTP ERROR", error); if (code === 500) { description = `${description}\nDetails: ${plainMessage}`; } @@ -186,7 +185,7 @@ export const getErrorContext = (error: any, silent: boolean = false): ErrorConte } if (!silent) { - console.warn("Request failed", code, description, technicalDetails, error); + console.error("Request failed", code, description, technicalDetails, error); } return { diff --git a/packages/utils/src/setupTests.ts b/packages/utils/src/setupTests.ts new file mode 100644 index 0000000000..245723fa8c --- /dev/null +++ b/packages/utils/src/setupTests.ts @@ -0,0 +1,11 @@ +jest.mock("@walletconnect/core", () => ({ + Core: jest.fn().mockImplementation(config => ({ + projectId: config.projectId, + })), +})); +jest.mock("@reown/walletkit", () => ({ + WalletKit: jest.fn(), +})); +jest.mock("@walletconnect/utils", () => ({ + WalletConnect: jest.fn(), +}));