Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show connected providers on disconnected UI #2

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
14 changes: 14 additions & 0 deletions src/components/App/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,23 @@ small {
}

button {
cursor: pointer;
font-size: 20px;
display: flex;
flex-direction: row;
align-content: space-between;
justify-content: center;
}

button.change-provider {
background-color: lightpink;
}

button .provider {
flex: 1;
line-height: 28px;
}

button > div {
height: 28px;
}
3 changes: 2 additions & 1 deletion src/components/Disconnected/ConnectWalletButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const ConnectWalletButton = memo(
text,
}: ConnectWalletButtonProps) => (
<button type="button" onClick={() => handleConnect(providerString)}>
{text} {connected ? "🟢" : "🔴"}
<div className="provider">{text}</div>
<div className="connected">{connected ? "🟢" : "🔴"}</div>
</button>
)
);
14 changes: 6 additions & 8 deletions src/components/Disconnected/Disconnected.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { memo } from "react";
import { ConnectWalletButton } from "./ConnectWalletButton";
import { initCoinbaseWalletProvider } from "../../hooks/useWeb3/connectors/coinbaseWallet";
import type { ProviderStringType } from "../../utils/types";
import { initMetaMaskProvider } from "../../hooks/useWeb3/connectors/metaMask";
import { initWalletConnectProvider } from "../../hooks/useWeb3/connectors/walletConnect";
import { providers } from "../../hooks/useWeb3/useWeb3";
import WalletConnectProvider from "@walletconnect/web3-provider";

