Skip to content

Commit

Permalink
feat: WalletConnect integration, part 7, sign
Browse files Browse the repository at this point in the history
  • Loading branch information
dianasavvatina committed Dec 16, 2024
1 parent 70005af commit f1c2f06
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe("<SignPayloadRequestModal />", () => {
render(<SignPayloadRequestModal request={request} />, { store });

await waitFor(() =>
expect(screen.getByText("mockDappName/dApp Pairing Request")).toBeVisible()
expect(screen.getByText("Sign Payload Request from mockDappName")).toBeVisible()
);
});

Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/utils/beacon/useHandleBeaconMessage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe("<useHandleBeaconMessage />", () => {

act(() => handleMessage(message));

await screen.findByText("mockDappName/dApp Pairing Request");
await screen.findByText("Sign Payload Request from mockDappName");
});

it("sends an error response to the dapp on close", async () => {
Expand All @@ -128,7 +128,7 @@ describe("<useHandleBeaconMessage />", () => {

act(() => handleMessage(message));

await screen.findByText("mockDappName/dApp Pairing Request");
await screen.findByText("Sign Payload Request from mockDappName");

act(() => screen.getByRole("button", { name: "Close" }).click());

Expand Down
11 changes: 11 additions & 0 deletions apps/web/src/components/SendFlow/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { type SigningType } from "@airgap/beacon-wallet";
import { Button, type ButtonProps } from "@chakra-ui/react";
import { type TezosToolkit } from "@taquito/taquito";
import { useDynamicModalContext } from "@umami/components";
import {
type Account,
type AccountOperations,
type EstimatedAccountOperations,
type ImplicitAccount,
type Operation,
estimate,
executeOperations,
Expand Down Expand Up @@ -82,6 +84,15 @@ export type SdkSignPageProps = {
headerProps: SignHeaderProps;
};

export type SignPayloadProps = {
requestId: SignRequestId;
appName: string;
appIcon?: string;
payload: string;
signer: ImplicitAccount;
signingType: SigningType;
};

export const FormSubmitButton = ({ title = "Preview", ...props }: ButtonProps) => {
const {
formState: { isValid },
Expand Down
54 changes: 41 additions & 13 deletions apps/web/src/components/WalletConnect/useHandleWcRequest.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { SigningType } from "@airgap/beacon-wallet";
import { useDynamicModalContext } from "@umami/components";
import { type ImplicitAccount, estimate, toAccountOperations } from "@umami/core";
import {
useAsyncActionHandler,
useFindNetwork,
useGetImplicitAccount,
useGetOwnedAccountSafe,
walletKit,
} from "@umami/state";
Expand All @@ -11,9 +13,14 @@ import { formatJsonRpcError } from "@walletconnect/jsonrpc-utils";
import { type SessionTypes, type SignClientTypes, type Verify } from "@walletconnect/types";
import { getSdkError } from "@walletconnect/utils";

import { SignPayloadRequestModal } from "../common/SignPayloadRequestModal";
import { BatchSignPage } from "../SendFlow/common/BatchSignPage";
import { SingleSignPage } from "../SendFlow/common/SingleSignPage";
import { type SdkSignPageProps, type SignHeaderProps } from "../SendFlow/utils";
import {
type SdkSignPageProps,
type SignHeaderProps,
type SignPayloadProps,
} from "../SendFlow/utils";

/**
* @returns a function that handles a beacon message and opens a modal with the appropriate content
Expand All @@ -25,6 +32,7 @@ export const useHandleWcRequest = () => {
const { openWith } = useDynamicModalContext();
const { handleAsyncActionUnsafe } = useAsyncActionHandler();
const getAccount = useGetOwnedAccountSafe();
const getImplicitAccount = useGetImplicitAccount();
const findNetwork = useFindNetwork();

return async (
Expand All @@ -40,22 +48,46 @@ 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", session);
}

case "tezos_sign": {
throw new WalletConnectError("Sign is not supported yet", "WC_METHOD_UNSUPPORTED", session);
case "tezos_sign": {
if (!request.params.account) {
throw new Error("Missing account in request");
}
const signer = getImplicitAccount(request.params.account);
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 signPayloadProps: SignPayloadProps = {
appName: session.peer.metadata.name,
appIcon: session.peer.metadata.icons[0],
payload: request.params.payload,
signer: signer,
signingType: SigningType.RAW,
requestId: { sdkType: "walletconnect", id: id, topic },
};

modal = <SignPayloadRequestModal opts={signPayloadProps} />;
onClose = async () => {
const response = formatJsonRpcError(id, getSdkError("USER_REJECTED").message);
await walletKit.respondSessionRequest({ topic, response });
};
return openWith(modal, { onClose });
}

case "tezos_send": {
if (!request.params.account) {
Expand Down Expand Up @@ -90,10 +122,6 @@ export const useHandleWcRequest = () => {
} 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", session);
};
Expand Down
79 changes: 0 additions & 79 deletions apps/web/src/components/beacon/SignPayloadRequestModal.test.tsx

This file was deleted.

1 change: 0 additions & 1 deletion apps/web/src/components/beacon/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./BeaconProvider";
export * from "./PermissionRequestModal";
export * from "./SignPayloadRequestModal";
export * from "./useHandleBeaconMessage";
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe("<useHandleBeaconMessage />", () => {

act(() => handleMessage(message));

await screen.findByText("mockDappName/dApp Pairing Request");
await screen.findByText("Sign Payload Request from mockDappName");
});

it("sends an error response to the dapp on close", async () => {
Expand All @@ -134,7 +134,7 @@ describe("<useHandleBeaconMessage />", () => {

act(() => handleMessage(message));

await screen.findByText("mockDappName/dApp Pairing Request");
await screen.findByText("Sign Payload Request from mockDappName");

act(() => screen.getByRole("button", { name: "Close" }).click());

Expand Down
21 changes: 18 additions & 3 deletions apps/web/src/components/beacon/useHandleBeaconMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ import {
WalletClient,
useAsyncActionHandler,
useFindNetwork,
useGetImplicitAccount,
useGetOwnedAccountSafe,
useRemoveBeaconPeerBySenderId,
} from "@umami/state";
import { type Network } from "@umami/tezos";
import { CustomError } from "@umami/utils";

import { PermissionRequestModal } from "./PermissionRequestModal";
import { SignPayloadRequestModal } from "./SignPayloadRequestModal";
import { SignPayloadRequestModal } from "../common/SignPayloadRequestModal";
import { BatchSignPage } from "../SendFlow/common/BatchSignPage";
import { SingleSignPage } from "../SendFlow/common/SingleSignPage";
import { type SdkSignPageProps, type SignHeaderProps } from "../SendFlow/utils";
import {
type SdkSignPageProps,
type SignHeaderProps,
type SignPayloadProps,
} from "../SendFlow/utils";

/**
* @returns a function that handles a beacon message and opens a modal with the appropriate content
Expand All @@ -32,6 +37,7 @@ export const useHandleBeaconMessage = () => {
const { openWith } = useDynamicModalContext();
const { handleAsyncAction } = useAsyncActionHandler();
const getAccount = useGetOwnedAccountSafe();
const getImplicitAccount = useGetImplicitAccount();
const findNetwork = useFindNetwork();
const removePeer = useRemoveBeaconPeerBySenderId();

Expand Down Expand Up @@ -83,7 +89,16 @@ export const useHandleBeaconMessage = () => {
break;
}
case BeaconMessageType.SignPayloadRequest: {
modal = <SignPayloadRequestModal request={message} />;
const signer = getImplicitAccount(message.sourceAddress);
const signPayloadProps: SignPayloadProps = {
appName: message.appMetadata.name,
appIcon: message.appMetadata.icon,
payload: message.payload,
signer: signer,
signingType: message.signingType,
requestId: { sdkType: "beacon", id: message.id },
};
modal = <SignPayloadRequestModal opts={signPayloadProps} />;
onClose = async () => {
await WalletClient.respond({
id: message.id,
Expand Down
Loading

0 comments on commit f1c2f06

Please sign in to comment.