Skip to content

Commit

Permalink
fix: WalletConnect, fixing toasts and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dianasavvatina committed Dec 17, 2024
1 parent c44f6ad commit 66b9772
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 82 deletions.
22 changes: 6 additions & 16 deletions apps/web/src/components/WalletConnect/WalletConnectProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const WalletConnectProvider = ({ children }: PropsWithChildren) => {
handleAsyncActionUnsafe(async () => {
const activeSessions: Record<string, SessionTypes.Struct> = walletKit.getActiveSessions();
if (!(event.topic in activeSessions)) {
throw new WalletConnectError("Session not found", "INVALID_EVENT");
throw new WalletConnectError("Session not found", "INVALID_EVENT", null);
}

const session = activeSessions[event.topic];
Expand All @@ -105,28 +105,18 @@ export const WalletConnectProvider = ({ children }: PropsWithChildren) => {
await handleWcRequest(event, session);
}).catch(async error => {
const { id, topic } = event;
const activeSessions: Record<string, SessionTypes.Struct> = walletKit.getActiveSessions();
const sdkErrorKey: SdkErrorKey =
let sdkErrorKey: SdkErrorKey =
error instanceof WalletConnectError ? error.sdkError : "SESSION_SETTLEMENT_FAILED";
const sdkErrorMessage = getSdkError(sdkErrorKey).message;
if (sdkErrorKey === "USER_REJECTED") {
console.info("WC request rejected", sdkErrorKey, event, error);
toast({
description: "Session request rejected",
status: "info",
});
} else {
if (error.message.includes("delegate.unchanged")) {
sdkErrorKey = "INVALID_EVENT";
}
console.warn("WC request failed", sdkErrorKey, event, error);
const dappName =
event.topic in activeSessions
? activeSessions[event.topic].peer.metadata.name
: "unknown dApp";
toast({
description: `Session request for ${dappName} failed: ${error.message}`,
status: "error",
});
}
// dApp is waiting so we need to notify it
const sdkErrorMessage = getSdkError(sdkErrorKey).message;
const response = formatJsonRpcError(id, sdkErrorMessage);
await walletKit.respondSessionRequest({ topic, response });
}),
Expand Down
137 changes: 75 additions & 62 deletions apps/web/src/components/WalletConnect/useHandleWcRequest.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useToast } from "@chakra-ui/react";
import { useDynamicModalContext } from "@umami/components";
import { type ImplicitAccount, estimate, toAccountOperations } from "@umami/core";
import {
Expand All @@ -7,7 +6,7 @@ import {
useGetOwnedAccountSafe,
walletKit,
} from "@umami/state";
import { CustomError, WalletConnectError } from "@umami/utils";
import { WalletConnectError } from "@umami/utils";
import { formatJsonRpcError } from "@walletconnect/jsonrpc-utils";
import { type SessionTypes, type SignClientTypes, type Verify } from "@walletconnect/types";
import { getSdkError } from "@walletconnect/utils";
Expand All @@ -27,7 +26,6 @@ export const useHandleWcRequest = () => {
const { handleAsyncActionUnsafe } = useAsyncActionHandler();
const getAccount = useGetOwnedAccountSafe();
const findNetwork = useFindNetwork();
const toast = useToast();

return async (
event: {
Expand All @@ -42,73 +40,88 @@ export const useHandleWcRequest = () => {
}>,
session: SessionTypes.Struct
) => {
await handleAsyncActionUnsafe(
async () => {
const { id, topic, params } = event;
const { request, chainId } = params;
await handleAsyncActionUnsafe(async () => {
const { id, topic, params } = event;
const { request, chainId } = params;

let modal;
let onClose;
let modal;
let onClose;

switch (request.method) {
case "tezos_getAccounts": {
throw new WalletConnectError("Getting accounts is not supported yet", "WC_METHOD_UNSUPPORTED");
}
switch (request.method) {
case "tezos_getAccounts": {
throw new WalletConnectError(
"Getting accounts is not supported yet",
"WC_METHOD_UNSUPPORTED",
session
);
}

case "tezos_sign": {
throw new WalletConnectError("Sign is not supported yet", "WC_METHOD_UNSUPPORTED");
}
case "tezos_sign": {
throw new WalletConnectError(
"Sign is not supported yet",
"WC_METHOD_UNSUPPORTED",
session
);
}

case "tezos_send": {
if (!request.params.account) {
throw new WalletConnectError("Missing account in request", "INVALID_EVENT");
}
const signer = getAccount(request.params.account);
if (!signer) {
throw new WalletConnectError(`Unknown account, no signer: ${request.params.account}`, "UNAUTHORIZED_EVENT");
}
const operation = toAccountOperations(
request.params.operations,
signer as ImplicitAccount
case "tezos_send": {
if (!request.params.account) {
throw new WalletConnectError("Missing account in request", "INVALID_EVENT", session);
}
const signer = getAccount(request.params.account);
if (!signer) {
throw new WalletConnectError(
`Unknown account, no signer: ${request.params.account}`,
"UNAUTHORIZED_EVENT",
session
);
const network = findNetwork(chainId.split(":")[1]);
if (!network) {
const response = formatJsonRpcError(id, getSdkError("INVALID_EVENT").message);
await walletKit.respondSessionRequest({ topic, response });
toast({ description: `Unsupported network: ${chainId}`, status: "error" });
return;
}
const estimatedOperations = await estimate(operation, network);
const headerProps: SignHeaderProps = {
network,
appName: session.peer.metadata.name,
appIcon: session.peer.metadata.icons[0],
};
const signProps: SdkSignPageProps = {
headerProps: headerProps,
operation: estimatedOperations,
requestId: { sdkType: "walletconnect", id: id, topic },
};

if (operation.operations.length === 1) {
modal = <SingleSignPage {...signProps} />;
} else {
modal = <BatchSignPage {...signProps} {...event.params.request.params} />;
}
onClose = async () => {
const response = formatJsonRpcError(id, getSdkError("USER_REJECTED").message);
await walletKit.respondSessionRequest({ topic, response });
};
// onClose = () => {
// throw new WalletConnectError("Rejected by user", "USER_REJECTED");
// };
}
const operation = toAccountOperations(
request.params.operations,
signer as ImplicitAccount
);
const network = findNetwork(chainId.split(":")[1]);
if (!network) {
throw new WalletConnectError(
`Unsupported network ${chainId}`,
"UNSUPPORTED_CHAINS",
session
);
}
const estimatedOperations = await estimate(operation, network);
const headerProps: SignHeaderProps = {
network,
appName: session.peer.metadata.name,
appIcon: session.peer.metadata.icons[0],
};
const signProps: SdkSignPageProps = {
headerProps: headerProps,
operation: estimatedOperations,
requestId: { sdkType: "walletconnect", id: id, topic },
};

return openWith(modal, { onClose });
if (operation.operations.length === 1) {
modal = <SingleSignPage {...signProps} />;
} else {
modal = <BatchSignPage {...signProps} {...event.params.request.params} />;
}
default:
throw new WalletConnectError(`Unsupported method ${request.method}`, "WC_METHOD_UNSUPPORTED");
onClose = async () => {
const response = formatJsonRpcError(id, getSdkError("USER_REJECTED").message);
await walletKit.respondSessionRequest({ topic, response });
};
onClose = () => {
throw new WalletConnectError("Rejected by user", "USER_REJECTED", session);
};

return openWith(modal, { onClose });
}
default:
throw new WalletConnectError(
`Unsupported method ${request.method}`,
"WC_METHOD_UNSUPPORTED",
session
);
}
);
});
};
};
12 changes: 8 additions & 4 deletions packages/utils/src/ErrorContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {type SdkErrorKey} from "@walletconnect/utils";
import { type SessionTypes } from "@walletconnect/types";
import { type SdkErrorKey } from "@walletconnect/utils";
export type ErrorContext = {
timestamp: string;
description: string;
Expand All @@ -13,10 +14,11 @@ export class CustomError extends Error {
}
}

export class WalletConnectError extends Error {
export class WalletConnectError extends CustomError {
sdkError: SdkErrorKey;
constructor(message: string, sdkError: SdkErrorKey) {
super(message);
constructor(message: string, sdkError: SdkErrorKey, session: SessionTypes.Struct | null) {
const dappName = session?.peer.metadata.name ?? "unknown";
super(session ? `Request from ${dappName} is rejected. ${message}` : message);
this.name = "WalletConnectError";
this.sdkError = sdkError;
}
Expand All @@ -32,6 +34,8 @@ export const handleTezError = (err: Error): string | undefined => {
return "The baker you are trying to stake to does not accept external staking.";
} else if (err.message.includes("empty_implicit_delegated_contract")) {
return "Emptying an implicit delegated account is not allowed. End delegation before trying again.";
} else if (err.message.includes("delegate.unchanged")) {
return "The delegate is unchanged. Delegation to this address is already done.";
}
};

Expand Down

0 comments on commit 66b9772

Please sign in to comment.