web3modal

Steps to integrate Apex into existing React apps with web3modal

Introduction

This tutorial is a step-by-step guide on integrating Apex Wallet into your dapp using the Web3Modal library. This guide assumes you have a React application already set up and running.

You can find the latest version of Apex on the Chrome Webstore or visit our official site.

Step 1: Add Web3Modal as a dependency

Install Web3Modal and its peer dependencies

yarn add web3modal ethers
npm install web3modal ethers

See Web3Modal documentation for more information

Step 2: Instantiate Web3Modal with wallet

Create a new file in your src or root directory called walletConfig.ts. Here we’ll instantiate the Apex connector that will integrate into your dapp. Copy the code below.

import { ethers } from "ethers";
import { useCallback, useMemo, useState } from "react";
import Web3Modal from "web3modal";
import { Bitski } from "bitski";
import Fortmatic from "fortmatic";

type ApexProvider = {
  isApexWallet?: boolean;
  request: (params: any) => Promise<any>;
  providers?: ApexProvider[];
};

/*
 * If the injected Apex provider is available this function will return
 * the Apex ethereum provider otherwise will return undefined.
 */
export function detectApexWalletProvider(): ApexProvider | undefined {
  if (
    typeof window !== "undefined" &&
    window.ethereum !== undefined &&
    (window.ethereum as ApexProvider)?.isApexWallet
  ) {
    return window.ethereum;
  }
  return window.ethereum?.providers?.find((p) => {
    return (p as ApexProvider).isApexWallet;
  });
}

export function useCreateProviders() {
  const [provider, setProvider] = useState();
  const [library, setLibrary] = useState<ethers.providers.Web3Provider>();

  const web3Modal = useMemo(() => {
    return new Web3Modal({
      providerOptions: {
        "custom-apex": {
          display: {
            logo: "https://gateway.pinata.cloud/ipfs/QmPgPhdwwiVPdZ7AdWJX2tajgZWNKJA8w12rNwPtr1PDvJ",
            name: "Apex",
            description: "Connect to Your Apex Wallet",
          },
          package: {
            id: "apex",
            name: "Apex",
            logo: "https://gateway.pinata.cloud/ipfs/QmPgPhdwwiVPdZ7AdWJX2tajgZWNKJA8w12rNwPtr1PDvJ",
            type: "web",
            check: "isApexWallet",
            package: null, // required
          },
          connector: async () => {
            const provider = detectApexWalletProvider();
            if (provider === undefined) {
              console.log("Apex is not installed, going to the download page.");
              window.open(
                "https://chrome.google.com/webstore/detail/apex-wallet/oppceojapmdmhpnmjpballbbdclocdhj?utm_source=Marketing%20Site",
                "_blank"
              );
            } else {
              try {
                await provider.request({ method: "eth_requestAccounts" });
              } catch (error) {
                throw new Error("User Rejected");
              }
              return provider;
            }
          },
        },
        // Add other wallets (See https://github.com/WalletConnect/web3modal#provider-options)
      },
    });
  }, []);

  const connect = useCallback(async () => {
    try {
      const provider = await web3Modal.connect();
      const library = new ethers.providers.Web3Provider(provider);
      setProvider(provider);
      setLibrary(library);
    } catch (error) {
      console.error(error);
    }
  }, [web3Modal]);

  const disconnect = useCallback(() => {
    setProvider(undefined);
  }, []);

  return { connect, disconnect, provider, library };
}

📘

Already integrated with Web3Modal?

You can just use lines 37-69 where ever you declare your providers. You then skip the rest of this tutorial!

Let's walk through what this code is doing:

  1. Declares a convenience type for window.ethereum.isApexWallet
  2. Adds a quick helper function detectApexWalletProvider to detect if Apex Wallet is available and grab the provider.
  3. Finally, the file declares a react hook to generate the provider configuration used in the next step.
    a. On line 52 we attempt to grab the Apex provider from the window, if it doesn't exist shoots the user to download Apex.
    b. On line 69 ☝️ you can also add Coinbase Wallet, WalletConnect, and Metamask by following this guide.
    c. This hook provides the connect, disconnect, provider for making requests, along with the library.

Step 3: Import and Setup WagmiConfig

In your App component file, or whatever parent component, import your code from Step 1, generate a provider config, and pass in the connect to the provider.

import { useCreateProviders } from "../Common/web3modal_walletConfig";
import { ApexStyleButton } from "./ApexUI";

export function Web3ModalExampleDApp() {
  const providerConfig = useCreateProviders();
  return (
    <div>
      {providerConfig.provider ? (
        <ApexStyleButton onClick={providerConfig.disconnect}>
          Disconnect
        </ApexStyleButton>
      ) : (
        <ApexStyleButton onClick={providerConfig.connectWallet}>
          Connect Wallet
        </ApexStyleButton>
      )}
    </div>
  );
}

What this code does.

  1. On line 5 get the providerConfig from the previous step.
    a. This hook also contains connect, disconnect, and provider if you need to use it elsewhere.
  2. On line 8 we check if the provider is defined and shows disconnect vs connect as a result.
    a. We either connect or disconnect accordingly.
    b. Note: we have a sample ApexStyleButton, but you can customize buttons how you'd like.

Additional Resources

🚧

Have a Question or Feedback?

Post in our discussion page!