type DisconnectedProps = {
handleConnect: (selectedProvider: ProviderStringType) => Promise<void>;
Expand Down Expand Up @@ -36,23 +35,22 @@ export const Disconnected = memo(({ handleConnect }: DisconnectedProps) => {
});

function isProviderConnected(providerString: ProviderStringType) {
const provider = providers[providerString];
switch (providerString) {
case "coinbase": {
const provider = initCoinbaseWalletProvider();
return !!provider.selectedAddress;
return !!provider?.selectedAddress;
}
case "metamask": {
const provider = initMetaMaskProvider();
return (
provider &&
provider.isMetaMask &&
// @ts-expect-error checking because coinbase wallet mocks metamask
!provider.isCoinbaseWallet &&
!!provider.selectedAddress
);
}
case "walletconnect": {
const provider = initWalletConnectProvider();
return provider.wc.connected;
return (provider as WalletConnectProvider).wc.connected;
}
}
}
15 changes: 10 additions & 5 deletions src/hooks/useWeb3/connectWithProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import Web3 from "web3";
import { connectCoinbaseWallet } from "./connectors/coinbaseWallet";
import { connectMetaMask } from "./connectors/metaMask";
import { connectWalletConnect } from "./connectors/walletConnect";
import { CoinbaseWalletProvider } from "@coinbase/wallet-sdk";
import { MetaMaskInpageProvider } from "@metamask/providers";
import WalletConnectProvider from "@walletconnect/web3-provider";
import type {
ConnectedReturnType,
EthereumProvider,
ProviderStringType,
} from "../../utils/types";

Expand All @@ -18,15 +22,16 @@ import type {
* This function only returns these values if the user successfully connects
*/
export const connectWithProvider = async (
provider: ProviderStringType
providerString: ProviderStringType,
provider: EthereumProvider
): Promise<ConnectedReturnType> => {
switch (provider) {
switch (providerString) {
case "coinbase":
return connectCoinbaseWallet();
return connectCoinbaseWallet(provider as CoinbaseWalletProvider);
case "metamask":
return connectMetaMask();
return connectMetaMask(provider as MetaMaskInpageProvider);
case "walletconnect":
return connectWalletConnect();
return connectWalletConnect(provider as WalletConnectProvider);
default:
// BEGIN COMMENT //
// THIS WILL NEVER HAPPEN BECAUSE WE DON'T SUPPORT ANY OTHER WALLETS
Expand Down
13 changes: 9 additions & 4 deletions src/hooks/useWeb3/connectors/coinbaseWallet.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Web3 from "web3";
import CoinbaseWalletSDK from "@coinbase/wallet-sdk";
import CoinbaseWalletSDK, {
CoinbaseWalletProvider,
} from "@coinbase/wallet-sdk";
import {
DEFAULT_CHAIN_ID,
APP_NAME,
APP_LOGO_URL,
INFURA_RPC_URL,
} from "../dappInfo";
} from "../../../utils/constants";
import type { ConnectedReturnType } from "../../../utils/types";

/**
Expand All @@ -22,11 +24,14 @@ export const initCoinbaseWalletProvider = () => {
return coinbaseWallet.makeWeb3Provider(INFURA_RPC_URL, DEFAULT_CHAIN_ID);
};

export const connectCoinbaseWallet = async (): Promise<ConnectedReturnType> => {
export const connectCoinbaseWallet = async <
TProvider extends CoinbaseWalletProvider
>(
provider: TProvider
): Promise<ConnectedReturnType> => {
// If the user selected Coinbase Wallet to connect
// We initialize the Coinbase Wallet SDK instance and
// we create the ethereum provider for Coinbase Wallet SDK
const provider = initCoinbaseWalletProvider();
// We initialize the Web3 instance
const web3 = new Web3(provider);

Expand Down
15 changes: 10 additions & 5 deletions src/hooks/useWeb3/connectors/metaMask.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import Web3 from "web3";
import type { MetaMaskInpageProvider } from "@metamask/providers";
import type { ConnectedReturnType } from "../../../utils/types";
import type { provider as Provider } from "web3-core";
import type {
ConnectedReturnType,
EthereumProvider,
} from "../../../utils/types";

// Initializes the MetaMask provider using the provider at window.ethereum
// We will prefer a provider where the property `isMetaMask` is set to true
export const initMetaMaskProvider = () =>
export const initMetaMaskProvider = (): MetaMaskInpageProvider =>
(window.ethereum as any)?.providers?.find(
(p: MetaMaskInpageProvider) => !!p.isMetaMask
) ?? window.ethereum;

export const connectMetaMask = async (): Promise<ConnectedReturnType> => {
const provider = initMetaMaskProvider();
export const connectMetaMask = async (
provider: EthereumProvider
): Promise<ConnectedReturnType> => {
// If the user selected MetaMask to connect
// We make sure that the user has MetaMask installed in their browser
if (!provider || !provider.isMetaMask || !window.ethereum) {
Expand All @@ -22,7 +27,7 @@ export const connectMetaMask = async (): Promise<ConnectedReturnType> => {
}

// We initialize the Web3 instance
const web3 = new Web3(provider);
const web3 = new Web3(provider as unknown as Provider);
// This opens the wallet provider prompt to connect to this dapp
// If the user was already connected, they will not be prompted
const accounts: string[] = await provider.request({
Expand Down
13 changes: 6 additions & 7 deletions src/hooks/useWeb3/connectors/walletConnect.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Web3 from "web3";
import WalletConnectProvider from "@walletconnect/web3-provider";
import { INFURA_PROJECT_ID } from "../dappInfo";
import type { provider } from "web3-core";
import { INFURA_PROJECT_ID } from "../../../utils/constants";
import type { provider as Provider } from "web3-core";
import type { ConnectedReturnType } from "../../../utils/types";

// Initializes the WalletConnect Provider
Expand All @@ -10,14 +10,13 @@ export const initWalletConnectProvider = () =>
infuraId: INFURA_PROJECT_ID,
});

export const connectWalletConnect = async (): Promise<ConnectedReturnType> => {
export const connectWalletConnect = async (
provider: WalletConnectProvider
): Promise<ConnectedReturnType> => {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
// If the user selected WalletConnect Wallet to connect
// Initialize the WalletConnectProvider
const provider = initWalletConnectProvider();
// We initialize the Web3 instance
const web3 = new Web3(provider as unknown as provider);
const web3 = new Web3(provider as unknown as Provider);

// This controls whether or not we fire the 'disconnect' listener
// This is because WalletConnect does not provide an removeEventListener
Expand Down
20 changes: 18 additions & 2 deletions src/hooks/useWeb3/useWeb3.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import Web3 from "web3";
import { useCallback, useEffect, useState } from "react";
import { connectWithProvider } from "./connectWithProvider";
import type { EthereumProvider, ProviderStringType } from "../../utils/types";
import type { EthereumProvider } from "../../utils/types";
import type { ProviderStringType } from "../../utils/types";
import { initCoinbaseWalletProvider } from "./connectors/coinbaseWallet";
import { initMetaMaskProvider } from "./connectors/metaMask";
import { initWalletConnectProvider } from "./connectors/walletConnect";

// This is all of the supported provider's EthereumProviders
export const providers = {
coinbase: initCoinbaseWalletProvider(),
metamask: initMetaMaskProvider(),
walletconnect: initWalletConnectProvider(),
} as const;

// The localstorage key for the selected provider
// If defined, value is either 'coinbase', 'metamask', or 'walletconnect'
Expand Down Expand Up @@ -33,12 +44,16 @@ export const useWeb3 = () => {
// Accepts the user's wallet provider selection
// Coinbase Wallet, MetaMask, or WalletConnect
async (selectedProvider: ProviderStringType) => {
if (!providers) return;
try {
const {
provider: connectedProvider,
web3: web3Instance,
accounts,
} = await connectWithProvider(selectedProvider);
} = await connectWithProvider(
selectedProvider,
providers[selectedProvider]
);
// Set the localstorage key with the selected wallet provider
// 'coinbase', 'metamask', or 'walletconnect'
// We will use this key to connect the user automatically
Expand Down Expand Up @@ -146,6 +161,7 @@ export const useWeb3 = () => {
}, []);

return {
providers,
providerString,
connectProvider,
changeProvider,
Expand Down
File renamed without changes.
12 changes: 3 additions & 9 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import type Web3 from "web3";
import type { CoinbaseWalletProvider } from "@coinbase/wallet-sdk";
import type { MetaMaskInpageProvider } from "@metamask/providers";
import type WalletConnectProvider from "@walletconnect/web3-provider";
import { providers } from "../hooks/useWeb3/useWeb3";

export type EthereumProvider =
| CoinbaseWalletProvider
| MetaMaskInpageProvider
| WalletConnectProvider;
export type ProviderStringType = keyof typeof providers;

// Our supported wallet providers are Coinbase Wallet, MetaMask, and WalletConnect
export type ProviderStringType = "coinbase" | "metamask" | "walletconnect";
export type EthereumProvider = typeof providers[ProviderStringType];

/**
* This represents the return type of the connectProvider function, which contains
Expand Down