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>
);
}