
A Crash Course in web3 for web2 Developers
Anthony Campolo presents a crash course on Web3 development for Web2 developers, demoing how to build a decentralized app using smart contracts and React
Episode Description
Anthony Campolo demonstrates Web3 composability by building and deploying a smart contract connected to a React frontend.
Episode Summary
Anthony Campolo presents a live coding demo at the Composability Summit, drawing parallels between Web3 development and Jamstack architecture to illustrate how blockchain-based applications are inherently composable. He walks through building a decentralized application (dApp) from scratch, starting with a Solidity smart contract that stores and updates a simple greeting message. After explaining the basics of blockchain as a distributed database, he compiles and deploys the contract to the Avalanche testnet using Hardhat, then connects it to a React frontend via the Ethers.js client library and MetaMask wallet. The demo covers both reading from and writing to the contract, showing how the application binary interface (ABI) acts as an API layer between the smart contract and the frontend. He then deploys the finished app to Layer0 (Edgio) so it's accessible as a live website. The key takeaway is that the smart contract and frontend are completely decoupled — the contract can be queried from any language or tool, making Web3 a natural fit for composable architecture where every piece of the stack can be swapped independently.
Chapters
00:00:00 - Introduction to Web3 Composability
Anthony Campolo opens the talk by introducing the concept of Web3 composability and drawing a direct comparison to Jamstack architecture. He explains that composability is about having modular, interchangeable pieces — like Lego blocks — where a frontend built with any framework can connect to various backend services, whether that's a headless CMS, a database, or in this case, a blockchain smart contract.
He sets the stage for the live demo, explaining that instead of slides and architecture diagrams, he'll walk through actual code to show what composability looks like in practice. The goal is to deploy a smart contract, read from it using a React frontend, write to it, and then deploy the whole application to a hosting provider — essentially basic CRUD operations against the blockchain.
00:03:47 - Setting Up the Smart Contract and Blockchain Basics
Anthony begins setting up the project structure, creating the Solidity contract, deployment scripts, and Hardhat configuration. He takes a moment to explain blockchain fundamentals for newcomers, describing it as a distributed database that lives on many computers simultaneously, maintaining a shared and tamper-resistant state — which is why apps built on it are called decentralized applications (dApps).
He walks through the smart contract code in detail, explaining the hello message variable, the constructor that sets it on deployment, the read function that returns the message, and the setter function that allows updates. He also covers environment variables like the RPC URL for connecting to the blockchain and the private key for the crypto wallet, noting that these contain sensitive information and should be kept out of version control.
00:09:23 - Compiling, Deploying, and Understanding the ABI
The focus shifts to the Hardhat configuration file, where Anthony explains the Solidity version setting and the concept of the application binary interface (ABI) — essentially a JSON specification that acts as an API for the smart contract, defining what methods are available and how to interact with them. He also explains why he's deploying to the Avalanche blockchain rather than Ethereum, citing its speed, lower cost, and environmental advantages.
After compiling the contract and generating the ABI, he deploys it to the Avalanche Fuji testnet, explaining that testnets allow developers to experiment without paying real gas fees. He verifies the deployment on Avalanche's block explorer, confirming the contract is live on the blockchain with a visible wallet address and timestamp, ready to be connected to the React frontend.
00:13:13 - Connecting the React Frontend to the Smart Contract
Anthony integrates the deployed contract into the React application by inserting the contract address and wiring up the fetch function that reads the hello message from the blockchain. He demonstrates clicking the button to retrieve the stored message, confirming the full read flow from smart contract through the ABI and Ethers.js into React state displayed in the browser.
He then adds write functionality by implementing the set hello function, which requires a wallet signature via MetaMask to create a verifiable transaction history on the blockchain. After demonstrating the input field and button for changing the message, he explains the inherent latency in blockchain transactions — the distributed network of computers needs time to reach consensus on the updated state before the change is confirmed.
00:19:00 - Deploying the dApp and Final Thoughts on Composability
With the application working locally, Anthony deploys it to Layer0 (Edgio) using their CLI tool, configuring the router for a single-page application setup and building the project into a static bundle. Once deployed, the dApp is live at a public URL where anyone with a MetaMask wallet configured for Avalanche can interact with the contract and change the stored message.
He wraps up by reinforcing the core message: the smart contract is completely decoupled from the frontend, and it can be queried from any programming language or tool — Curl, Ruby, JavaScript, or anything else. This separation of concerns is what makes Web3 inherently composable, echoing the same principles that make Jamstack architecture powerful. He invites viewers to explore the deployed contract themselves and points to his social channels and QuickNode streams for more Web3 content.
Transcript
00:00:01 - Anthony Campolo
Hello everyone, my name is Anthony Campolo, and I'm going to be showing you Web3 composability. This is the Composability Summit. Thank you to Scott and Ishan for the invitation to present here. I am a representative of the Web3 world, coming to you to tell you a little bit about what Web3 is and how it fits into this whole composability thing. I want to really get across in this talk that Web3 has a lot in common with things like the Jamstack.
00:00:36 - Anthony Campolo
I know this isn't a Jamstack conference, but Jamstack, to me, is a really good example of composability. This idea of having different pieces that we can take and easily slot together, to me, is really the promise of composability: that we can work with our architecture a little bit like it's just Lego pieces we're combining together. So you can have a frontend, and that frontend could be any kind of JavaScript or even non-JavaScript thing you want. It could be different frameworks, it can be SSR, it could be client-side rendered, it could be pure static, but then that could be querying some sort of backend.
00:01:17 - Anthony Campolo
So the backend traditionally has been something like a headless CMS, or maybe just an actual database if you're going full-stack Jamstack. But in this talk, we're going to be looking at how blockchain fits into this, and how composability works when you're composing a frontend with maybe a smart contract. So there's not going to be any slides here. I'm just going to be walking through an actual code demo, because I think that's going to be the easiest way to understand what's going on here. I think when it comes to this talk of micro frontends and micro backends, or microservices, then you get into this world where you have a bunch of boxes and lines pointing together with boxes, and it's like, wait, what is actually happening here?
00:02:03 - Anthony Campolo
I want to actually show what it's like to work with this stuff. What is the code really doing? What we're going to do is deploy a smart contract, then query that smart contract, or read from that smart contract, from a React frontend. Then we're going to give ourselves the ability to write to that smart contract. So you can think of it like some basic CRUD functionality: create, read, update, delete.
00:02:29 - Anthony Campolo
Oh, you can't delete anything on the blockchain. It's just going to be create, read, update, and then we're going to deploy that to Edgio, everyone's favorite hosting provider. So I'm going to go ahead and share my screen here. And now we got that going, let's minimize that. I've already got a project set up for us here.
00:02:53 - Anthony Campolo
So all I've done is create a basic React app and haven't done anything else. The first thing we're going to do is install some dependencies. These dependencies include dotenv for our environment variables, Hardhat, which is our kind of CLI development environment. That's what's going to give us the ability to deploy the smart contract. Ethers is our client library that lets our frontend interact with the smart contract.
00:03:24 - Anthony Campolo
Because when we deploy the contract, there's going to be certain methods that we can read from it. You can kind of see here in the smart contract that we're going to get into. And then Hardhat Ethers, which is from the creators of Hardhat, and that's just the library to integrate the two together. When we deploy the contract, we can use some Ethers methods, and then the CLI for Layer0.
00:03:47 - Anthony Campolo
Layer0 being where we will deploy this. Let's go ahead and run that, and that's going to install all of our dependencies. We're then going to set up our project structure. When you create a Hardhat project, you have contracts, and then you have scripts, and our contract is going to be written in Solidity. Solidity is the programming language of the blockchain for Ethereum specifically, and then other EVM-compatible chains.
00:04:17 - Anthony Campolo
If you don't know anything about blockchain, or any of these words that I'm saying here, it's not super important. The main thing is that we have a blockchain that we're going to be able to deploy a program to, and that program can do any sort of arbitrary logic that you can think of. Then we're going to have a simple little contract that's going to be Hello World, we're then going to have a deployment script, and we're then going to have our Hardhat configuration. I've already set up our environment variables here, so I'm going to skip this step. But for our environment variables, we have an RPC URL, and that is how we're actually connecting to the blockchain itself.
00:05:04 - Anthony Campolo
And if you don't know what a blockchain is, I should probably give the blockchain kind of 101. For anyone who hasn't heard it before, blockchain is like a distributed database that lives on many people's computers all at once. So if you think of a Postgres database, it's kind of like that. It's not relational, but it's a way to store data and a way to interact with the data that's stored on it.
00:05:28 - Anthony Campolo
And the difference is that that database is saved on multiple people's computers all at once, and they're all synced together to have a shared state of the world. This is useful if you want to have something that we can all connect to, we can all interact with, that is not necessarily owned by any one person and is not easily tampered with, because it's on multiple different computers. It's decentralized. And so this is why what we're building is called a dApp, a decentralized app, because we're interacting with a decentralized network of computers. If you want to know more about that, the philosophy and history of blockchain, there's a ton of material out there, but for this talk, we're going to be more focused.
00:06:14 - Anthony Campolo
So just looking at, like, how do you actually do this stuff? The last thing I did here was add our env key to our gitignore, because this has private information: our RPC URL and then our private key for our crypto wallet. We'll look at the crypto wallet in a little bit. So this is our smart contract, and what's happening here is we have a variable which is just called hello message.
00:06:45 - Anthony Campolo
And so this is pretty comprehensible. If you've ever done any sort of programming language before where you've worked with objects and constructors, this should be fairly comprehensible. Here we have a variable, the hello message, and then we have a constructor that will set the hello message when we deploy the contract. So when we deploy the contract, we're going to feed in a message, and that's going to be the variable that's saved in the contract state. We then have two functions.
00:07:16 - Anthony Campolo
We have a hello function, and the hello function just reads back the hello message. So it's going to have a message that's going to say hello from something, and when you read that message, you trigger the hello function, and then it reads back that hello message variable. And then since we also said this is going to have updating functionality and creating functionality, we have the set hello function. The set function is what will allow us to change that message.
00:07:46 - Anthony Campolo
So when we first deploy it, we're going to pass in a message into the constructor that will set it. But then if we want to change it at any point, we can run the set hello function, and that will allow us to change that message by setting the message that we pass in to the hello message variable. So the underscore is for any time we're passing in a new message, or passing in the first message to set. And then whatever we pass into it will be set to the canonical variable, which is the hello message variable.
00:08:20 - Anthony Campolo
So go ahead and save that. Then the other thing we have is our deployment script. Our deployment script will have an Ethers method, which is get contract factory. What this is doing is taking our contract, which is HelloWorld.sol, and instantiating that contract. By instantiating the contract, we can then deploy it and pass in a message.
00:08:49 - Anthony Campolo
So this was the message here that I was talking about setting through the constructor. This will be the message that we will set to that hello message variable. We'll say, "Hello from Composability Summit." Then we actually run that deployed method, which deploys the contract itself, and we will get some information logged out, including the contract's address and then the signer's key as well. All right, now we have that.
00:09:23 - Anthony Campolo
We only have one other file that we will need to actually deploy our contract. Here we have just a couple things. In our config, we have the version of Solidity, which we set up here, 0.8.6. We also have where we want the artifacts to go.
00:09:48 - Anthony Campolo
What this is, is something called an application binary interface. It's a fancy term, but it just means that we're going to generate basically an API for our smart contract. And that API is going to correspond to these methods, the hello method and the set hello method, and there's going to be basically a big old JSON file that's going to specify exactly what the contract can do and how you can interact with the contract. When we do that, it's going to take that big JSON blob and stick it in our project. So we want it to go into our src, because that's where our React app is that we generated.
00:10:28 - Anthony Campolo
And then finally we have the actual network that we're deploying to. This is because there are multiple different blockchains. When you're doing this, you can deploy this exact same contract to the Ethereum blockchain if you wanted to. We're going to be doing it to the Avalanche blockchain. If you want to know the difference between Ethereum and Avalanche, that's a long rabbit hole to go down.
00:10:48 - Anthony Campolo
But the most important thing is that Avalanche is a newer, more scalable, more environmentally friendly, and faster and cheaper blockchain that basically does exactly what Ethereum does. So that's why I'm a big fan of it and I like building on it. And the way we're going to connect to it is with our QuickNode URL. Just so you know, QuickNode is a blockchain company that I work for, so that is why I'll be using that in particular. But there are other ways to do this.
00:11:22 - Anthony Campolo
There's plenty of other RPC node providers as well, so that is just the way I will be doing it. And then we also have our private key, which is for our wallet. In particular, we will be using MetaMask right here. All right, now that is our actual contract stuff.
00:11:44 - Anthony Campolo
And so this is why I say this is all composable, because the contract itself is decoupled from our frontend. Now, the frontend itself is going to be a React app, but it doesn't have to be a React app. It could be any app that you want. Here we just have a basic React app with state that's going to be a hello variable and then a set hello value, basically a setter. And we're going to run the fetch hello function.
00:12:21 - Anthony Campolo
And what this is going to do is take in the information for our contract, which includes our API and then our provider, which is how it knows to connect to MetaMask, our specific wallet that we'll be using. Then we run a try-catch, which runs the hello method on the contract, which is what is set here. So that is now a function that we can just call in JavaScript because of our ABI. Then we will set the result of that function to a variable called data, and that will contain the message of our contract, the hello message variable. Then we'll run set hello value to set that message to the state.
00:13:13 - Anthony Campolo
And once we've done that, then we can just display it as a variable here in our div. And the way we run it is by running this button, which has an onClick, and that runs fetchHello. So this is kind of your React useState 101. If you've never done React before, then you're probably like, what is happening here?
00:13:32 - Anthony Campolo
But if you have done React, then this should be fairly comprehensible. The only thing we need to do here is insert our actual contract address, which we don't have yet because we have not deployed our contract yet. Now to deploy our contract, we're going to run yarn hardhat compile. That's going to take the contract and create all of our important bits and pieces, including the application binary interface. We now have this here if we want to see what I've been talking about this whole time.
00:14:04 - Anthony Campolo
This ABI. This is the ABI. So this is our big old JSON blob that has things like hello and setHello. But this is not yet an actual contract on the blockchain because we have not deployed it to the chain. We do that by running the deploy script and then telling it what network we want to deploy to specifically.
00:14:28 - Anthony Campolo
So Fuji is the Avalanche testnet, and the reason why we're using a testnet is because we want to be able to create this project and interact with it without having to pay any money. Because if you're actually doing this on Ethereum mainnet or Avalanche mainnet, then every time you run the setter, every time you set the hello message, that is going to say, hey, you need to pay a little bit of gas fee to do this. That's because computers aren't free, so you can't use the network necessarily for free unless you're using the testnet. The testnet you can do whatever you want with and you don't have to pay anything. So we're going to run this, and then it's going to log out this contract here.
00:15:10 - Anthony Campolo
And then if we want to see that this contract is actually live, we can check it out here on Avalanche Snowtrace. So this is like Etherscan if you've ever done this before. We can actually see our contract living on the blockchain itself. We can see it was deployed 36 seconds ago, and we can see my wallet address there that deployed it. So it is there, it is live, and we can now interact with it in our React app by including it right here in our contract address.
00:15:47 - Anthony Campolo
Now that we've done all that, we can kick open our development server, and here we will see this, and it will let us actually see the message by clicking, "Hello from Composability Summit." That was the message that we fed in here in our deployment script, which then set it to the hello message variable, which then we read out in our state by running contract.hello and then feeding it into our actual component here. So that's all cool, but you're thinking, wait, how do I write to it, though? That is where our set hello function comes in. So the set hello function we'll put right here under our fetch hello.
00:16:35 - Anthony Campolo
And it's very similar to the other function we created, the only difference being that we're also now including the signer, because when we change the message, we have to sign it with our wallet. That way, every time it's changed, there's a history and a ledger that basically says, hey, this was changed from this to this, and it was done by this person's wallet. Then we will run the set hello method on the contract and give it the current hello variable. And then the way we actually feed that into the React app is with an input and a button. So the input will give us a target, which will set the value to the event, and then it'll set that to the hello value, and it will be triggered by this button, which has an onClick for the set hello function.
00:17:36 - Anthony Campolo
So now we got all that. Let's go back here. Now we see all that. If we actually open up our developer tools, we can see here that every time we click the button or change it, it's going to give us this message, which lets us know that we're setting the variable to this message. And also it'll give us the contract address as well.
00:18:05 - Anthony Campolo
So let's change this to "Hello from AJC Webdev." That's me. That's going to say, hey, you need to confirm this transaction and you need to sign it. So we're going to confirm it. And now we will sit and wait patiently as this goes through, because one thing that you need to know about blockchain is that, because it is a huge distributed network of multiple computers talking to each other simultaneously, that means that they have to agree on the state, and that requires a little bit of time. So always be patient when working with blockchains.
00:18:42 - Anthony Campolo
But now we see here we got our new message. So if we refresh the page and click again, then we get this new message. All right, so that's pretty exciting. But right now we just have a project living on our computer. We don't have an actual website yet, or a dApp.
00:19:00 - Anthony Campolo
So the way we do that is with this sweet Layer0 init command. What this is going to do is allow us to configure our project to run on Layer0's servers, or Edgio. And now we have this. We need to give it a website.
00:19:19 - Anthony Campolo
I'm going to set it to one that I've already been using here, and that is going to configure our project to work with their platform. Now we're going to grab this chunk of code here to configure the router. This is because we are basically using a single-page application setup. So we need to let it know where it needs to spit out the actual project and where to read it from. So we're telling it to basically take a look at our index.html file, and then we're going to run our yarn build, and this is going to build our whole project into a static bundle.
00:20:04 - Anthony Campolo
And then we will be able to deploy this bundle to Layer0's servers. Once we have done that, we'll have the exact same project, but instead of on our localhost, it will be living on an actual URL that others can visit and interact with. So anyone who has a MetaMask wallet configured for Avalanche could also interact with this contract and change the message if they are so inclined. So after you watch this, you can go check out the contract yourself and play around with it. All right, let's close out some windows here.
00:20:47 - Anthony Campolo
All right, great. So this should be good to go now. Let's open it up. Here is our project. We see the last message that we set.
00:20:58 - Anthony Campolo
Hello from AJC Web Dev. Let's say hello from Edgio. It will ask us again to confirm this transaction. We'll go ahead and confirm. Then this will, in due time, give us the new message, and then that will be the entire demo.
00:21:21 - Anthony Campolo
Hopefully this gives you a bit of an idea of what we mean when we say Web3 is Jamstack by default, or Web3 is composable. Because as you see here, we have this contract, and the contract is completely decoupled from our frontend. We can interact with this contract however we want. If you wanted to just send straight RPC methods to it to get this message back, you could do that.
00:21:43 - Anthony Campolo
You could do that from curl, you could do it from lots of different libraries. I just used Ethers.js, because it's one that I'm familiar with. But you could do it with a Ruby library if you wanted to. You could do it in any programming language you can possibly think of.
00:21:57 - Anthony Campolo
So this is really the composability dream here, because we want to have all the pieces of our application separate. We want to have our concerns separated, and this gives us the ability to have a contract that has all of the functionality, has the API methods, and has the data living on it. But then we also have a frontend client that can connect to it, and your frontend client can be however you want to set that up. Thank you so much for watching my presentation. Really appreciate it.
00:22:27 - Anthony Campolo
And if you want to learn more, check out quicknode.com. If you want to get in contact with me, I'm AJC Webdev on Twitter and GitHub, and pretty much anywhere on the internet. We do a lot of content like this. If this is something you found interesting and you want to learn more, you can check out QuickNode HQ on Twitch, where I do regular live streams to walk through stuff like this and also bring on guests.
00:22:53 - Anthony Campolo
And I'm sure we'll have some Edgio folks on soon to learn a little bit about how to make this platform really work well for Web3. Thank you so much for watching, and hope to see you soon.