Last active
March 1, 2024 03:43
-
-
Save pedrouid/5d081f8f13d13d12762bc880ce79a000 to your computer and use it in GitHub Desktop.
EIP-6963 react example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import * as uuid from 'uuid'; | |
import { WindowProvider } from "@wagmi/connectors" | |
import defaultProviderIcon from "../assets/defaultProviderIcon.png" | |
// copied from https://github.com/wagmi-dev/references/blob/main/packages/connectors/src/utils/getInjectedName.ts | |
function getInjectedName(ethereum?: WindowProvider) { | |
if (!ethereum) return 'Injected' | |
const getName = (provider: WindowProvider) => { | |
if (provider.isApexWallet) return 'Apex Wallet' | |
if (provider.isAvalanche) return 'Core Wallet' | |
if (provider.isBackpack) return 'Backpack' | |
if (provider.isBifrost) return 'Bifrost Wallet' | |
if (provider.isBitKeep) return 'BitKeep' | |
if (provider.isBitski) return 'Bitski' | |
if (provider.isBlockWallet) return 'BlockWallet' | |
if (provider.isBraveWallet) return 'Brave Wallet' | |
if (provider.isCoinbaseWallet) return 'Coinbase Wallet' | |
if (provider.isDawn) return 'Dawn Wallet' | |
if (provider.isDefiant) return 'Defiant' | |
if (provider.isEnkrypt) return 'Enkrypt' | |
if (provider.isExodus) return 'Exodus' | |
if (provider.isFrame) return 'Frame' | |
if (provider.isFrontier) return 'Frontier Wallet' | |
if (provider.isGamestop) return 'GameStop Wallet' | |
if (provider.isHyperPay) return 'HyperPay Wallet' | |
if (provider.isImToken) return 'ImToken' | |
if (provider.isHaloWallet) return 'Halo Wallet' | |
if (provider.isKuCoinWallet) return 'KuCoin Wallet' | |
if (provider.isMathWallet) return 'MathWallet' | |
if (provider.isOkxWallet || provider.isOKExWallet) return 'OKX Wallet' | |
if (provider.isOneInchIOSWallet || provider.isOneInchAndroidWallet) | |
return '1inch Wallet' | |
if (provider.isOpera) return 'Opera' | |
if (provider.isPhantom) return 'Phantom' | |
if (provider.isPortal) return 'Ripio Portal' | |
if (provider.isRabby) return 'Rabby Wallet' | |
if (provider.isRainbow) return 'Rainbow' | |
if (provider.isStatus) return 'Status' | |
if (provider.isTalisman) return 'Talisman' | |
if (provider.isTally) return 'Taho' | |
if (provider.isTokenPocket) return 'TokenPocket' | |
if (provider.isTokenary) return 'Tokenary' | |
if (provider.isTrust || provider.isTrustWallet) return 'Trust Wallet' | |
if (provider.isXDEFI) return 'XDEFI Wallet' | |
if (provider.isZerion) return 'Zerion' | |
if (provider.isMetaMask) return 'MetaMask' | |
} | |
// Some injected providers detect multiple other providers and create a list at `window.ethereum.providers` | |
if (ethereum.providers?.length) { | |
// Deduplicate names using Set | |
// Coinbase Wallet puts multiple providers in `ethereum.providers` | |
const nameSet = new Set<string>() | |
let unknownCount = 1 | |
for (const provider of ethereum.providers) { | |
let name = getName(provider) | |
if (!name) { | |
name = `Unknown Wallet #${unknownCount}` | |
unknownCount += 1 | |
} | |
nameSet.add(name) | |
} | |
const names = [...nameSet] | |
if (names.length) return names | |
return names[0] ?? 'Injected' | |
} | |
return getName(ethereum) ?? 'Injected' | |
} | |
// this is oversimplified but it comes from the spec here: https://eips.ethereum.org/EIPS/eip-1193 | |
interface EIP1193Provider { | |
request: (payload: { method: string, params: params?: unknown[] | object }) => Promise<unknown> | |
} | |
// this matches the spec here: https://eips.ethereum.org/EIPS/eip-6963 | |
interface EIP6963ProviderInfo { | |
walletId: string; | |
uuid: string; | |
name: string; | |
icon: string; | |
} | |
// this matches the spec here: https://eips.ethereum.org/EIPS/eip-6963 | |
interface EIP6963ProviderDetail { | |
info: EIP6963ProviderInfo; | |
provider: EIP1193Provider; | |
} | |
// this will enrich the interface to include a boolean for connected and accounts | |
interface EVMProviderDetected extends EIP6963ProviderDetail { | |
connected: boolean; | |
accounts: string[]; | |
} | |
function App() { | |
const [providers, setProviders] = React.useState<EVMProviderDetected[]>([]); | |
if (typeof window.ethereum !== "undefined") { | |
const windowProvider = { | |
info: { | |
walletId: "window-ethereum-provider", | |
uuid: uuid.v4(), | |
name: getInjectedName(window.ethereum), | |
icon: defaultProviderIcon | |
} | |
provider: window.ethereum, | |
connected: false, | |
accounts: [] | |
} | |
setProviders([...providers, windowProvider]) | |
} | |
window.addEventListener( | |
"eip6963:announceProvider", | |
(event: EIP6963AnnounceProviderEvent) => { | |
const announcedProvider = { | |
...event.detail, | |
connected: false, | |
accounts: [] | |
} | |
setProviders([...providers, newProvider]) | |
} | |
); | |
window.dispatchEvent(new Event("eip6963:requestProvider")); | |
async function connectProvider(selectedProvider: EVMProviderDetected) { | |
// requesting accounts with EIP-1102: https://eips.ethereum.org/EIPS/eip-1102 | |
const accounts = await selectedProvider.request({ method: "eth_requestAccounts" }) | |
// once succesful we filter out the previous provider and update with new state | |
const updatedProvider = { | |
...selectedProvider, | |
connected: true, | |
accounts, | |
} | |
const otherProviders = providers.filter(provider => provider.info.uuid !== selectedProvider.info.uuid) | |
setProviders([ | |
...ohterProviders, | |
updatedProvider | |
]) | |
} | |
return ( | |
<div> | |
{providers.map(provider => ( | |
<div onClick={connectProvider(provider)}> | |
<div>{provider.info.name}</div> | |
<img src={provider.info.icon} /> | |
{provider.connected && <div>accounts: {provider.accounts}</div>} | |
<div> | |
))} | |
</div> | |
); | |
} | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment