From 1ea0e68a067fbf70632e19ee5eaf6b969e49ef9e Mon Sep 17 00:00:00 2001 From: Shawn Tobin Date: Mon, 6 Nov 2023 18:06:39 +0800 Subject: [PATCH] Fix broken Master Ticket process with WalletConnect on L1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useWalletConnect.ts: - Removed PeerMeta state variable to reduce some state complexity since it’s not used outside of the hook definition anyway. I noticed an issue where it sometimes was returning null when it should have been set, so rather than put in a fix for this it might as well just be removed IMO. Deriving from ‘session’ when needed works as expected. ResetExecute.tsx: - Removed the WalletConnect session check from within performReticket and instead now using 2 separate useEffects to ensure correct execution based on wallet type. Other login methods shouldn’t need to wait for ‘connector’ and ‘session’, which are specific to WalletConnect. WalletConnect.tsx Metamask.jsx - Deleted these components since they’re not being used. Bridge no longer renders a tab screen for Metamask or WalletConnect. Tested successfully on mainnet with Zerion and Ledger. --- src/lib/useWalletConnect.ts | 25 ++-- src/views/Login/Metamask.jsx | 128 ------------------- src/views/Login/Other.tsx | 4 - src/views/Login/WalletConnect.tsx | 123 ------------------ src/views/UrbitID/ResetKeys/ResetExecute.tsx | 39 +++--- 5 files changed, 27 insertions(+), 292 deletions(-) delete mode 100644 src/views/Login/Metamask.jsx delete mode 100644 src/views/Login/WalletConnect.tsx diff --git a/src/lib/useWalletConnect.ts b/src/lib/useWalletConnect.ts index a5fce8419..eddb5c413 100644 --- a/src/lib/useWalletConnect.ts +++ b/src/lib/useWalletConnect.ts @@ -14,13 +14,6 @@ import { isGoerli } from './flags'; import { ITxData } from './types/ITxData'; import { mayCreateHexString } from './utils/hex'; -type PeerMeta = { - description: string; - icons?: string[]; - name: string; - url: string; -}; - type PersonalSign = { message: string; address: string; @@ -42,20 +35,17 @@ export const useWalletConnect = () => { const [connector, setConnector] = useState(null); const [address, setAddress] = useState(null); - const [peerMeta, setPeerMeta] = useState(null); const [session, setSession] = useState(null); const [modal, setModal] = useState(null); const resetSession = () => { setSession(null); setAddress(null); - setPeerMeta(null); }; const updateSession = (_session: SessionTypes.Struct) => { setSession(_session); setAddress(_session.namespaces.eip155.accounts[0].slice(9)); - setPeerMeta(_session.peer.metadata); }; const initConnector = async () => { @@ -195,15 +185,17 @@ export const useWalletConnect = () => { }; const peerIcon = useMemo(() => { - if (!peerMeta?.icons) { + if (!session?.peer?.metadata?.icons) { return null; } // Some peers return a list of empty string(s) :) - const iconCandidates = peerMeta.icons.filter(pm => pm !== ''); + const iconCandidates = session?.peer?.metadata?.icons.filter( + pm => pm !== '' + ); return iconCandidates.length > 0 ? iconCandidates[0] : null; - }, [peerMeta]); + }, [session]); const signTransaction = async ({ from, @@ -221,7 +213,7 @@ export const useWalletConnect = () => { } // Ledger Live needs to use fakeSign instead since it sends the txn upon signing - if (peerMeta?.name === 'Ledger Wallet') { + if (session?.peer?.metadata?.name === 'Ledger Wallet') { reject(new Error('METHOD_NOT_SUPPORTED')); return; } @@ -315,8 +307,7 @@ export const useWalletConnect = () => { // Event handlers const onSessionDelete = () => { - setAddress(null); - setPeerMeta(null); + resetSession(); resetWallet(); }; @@ -348,10 +339,10 @@ export const useWalletConnect = () => { authenticate, connect, connector, + session, disconnect, isConnected, peerIcon, - peerMeta, initConnector, signTransaction, sendTransaction, diff --git a/src/views/Login/Metamask.jsx b/src/views/Login/Metamask.jsx deleted file mode 100644 index 2eb9bbfb3..000000000 --- a/src/views/Login/Metamask.jsx +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; -import { Grid, Text, LinkButton, H5 } from 'indigo-react'; -import { Just } from 'folktale/maybe'; -import { FORM_ERROR } from 'final-form'; - -import { useWallet } from 'store/wallet'; -import { useNetwork } from 'store/network'; - -import { abbreviateAddress } from 'lib/utils/address'; -import { WALLET_TYPES } from 'lib/constants'; -import { MetamaskWallet } from 'lib/metamask'; -import { getAuthToken } from 'lib/authToken'; -import useLoginView from 'lib/useLoginView'; - -import SubmitButton from 'form/SubmitButton'; -import BridgeForm from 'form/BridgeForm'; -import Window from 'components/L2/Window/Window'; -import HeaderPane from 'components/L2/Window/HeaderPane'; -import BodyPane from 'components/L2/Window/BodyPane'; -import { Row } from '@tlon/indigo-react'; -import Web3 from 'web3'; - -export default function Metamask({ className, goHome }) { - useLoginView(WALLET_TYPES.METAMASK); - const { - setWallet, - setWalletType, - setAuthToken, - setFakeToken, - skipLoginSigning, - } = useWallet(); - - const { setMetamask } = useNetwork(); - - useEffect(() => { - setMetamask(true); - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - const onSubmit = useCallback(async () => { - try { - setMetamask(true); - const accounts = await window.ethereum.request({ - method: 'eth_requestAccounts', - }); - const wallet = new MetamaskWallet(accounts.result[0]); - const web3 = new Web3(window.ethereum); - setWallet(Just(wallet)); - setWalletType(WALLET_TYPES.METAMASK); - - if (skipLoginSigning) { - setFakeToken(); - return; - } - - const authToken = await getAuthToken({ - address: wallet.address, - walletType: WALLET_TYPES.METAMASK, - web3, - }); - - setAuthToken(Just(authToken)); - } catch (e) { - console.error(e); - return { [FORM_ERROR]: e.message }; - } - }, [ - setMetamask, - setWallet, - setWalletType, - skipLoginSigning, - setAuthToken, - setFakeToken, - ]); - - return ( - - {(window.ethereum && Login({ onSubmit, goHome })) || Unsupported()} - - ); -} - -function Unsupported() { - return ( - <> - - Unsupported - - - Metamask is not installed on this browser.
- - Get Metamask - -
- - ); -} -function Login({ onSubmit, goHome }) { - return ( - - - -
Metamask
-
-
- - - If you wish to login with a different wallet, please change it in the - Metamask extension - - - {({ handleSubmit }) => ( - - - Login - {window.ethereum.selectedAddress && - ' as ' + abbreviateAddress(window.ethereum.selectedAddress)} - - - )} - - -
- ); -} diff --git a/src/views/Login/Other.tsx b/src/views/Login/Other.tsx index 73243fb89..b97cd64d1 100644 --- a/src/views/Login/Other.tsx +++ b/src/views/Login/Other.tsx @@ -1,10 +1,8 @@ import React, { useState } from 'react'; import { Icon } from '@tlon/indigo-react'; -import Metamask from './Metamask'; import Ticket from './Ticket'; import Mnemonic from './Mnemonic'; -import WalletConnect from './WalletConnect'; import LoginSelector from './LoginSelector'; import { ReactComponent as MetamaskIcon } from 'assets/metamask.svg'; import { ReactComponent as WalletConnectIcon } from 'assets/wallet-connect.svg'; @@ -17,9 +15,7 @@ export const NAMES = { }; const VIEWS = { - [NAMES.METAMASK]: Metamask, [NAMES.MNEMONIC]: Mnemonic, - [NAMES.WALLET_CONNECT]: WalletConnect, [NAMES.MASTER_TICKET]: Ticket, }; diff --git a/src/views/Login/WalletConnect.tsx b/src/views/Login/WalletConnect.tsx deleted file mode 100644 index 04c8941a3..000000000 --- a/src/views/Login/WalletConnect.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { Image, Row, Text } from '@tlon/indigo-react'; -import BridgeForm from 'form/BridgeForm'; -import FormError from 'form/FormError'; -import SubmitButton from 'form/SubmitButton'; -import { Grid } from 'indigo-react'; -import { WALLET_TYPES } from 'lib/constants'; -import useLoginView from 'lib/useLoginView'; -import { useWalletConnect } from 'lib/useWalletConnect'; -import { abbreviateAddress } from 'lib/utils/address'; -import { ForwardButton, RestartButton } from 'components/Buttons'; -import Window from 'components/L2/Window/Window'; -import HeaderPane from 'components/L2/Window/HeaderPane'; -import BodyPane from 'components/L2/Window/BodyPane'; - -interface WalletConnectLoginProps { - className?: string; - goHome: () => void; -} - -const WalletConnectLogin = ({ className, goHome }: WalletConnectLoginProps) => { - useLoginView(WALLET_TYPES.WALLET_CONNECT); - - const { - address, - authenticate, - connect, - connector, - disconnect, - isConnected, - peerIcon, - peerMeta, - } = useWalletConnect(); - - const onSubmit = async () => { - await authenticate(); - return; - }; - - return ( - connector && ( - - - -
WalletConnect
-
-
- - - {!isConnected() && ( - - Note that WalletConnect is a young protocol, not all wallets may - work fully - - )} - - {isConnected() && peerMeta && ( - - - - {peerIcon ? ( - - ) : ( - Icon Unavailable - )} - - - {peerMeta.name} - - {address ? abbreviateAddress(address) : null} - - - disconnect - - - - - )} - - - {({ handleSubmit, submitting }: any) => ( - - {isConnected() ? ( - <> - - - - {submitting - ? 'Please check your WalletConnect wallet' - : 'Authenticate'} - - - ) : ( - <> - - {'Connect'} - - - )} - - )} - - - -
- ) - ); -}; - -export default WalletConnectLogin; diff --git a/src/views/UrbitID/ResetKeys/ResetExecute.tsx b/src/views/UrbitID/ResetKeys/ResetExecute.tsx index 0e3f399f9..875d3a62b 100644 --- a/src/views/UrbitID/ResetKeys/ResetExecute.tsx +++ b/src/views/UrbitID/ResetKeys/ResetExecute.tsx @@ -77,7 +77,7 @@ export default function ResetExecute({ signTransaction: wcSign, sendTransaction: wcSend, connector, - isConnected, + session, } = useWalletConnect(); const { performL2SpawnReticket } = useReticketL2Spawn(); @@ -128,17 +128,6 @@ export default function ResetExecute({ ); const performReticket = useCallback(async () => { - // due to react shenanigans we may need to wait for the connector - if ( - walletType === WALLET_TYPES.WALLET_CONNECT && - (!connector || isConnected()) - ) { - setGeneralError(new Error('Awaiting WalletConnect connection...')); - return; - } - - setGeneralError(undefined); - const l2point = await api.getPoint(point); const details = need.details(getDetails(point)); const networkRevision = convertToInt(details.keyRevisionNumber, 10); @@ -200,7 +189,6 @@ export default function ResetExecute({ } }, [ api, - connector, contracts, getDetails, handleUpdate, @@ -215,20 +203,31 @@ export default function ResetExecute({ walletType, wcSend, wcSign, - isConnected, web3, ]); + // For WalletConnect + useEffect(() => { + if (walletType === WALLET_TYPES.WALLET_CONNECT) { + if (connector && session?.acknowledged) { + setGeneralError(undefined); + performReticket(); + } else { + setGeneralError(new Error('Awaiting WalletConnect connection...')); + } + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [connector, session, walletType]); + + // For non-WalletConnect wallets useEffect(() => { - if (!connector) { - return; + if (walletType && walletType !== WALLET_TYPES.WALLET_CONNECT) { + performReticket(); } - performReticket(); - // We want to perform the reticket only once, after the WalletConnect - // connector has finished instantiating and setting up a websocket // eslint-disable-next-line react-hooks/exhaustive-deps - }, [connector]); + }, [walletType]); const renderAdditionalInfo = () => { if (generalError) {