Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/next-common/components/header/drawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ export default function SidebarAccount() {

export function WalletConnectDisconnectLoading({ type }) {
const { disconnectLoading } = useWalletConnect();
if (!disconnectLoading || type !== "logout") {
const { disconnectLoading: evmDisconnectLoading } =
useConnectedAccountContext();
if (!(disconnectLoading || evmDisconnectLoading) || type !== "logout") {
return null;
}
return <Loading size={16} />;
Expand Down
65 changes: 42 additions & 23 deletions packages/next-common/components/linkedAddress/popup.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,51 @@
import { noop } from "lodash-es";
import Popup from "../popup/wrapper/Popup";
import { useAccount, useConnect } from "wagmi";
import { useConnection, useConnect, useConnectors } from "wagmi";
import WalletSubstrateSingleSigOptions from "../wallet/options/substrate/singleSig";
import WalletEVMOptions from "../wallet/options/evm";
import { useWeb3WalletView } from "next-common/hooks/connect/useWeb3WalletView";
import { useUnmount } from "react-use";
import useEVMWalletConnect from "next-common/hooks/connect/useEVMWalletConnect";
import { WalletConnectQrCode } from "../login/web3/walletconnect";

export default function LinkedAddressSelectWalletPopup({
selectedWallet,
onSelect = noop,
onClose = noop,
}) {
const { isSubstrateView, isEVMView, resetView } = useWeb3WalletView();
const { connector } = useAccount();
const { connect } = useConnect();
const { connector } = useConnection();
const { mutate } = useConnect();
const connectors = useConnectors();
const walletConnect = useEVMWalletConnect(
connectors.find((item) => item.id === "walletConnect"),
);

useUnmount(resetView);

async function handleSelectWallet(wallet) {
if (wallet.connector?.id === connector?.id) {
onSelect(wallet);
return;
}

if (wallet.connector.id === "walletConnect") {
if (await walletConnect.open()) {
onSelect(wallet);
}
return;
}

mutate(
{ connector: wallet.connector },
{
onSuccess() {
onSelect(wallet);
},
},
);
}

return (
<Popup className="p-[48px]" onClose={onClose}>
<h3 className="text20Bold text-textPrimary">
Expand All @@ -31,28 +60,18 @@ export default function LinkedAddressSelectWalletPopup({
/>
)}

{isEVMView && (
{isEVMView && walletConnect.isOpen && (
<WalletConnectQrCode
uri={walletConnect.uri}
backTitle="Back to EVM"
onBack={walletConnect.close}
/>
)}

{isEVMView && !walletConnect.isOpen && (
<WalletEVMOptions
selectedWallet={selectedWallet}
onSelect={(wallet) => {
function select() {
onSelect(wallet);
}

if (wallet.connector?.id === connector?.id) {
select();
return;
}

connect(
{ connector: wallet.connector },
{
onSuccess() {
select();
},
},
);
}}
onSelect={handleSelectWallet}
/>
)}
</Popup>
Expand Down
68 changes: 51 additions & 17 deletions packages/next-common/components/login/web3/evm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,38 @@ import AddressSelect from "next-common/components/addressSelect";
import WalletEVMOptions from "next-common/components/wallet/options/evm";
import { useConnectedAccountContext } from "next-common/context/connectedAccount";
import { useEVMAccounts } from "next-common/hooks/connect/useEVMAccounts";
import useEVMWalletConnect from "next-common/hooks/connect/useEVMWalletConnect";
import { useEVMWallets } from "next-common/hooks/connect/useEVMWallets";
import { useWeb3Login } from "next-common/hooks/connect/useWeb3Login";
import PrimaryButton from "next-common/lib/button/primary";
import { metamask } from "next-common/utils/consts/connect";
import { normalizedMetaMaskAccounts } from "next-common/utils/metamask";
import { useEffect, useState } from "react";
import { useAccount, useConnect } from "wagmi";
import { useConnection, useConnect } from "wagmi";
import LoginAddressNotDetectedMessage from "../addressNotDetectedMessage";
import { Label } from "../styled";
import { WalletConnectQrCode } from "./walletconnect";

export default function LoginWeb3EVM() {
const { lastConnectedAccount } = useConnectedAccountContext();
const { connector, isConnecting, isConnected } = useAccount();
const { connect, isError } = useConnect();
const { connector, isConnected } = useConnection();
const { mutate, isError, isPending: isConnecting } = useConnect();
const [selectedAccount, setSelectedAccount] = useState();
const { accounts } = useEVMAccounts();
const wallets = useEVMWallets();
const walletConnect = useEVMWalletConnect(
find(wallets, ["connector.id", "walletConnect"])?.connector,
);
const connectedWallet = find(wallets, ["connector.id", connector?.id]);
const [web3Login, web3Loading] = useWeb3Login();

const [selectedWallet, setSelectedWallet] = useState();
useEffect(() => {
if (selectedWallet) {
if (selectedWallet?.connector?.id === connectedWallet?.connector?.id) {
return;
}

setSelectedWallet(connectedWallet);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [connectedWallet]);
}, [connectedWallet, selectedWallet]);
useEffect(() => {
setSelectedWallet(connectedWallet);
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -46,23 +50,53 @@ export default function LoginWeb3EVM() {
setSelectedAccount(lastUsedAddress);
} else if (accounts?.length > 0) {
setSelectedAccount(accounts?.[0]);
} else {
setSelectedAccount();
}
}, [accounts, lastConnectedAccount?.address]);

async function handleSelectWallet(wallet) {
if (wallet.connector.id === connector?.id && isConnected) {
setSelectedWallet(wallet);
return;
}

if (wallet.connector.id === "walletConnect") {
await walletConnect.open(async ({ accounts: addresses }) => {
const [account] = normalizedMetaMaskAccounts(
addresses,
wallet.connector.id,
);
await web3Login({ account, wallet: metamask.extensionName });
});
return;
}

mutate(
{ connector: wallet.connector },
{
onSuccess() {
setSelectedWallet(wallet);
},
},
);
}

if (walletConnect.isOpen) {
return (
<WalletConnectQrCode
uri={walletConnect.uri}
backTitle="Back to EVM"
onBack={walletConnect.close}
/>
);
}

return (
<div className="space-y-6">
<WalletEVMOptions
selectedWallet={selectedWallet}
onSelect={(wallet) => {
connect(
{ connector: wallet.connector },
{
onSuccess() {
setSelectedWallet(wallet);
},
},
);
}}
onSelect={handleSelectWallet}
/>

{isConnecting && (
Expand Down
104 changes: 68 additions & 36 deletions packages/next-common/components/login/web3/walletconnect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,42 @@ import { useWalletConnectAccounts } from "next-common/hooks/connect/useWalletCon
import { useWeb3Login } from "next-common/hooks/connect/useWeb3Login";
import { useWeb3WalletView } from "next-common/hooks/connect/useWeb3WalletView";
import { toDataURL as QrcodeToDataURL } from "qrcode";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useInterval, useUnmount } from "react-use";
import { Skeleton } from "next-common/components/skeleton";
import { useDispatch } from "react-redux";
import { newErrorToast } from "next-common/store/reducers/toastSlice";

const SIZE = 200;
const REFRESH_QRCODE_INTERVAL = 4 * 60 * 1000; // 4 minutes

export default function LoginWeb3WalletConnect() {
const { setView } = useWeb3WalletView();
const { connect, session, provider } = useWalletConnect();
const [qrCode, setQrCode] = useState(null);
const dispatch = useDispatch();
const [uri, setUri] = useState(null);
const [web3Login] = useWeb3Login();
const accounts = useWalletConnectAccounts();
const loginSession = useRef(null);
const [refreshCount, setRefreshCount] = useState(0);

useEffect(() => {
if (session) {
return;
}

connect().then((result) => {
if (result?.uri) {
setUri(result.uri);
}
});
}, [connect, session, refreshCount]);
let active = true;
connect()
.then((result) => {
if (active && result?.uri) {
setUri(result.uri);
}
})
.catch((error) => dispatch(newErrorToast(error.message)));
return () => {
active = false;
};
}, [connect, session, refreshCount, dispatch]);

useInterval(
() => {
Expand All @@ -45,29 +54,20 @@ export default function LoginWeb3WalletConnect() {
);

useEffect(() => {
if (!uri) {
if (
!accounts?.length ||
!session?.topic ||
loginSession.current === session.topic
) {
return;
}

QrcodeToDataURL(uri, {
width: SIZE,
height: SIZE,
margin: 0,
}).then(setQrCode);
}, [uri]);

useEffect(() => {
if (accounts?.length) {
const account = accounts[0];

if (account) {
web3Login({
account: { address: account?.address },
wallet: account.meta?.source,
});
}
}
}, [accounts, web3Login]);
loginSession.current = session.topic;
const account = accounts[0];
web3Login({
account: { address: account.address },
wallet: account.meta?.source,
});
}, [accounts, session?.topic, web3Login]);

useUnmount(() => {
if (provider) {
Expand All @@ -82,27 +82,59 @@ export default function LoginWeb3WalletConnect() {
}
});

return (
<WalletConnectQrCode
uri={uri}
backTitle="Back to Substrate"
onBack={() => setView("substrate")}
/>
);
}

export function WalletConnectQrCode({ uri, backTitle, onBack }) {
const [qrCode, setQrCode] = useState(null);
const dispatch = useDispatch();

useEffect(() => {
let active = true;
setQrCode(null);
if (uri) {
QrcodeToDataURL(uri, { width: SIZE, height: SIZE, margin: 0 })
.then((code) => {
if (active) {
setQrCode(code);
}
})
.catch((error) => {
if (active) {
dispatch(newErrorToast(error.message));
}
});
}
return () => {
active = false;
};
}, [uri, dispatch]);

return (
<div>
<WalletOptionsWrapper className="mb-6">
<WalletOption
installed
logo={<ArrowCircleLeft className="text-textSecondary" />}
title="Back to Substrate"
onClick={() => {
setView("substrate");
}}
title={backTitle}
onClick={onBack}
/>
</WalletOptionsWrapper>

<WalletGroupTitle>Scan With Your Phone</WalletGroupTitle>

<div className="flex justify-center">
<div className="rounded-xl border border-neutral300 overflow-hidden p-4">
<div className="" style={{ width: SIZE, height: SIZE }}>
<div style={{ width: SIZE, height: SIZE }}>
{qrCode ? (
/* eslint-disable-next-line */
<img src={qrCode} alt="qrcode" />
// eslint-disable-next-line @next/next/no-img-element
<img src={qrCode} alt="WalletConnect QR code" />
) : (
<Skeleton className="w-full h-full rounded-lg" />
)}
Expand Down
Loading
Loading