William Schwab
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
      • No invitee
    • Publish Note

      Publish Note

      Everyone on the web can find and read all notes of this public team.
      Once published, notes can be searched and viewed by anyone online.
      See published notes
      Please check the box to agree to the Community Guidelines.
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
No invitee
Publish Note

Publish Note

Everyone on the web can find and read all notes of this public team.
Once published, notes can be searched and viewed by anyone online.
See published notes
Please check the box to agree to the Community Guidelines.
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
1
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
## How to Use Web3React in Your Next Project ##### By [Gerhard Steenkamp](https://twitter.com/GerhardSteenka9) and [William Schwab](https://twitter.com/William94029369) Here at Linum Labs we've built up a good amount of experience integrating wallets into apps. The go-to interface for doing this is almost certainly Pedro Gomes's [web3modal](https://github.com/web3modal/web3modal), which is an excellent resource. We've been working a lot with another interface we hear mentioned less often - Uniswap's Noah Zinmeister's [`web3react`](https://github.com/NoahZinsmeister/web3-react) library. There are a lot of touches in it that we really enjoy. There isn't much written about how to use it, though. We wrote some internal docs, and then realized that it would be great to share with the larger ecosystem. If you are from the `web3react` repo, we'd love to contribute our docs however suits you best. Please get in touch! Table of Contents * [Initial Setup](#Initial-Setup) * [Wallet and Provider Connectors](#Wallet-and-Provider-Connectors) * [Connecting Wallets](#Connecting-Wallets) * [Connecting with the Wallet](#Connecting-with-the-Wallet) * [Interacting with Wallets and Providers](#Interacting-with-Wallets-and-Providers) * [Disconnecting a Wallet](#Disconnecting-a-Wallet) * [Web3React API Reference](#Web3React-API-Reference) * [`connector`](#connector) * [`account`](#account) * [`activate`](#activate) * [`active`](#active) * [`chainId`](#chainId) * [`deactivate`](#deactivate) * [`error`](#error) * [`provider`](#provider) * [`setError`](#setError) * [Custom Functions](#Custom-Functions) * [Conclusion](#Conclusion) ### Initial Setup The first thing you'll need to do is install the `web3react` packages. You'll always need the `core` package, and will also need the `web3react` connectors for any wallets you plan on integrating. We'll talk about the wallet connectors separately [here](#Wallet-and-Provider-Connectors). For core, if you're using Yarn, you'd use: ``` yarn add @web3-react/core ``` In order to make use of `web3react` inside your React app, you'll need to do a few things inside the `App` component: - import the `Web3ReactProvider` from `@web3-react/core` - wrap the app with a special `Web3ReactProvider` component - add a `getLibrary` function Your `App` component might look something like this: ```typescript import { Web3ReactProvider } from '@web3-react/core' import { Web3Provider } from "@ethersproject/providers"; function getLibrary(provider, connector) { return new Web3Provider(provider); } const App => () { return ( <Web3ReactProvider getLibrary={getLibrary}> <YourAwesomeComponent /> </Web3ReactProvider> ) } ``` (This example is loosely based on the `web3react` [docs](https://github.com/NoahZinsmeister/web3-react/tree/v6/docs#web3reactprovider).) The code above assumes that you're using [Ethers.js](https://docs.ethers.io) (specifically the [`Web3Provider`](https://docs.ethers.io/v5/api/providers/other/#Web3Provider) from Ethers), but the same can be done in web3.js. The idea is that you need to import a provider (generally via Ethers or Web3.js in the JavaScript/TypeScript space), and then instantiate and return it in the `getLibrary` function. ### Wallet and Provider Connectors Wallets and web3 providers (such as Infura) connect to an app in `web3react` via a `connector`. If you wish to add a new wallet or provider, there is likely already a web3react package to aid the process. There is a list of packages on the landing page of the GitHub repo ([here](https://github.com/NoahZinsmeister/web3-react)). ### Connecting Wallets We'll describe the process of connecting a wallet using `web3-react`, and also use MetaMask and Portis as examples with code snippets. First you'll need to get the connector for the desired wallet from the `web3-react` repo. You can find the code for the connectors [here](https://github.com/NoahZinsmeister/web3-react/tree/v6/packages), though each is also its own npm package, and should be added to your project using Yarn or NPM, installing each separately as needed. If we wanted MetaMask, we would get the package using `yarn add @web3-react/injected-connector`. (The `injected-connector` isn't specific to MetaMask - any wallet which works by injecting itself into the browser (like Brave) will also use this package.) For Portis, it would be `yarn add @web3react/portis-connector`. Each wallet needs its own unique instantiation details. We won't give a guide for each wallet here other than giving our WalletConnect example. If you want to add something else, head over to the package details in the `web3-react` repo and see what you'll need there. We'll start with the Portis example since most other wallets follow the same pattern. We'd head over to the [`portis-connector` directory](https://github.com/NoahZinsmeister/web3-react/tree/v6/packages/portis-connector). In the `src/` directory there we can see an `index.ts` file, which has a TypeScript interface called `PortisConstructorArguments`. These are the arguments you'll need when creating a Portis connector inside your app: ```typescript interface PortisConnectorArguments { dAppId: string networks: Network[] config?: any } ``` MetaMask (and other injected wallets) work a bit differently than most of the other connectors, as its only argument is an array called `supportedchainIds`, which, as its name implies, is a list of `chainId` numbers the dapp should support. ```typescript export interface AbstractConnectorArguments { supportedChainIds?: number[] } ``` We'll need this information in a minute. To connect MetaMask in your app, import the injected connector: ```typescript import { InjectedConnector } from '@web3-react/injected-connector' ``` For Portis: ```typescript import { PortisConnector } from '@web3-react/portis-connector' ``` This is something you'll want to have run when your app instantiates (most likely), and you'd like it to be available anywhere in your app that interacts with the blockchain. As a result, in a global state store or high up in the tree make sense. As mentioned before, the only argument is an array of `supportedChainId`s. If we're testing on Goerli, this means all we'd need to add is: ```typescript export const injectedProvider = new InjectedConnector({ supportedChainIds: [5] }); ``` (`chainId 5` is the Goerli testnet, you can replace that with whatever chain you want to work with or add several if your app is deployed on more than one network.) Portis has more arguments. For one, you'll need to set up a dApp ID at [Portis](https://portis.io). The optional config argument is specified in [their docs](https://docs.portis.io/#/configuration); it allows you to set a number of options, and is worth checking out if you're building with Portis. `network` works identically to `supportedChainIds` in the injected connector - it's an array of `chainId` numbers to be supported. ```typescript export const portis = new PortisConnector({ dAppId: "YOUR_DAPP_ID", network: [5] }); ``` Next, if you are instantiating the connector in one place, but need access to the wallet in another, import your wallet wherever you need it like this: ```typescript import { injectedProvider, portis } from "wherever/you/put/the/connector/instantiation"; ``` ### Connecting with the Wallet In order to connect with the wallet we've added, you'll need to form a `handleConnect` function, which takes a connector as an argument. We'll give an example of how you might want a funciton like this to look. We'll assume you're using [web3.js](https://web3js.readthedocs.io/en/v1.3.4/index.html), and that you have a connection to [Infura](https://infura.io), [Alchemy](https://alchemy.com), or a similar provider in order to instantiate a provider, and that you're storing your API key using `dotenv`. (If you don't, go and set up a free account by either.) If you're using this snippet, make sure the entire endpoint URL is in the `.env` file, like `https://eth-goerli.alchemyapi.io/v2/deadbeef_deadbeef_deadbeef`. ```typescript const handleConnect = (connector: any) => { // read-only let web3 = new Web3(new Web3.providers(proccess.env.API_ENDPOINT)); await activate(connector); let { provider } = await connector.activate(); // signer web3 = new Web3(provider); } ``` If you're using [ethers](https://docs.ethers.io): ```typescript import { Web3Provider } from '@ethersproject/providers'; const handleConnect = (connector: any) => { // read-only let ethersProvider = new ethers.providers.JsonRpcProvider(proccess.env.API_ENDPOINT); let { provider } = await connector.activate(); // signer const signer = provider.getSigner(); ethersProvider = new Web3Provider(signer); } ``` This is a very basic function - there's a good chance that you'll want to add some functionality to it, like reloading contracts once there's a signer attached, or a `try/catch` for disconnecting the wallet on a failed connection attempt. From a UI perspecitve, there are also intermediate states that you'll want to handle, like connecting (to provide a spinner) and the like. ### Interacting With Wallets and Providers Once you have a connected provider and/or wallet, `web3react` gives you a number of modules for interacting with the wallet. In any component interacting with the wallet, first import `useWeb3React`: ```typescript import { useWeb3React } from "@web3-react/core"; ``` Then destructure the relevant modules from `web3react` like so: ```typescript const { account, activate, active, chainId, connector, deactivate, error, provider, setError, } = useWeb3React(); ``` We'll give a detailed rundown of what you can do with this in the section called [Web3React API Reference](#web3react-api-reference). Before we get to that, we'll detail how to disconnect a wallet. ### Disconnecting a Wallet `web3react` provides two different functions for disconnecting a wallet: `deactivate` and `close` before. You can see `deactivate` in the code above - it can be destructured directly from the object you get when you call `userWeb3React`. `close` is a custom function that most, but not all, wallets have. Unfortunately, it can be hard to know which to call when. In addition, MetaMask and the injected connectors do not have a `close` function, which can cause an error if it is called, and some wallets will not be cleared from the DOM _unless_ `close` is called, meaning that you cannot rely on `deactivate`. As a result, you may want to implement a generic `disconnectWallet` function which ensures that the right functions are called for disconnecting the wallet fully. ### Web3React API Reference From here we'll do our best to describe any function in `web3react` that we're aware of, what it does, and how to use it. It's worth noting that since we're using `web3react`, all wallet interactions should now go throught `web3react` using `web3react`'s syntax, as opposed to using the wallet's own API. #### `connector` This object represents that `connector` that is connected right now. It extends `Abstract-Connector`. A number of the functions that `connector` exposes are also available directly through `useWeb3React()`, even without using `connector` directly. The rest of the functions that `connector` expose can change from wallet to wallet - not everything here will necessarily be implemented in every wallet, and the functions might behave differently from wallet to wallet. One particularly pertinent example is the `connector.close()` functions, which removes a wallet from the DOM. This can mean needing various checks when calling these functions, such as a `try/catch` or an `if` checking which wallet is connected (`if connector === walletConnect`, for example). We discussed disconnecting wallets in more detail above, in the [Disconnecting a Wallet](#Disconnecting-a-Wallet) section. If a `supportedChainIds` array was provided when the wallet was instantiated (highly recommended), it is also available through `connector.supportedChainIds`. In addition, there are a number of outputs sent to the console from `connector`. You can see these in the abstract class [here](https://github.com/NoahZinsmeister/web3-react/blob/v6/packages/abstract-connector/src/index.ts). #### `account` _(Also accessible as `connector.getAccount()`)_ This is the address of the connected wallet - anytime you need the user's address, you can use `account`. ```typescript const displayAddress = () => ( <div>Your address is: {account}</div> ) ``` #### `activate` _(Also accessible as `connector.activate(<WALLET_NAME>)`)_ Used when connecting a new wallet. If you have a `walletConnect` built from `WalletConnectConnector`: ```typescript activate(walletConnect); ``` This is used in the example above for connecting a wallet. #### `active` A boolean showing if the user has a connected wallet, useful in conditional rendering. ```typescript if(active){ ... } // or: active && <PaymentModal> ``` #### `chainId` _(Also accessible as `connector.getChainId()`)_ Number representation of the `chainId` the user is connected to. Useful for only displaying modals when the user is connected to supported networks, or displaying an alert when they are not. For a comprehensive list of chains (both production and test networks), see [ChainId Network](https://chainid.network). ```typescript if(chainId === 1){ return <PaymentModal> } else { return <>Please connect to Ethereum's Mainnet</> } ``` #### `deactivate` _(Also accessible as `connector.deactivate()`)_ Deactivate disconnects the wallet from the app. It is important to note that if the wallet has injected an iframe (like Portis, for example), it will not be removed from the DOM, which can lead to issues if the user tries to reconnect. In these cases, it is better to use `connector.close()`. We'll discuss disconnecting the user separately. ```typescript const disconnect = () => ( <button onClick={deactivate}>Disconnect</button> ) ``` #### `error` The `error` library exposes a number of potential errors that it recognizes. It does not stop execution when they are triggered, but rather gives the architect room to catch each error and customize how the applicaiton should react to it. Most of these errors vary from wallet to wallet, and unfortunately not all are documented. We'll give one example to give an idea of how they work and then list errors from MetaMask/injected providers and Portis. Most dApps support some chains (generally mainnet and some testnets), but not all. Properly identifying if the user is on a supported chain is a crticial part of good UX in a dApp. `web3-react` exposes a `UnsupportedChainIdError` that allows you to detect when a user is on an unsupported chain. This error relies on an array of supported chains being supplied when the wallet is instantiated. You can pass in a supportedChainIds as an argument when instantiating a waller, an array of numbers. This, or something like it, is either a mandatory or optional argument for every connector/wallet that `web3-react` recognizes. This example assumes you've passed in an array with supported chains. First, import the error: ```typescript import { UnsupportedChainIdError } from '@web3-react/core'; ``` Then destructure it from the `useWeb3React` object: ```typescript const { // whichever other web3-react libraries you need, chainId, error } = useWeb3React(); ``` Now if you wanted to have a specific reaction in the app, you can now use it. (Remember that `supportedChainIds` is an optional argument.) Here's one example: ```typescript if(Boolean(connector.supportedChainIds) && !connector.supportedChainIds.includes(chainId)) { throw new UnsupportedChainIdError(chainId, connector.supportedChainIds); } ``` The other globally available error is `StaleConnectorError`. There are also custom errors depending on your wallet. We'll list MetaMask's: - `NoEthereumProviderError`: used when an injected provider is expected to be there but isn't ([example](https://github.com/NoahZinsmeister/web3-react/blob/v6/packages/injected-connector/src/index.ts#L70)) - `UserRejectedRequestError`: used if the user rejects a transaction through the injected provider **Portis** does not have any custom errors. #### `provider` _(Also accessible as `connector.getProvider()`)_ This is the same as the concept of a provider in web3.js. It also contains a signer unlike the Ethers paradigm where the provider and signer are two separated entities. This means that when using web3, the `provider` is passed in at contract instantiation, but with Ethers a simple provider (for example, using `ethers.getDefaultProvider()`) is sufficient for instantiating a contract, but the `web3react` provider will need to be connected to send transactions. (This might be a bit confusing. There is a dedicated section for working with contracts in Warp Core later.) ```typescript myContract.connect(provider).myFunction{ value: 1 }(); //ethers myContract = new web3.Contract(abi, address, provider); // web3 ``` #### `setError` `setError` takes an `Error` as an argument. `Error` is a built-in TypeScript type: ```typescript interface Error { name: string; message: string; stack?: string; } ``` When called, it reloads `web3react`. This is used internally in the library when errors happen - `web3react` will call `setError` and try to reload. You can also use this manually if you'd like to create a custom error which will then be available throughout the project. You can set a new error type like this ```typescript const { setError } = useWeb3React(); setError({ name: "fooError", message: "you got a foo error"}); ``` Then you can use that error anywhere in the app: ```typescript const { error } = useWeb3React(); if(error && error.name === "fooError"){ doSomething(); } ``` #### Custom Functions In addition to the global functions above, some wallets (connectors) have their own unique functions exposed by `web3react`. These can be very important. `close()`, for example, will fully clear DOM-based wallets from the DOM, which `deactivate()` will not. If you'd like to find the custom functions for a given wallet, as of this writing you will need to actually look through the code of the connector to see what's there. The directory of all the connectors is [here](https://github.com/NoahZinsmeister/web3-react/tree/v6/packages). For example, if we're looking to see if there are any special functions for Portis, we'd go to the [Portis connector](https://github.com/NoahZinsmeister/web3-react/blob/v6/packages/portis-connector/src/index.ts), where we'd see the global (public) functions (`activate`, `getProvider`, `getChainId`, `getAccount`, `deactivate`), and then also a[`changeNetwork`](https://github.com/NoahZinsmeister/web3-react/blob/v6/packages/portis-connector/src/index.ts#L115) and [`close`](https://github.com/NoahZinsmeister/web3-react/blob/v6/packages/walletconnect-connector/src/index.ts#L126) function. ### Conclusion That's a wrap! We've detailed how you to integrate Web3React into your project, how to use it with the wallets you'd like, and what you can do with it once you're up and running. We think Web3React is an excellent library, and hope this article helps people get started with it in their own projects!

Import from clipboard

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.
Upgrade
All
  • All
  • Team
No template found.

Create custom template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

How to use Slide mode

API Docs

Edit in VSCode

Install browser extension

Get in Touch

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Upgrade to Prime Plan

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

No updates to save
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Upgrade

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Upgrade

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully