Skip to content

Wagmi

Wagmi enables application developers to focus on building high-quality, high-performance experiences for Ethereum by prioritizing developer experience, performance, feature coverage, and stability. It provides developers with intuitive building blocks to create their Ethereum applications.

Quick Start

1.Install Dependencies

js
pnpm add wagmi
pnpm add wagmi

2.Configuring chains and providers

js
import { configureChains, allChains } from "wagmi";
import { alchemyProvider } from "wagmi/providers/alchemy";
import { publicProvider } from "wagmi/providers/public";

// Configure chains & providers with the Alchemy provider.
// Two popular providers are Alchemy (alchemy.com) and Infura (infura.io)
const { chains, provider } = configureChains(allChains, [
  alchemyProvider(),
  publicProvider(),
]);
import { configureChains, allChains } from "wagmi";
import { alchemyProvider } from "wagmi/providers/alchemy";
import { publicProvider } from "wagmi/providers/public";

// Configure chains & providers with the Alchemy provider.
// Two popular providers are Alchemy (alchemy.com) and Infura (infura.io)
const { chains, provider } = configureChains(allChains, [
  alchemyProvider(),
  publicProvider(),
]);

3.create BitgetWalletConnector

js
import { InjectedConnector } from "wagmi/connectors/injected";

class BitgetWalletConnector extends InjectedConnector {
  constructor({ chains = [], options_ = {} }) {
    const options = {
      name: "BitgetWallet",
      ...options_,
    };
    super({ chains, options });

    this.id = "BitgetWallet";
    this.ready =
      typeof window != "undefined" &&
      !!this.findProvider(window?.bitkeep?.ethereum);
  }
  async getProvider() {
    if (typeof window !== "undefined") {
      // TODO: Fallback to `ethereum#initialized` event for async injection
      // https://github.com/BitKeep/detect-provider#synchronous-and-asynchronous-injection=
      this.provider = window.bitkeep?.ethereum;
    }
    return this.provider;
  }
  getReady(ethereum) {
    if (!ethereum.isBitKeep || !ethereum) return;
    // Brave tries to make itself look like BitKeep
    // Could also try RPC `web3_clientVersion` if following is unreliable
    if (ethereum.isBraveWallet && !ethereum._events && !ethereum._state) return;
    if (ethereum.isTokenPocket) return;
    if (ethereum.isTokenary) return;
    return ethereum;
  }
  findProvider(ethereum) {
    if (ethereum?.providers) return ethereum.providers.find(this.getReady);
    return this.getReady(ethereum);
  }
}
import { InjectedConnector } from "wagmi/connectors/injected";

class BitgetWalletConnector extends InjectedConnector {
  constructor({ chains = [], options_ = {} }) {
    const options = {
      name: "BitgetWallet",
      ...options_,
    };
    super({ chains, options });

    this.id = "BitgetWallet";
    this.ready =
      typeof window != "undefined" &&
      !!this.findProvider(window?.bitkeep?.ethereum);
  }
  async getProvider() {
    if (typeof window !== "undefined") {
      // TODO: Fallback to `ethereum#initialized` event for async injection
      // https://github.com/BitKeep/detect-provider#synchronous-and-asynchronous-injection=
      this.provider = window.bitkeep?.ethereum;
    }
    return this.provider;
  }
  getReady(ethereum) {
    if (!ethereum.isBitKeep || !ethereum) return;
    // Brave tries to make itself look like BitKeep
    // Could also try RPC `web3_clientVersion` if following is unreliable
    if (ethereum.isBraveWallet && !ethereum._events && !ethereum._state) return;
    if (ethereum.isTokenPocket) return;
    if (ethereum.isTokenary) return;
    return ethereum;
  }
  findProvider(ethereum) {
    if (ethereum?.providers) return ethereum.providers.find(this.getReady);
    return this.getReady(ethereum);
  }
}

4.Set Up Client

