diff --git a/src/Router.tsx b/src/Router.tsx
index b97995421..2442eb35c 100644
--- a/src/Router.tsx
+++ b/src/Router.tsx
@@ -18,7 +18,7 @@ import { withSideMenu } from "./views/withSideMenu";
import HelpView from "./views/help/HelpView";
import AddressBookView from "./views/addressBook/AddressBookView";
import BatchPage from "./views/batch/BatchPage";
-import { resetBeacon, useBeaconInit } from "./utils/beacon/beacon";
+import { BeaconProvider, resetBeacon } from "./utils/beacon/beacon";
import TokensView from "./views/tokens/TokensView";
import { useDeeplinkHandler } from "./utils/useDeeplinkHandler";
import { AnnouncementBanner } from "./components/AnnouncementBanner";
@@ -39,27 +39,27 @@ const loggedOutRouter = createHashRouter([
]);
const MemoizedRouter = React.memo(() => {
- const beaconNotificationModal = useBeaconInit();
const dynamicModal = useDynamicModal();
return (
-
-
- )} />
- )} />
- )} />
- )} />
- )} />
- )} />
- )} />
- )} />
- )} />
- } />
-
- {dynamicModal.content}
- {beaconNotificationModal}
+
+
+
+ )} />
+ )} />
+ )} />
+ )} />
+ )} />
+ )} />
+ )} />
+ )} />
+ )} />
+ } />
+
+ {dynamicModal.content}
+
);
diff --git a/src/components/SendFlow/Beacon/BeaconSignPage.tsx b/src/components/SendFlow/Beacon/BeaconSignPage.tsx
index 9f8d3091b..5e5993317 100644
--- a/src/components/SendFlow/Beacon/BeaconSignPage.tsx
+++ b/src/components/SendFlow/Beacon/BeaconSignPage.tsx
@@ -29,7 +29,6 @@ const BeaconSignPage: React.FC = ({ operation, onBeaconSucc
case "fa1.2":
case "fa2":
case "contract_origination":
- // this line will not reach, but better safe than sorry
throw new Error("Unsupported operation type");
}
};
diff --git a/src/components/SendFlow/Beacon/useSignWithBeacon.tsx b/src/components/SendFlow/Beacon/useSignWithBeacon.tsx
index ab23922c3..e96c51bf8 100644
--- a/src/components/SendFlow/Beacon/useSignWithBeacon.tsx
+++ b/src/components/SendFlow/Beacon/useSignWithBeacon.tsx
@@ -13,10 +13,10 @@ export const useSignWithBeacon = (
operation: ImplicitOperations,
onBeaconSuccess: (hash: string) => Promise
) => {
+ const { onClose } = useContext(DynamicModalContext);
const [fee, setFee] = useState(null);
const network = useSelectedNetwork();
const { isLoading: isSigning, handleAsyncAction } = useAsyncActionHandler();
- const { handleAsyncAction: handleFeeEstimation } = useAsyncActionHandler();
const { openWith } = useContext(DynamicModalContext);
const form = useForm<{ sender: string; signer: string }>({
mode: "onBlur",
@@ -27,20 +27,25 @@ export const useSignWithBeacon = (
});
useEffect(() => {
- const estimateFee = () =>
- handleFeeEstimation(
+ const estimateFee = () => {
+ handleAsyncAction(
async () => {
const fee = await estimate(operation, network);
setFee(fee);
},
- err => ({
- title: "Error",
- description: `Error while processing beacon request: ${err.message}`,
- status: "error",
- })
+ err => {
+ onClose();
+ return {
+ title: "Error",
+ description: `Error while processing beacon request: ${err.message}`,
+ status: "error",
+ };
+ }
);
+ };
estimateFee();
- }, [network, operation, handleFeeEstimation]);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [network, operation]);
const onSign = async (tezosToolkit: TezosToolkit) =>
handleAsyncAction(async () => {
diff --git a/src/utils/beacon/BeaconNotification/BeaconRequestNotification.tsx b/src/utils/beacon/BeaconNotification/BeaconRequestNotification.tsx
index 97ea442c3..fbc5a4990 100644
--- a/src/utils/beacon/BeaconNotification/BeaconRequestNotification.tsx
+++ b/src/utils/beacon/BeaconNotification/BeaconRequestNotification.tsx
@@ -3,17 +3,13 @@ import {
BeaconRequestOutputMessage,
OperationRequestOutput,
OperationResponseInput,
+ PartialTezosOperation,
TezosOperationType,
} from "@airgap/beacon-wallet";
import { useToast } from "@chakra-ui/react";
import React from "react";
import { ImplicitOperations } from "../../../components/sendForm/types";
-import {
- isValidContractPkh,
- parseContractPkh,
- parseImplicitPkh,
- parsePkh,
-} from "../../../types/Address";
+import { isValidContractPkh, parseContractPkh, parseImplicitPkh } from "../../../types/Address";
import { Operation } from "../../../types/Operation";
import { useGetImplicitAccountSafe } from "../../hooks/accountHooks";
import { walletClient } from "../beacon";
@@ -78,8 +74,50 @@ export const BeaconNotification: React.FC<{
}
};
+const partialOperationToOperation = (
+ partialOperation: PartialTezosOperation,
+ signer: ImplicitAccount
+): Operation | null => {
+ switch (partialOperation.kind) {
+ case TezosOperationType.TRANSACTION: {
+ const { destination, amount, parameters } = partialOperation;
+ const isContractCall = isValidContractPkh(destination) && parameters;
+ if (isContractCall) {
+ return {
+ type: "contract_call",
+ amount,
+ contract: parseContractPkh(destination),
+ entrypoint: parameters.entrypoint,
+ args: parameters.value,
+ };
+ } else {
+ return {
+ type: "tez",
+ amount,
+ recipient: parseImplicitPkh(partialOperation.destination),
+ };
+ }
+ }
+ case TezosOperationType.DELEGATION: {
+ const { delegate } = partialOperation;
+
+ if (delegate) {
+ return {
+ type: "delegation",
+ sender: signer.address,
+ recipient: parseImplicitPkh(delegate),
+ };
+ } else {
+ return { type: "undelegation", sender: signer.address };
+ }
+ }
+ default:
+ return null;
+ }
+};
+
const toOperation = (
- { operationDetails, sourceAddress }: OperationRequestOutput,
+ { operationDetails }: OperationRequestOutput,
signer: ImplicitAccount
): ImplicitOperations => {
if (operationDetails.length === 0) {
@@ -92,35 +130,7 @@ const toOperation = (
const partialOperation = operationDetails[0];
- let operation: Operation | undefined = undefined;
-
- if (partialOperation.kind === TezosOperationType.TRANSACTION) {
- const { destination, amount, parameters } = partialOperation;
- operation =
- isValidContractPkh(destination) && parameters
- ? {
- type: "contract_call",
- amount,
- contract: parseContractPkh(destination),
- entrypoint: parameters.entrypoint,
- args: parameters.value,
- }
- : {
- type: "tez",
- amount,
- recipient: parseImplicitPkh(partialOperation.destination),
- };
- } else if (partialOperation.kind === TezosOperationType.DELEGATION) {
- const sender = parsePkh(sourceAddress);
- operation = partialOperation.delegate
- ? {
- type: "delegation",
- sender,
- recipient: parseImplicitPkh(partialOperation.delegate),
- }
- : { type: "undelegation", sender };
- }
-
+ const operation = partialOperationToOperation(operationDetails[0], signer);
if (!operation) {
throw new Error(`Unsupported operation: ${partialOperation.kind}`);
}
diff --git a/src/utils/beacon/beacon.tsx b/src/utils/beacon/beacon.tsx
index 870b7e405..59bcfc005 100644
--- a/src/utils/beacon/beacon.tsx
+++ b/src/utils/beacon/beacon.tsx
@@ -1,15 +1,10 @@
-import {
- BeaconRequestOutputMessage,
- ConnectionContext,
- ExtendedP2PPairingResponse,
- Serializer,
- WalletClient,
-} from "@airgap/beacon-wallet";
-import { Modal, useDisclosure, useToast } from "@chakra-ui/react";
-import { useEffect, useRef } from "react";
+import { ExtendedP2PPairingResponse, Serializer, WalletClient } from "@airgap/beacon-wallet";
+import { useToast } from "@chakra-ui/react";
+import { useContext, useEffect } from "react";
import { useQuery, useQueryClient } from "react-query";
import { BeaconNotification } from "./BeaconNotification";
import { makePeerInfo, PeerInfo } from "./types";
+import { DynamicModalContext } from "../../components/DynamicModal";
const makeClient = () =>
new WalletClient({
@@ -58,52 +53,22 @@ export const useAddPeer = () => {
};
};
-export const useBeaconModalNotification = () => {
- const { isOpen, onOpen, onClose } = useDisclosure();
- const beaconMessage = useRef();
-
- return {
- modalElement: (
-
- {beaconMessage.current && (
-
- )}
-
- ),
-
- onOpen: (message: BeaconRequestOutputMessage, _: ConnectionContext) => {
- beaconMessage.current = message;
- onOpen();
- },
- };
-};
-
-// Need this ignore BS because useEffect runs twice in development:
-// https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development
-export const useBeaconInit = () => {
- const { modalElement: beaconModal, onOpen } = useBeaconModalNotification();
- const ignore = useRef(false);
- const handleBeaconMessage = useRef(onOpen);
-
+export const BeaconProvider: React.FC<{
+ children: React.ReactNode;
+}> = ({ children }) => {
+ const { openWith, onClose } = useContext(DynamicModalContext);
useEffect(() => {
- if (!ignore.current) {
- walletClient
- .init()
- .then(() => {
- walletClient.connect(handleBeaconMessage.current);
- })
- .catch(console.error)
- .finally(() => {
- ignore.current = false;
+ walletClient
+ .init()
+ .then(() => {
+ walletClient.connect(message => {
+ openWith();
});
- }
-
- return () => {
- ignore.current = true;
- };
- }, []);
+ })
+ .catch(console.error);
+ }, [onClose, openWith]);
- return beaconModal;
+ return <>{children}>;
};
export const resetBeacon = async () => {