Skip to content

Commit

Permalink
feat: add pre-signature dialog before connecting WalletConnect (#454)
Browse files Browse the repository at this point in the history
  • Loading branch information
helciofranco authored Jan 14, 2025
1 parent 881be12 commit 71256d8
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 84 deletions.
7 changes: 7 additions & 0 deletions .changeset/honest-meals-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@fuel-connectors/walletconnect-connector": minor
"@fuels/connectors": minor
"@fuels/react": minor
---

Added a pre-signature dialog to the `WalletConnectConnector` to inform users about the signature purpose.
25 changes: 25 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
List the issues this PR closes in a bullet list format, e.g.:
- Closes #X
- Closes `FE-Z`
-->

# Summary
<!--
Please include a summary of your changes if something is not self-explanatory from the closed issues.
Many times this section is not needed as the closed issues themselves explains the reason of the PR exists. On that case just remove this section it.
-->

# Checklist

- [ ] I've added error handling for all actions/requests, and verified how this error will show on UI.
- [ ] I've reviewed all the copies changed/added in this PR (use AI if needs help)
- [ ] I've included the reference to the issues being closed (Github and/or Linear)
- [ ] I've changed the Docs to reflect my changes (project setup, run commands, etc…)
- [ ] I've put docs links where it may be helpful.
- [ ]
- [ ] I've added error handling for all actions/requests, and verified how it will show on UI (or verifying error handling was needed)
- [ ] I've reviewed all the copies changed/added in this PR, using AI if needed (or no copy changes were made)
- [ ] I've included the reference to the Github and/or Linear issues being closed (or no issues to reference)
- [ ] I've changed the Docs to reflect my changes (or no doc updates were needed)
- [ ] I've put docs links where it may be helpful (or no doc links were needed)
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ test.describe('WalletConnectConnector', () => {
// First-time connection requires a message signature (to prove ownership of the wallet)
const connect: ConnectorFunctions['connect'] = async (page) => {
await commonConnect(page);
await page.getByText('Sign', { exact: true }).click();
await metamask.confirmSignature();
};

Expand Down
7 changes: 1 addition & 6 deletions packages/react/src/providers/FuelUIProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ export function FuelUIProvider({
[handleStartConnection],
);

const setRoute = useCallback((state: Routes) => {
setDialogRoute(state);
}, []);

const isLoading = useMemo(() => {
const hasLoadedConnectors =
(fuelConfig.connectors || []).length > connectors.length;
Expand Down Expand Up @@ -224,7 +220,7 @@ export function FuelUIProvider({
// Dialog only
dialog: {
route: dialogRoute,
setRoute,
setRoute: setDialogRoute,
connector,
isOpen,
connect: handleSelectConnector,
Expand All @@ -248,7 +244,6 @@ export function FuelUIProvider({
isOpen,
handleCancel,
handleStartConnection,
setRoute,
handleSelectConnector,
handleConnect,
handleRetryConnect,
Expand Down
70 changes: 61 additions & 9 deletions packages/react/src/ui/Connect/components/Connector/Connecting.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Routes, useConnectUI } from '../../../../providers/FuelUIProvider';
import { ConnectorIcon } from '../Core/ConnectorIcon';

import { useEffect } from 'react';
import type { ConnectorEvent } from 'fuels';
import { useEffect, useMemo, useState } from 'react';
import { Spinner } from '../../../../icons/Spinner';
import { useFuel } from '../../../../providers/FuelHooksProvider';
import {
ConnectorButton,
ConnectorButtonPrimary,
Expand All @@ -17,7 +19,19 @@ type ConnectorProps = {
className?: string;
};

export interface CustomCurrentConnectorEvent extends ConnectorEvent {
metadata?: {
pendingSignature: boolean;
};
}

enum ConnectStep {
CONNECT = 'connect',
SIGN = 'sign',
}

export function Connecting({ className }: ConnectorProps) {
const { fuel } = useFuel();
const {
error,
isConnecting,
Expand All @@ -27,12 +41,51 @@ export function Connecting({ className }: ConnectorProps) {
isConnected,
} = useConnectUI();

const [connectStep, setConnectStep] = useState<ConnectStep>(
ConnectStep.CONNECT,
);

const { description, operation, cta } = useMemo(() => {
if (connectStep === ConnectStep.CONNECT) {
return {
description: `Click on the button below to connect to ${location.origin}.`,
operation: 'connection',
cta: 'Connect',
};
}

return {
description:
'Sign this message to prove you own this wallet and proceed. Canceling will disconnect you.',
operation: 'signature',
cta: 'Sign',
};
}, [connectStep]);

// Auto-close connecting
useEffect(() => {
if (isConnected && route === Routes.CONNECTING && !isConnecting) {
cancel();
}
}, [isConnected, route, isConnecting, cancel]);

// Switching to signing ownership mode
useEffect(() => {
const onCurrentConnectorChange = (e: CustomCurrentConnectorEvent) => {
if (e.metadata && 'pendingSignature' in e.metadata) {
setConnectStep(
e.metadata.pendingSignature ? ConnectStep.SIGN : ConnectStep.CONNECT,
);
}
};

fuel.on(fuel.events.currentConnector, onCurrentConnectorChange);

return () => {
fuel.off(fuel.events.currentConnector, onCurrentConnectorChange);
};
}, [fuel]);

if (!connector) return null;

return (
Expand All @@ -47,16 +100,15 @@ export function Connecting({ className }: ConnectorProps) {
</ConnectorImage>
<ConnectorContent>
<ConnectorTitle>{connector.name}</ConnectorTitle>
{error ? (
<ConnectorDescriptionError>{error.message}</ConnectorDescriptionError>
) : isConnecting ? (
{isConnecting ? (
<ConnectorDescription>
Requesting connection to <br /> {connector.name}.
Requesting {operation} to <br /> {connector.name}.
</ConnectorDescription>
) : (
<ConnectorDescription>
Click on the button below to connect to {location.origin}.
</ConnectorDescription>
<ConnectorDescription>{description}</ConnectorDescription>
)}
{error && (
<ConnectorDescriptionError>{error.message}</ConnectorDescriptionError>
)}
</ConnectorContent>
{isConnecting ? (
Expand All @@ -65,7 +117,7 @@ export function Connecting({ className }: ConnectorProps) {
</ConnectorButton>
) : (
<ConnectorButtonPrimary onClick={() => retryConnect(connector)}>
Connect
{cta}
</ConnectorButtonPrimary>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ export const DialogContent = (props: Dialog.DialogContentProps) => {
style={dialogContentStyle}
{...props}
className="fuel-connectors-dialog-content"
// Workaround to prevent closing dialog when interacting with WalletConnect Modal
onPointerDownOutside={(e) => {
const walletConnectDialog = document.querySelector('w3m-modal');
if (walletConnectDialog?.classList.contains('open')) {
e.preventDefault();
}
}}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export function DialogFuel({
open,
onOpenChange,
}: DialogRadix.DialogProps & { theme: 'dark' | 'light' }) {
// const currentConnector = fuel.currentConnector();
// Fix hydration problem between nextjs render and frontend render
// UI was not getting updated and theme colors was set wrongly
// see more here https://nextjs.org/docs/messages/react-hydration-error
Expand Down
8 changes: 4 additions & 4 deletions packages/react/src/ui/Connect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import { DialogContent } from './components/Core/DialogContent';
import { DialogFuel } from './components/Core/DialogFuel';
import { ExternalDisclaimer } from './components/ExternalDisclaimer/ExternalDisclaimer';

const ConnectRoutes = ({ state }: { state: Routes }) => {
switch (state) {
const ConnectRoutes = ({ route }: { route: Routes }) => {
switch (route) {
case Routes.LIST:
return <Connectors />;
case Routes.INSTALL:
Expand All @@ -36,7 +36,7 @@ export function Connect() {
const {
theme,
cancel,
dialog: { isOpen, route: state, connector, back },
dialog: { isOpen, route, connector, back },
} = useConnectUI();

const handleOpenChange = (openState: boolean) => {
Expand All @@ -55,7 +55,7 @@ export function Connect() {
</DialogHeader>
<Divider />
<DialogMain>
<ConnectRoutes state={state} />
<ConnectRoutes route={route} />
</DialogMain>
</DialogContent>
</DialogFuel>
Expand Down
Loading

0 comments on commit 71256d8

Please sign in to comment.