FullStack Web3 — Everything You Need to Know

We learn exactly how web3 / blockchain / smart contract applications work in the front end using HTML and JavaScript. We then go through 6 different ways you can connect your Metamask, Phantom, or other blockchain wallet address to your front end. We’ll look at popular Nextjs / React packages to make your development lifecycle 100 times easier.

Patrick Collins
Better Programming

--

Six ways to connect your smart contracts to a front end
Connecting your frontend to your smart contracts/web3 applications/blockchain.

You’ve just built an amazing web3 application with solidity, rust, or maybe vyper, and you tell your non-developers friends “to interact with it, you just need to call these functions I’ve written with your backend scripts.”

And to your surprise, none of them knew what you were talking about.

Connecting to a front end in web3
Image source

In this article, we’ll learn exactly how web3 / blockchain / smart contract applications work in the frontend using HTML and JavaScript.

Next, we’ll then go through six different ways you can connect your Metamask, Phantom, or other blockchain wallet address to your frontend.

Finally, we’ll look at popular Nextjs / React packages to make your development lifecycle 100 times easier.

So, let’s get started.

Introduction

In order for web3 to be approachable to the masses, we need to have user-friendly frontends and websites. There are a few challenges that full stack software engineers run into when approaching this problem in the blockchain space.

  1. How do I connect Metamask to my UI? (Or Walletconnect, Phantom, etc.)
  2. How do I execute a transaction with my smart contract from a website?
  3. What are the tools the best of the best are doing?

So, in asking myself this problem and trying to figure out what to recommend to developers, I ended up looking at nearly ALL the most popular solutions. So in this article, we are going to:

  1. Understand what is going on in the browser when we want to interact with or send a transaction to a blockchain.
  2. We look at six of the most popular methods to connect to our web3 applications
  3. Give code examples and show what all the biggest players in the space use, so you can use the same tools!

If you’d like to see what some professional frontends look like right now, you can take a look at the Aave or Uniswap website.

Excited? Me, too. Let’s go.

How to Connect my Smart Contract to Metamask

Or another wallet in the browser, like Phantom, Walletconnect, etc.

How to connect my hardhat, brownie, dapptools, foundry smart contract application to an Ethereum wallet
How to connect my smart contract to Metamask

Most “backends” to your web3/blockchain applications are going to be built with a framework like Hardhat, Brownie, DappTools, Anchor, or Foundry (or if you believe in the heart of the cards the Remix tool ). Our frontends are going to use anything and everything you’ve learned in traditional web2 space. HTML, JavaScript, CSS, and frameworks like NextJS, React, and Angular.

So if you’re familiar with traditional web development, you’ll be ahead of the game!

What Goes on in the Browser With Metamask

Now, if you want to follow along with this, please install Metamask. You can watch this video for a more in-depth follow-along.

Hit inspect so we can see what’s going on in the browser with metamask
Right-click, and hit inspect

Now, in your browser, right now, right-click the screen and hit “inspect” or “inspect element,” and you’ll see something like this:

Browser debugging tools
Hitting “inspect” to see all the browser debugging tools.

This will show all the code that the website is using to render what you see on the screen. Then, if you hit sources in the top bar you’ll see something like this. (If you can’t see sources, you can hit the >> button to show more options.)

Let’s look at how wallets are injected into the browser.
Hitting “Sources” to see all the files that make up the web page.

If you have Metamask installed in your browser, you’ll see a “Metamask” file on the left. If you have Phantom installed, you’ll see a “Phantom.”

These browser add-ons/plugins do something interesting, they automatically “inject” themselves into your browser and show up as a part of the website you’re on. This gives the website the opportunity to interact with them.

There is an object in every browser called the window object. We can see this object by clicking on the console tab, (similar to how we clicked on sources ) we drop into a JavaScript console, where we can write JavaScript and interact with JavaScript objects.

Let’s go ahead and type window and see what we get.

Looking at window.ethereum in the browser. (And window.solana)
Type `window` and hit enter in the `console` tab

Awesome! We see the JavaScript window object in our browser. Now, since we have a Metamask source, this should mean we have an ethereum attribute attached to our window object. Type window.ethereum and see what you get (or window.solana if you have Phantom).

