Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@MCarlomagno
Last active July 19, 2023 22:36
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MCarlomagno/4950a78883f9d3a8229cbd84758b3bf0 to your computer and use it in GitHub Desktop.
Save MCarlomagno/4950a78883f9d3a8229cbd84758b3bf0 to your computer and use it in GitHub Desktop.
🦊πŸͺ React hook for Metamask extension using ethers.js. The hook includes some of the most common use cases such as wallet connection, events listening, transaction, addresses and signer management.
import * as ethers from 'ethers';
import {
ExternalProvider,
JsonRpcSigner,
Network,
Web3Provider
} from '@ethersproject/providers';
import { useState } from 'react';
declare global {
interface Window {
ethereum: ExternalProvider;
}
}
type ExtensionForProvider = {
on: (event: string, callback: (...params: any) => void) => void;
};
// Adds on stream support for listening events.
// see https://github.com/ethers-io/ethers.js/discussions/3230
type GenericProvider = ExternalProvider & ExtensionForProvider;
interface ProviderRpcError extends Error {
message: string;
code: number;
data?: unknown;
}
function useMetamask() {
const [provider, setProvider] = useState<Web3Provider | null>(null);
const [signer, setSigner] = useState<JsonRpcSigner | null>(null);
const [accounts, setAccounts] = useState<string[]>([]);
const [network, setNetwork] = useState<Network | null>(null);
const setupProvider = () => {
if (!window.ethereum) throw Error('Could not find Metamask extension');
if (provider) return provider;
const newProvider = new Web3Provider(window.ethereum);
listenToEvents(newProvider);
setProvider(newProvider);
return newProvider
}
const listenToEvents = (provider: Web3Provider) => {
(window.ethereum as GenericProvider).on('accountsChanged', (acc: string[]) => {
setAccounts(acc)
});
(window.ethereum as GenericProvider).on('networkChanged', async (net: number) => {
console.log("networkChanged", net);
});
(window.ethereum as GenericProvider).on('disconnect', (error: ProviderRpcError) => {
throw Error(error.message);
});
}
const connect = async () => {
const provider = setupProvider();
const accounts: string[] = await provider.send("eth_requestAccounts", []);
const network: Network = await provider.getNetwork();
const signer: JsonRpcSigner = provider.getSigner();
setNetwork(network);
setAccounts(accounts);
setSigner(signer);
}
const getAccounts = async () => {
const provider = setupProvider();
const accounts: string[] = await provider.send("eth_accounts", []);
setAccounts(accounts);
return accounts;
}
const sendTransaction = async (from: string, to: string, valueInEther: string) => {
const provider = setupProvider();
const params = [{
from,
to,
value: ethers.utils.parseUnits(valueInEther, 'ether').toHexString()
}];
const transactionHash = await provider.send('eth_sendTransaction', params);
return transactionHash;
}
return {
signer,
accounts,
network,
connect,
getAccounts,
sendTransaction
}
}
export { useMetamask }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment