Learning Ethers.js and Connecting to Metamask

Learning Ethers.js and Connecting to Metamask

I spent today working on the frontend React app for my vault contracts. I have a bit of experience with React. I recently refreshed my knowledge by building a simple app that used web3.js to pull information from a static provider in the app, do some calculations, and display it. Based on that, I expected today to be easy. I was wrong.

Swapping in ethers.js for web3.js

I started working with Hardhat and Ethers.js recently building out the test cases for my Raider LP Vault contract. I really liked how simple the API was for Ethers.js to call on-chain methods and create new instances of a Contract with different signers. Therefore, I decided I would use it on the frontend of the app as well.

Overall, I'm still happy with the decision, but it caused me to spend a lot of time pouring over the docs (which have good information about the API, but not a lot of examples) and Stack Overflow examples to troubleshoot certain areas. Especially, the next section...

Connecting to MetaMask

I had a hard time getting the Web3 Ethereum provider from MetaMask configured in my app. As with anything in Web3, there are multiple asynchronous calls to get information about the provider. I started out trying to follow the docs, but there is very little information past which functions to call to get the actual provider.

It was challenging to get the various steps orchestrated to line up correctly with the React rendering lifecycle. I use React Functional components pretty much exclusively, and, therefore, leverage the useEffect and useLayoutEffect hooks to populate state when initializing the UI.

When counting on a browser-injected web3 provider, you need to observe and handle various situations related to the following variables:

  1. Whether they have MetaMask (or another browser wallet) installed.
  2. Whether they are on the correct network for your application.
  3. Whether their wallet is connected to your application.

To account for the first variable, I ended up using function that could execute in the initial javascript load to populate a state variable (isMetaMask). This is important because you need to know if there is a browser provider before you try to call your initialize function for the other data. Otherwise, you would have reference errors without a provider injected and the page would crash.

 const isMetaMaskInstalled = () => {
     const { ethereum } = window;
     return Boolean(ethereum && ethereum.isMetaMask);
 };

const [isMetaMask, setMetaMask] = useState(isMetaMaskInstalled());

For the other variables, chain ID and wallet status, I wrote an initialize script that is called when the layout is rendered to update additional state variables. These variables control whether or not the different modal messages are shown and prompt the user's next step. The useLayoutEffect hook is set to watch for the chainId property changing on the browser provider to then prompt a re-load. This is a security best practice from MetaMask.

useLayoutEffect(() => {
    if (isMetaMask) {
        initialize();
    }
 }, [window.ethereum.chainId]);

Other Technologies

Developing Web3 applications front to end by yourself requires a myriad of skills. You have to be part developer, designer, architect, CSS monkey, tester, and security practitioner.

As I was working through the frontend buildout today, I leveraged a couple non-web3 libraries that I really enjoy: BlueprintJS, Sass, and Tachyons.

Blueprintjs is a UI library built on React that provides a lot of components to use out of the box. They have consistent theming and are well suited to data-rich applications. Additionally, BlueprintJS defines Sass variables for its theme elements so it's easy to customize the look without losing the functionality.

Tachyons is a lightweight styling library that I use for inline, one-off styles and grid layouts. Pairing it with BlueprintJS lets me pick and choose where to get granular. Combined, they help me build reasonable looking apps in a short amount of time.

Here are some snapshots of the mocked up Raider Vault UI. I plan to wire it up to Ethers.js and test on my local development environment tomorrow.

Home page

Vaults page