You’ll see an object response! If you didn’t have Metamask, you’d get an undefined. Each browser wallet will add its own attribute to the window object, and you can usually find it in their documentation. Here is the Metamask documentation talking exactly about window.ethereum .

Note: In prior versions, this was window.web3 it has since been changed to window.ethereum

This is what’s known as our blockchain provider or our blockchain connection window.ethereum will be our provider. So why do we need that?

Blockchain Connection / Provider

Whenever we want to read data from a blockchain, call a function, or make a transaction, we need to connect to the blockchain network. If we send a transaction, we need to send the signed transaction to one blockchain node so that it can send it out to all the other blockchain nodes in the network. You can learn more about blockchain 101 in lesson 0 of this FreeCodeCamp video.

You might have used an RPC URL from Alchemy, Infura, or Moralis Speedy Nodes in your blockchain applications before. These are all “node-as-a-service” providers, and give us an HTTP endpoint to send requests to a blockchain node. The same happens with cryptocurrency wallets, our Metamasks have a connection to a blockchain node built-in. In fact, if you go to your Metamask “networks” tab, you can see the exact RPC URL your Metamask is using!

Metamask networks tab — RPC URL for connecting your front end
Networks tab in Metamask — to see blockchain RPC URL

Boom! So whenever we do something with our Metamask, we make an API call to this RPC URL.

Connecting to a Cryptocurrency Wallet with HTML and JavaScript

Now, we are going to first show how this is all done in HTML and JavaScript, and then we will move on to our Nextjs/React examples. I have a full example of connecting to a cryptocurrency wallet using HTML/JavaScript in my Github here, and a list of all examples also in my GitHub.

First, let’s create a standard HTML document, and we will get it a Connect button.

<!DOCTYPE html>
<html>
<head>
<title>Javascript Test</title>
</head>
<body>
<button id="connectButton">Connect</button>
</body>
</html>

We can add some functionality to our button by adding a script tag and creating a JavaScript function that looks for the window.ethereum and if it finds it, it makes a request to connect.

And that’s all you need! The eth_requestAccounts comes directly from the Metamask documentation. If you were to name this index.html and run this in a browser, your metamask would pop up asking to connect.

Connect your dapp with Metamask using smart contracts
Metamask asking to connect

Sending a Transaction

Now that we’ve connected our Metamask, it’s time to send a transaction. This is where we can use packages like ethersjs and web3js to connect our provider and then send a transaction. Typically, some sample JavaScript to execute a function / send a transaction in JavaScript would look like this:

const etheres = require("ethers")contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
const abi = // some big javascript ABI here...
const provider = new ethers.providers.JsonRpcProvider(/* alchemy or infura */)
const wallet = new ethers.Wallet(/* Private key */, provider)
const contract = new ethers.Contract(contractAddress, abi, wallet)
const contractWithSigner = contract.connect(wallet)
const transactionResponse = contract.someFunction()

The only difference for sending transactions in a browser is that we change the provider to be our window.ethereum and our wallet will now come directly from our provider . Since our metamask is both our provider and wallet (or signer) our code will look like this.

const etheres = require("ethers")contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
const abi = // some big javascript ABI here...
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, abi, signer)
const contractWithSigner = contract.connect(wallet)
const transactionResponse = contract.someFunction()

You’ll notice, only the two lines in the middle changed, instead getting our wallet from the window.ethereum and our signer comes from our provider (aka metamask).

Now there is an issue here. Our browsers can’t understand require (and sometimes import has issues) so we can add some packages to help us out.

Since I don’t want this to turn into a frontend-focused blog, I’ll not just point you at my html-js-ethers-connect example which shows us how to run the rest of the example yourself. You’ll just need the following installed:

Then, you can follow the instructions in the README.md to get setup and do a full example with pure HTML and JavaScript for sending transactions in the browser!

And boom! You’ll have a working minimalistic frontend with your smart contracts!

Top 5 Best Frontend Web3 Setups

In no particular order. This could probably be it’s own blog…

Top full-stack and front end web3/blockchain/smart contract dapp setups
Top 5 Frontend Web3 Setups

Now, let’s get into giving you the tools you need for a full stack application. For each of these setups, I’ll include:

  1. How to set them up
  2. Minimalistic Demos
  3. Real-World Examples

So you can pick which one suits you the best! We are working with NextJS for all of these because ReactJS is the most popular frontend framework on the planet right now, and NextJS is built on top of it, and in my opinion is much more user-friendly than raw ReactJS. However, you could 100% work with Angular, Svelte, or otherwise.

You can find all my minimalistic code example full-stack-web3-metamask-connectors repository, which links out to all the demos.

Setting up a basic NextJS project

To get started, all of these projects are going to start with a basic nextJS project. You’ll need Node, Git, and Yarn installed to move forward. You can additionally follow along with the nextjs getting started documentation.

Run the following:

yarn create next-app full-stack-web3
cd full-stack-web3

And you’re done! You now have a basic setup. You can run yarn dev now to see what your current website would look like. And finally, just to delete all the “stuff” that it starts you out with, go into your index.js file, and delete everything so it just is:

export default function Home() {
return <div>Hi</div>;
}

And now your frontend will just say “Hi.”

Setting up a local hardhat blockchain and contract

Now, since we are going to be testing executing functions, we are going to need a blockchain to send transactions to, and a smart contract to work with. I’ve already got one set up for you located at my hardhat-simple-storage GitHub. To set this up you can follow the README.md or run the following in a different terminal than the one running your frontend:

git clone https://github.com/PatrickAlphaC/hardhat-simple-storage
cd hardhat-simple-storage
yarn
yarn hardhat node

This will give you an output that will start a local blockchain, give you some temporary fake private keys, and deploy our SimpleStorage contract which has a store function that we are going to use. It takes a uint256 _favoriteNumber as input, and stores the number to a public variable. You can view the contract in the SimpleStorage.sol file.

Setup your metamask with our local blockchain

Now, we’ll want to connect our Metamask to our local fake blockchain. Why? So that we can send transactions and test quickly. This resembles a real blockchain, but this one we have control over. You could use a testnet if you like and skip this, but you’ll have to wait a long time for transactions to process, which no one wants.

Where the blockchain node is running, you’ll see an output like: Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/ . This is going to be our RPC URL similar to Alchemy.

Now, in a Metamask without any real funds associated with it (please don’t ever use a Metamask with real funds for developing. Create a new browser profile or download another browser with Metamask) hit the networks button at the top, and “Add Network.”

Set it up like you see below and hit save. Then make sure you switch to that network (select it in the networks dropdown).

Now, hit the big circle in the top right, and hit “import account.”

And add one of the private keys from the output of the yarn hardhat node command. You should now have an account, be on a local network, and have some fake test ETH. Your Metamask should look something like this:

And we are ready to go :)

Important note: If you ever run into an issue with your nonce being off, or transactions not sending properly. In your metamask while your imported account from hardhat is selected, go to the circle in the top right -> settings -> advanced -> reset account. This will remove the nonce issue.

Raw Ethers Setup

🧑‍💻 Link to my full code here

Connect your smart contract to a front end with Ethersjs
Ethers.js Setup

The simplest way to get started is just to use some of the tools you’re already familiar with, like Ethers. We can literally copy-paste what we did in our HTML setup into our index.js file.

For this, we added some extra functionality for us to display “Please install Metamask” or “Connected” when connected or the user doesn’t have Metamask. You’ll also see commands like useState and useEffect. These are known as React Hooks, and you can learn all about them from this Fireship video or the react docs. Although this app would work OK without them, we just wouldn’t be able to save the state of the application between renders.

Pros:

  • Most granular control of our UI using Ethers

Cons:

  • We have to write a lot of our own code, including Contexts.
  • Is hard to support more than just Metamask connections (yes, there are other ways to connect to wallets!)

Real-world examples

Nader Dabit Explainer

Also, in future examples, I’m going to import the abi from another file, so it doesn’t clog up the article.

Web3Modal Setup

🧑‍💻 Link to my full code here

Connect your smart contract application to metamask and walletconnect
WalletConnect Logo

One of the other most popular ways to connect EVM-based blockchain applications to wallets is with Walletconnect. All of the examples I’m going to show (including the raw Ethers one) can connect to Walletconnect (and should!), so our Web3Modal setup isn’t the only one that can do this. One fantastic tool that members of the wallet connect team created was this Web3Modal tool, which allows us to have a framework to connect to ANY provider, including Ledger, WalletConnect, Torus, Coinbase Wallet, and more!

We just need to import the package, and our index.js might look like this:

You’ll see, we set up some providerOptions to tell our frontend what wallets we want to support, and what chains we want to support. We need to set a NEXT_PUBLIC_RPC_URL which points to another RPC_URL to connect to a blockchain. If we use walletconnect, we actually don’t use the built-in blockchain nodes of our users' metamasks.

Pros

  • Easy to integrate multiple wallets
  • Ethers is nice

Cons

  • Still no built-in contexts

Real-World Examples

And if you’re looking to see some cutting-edge front-end use of Web3Modal, blockchains, and more, be 100% sure to check out Scaffold-ETH. It is an amazing learning tool by Austin Griffith that you can use to deconstruct some best practices.

Moralis

🧑‍💻 Link to my full code here

Full-Stack Smart Contract / Web3 / Blockchain Setup with Moralis
Moralis Logo

Now Moralis (or more specifically, react-moralis) is the first package to include context managers, which are INCREDIBLY helpful. They allow our whole app to share state easily between components, which is necessary since we need to pass around Metamask authorization.

Moralis was created by Ivan on Tech and team, to not only help developers connect to Metamask, but also help with any other backend systems a full-stack app might need. Etherscan and Opensea are both examples of web3 applications that still need backends and databases. Why? Because oftentimes you want to add a ton of functionality that would cost too much gas to do on-chain!

So you’ll still want to have your smart contract do all the main work, but Moralis can do all the work around it. Here is what our code for Moralis might look like:

You’ll see Moralis come with powerful hooks like useWeb3Contract that make getting state and interacting with our contracts even easier, and without the need for ethers! Instead of us writing our own connect function, Moralis comes with a function to do that for us as well with enableWeb3 .

Additionally, in our _app.js we’ll need to wrap our whole app with a Context provider, and we can do that like so:

import "../styles/globals.css";
import { MoralisProvider } from "react-moralis";
function MyApp({ Component, pageProps }) {
return (
<MoralisProvider initializeOnMount={false}>
<Component {...pageProps} />
</MoralisProvider>
);
}
export default MyApp;

Morlais has built-in optionality to set up your frontend with a database as well, however, if you just want to use the hooks and functions, you can set initializeOnMount to false, and only set up a server if you want in the future!

Pros

  • Context provider
  • Minimalistic built-in functionality for interacting with smart contracts
  • Optionality to include a backend for an even more feature-rich frontend

Cons

  • Have to manually add your own wallets

Real-World Examples

Web3-React

🧑‍💻 Link to my full code here

Build a full-stack dapp with web3-react
Uniswap Logo

Uniswap Engineering Lead Noah Zinsmeister and friends have built an amazing package called web3-react. This is one of the most widely used packages by top projects like Uniswap, Aave, and Compound. It also contains a context manager and a number of incredibly powerful hooks for you to just get started and get going, and some web3 wallet built-in connections.

Here is what your index.js might look like:

And our _app.js :

As you can see, we still use ethers to interact with our smart contracts, but we use hooks to enable our Metamask and any other wallet providers that we’d like!

Pros

  • Context provider
  • Minimalistic built-in functionality for interacting with smart contracts
  • Built-in wallet connections

Cons

  • Not as easy wallet setup as web3modal
  • Need to write or use your own hooks to interact with your smart contracts.

Real-World Examples

useDapp

🧑‍💻 Link to my full code here

Build a full stack web3 application with usedapp
Ethworks Logo

Ethworks is the team behind popular tools like waffle, which is one of the most popular testing frameworks that's even used by hardhat. They’ve done it again and made a framework similar to moralis with all the hooks and tools for building a frontend, and including a context provider.

Here is what our index.js might look like:

And our _app.js

We pass a config to our application that can include supported blockchains and other features for connecting. Similar to Moralis, useDapp comes with functions activateBrowserWallet to activate metamask / browser wallet and hooks like useContractFunction to interact with our smart contract (you don’t have to use ethers!).

Pros

  • Context provider
  • Minimalistic built-in functionality for interacting with smart contracts

Cons

  • Not as easy wallet setup as web3modal
  • No optionality for a built-in database

Real-World Examples

Summary

I know this was a long one, but that’s what I do, I make sure to go through everything and make sure I know what’s going on to give you the best guides in the space.

Happy coding!

--

--