js
import { createClient } from "wagmi";
import { MetaMaskConnector } from "wagmi/connectors/metaMask";
import BitgetWalletConnector from "./connectors/BitgetWalletConnector";

const mainnetIds = [1, 10, 137, 42161]; // BitgetWallet only supports the  mainnet network for the time being
// Set up client
const client = createClient({
  autoConnect: true,
  connectors: [
    new MetaMaskConnector({ chains }),
    new BitgetWalletConnector({
      chains: chains.filter((v) => mainnetIds.includes(v.id)),
      options: {
        name: "BitgetWallet",
        icon: "./assets/bitkeep-icon.png",
      },
    }),
  ],
  provider,
});
import { createClient } from "wagmi";
import { MetaMaskConnector } from "wagmi/connectors/metaMask";
import BitgetWalletConnector from "./connectors/BitgetWalletConnector";

const mainnetIds = [1, 10, 137, 42161]; // BitgetWallet only supports the  mainnet network for the time being
// Set up client
const client = createClient({
  autoConnect: true,
  connectors: [
    new MetaMaskConnector({ chains }),
    new BitgetWalletConnector({
      chains: chains.filter((v) => mainnetIds.includes(v.id)),
      options: {
        name: "BitgetWallet",
        icon: "./assets/bitkeep-icon.png",
      },
    }),
  ],
  provider,
});

Use in React App

jsx
import {
  WagmiConfig,
  useConnect,
  useAccount,
  useDisconnect,
  useSignMessage,
  useNetwork,
  useSwitchNetwork,
} from "wagmi";
import { verifyMessage } from "ethers/lib/utils";

const { isConnected, connector } = useAccount();
const { connect, connectors, error, isLoading, pendingConnector } =
  useConnect();
const { disconnect } = useDisconnect();

export function NetworkSwitcher() {
  const { chain } = useNetwork();
  const { chains, error, isLoading, pendingChainId, switchNetwork } =
    useSwitchNetwork();

  if (!chain) return null;

  return (
    <div>
      <div>
        Connected to {chain?.name ?? chain?.id}
        {chain?.unsupported && " (unsupported)"}
      </div>

      {switchNetwork && (
        <div>
          {chains.map((x) =>
            x.id === chain?.id ? null : (
              <button key={x.id} onClick={() => switchNetwork(x.id)}>
                {x.name}
                {isLoading && x.id === pendingChainId && " (switching)"}
              </button>
            )
          )}
        </div>
      )}

      <div>{error && error.message}</div>
    </div>
  );
}

function SignMessage() {
  const recoveredAddress = React.useRef();
  const { data, error, isLoading, signMessage } = useSignMessage({
    onSuccess(data, variables) {
      // Verify signature when sign message succeeds
      const address = verifyMessage(variables.message, data);
      recoveredAddress.current = address;
    },
  });

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const formData = new FormData(event.target);
        const message = formData.get("message");
        signMessage({ message });
      }}
    >
      <label htmlFor="message">Enter a message to sign</label>
      <textarea
        id="message"
        name="message"
        placeholder="The quick brown fox…"
      />
      <button disabled={isLoading}>
        {isLoading ? "Check Wallet" : "Sign Message"}
      </button>

      {data && (
        <div>
          <div>Recovered Address: {recoveredAddress.current}</div>
          <div>Signature: {data}</div>
        </div>
      )}

      {error && <div>{error.message}</div>}
    </form>
  );
}

export function Profile() {
  const { isConnected, connector } = useAccount();
  const { connect, connectors, error, isLoading, pendingConnector } =
    useConnect();
  const { disconnect } = useDisconnect();

  return (
    <div>
      <div className="block">
        {isConnected && (
          <button onClick={() => disconnect()}>
            Disconnect from {connector?.name}
          </button>
        )}
        {connectors.map((connector) => (
          <button
            disabled={!connector.ready}
            key={connector.id}
            onClick={() => connect({ connector })}
          >
            <img src={connector.icon}></img>
            {connector.name}
            {!connector.ready && " (unsupported)"}
            {isLoading &&
              connector.id === pendingConnector?.id &&
              " (connecting)"}
          </button>
        ))}
        {error && <div>{error.message}</div>}
      </div>

      <div className="block">
        <Account></Account>
      </div>
      <div className="block">
        <NetworkSwitcher></NetworkSwitcher>
      </div>

      {isConnected && (
        <div className="block">
          <SignMessage />
        </div>
      )}
    </div>
  );
}

