RainbowKit

Steps to integrate Apex into React Apps with RainbowKit

Introduction

This tutorial is a step-by-step guide on integrating Apex Wallet into your dapp using the RainbowKit 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 RainbowKit as a dependency

Install RainbowKit and its peer dependencies

yarn add @rainbow-me/rainbowkit wagmi ethers
npm install @rainbow-me/rainbowkit wagmi ethers

See RainbowKit documentation for more information

Step 2: Instantiate Apex, Wagmi, & Rainbow Client

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 { chain, configureChains } from "wagmi";
import { alchemyProvider } from "wagmi/providers/alchemy";
import { publicProvider } from "wagmi/providers/public";
import { createClient } from "wagmi";
import { useMemo } from "react";
import { InjectedConnector } from "wagmi/connectors/injected";
import { Ethereum, InjectedConnectorOptions } from "@wagmi/core";
import { Chain } from "wagmi";
import { connectorsForWallets } from "@rainbow-me/rainbowkit";

type ExtendedEthereum = Ethereum & {
  isApexWallet?: boolean;
};

// API key for Ethereum node
const apiKey = process.env.ALCHEMY_ID;

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

export class ApexConnector extends InjectedConnector {
  id = "apex";
  name = "Apex";
  ready = detectApexWalletProvider() !== undefined;
  constructor({
    chains,
    options,
  }: {
    chains?: Chain[];
    options?: InjectedConnectorOptions;
  }) {
    super({ chains, options });
    this.ready = true;
  }

  async getProvider(): Promise<Ethereum | undefined> {
    return detectApexWalletProvider();
  }
}

// Configure client and chains for connector support
export function useCreateProviders() {
  const { chains, provider, webSocketProvider } = useMemo(() => {
    return configureChains(
      // add other chains here
      [chain.mainnet, chain.polygon, chain.optimism, chain.arbitrum],
      [alchemyProvider({ apiKey }), publicProvider()]
    );
  }, []);

  const providersConfig = useMemo(() => {
    const apexWallet = {
      id: "apex",
      name: "Apex",
      iconUrl:
        "https://gateway.pinata.cloud/ipfs/QmPgPhdwwiVPdZ7AdWJX2tajgZWNKJA8w12rNwPtr1PDvJ",
      iconBackground: "#0F1D28",
      downloadUrls: {
        browserExtension:
          "https://chrome.google.com/webstore/detail/apex-wallet/oppceojapmdmhpnmjpballbbdclocdhj",
      },
      createConnector: () => {
        return {
          connector: new ApexConnector({
            chains,
          }),
        };
      },
    };

    const connectors = connectorsForWallets([
      {
        groupName: "Recommended",
        // Add any other wallet types here. (See https://www.rainbowkit.com/docs/custom-wallet-list)
        wallets: [apexWallet],
      },
    ]);

    const client = createClient({
      autoConnect: true,
      connectors,
      provider,
      webSocketProvider,
    });

    // Set up client
    return {
      client,
      chains,
      provider,
      webSocketProvider,
    };
  }, [chains, provider, webSocketProvider]);

  return providersConfig;
}

📘

Already integrated with RainbowKit?

You can just use lines 65-91 where ever you declare your connectors. 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. Gets the apiKey for your Alchemy RPC URL; you can optionally switch providers on line 60. See this
  3. Adds a quick helper function detectApexWalletProvider to detect if Apex Wallet is available and grab the provider.
  4. Declares a new class, ApexConnector, which overrides some of the functionality of wagmi's InjectedConnector
  5. Finally, the file declares a react hook to generate the wagmi client configuration used in the next step.
    a. *You may want to update the chains on line 59.*
    b. On line 88 ☝️ you can also add Coinbase Wallet, WalletConnect, and Metamask by following this guide.

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 client.

import { ConnectButton, RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { WagmiConfig } from "wagmi";
import { useCreateProviders } from "./walletConfig";
import "@rainbow-me/rainbowkit/styles.css";

export function RainbowExampleDApp() {
  const providerConfig = useCreateProviders();
  // You can also get your chains, provider, and websocket provider here as well.
  return (
    <WagmiConfig client={providerConfig.client}>
      <RainbowKitProvider chains={providerConfig.chains}>
        {/*Add your application components here*/}
        <ConnectButton />
      </RainbowKitProvider>
    </WagmiConfig>
  );
}

What this code does.

  1. On line 7 get the providerConfig from the previous step.
    a. This hook also contains chains, providers, and WebSocket if you need to use it elsewhere.
  2. On line 10 wrap our App Components in WagmiConfig, RainbowKitProvider, and pass in the providerConfig params .
    a. This allows you to use all the powerful hooks defined by wagmi.
  3. Lastly, we add a sign-in component <ConnectButton />. This button component handles connecting, disconnecting, and sending the user to the Apex Download Page.

Additional Resources

🚧

Have a Question or Feedback?

Post in our discussion page!