function App() {
  return (
    <div className="App">
      <WagmiConfig client={client}>
        <Profile />
      </WagmiConfig>
    </div>
  );
}
import {
  WagmiConfig,
  useConnect,
  useAccount,
  useDisconnect,
  useSignMessage,
  useNetwork,
  useSwitchNetwork,
} from "wagmi";
import { verifyMessage } from "ethers/lib/utils";

const { isConnected, connector } = useAccount();
const { connect, connectors, error, isLoading, pendingConnector } =
  useConnect();
const { disconnect } = useDisconnect();

export function NetworkSwitcher() {
  const { chain } = useNetwork();
  const { chains, error, isLoading, pendingChainId, switchNetwork } =
    useSwitchNetwork();

  if (!chain) return null;

  return (
    <div>
      <div>
        Connected to {chain?.name ?? chain?.id}
        {chain?.unsupported && " (unsupported)"}
      </div>

      {switchNetwork && (
        <div>
          {chains.map((x) =>
            x.id === chain?.id ? null : (
              <button key={x.id} onClick={() => switchNetwork(x.id)}>
                {x.name}
                {isLoading && x.id === pendingChainId && " (switching)"}
              </button>
            )
          )}
        </div>
      )}

      <div>{error && error.message}</div>
    </div>
  );
}

function SignMessage() {
  const recoveredAddress = React.useRef();
  const { data, error, isLoading, signMessage } = useSignMessage({
    onSuccess(data, variables) {
      // Verify signature when sign message succeeds
      const address = verifyMessage(variables.message, data);
      recoveredAddress.current = address;
    },
  });

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const formData = new FormData(event.target);
        const message = formData.get("message");
        signMessage({ message });
      }}
    >
      <label htmlFor="message">Enter a message to sign</label>
      <textarea
        id="message"
        name="message"
        placeholder="The quick brown fox…"
      />
      <button disabled={isLoading}>
        {isLoading ? "Check Wallet" : "Sign Message"}
      </button>

      {data && (
        <div>
          <div>Recovered Address: {recoveredAddress.current}</div>
          <div>Signature: {data}</div>
        </div>
      )}

      {error && <div>{error.message}</div>}
    </form>
  );
}

export function Profile() {
  const { isConnected, connector } = useAccount();
  const { connect, connectors, error, isLoading, pendingConnector } =
    useConnect();
  const { disconnect } = useDisconnect();

  return (
    <div>
      <div className="block">
        {isConnected && (
          <button onClick={() => disconnect()}>
            Disconnect from {connector?.name}
          </button>
        )}
        {connectors.map((connector) => (
          <button
            disabled={!connector.ready}
            key={connector.id}
            onClick={() => connect({ connector })}
          >
            <img src={connector.icon}></img>
            {connector.name}
            {!connector.ready && " (unsupported)"}
            {isLoading &&
              connector.id === pendingConnector?.id &&
              " (connecting)"}
          </button>
        ))}
        {error && <div>{error.message}</div>}
      </div>

      <div className="block">
        <Account></Account>
      </div>
      <div className="block">
        <NetworkSwitcher></NetworkSwitcher>
      </div>

      {isConnected && (
        <div className="block">
          <SignMessage />
        </div>
      )}
    </div>
  );
}

function App() {
  return (
    <div className="App">
      <WagmiConfig client={client}>
        <Profile />
      </WagmiConfig>
    </div>
  );
}

API Reference

wagmi