This tutorial demonstrates how to build a censorship-resistant on-chain blog using a combination of Hardhat for smart contract development, Next.js for the frontend, IPFS for decentralized content storage, and The Graph for flexible data querying, showcasing how these technologies together enable permanent, immutable applications that remain accessible as long as the underlying network operates.
Full Stack Web3 Development: Tools, Protocols, and Frameworks
Added:hello and welcome to the complete guide to full stack web3 development today we want to cover all the tools and technologies that you need to get up and running as a developer in web3 some of the tools and technologies that we'll be implementing and using are hard hat polygon ipfs solidity and nexjs we'll also be deploying our smart contracts into the graph protocol to build out a more flexible api and then on top of that at the end of the project we'll deploy our code to radical which is a decentralized git hosting protocol this tutorial will follow along with my written guide that's also by the same name the complete guide to full stack web3 development that i will also link below in the notes the code base and everything you need to know is copy and paste and i will try to keep it up to date as the different technologies change in the future so i would say that if you run into any errors definitely check out the code that i have written in this actual tutorial because it might be more up to date the application that we're going to be building is an on-chain blog that looks something like this this app will allow us to create posts upload the metadata to ipfs and then anchor the hash to each post on chang giving us a permanent and immutable and censorship resistant blog that should stay up as long as the network is up this is really interesting because we can just pay for a transaction and then we don't have to pay any hosting fees after the transaction is on chain our application and our blog should continue to run now this may or may not be the best use case for this type of technology though i think it is kind of interesting but i think the real power and the real value here is by the end of this tutorial putting all these things together should open your mind and give you a good feeling of how you might actually implement these technologies to build out your own ideas one prerequisite for this tutorial is to have the latest version of node.js installed so i would recommend having 16.14.0 or later and one great way to install node.js in my opinion is using nvm or node version manager this allows you to create and update and move between different versions of node.js very easily with that being said we'll go ahead and open our terminal and get started writing some code the first thing we'll do is use npx to create a new next.js app next we'll change into the new directory and we'll go ahead and install our dependencies and you can use yarn npm or pnpm or whatever your favorite version of a package manager is so i'm going to say yarn add and here i'm just going to go ahead and paste in all the different dependencies and i'll kind of walk through some of these really quickly so ethers.js is going to be the client library but also we're going to be using this in our test to interact with the network a hard hat is going to be the development environment and these next few dependencies in the second row account are supporting the different things that we're going to be needing to do with hard hat we'll also be installing web3 model and wallet connect these are really nice libraries that allow us to interact with the user's wallet and their identity we're going to be having a markdown editor for writing our blog posts so react markdown easy markdown editor give us both a markdown editor as well as a way to render our markdown in a react application and also react simple markdown editor is going to be providing us with some css to support those previous libraries we're going to be installing ipfs http client to interact with the ipfs network we're going to be installing emotion css for our ability to create styling in our application css and js library and then we're going to be open installing open zeppelin contracts to provide us with some helper functionality that we're going to be using in our smart contract all right now that we have our dependencies installed we want to go ahead and initialize our solidity development environment using hardhat so i should be able to run npx hardhat now what we're going to notice here is that we might have an error because if there is already a readme file the new version of a hard hat doesn't like that and they like to create their own and there is no way to override that so if we run this command and we go ahead and accept these we might get this error so what we might want to do now is just go ahead and just remove readme dot md and then try mpx hard hat again and here we're going to go ahead and choose the basic sample project the project root will be where we're at and then we'll add a git ignore and what should happen now is we should now see we have a contracts directory we also have a couple of other things like tests that was created for us and the script that was created for us so i'm gonna go ahead and open up our project in our text editor i'm using this code command for vs code and this is just kind of like a shortcut for me to be able to open my text editor whenever i'd like a lot of people ask me what vs code theme i'm using this is cyberpunk so you can just kind of like search for that in the um you know the s code i would say like store or whatever they call that um so what i want to do is go ahead and configure our hard hat configuration and this is going to allow us to go ahead and set up the networks that we want to deploy to so um i don't really need some of this code here or these comments so i'm just going to delete that to kind of make this a little more concise the one thing we want to go ahead and set up is a configuration for the local network that we're going to be working with so we can do that by passing in a networks object and the first thing that we're going to configure is hardhat and we're going to set the chain id as 1337. the reason that we're doing that is we're going to be using metamask and i believe by default the localhost of metamask has this chain id so that's kind of why we need to set that we also want to configure a couple of networks we're going to be working with polygon so i might go ahead and configure a couple of these network configurations though i don't think we're going to be deploying to mumbai we will be deploying to polygon so here i'm going to just comment these out because we have to set these environment variables or else this won't work so for now i'm just coming and commenting it out until we do that but for polygon i'm just setting the url for the rpc node that we're going to be interacting with and and then setting an array of accounts that will be read off of an environment variable later on and i'm just leaving those commented out for now because we're going to first deploy to the actual local test network so that is configured and i'm going to close that the next thing we're going to do is we're going to go ahead and open our styles our globals.css and here we're going to go ahead and configure a couple of different styles that are going to be for our markdown editor because we want to render our our actual blog post in markdown and we want to kind of like configure some generic styles that are just going to kind of make it look a little nicer so i'm going to go ahead and start with this dot easymdecontainer.editor toolbar and remove the border there i'm going to add for this dot easymde container.codmirror we're going to set the border to none as well and the background to none and again all this code should be able for you to copy and paste out of the tutorial out of the written tutorial so for the editor preview we want to set the background color to white we're just kind of overriding some of the defaults that are part of this to kind of go with our theme that we're going to be working with um this is a pretty long one right here and um we want to enable a background color of transparent for the editor or i'm sorry for the renderer i believe and and then finally we want to set the pre which is going to be for our code so if we kind of like write some markdown and we implement code we want to set the background color to this really light color and then for our block quote we want to override the default styles and we want to add a border left a padding left and remove the margin that is there by default so those are just some really basic styles to override the markdown editor styles that we'd get out of the box so i'll go ahead and save that and now we're going to go ahead and write our smart contract so the smart contract that we're going to write is going to go into this contracts folder and i'm just going to rename this greeter to something like blog.sol and i will go ahead and remove this code and we'll say contract blog and then we should be ready to go and i'm also going to go ahead and import something from the open zeppelin contracts we're going to use a utility called counters and this is just a good way for us to implement an incremental counter that will allow us to kind of keep up with indexes and stuff like that so the first two variables that we want to set in our contract are going to be the name and the owner of the contract so when we deploy this we're going to set both of these values and we'll also have a function that will allow the person to update the name at a later time we'll go ahead now and set a variable for our counter so we're going to say using counters for counters.counter we want to say we want a variable called underscore post ids and this is going to be a counter so we can call these methods on post ids like increment and decrement we're going to next go ahead and set up a struct for our post so our post is going to be what we're going to allow the user to kind of create as a blog post so the values that we're going to be setting are a post id a title a content and a published boolean the content is going to be the ipfs hash of where the post has been stored the title will be something that will allow the user to update and then the id will just be the id the publish boolean is going to be a way for us to do kind of like a way to show and hide posts that are published or not published so let's say maybe we're kind of iterating on a post and we don't want it to be published we can go ahead and kind of set that to be uh true or false all right so the next two things that we want to set up are a couple of mappings so we want to be able to have these lookups you could think of them as for us to be able to find a post using the post id or the hash to where it was published on ipfs and we're going to be having um we're going to be needing both of those lookups based on how the smart contract is written so you could think of these as like an object or something like that if you've ever or a map or something like that in another language if you've never really dealt with those before next we're going to go ahead and define a couple of events maybe these aren't that important for what we're doing because we're not going to actually be implementing the events themselves on our front end but let's say that we wanted to do something like um what we're going to be actually using these for is when we deploy to the graph protocol we want to be able to listen for new post creation and new posts being updated and kind of update our subgraph so you can use these events there but you can also actually listen to these on the client if you want to kind of keep up with updates as they're happening on the smart contract so that's kind of all the basic variables we want to get set up next we'll go ahead and set our constructor so for the constructor the only thing we'll be passing in is the name we're going to go ahead and set the name as the name that's passed in to the constructor and then we're going to set the owner as message.sender which is going to be the person that deploys this contract and we're going to go ahead and also have a function to update the name so update name will just allow the user to update the name this isn't probably like the most important thing right we're probably not going to be reading the name from the smart contract but it's pretty cool just to maybe have it set up that way we're going to have a transfer ownership function and the transfer ownership function is going to take in the address of the new owner and we're going to have this only owner identifier that we're going to go ahead and create now and this will just say okay only the [Music] owner can call this can call this because obviously we don't want just a random person doing that so we'll go ahead and create this modifier and this modifier will require the message.center to be the owner and then now we can basically have this transfer ownership function work properly all right so the next function that we'll implement is the fetch posts or fetch post function this is a very basic function that's just going to allow us to fetch a single post by hash so we're going to be using that hash to post lookup that we created a moment ago and this will just return a single post based on the hash that it was deployed to next we're going to have the actual function for creating a new post this is uh you know probably the largest function that we've created so far so create posts will take in a title and a hash and um we have this only owner modifier there as well if you wanted to be the if you want this to be completely like permissionless or i would say open like allow anyone to different to create a post or whatever and then maybe you would use something like the graph to filter for a certain user or something like that then you would just remove this and then this would be a public blog meaning anyone could probably update it and then you might keep that only owner for updating a post but uh but but the way that we're writing this contract means only the person that deployed this will be able to use it so we're gonna increment the post ids so we're starting off with that post ids set to zero so the first post will have a post id of one and then the second one of two and then every time a new post is created we're kind of like incrementing we go ahead and set a variable for the post id we create a new uh post using that struct that we created earlier and all the values here by default will be null and then we'll go ahead and set those values onto that post and then finally we'll go ahead and set the hash to post lookup or the hash to post mapping you could call it is what kind of we call in solidity to that actual post and then we'll admit this post created event and every time a new post is created this event will fire and that's kind of the whole idea um the next function we want is now that we have create posts we also want to have update post and update post is going to take in the post id the title the hash and the published boolean um so when we call update post we can go ahead and you know set all those values on the posts so the first thing that we'll do is we'll go ahead and look up the post using the post id we'll set the title the publish the content all those different values and then we will update both the the mapping or the lookup for the id to post as well as the hash to post and then we'll omit that event for a post being updated the last function that we need for our contract is just a way to fetch all these posts because if we're creating them we want to query for those or i would say just read those because we don't really have a true query capability until we use something like the graph so this fetch post function will just um first of all we want for solidity you have to you can't have like dynamically sized arrays you need to know the exact size of that array so we can just find out the size of that array by using this item count variable and we know that that will be the number of posts that are created because we've been iterating and incrementing that every time a new one's been created so what we do is then we loop through the all the posts and we create a new array called posts here and then we return those posts and then uh when we call this function it'll just return all those posts to us so with that being said we should be able to go ahead and test this out so we should go to tests slash sample test and we're going to go ahead and say describe blog and we're going to create a couple of different tests in here and we're also going to delete this code here so the first test that we're going to create is to see that it should create a post so we're going to go ahead and deploy the blog we're going to go ahead and create a post and then we're going to fetch posts and we're going to expect the first item in that array the title to equal my first post so that's pretty straightforward we should be able to also edit a post so here we're going to um create and deploy the the blog we're going to create a post we're going to update the post and then we're going to expect the updated title to equal the updated title so we're going to create the title as my second post and uh the updated title will be my updated post and then finally we will just test out that we can update the blog name so um the main thing happening here is that we're gonna call blog.updatename and then we're going to expect the new name to be my new blog as opposed to my blog all right so with that being said we should be able to go ahead and test this out by going to our terminal and running npx hard hats test and if this test is successful then we should get some output here and looks like everything is passing which is great so our test is working that means our smart contract is working now let's go ahead and deploy that contract to the local network so to deploy the network we need to go ahead and create a network so the great thing about hardhat is it comes built in with some really great tooling for this so to create a local ethereum node all we need to do is run npx hard hat node and this should go ahead and create a nice ethereum node for us and here we have this local network running and all these different private keys and accounts that have been created for us obviously there's a nice warning here that these are publicly known so never actually use these for real value we're just going to be using these for testing purposes and stuff like that so what we might want to do now is to go ahead and import one of these accounts into our metamask and we want to import account number zero because this is going to be by default the account that our project is deployed to unless we specify a different account so what we can do is copy this private key and we can go to our meta mask wallet here and we can go to import account and i can type in or paste in the private key and now we have this account that's been imported for us and um we can now go ahead and use this and what we're going to basically do now is we need to go ahead and switch to the test network but we don't really have that showing up yet so before we cannot do anything we need to to do that so what we can do is we can go to settings and go to advanced and we can go to show test networks and if that worked then we should be able to go back here and see that we have localhost and we should be able to go ahead and switch to localhost all right so great we see that we have ten thousand each and we're on localhost now we can go ahead and deploy and the way that we're gonna do that is we need to first update our deploy script so what i'm going to do is open up the scripts we're going to go to sample script and rename this to deploy and we'll go ahead and maybe delete a lot of this boilerplate code all right cool so instead of saying const greeter we want to deploy our blog so we could say blog and then we could just say blog because this is going to look for the name of this contract which is blog and then we can call this blog we can say blog.deploy and we need to paste you know set the name of our blog so i could just say my web3 blog or something like that and then we can wait for the blog to be deployed and then this will go ahead and log out the address now it would be nice to actually have the address of both the blog as well as the user creating this blog to have that information saved to a file locally because we're going to use that later so what we can do is actually import fs which is i think it's like file service from node.js and this will give us some apis to write to the local file system actually might be file system so we can say fs.write file sync we can create the name of the file which we want to write to so here we want to write to a new file called config.js and we want to save locally both the contract address as well as the owner address we're going to be doing some user interface stuff where we're going to check to see if the currently signed in user is the user that created this this blog so having that created and written locally to us is really nice so this is just a way to do that we can do that with the blog address and the blog signer address so this will go ahead and create a new file called config.js when we deploy so we have this deploy script and we can go ahead and deploy this now by running npx hard hat run scripts slash deploy.js and then i might just jump to a new line here and i'll say dash network localhost and if this deploys correctly then we should see a couple of things first of all we should see that we have a little bit of eth gone out of our wallet and there we go we see that we have now instead of ten thousand we have 99.99.9988 um so that's great we show we also should see that new config.js file so here we have the contract address as well as the owner address that was written to the files so that's great and we're going to be kind of needing to use that in just a moment so the fact that we have it already you know set up for us is great so i'm gonna go ahead and close those two files and we can go now to the next steps and we're gonna go ahead and start creating some code for our next js app our front end application so um one thing that we're going to be needing to do is switch between a few different environments so we want to deploy to the well we've actually already deployed to the local network but we also might want to deploy to a live test network as well as the main network and we're going to be needing to configure some rpc endpoints so the to way that i'm going to do that is just to have this.env.lo file set up and this is going to allow us to kind of set up a couple of environment variables and by default starting off we're going to start with the environment being local meaning we're kind of working with localhost in addition to that we want to have a couple of svgs that we're going to be using for our front end so the sgv svgs that we're going to be using are going to be ways for us to kind of like have a nice image so if i go to the complete guide to full stack web3 development and i go down to if i find the svg we'll have like this logo.svg and rightarrow.svg so what i need to do is create a folder i'm sorry go into the public folder and create two files logo.svg and just copy this svg so i'm going to go to public logo.svg paste this code in there and then i also want to go to write dash arrow.svg and paste in the code there all right and we're good to go so we have our our logos for our front end and the icons and stuff and we can now continue out and write some code so and uh we're gonna we're gonna be obviously writing react since we're using next.js and we're gonna need a way to share um i would say state throughout our application there's a couple ways to do this in a react application the best way in my opinion is using context so we're going to go ahead and create a file called context.js and the root of our app and this is going to hold a context that we're going to be using to share our account information throughout our application so i can import this function or this helper or this utility called create context from react and then i'm going to go ahead and create some account context and it's going to be by default set to null and then later on we're going to be actually you know updating that and sharing that throughout our application so now that we have that set up we can go ahead and close this and we'll go to underscore app.js in the pages directory and we're going to go ahead and set up a couple of things first of all we're going to set up our navigation and in addition to that we also want to go ahead and set up a button that allows the user to connect their wallet and this is going to be quite a big file we're going to be doing a lot of imports so i'll go ahead and probably start by just deleting everything and now we can go ahead and just drop in our imports so we have a couple of styles going on here so we have this styles slash globals.css as well as this easy markdown editor uh styling so app.js is kind of like the entry point to your application and it also kind of contains where the components that are going to be rendered are displayed and this is often kind of like where you put your navigation and any global imports that you need so that's kind of why we're doing those imports here i will go back here at the top though and we're going to be importing use state from react for managing local state we're going to be importing the link component from next link and this will allow us to create links between pages we're importing the css prop from emotion or this is maybe like the css api from emotion allowing us to create styles using emotion we're importing the ethers library from ethersjs we're importing web3 modal which is going to allow us to have an easy way to get the user's wallet using that library along with wallet connect provider from a wallet connect and wallet connect essentially allows the user to choose different wallets other than metamask and you often see web3 modal and wallet connect used together we're going to import the account context from context and this is going to be how we manage and update the address of the sign in user and pass that information around the application we're importing the owner address this is going to be the address of the owner that deployed this contract so this may or may not be the same as the sign in user so with that being said we'll go ahead and now create a function called app and you know when we deleted that code when we open this file there was a couple of arguments passed in here the component and the page props this is kind of how next.js allows you to render or use underscrap.js is kind of like this container for the rest of your application so um now we have this very you know empty component so let's go ahead and start by creating some local state first of all we want to set the account variable for the user that is currently signed in so when the user clicks the button to connect and we connect their wallet then we'll be calling that set account function that will update this account variable and by default we're setting it to null we're also going to have a function called get web3 modal and this is going to be nice because this will just be a way for us to create a new instance of web through modal and then return it we're setting a couple of default options like we're setting the cache provider and we have this provider options that allows us to configure wallet connect and if you want to use wallet connect you need to set your inferior id so maybe that's a good time for us to go ahead and check that out so i'm going to go to infura and i'm going to go to dashboard and here i have already created a new project i could have just clicked there but we have this full stack web3 project i can go to project settings and i can go ahead and copy this project id and don't worry after this tutorial i'll go ahead and delete that but that's we're going to do here and inferior also gives you a couple of different endpoints and we're going to be using the polygon main net endpoint later on so with that being said that's our get web3 modal function and now we're going to have the connect function which is what calls this function and gets the instance so this is going to be the button that we're going to be using to allow the user to kind of authenticate and this is the function that's going to be attached that button and the first thing we do is we get the web3 modal we connect we create a provider using ethersjs we get the accounts and then we get the first item in that array of accounts which will be the sign in user and then we call set account passing in that account and this will go ahead and set that local state and then that is about all the functionality we have here as far as functions are concerned we now just want to return our ui and here we're going to start off with a div and some nav so this is a very basic structure for us so far we have this nav and in the nav we're going to have a couple of different links so we're going to have a header and then we're going to have a couple of links below the header the header is going to be the image that svg that we created and also maybe like a title or something like that so let's go ahead and create that first in our nav so we'll go ahead and create a couple of links here in the header this first link is going to link using the uh logo that we you know uh used or created earlier with the svg so this is going to create a link for that and that will just go home so when the user clicks on the logo it just takes them back home and then we also have another link home to this title container that will say full stack web3 and we also are starting to be introduced to something new these class names we're going to be setting up the values of these class names in just a moment using emotion css but uh the nice thing about this is that we can kind of like just reference them here and then create them elsewhere usually i like to create them in the same file but you could obviously put that in a separate file the next thing we want to do is we want to check to see if the current user is signed in and if they are not we want to go ahead and say okay if the if there is no account meaning the user is not signed in we want to show a button and this button is going to call this connect function and this is going to allow the user to sign in essentially and then if we do have an account like if the user is signed in we just want to kind of like display their account number this is kind of similar to how you might say okay if the user is signed in we're going to like show their their username or something like that and instead we're kind of just showing their account number and below like the header we're going to have a couple of links so maybe a good way to kind of see how this would look is to go back to the complete guide to full stack ethereum development and find the images of the final application this is a lot of code i know okay here we go so yeah so what we've created so far is like this top part what we're going to now create are these two buttons here so we have like the the image and we have the account id and then next we're going to create the home and create post buttons and that's going to be in this like class called link container the first link that we're going to show is going to be a link just to go back home so it's going to link back to the root and we're going to say home and that's pretty much it and our nav doesn't have a lot of stuff the only other link that we're going to show is if that user is signed in and they are the person that created this blog then we give them the option to also create a post so the way that we do that is we're we're gonna check to see if the account that is signed in is equal to the owner address the owner address is that address that is the deployer of this contract and if that is the case then we're gonna show a button that says that they can create a post so that's about it the last thing we want to do is have our main container and this is going to be below the nav and this is going to be where we render our actual application so this is kind of like you know the nav is going to be outside and then this is going to render each page so we kind of navigate between pages uh everything above is going to stay the same and all of this stuff is going to or actually this stuff right here is going to change now we want to actually pass in the uh context for the currently signed in account and have that available and also re-rendered throughout the app so the the way that we're going to do that is using context so we have this accountcontext.provider and at first when the context was created the value was set to null but now that we have the value of the account we can now reset that by passing in the value here so when this value changes this will be updated and then the the child components you could think of are going to be re-rendered as well and then we're also passing in the connect function here as props so this way we can kind of call that connect function elsewhere um the last thing that we're going to do is go ahead and create all these css properties i'm not going to kind of walk through all of these i will walk through just one because the rest of these should be copy and paste but um just to kind of give you an idea of how the css prop works in a motion here we basically are just going to say you know some my variable or something like that is equal to css and then we have like this open and closed string and then within this string this is kind of where we set the values template strings or simple literals and then here we're able to just write straight up css so like a lot of times when you're writing css and javascript you'll say like you'll have to use this type of notation or you might even have to put that in like you know parentheses i'm sorry in quotes but the cool thing about emotion is that you can just write regular css and you also have the ability to do stuff like hover fx and um and all the different css stuff that you would want for um you know a non-trivial application so now that we have that done i'm just going to kind of copy and paste the rest of this css so we have this account info we have this container we have link container we have nav we have header description title container title button container we have our button style we have our link and then the last thing we want to do is make sure we have a default export so we want to say export default app and that is going to be that should resemble the name of this component here all right so that was a lot but um hopefully we you know got all that stuff right again i think all this stuff should be copy and paste so with that being said um we can now go on to our next component and then maybe after we create this component we can consider uh testing it out or something like that before we continue writing the rest of the code so right now the only page that we have is index.js and this is going to be kind of like the home page so it might make sense for us to go ahead and edit that so i'm going to start off by deleting everything again and we're going to start with our imports and a lot of these are going to be the same so we're importing css from motion we're importing use context from react which is actually new we haven't used use context use context is a helper that allows us to extract the context that was set from the actual previous component we're going to be importing use router from next router and this is a api from next.js that allows us to do stuff with routing so you might use use router to navigate programmatically or you might use use router to read properties off of the actual url and things like that i think we're going to be using it to route programmatically um let's see how we're going to use it actually yep we're going to use it to do that okay so we have also the link component which we've already used and we have that account context which we've already used the next thing we're going to do is um we're going to go ahead and import the contract address and the owner address from the configuration so we you know again had this config that was written to the file system when we deployed so we just want to kind of like get access to those uh the next thing we want to do is import our abi so when we deployed this we actually had an artifacts folder that was created for us and here we have what's known as the abi or the application binary interface and you can think of this as kind of like the contract interface for us to talk to the network and if you've ever used something like graphql you have something like a graphql query that you have to pass in along with the http request you can think of that as something like this it describes all the things kind of happening your smart contract but we need the abi because this is how the ethers library connects and understands like the different functionality available in your smart contract and you can either run npx hard hat compile to just compile this every time your contract changes or when you deploy it should also do that so here you should see under we have artifacts slash contracts slash blog dot soul slash blog.json you don't really need to know what's going on here but just know that that's what we're importing and we're going to be using that with ethers.js to basically talk to our uh to the network so next we're going to go ahead and create a default component called home and this will have a props component i'm sorry a props property that we're going to be passing in as the argument there and this these are going to be the props that are going to be fetched when this application is rendered and the props are going to be the data that the network is going to return when we call fetch posts because like the main i would say page for our application is just going to list all of our posts and we're going to be using next.js server side rendering to go ahead and fetch those so um we're going to be fetching them on the server and maybe we'll go ahead and like create that function that does that so we have this like get server side props function and then we like return like you know array of posts or whatever like this isn't actually the api but whatever we return uh you know it's going to be the props that we return are going to be kind of available there so we'll write that code in just a moment um there's not going to be a ton going on here so here we're going to go ahead and destructure the posts off of the props and this should be an array and it should be an empty array if there are no posts and if there are posts it should be an array with some details there we're going to then get the account of the signed in user from cons from the context we're going to get a reference to the router and then we're going to create a function called navigate that's going to allow us to go to uh slash create post because what we basically want to do here is like if we have posts we want to render those posts obviously but the first time you run the application you're not going to have any posts because no posts have been created yet so we might want to just have a button that says okay there's no post created if you are the user that created this this application then um we want to have a button that allows you to create your first post the next thing we want to do is just go ahead and have our user interface here so we'll go ahead and return a div and then we can go ahead and create our content here so the first div that we want to create is our array of posts so i will go ahead and say okay we want to render our array of posts and i will give that a class name of post list and then here we can basically say posts dot map okay there we go yeah we want to just basically return something so that could be that but obviously it's not going to be that so for every post we want to render like a link to kind of view that post so one way that we could do that is basically to render a link that looks something like this and the data coming back is going to be an array for each individual post so like the post itself will have an array and then the inside that array it's going to have the information about the posts so what we want to do is get the id of the hash and we want to kind of render a link to where we can kind of link to that and this will be more apparent actually later on after we go ahead and get the rest of this code written next with next link you actually need to render an anchor component you don't actually have to do this but i believe it's kind of like best practice and then within this anchor component is going to be the the ui that we want to render so here we're going to render a div and here we give like some styling we have a uh we want to render the post name so in this array that's being returned from our smart contract the third item here is like the hash or the i o of the actual content and then the second item which is the post one in the array is going to be the name so with that we should be able to go ahead and like render the you know each item that's in the array and we're going to have like a right arrow which is that svg that we created to kind of have a little bit of nice user interface that goes along with that i guess you could say so outside of that we also want to so so this is going to be us rendering the post lists but we also want to take into account the fact that there might not be a post list meaning that this application has not yet been created a post and the user that deployed this might want to go ahead and like create that we want to give them maybe some some user interface that shows them hey there's no post created so go ahead and create a post so what we want to do here is we want to go ahead and open these curly braces i want to say something like this if the account that is currently signed in is equal to the owner address and there are posts and the there are zero posts that have been created yet we want to kind of render this this button and this button is just going to like allow them to create their first post of course we'll also have this that navigation item that allows them to create a post but this is kind of maybe a little bit extra stuff that actually looks kind of nice so we have this button that says create your first post and then we have this image with the right arrow we also use that right arrow above with all of that being said that should be all that we need um we're going to create this git service.props but before we do that let's go ahead and drop in our styles we have quite a few again i highly recommend um you know it's good to type out stuff sometimes for sure but um i also recommend considering just copying pasting the styling the styles and stuff because it's just a lot so we have the arrow container we have post title we have link style we have post lists we have container we have button style then we have arrow we have small arrow okay so those are the styles that we're working with the last thing we want to do is we want to [Music] work with git server side props and this is going to be interesting because this is where we actually call the network to talk to the contract that we've deployed and to do that we need to have a provider and what we want to basically do now is detect depending on the network how we go ahead and set up this provider so if we are accessing the local hosts we can just call a json rpc provider if we're on test nat we want to set a specific uri and if we are on anything else we want to use the polygon mainnet and the two that we're going to be really working with today are going to be local and polygon mainnet but either way like this will just do some logic and of course this could be abstracted away a little better maybe you could put all this into a separate file and just import it but i thought because it's only being repeated a couple of times we would do it this way to be more clear since this is a tutorial next we're going to go ahead and create a variable called contract that's going to create a connection to our contract using the abi that we imported earlier the contract address and the provider there and then now we can actually talk to the contract so it's pretty simple here we can just call it contract.fetch posts this is going to return that array of posts and now we can return our props this is going to be uh an array of posts this will be an empty array if there are no posts created if there are posts created then it will show the posts that have been created so with that being said like this git server side props function should fire when this component is rendered and we should have these props passed in here now of course when we like run this if we run this now we're not going to have any posts so um you know that's something to keep into consideration so let's go ahead and try to run this now i'm not positive that this will work yet but let's go ahead and try it so we should be able to go uh npx i'm sorry yeah npm run dev and we should get a localhost 3000 all right looks like our user interface is indeed rendering and if we click connect we should be able to go ahead and cool connect to that account and there we go we have our create our first post button which is great because that means our authentication is working and it's recognized that we are indeed the user that created this uh deployed this contract so that's looking pretty nice so let's keep going so i'm gonna go back to my text editor and we want to have the component for creating a post so under pages we're going to create a new file called createposts.js and we'll start by grabbing our imports we've seen use state already we haven't seen use ref or use effect so this is new i would say that use effect is kind of like a life cycle hook for react meaning that we will be able to listen to when the component is loaded or or do different things based on when the component is loaded and used ref allows us to create a reference to different items that we're going to be needing to kind of like work around the default react apis so if we don't want to deal with some of the lifecycle stuff we can actually use use ref to do that it's a little bit beyond the scope of this but you'll see how this works in just a moment we're also using use router again whoops we're using dynamic from nextjet dynamic which is interesting because this is something i had to implement for this application in particular mainly because i noticed that one of the libraries that i'm using for this application which is the simple markdown editor does not work on the server it only works on the client which makes sense right because like you're using a markdown editor so basically what this allows you to do is dynamically import and you can specify that you don't want this to work on the server only on the client so only when it's ready we'll go ahead and import that on the client we're importing css from emotion again ether is from ether.js and we're importing this is actually new as well uh we're we're now for working with ipfshttpclient and we're going to use this create function that will allow us to create new items on ipfs we've used the contract address before so we're going to go ahead and import that again we've also imported the blog api before so we're doing that again and we're going to create an instance of the ipfs client by calling create and then passing in the ipfs endpoint that we want to work with and this is like a public endpoint that seems to work pretty well again like you might want to connect to your own ipfs endpoint i think you can do that with infuria and in different and a bunch of different other ways as well but for now we can probably use that and it should work next we're going to go ahead and create a reference to simple markdown editor by using this dynamic import and this is going to say okay we want to have this callback function as the first argument where we're going to import react simple markdown editor and then the configuration that we're we're interested in is setting ssr to false so this is going to allow us to use this simple markdown editor in a next.js app which by default uh doesn't work next we're going to go ahead and create an initial state object where the post title and the post content are both set to to an empty string and then finally we'll have our create post function and this is going to be our component and then we can say we want to have a default export of create post so let's go and do that before we forget all right so with that being said let's go ahead and create a few pieces of state the first pieces of state that we're going to create are going to be for our post and then this by default we're going to set the initial state to be this object we're going to create an image in a set image function which this is going to allow us to create a cover image so if we want to have a nice cover image like you see in a lot of different blogging platforms we're going to be able to set that with this function and then when we upload ipfs we can decide whether or not you know certain properties exist and we can just upload them using ipfs and json objects we also are going to create some loaded state some pretty basic loaded state this is going to allow us to do some stuff with how we have this weird stuff with this importing of simple markdown editor meaning like we might have some ui lag so what i want to do is kind of create a hack here and say okay um we only want to show certain things if this loaded boolean is true and then when the component loads we want to set a timeout to kind of try to time this and i'm going to use like 500 milliseconds because it seems to work pretty good and we're going to say like after the after this component loads after one half of a second we want to call set loaded and we want to set it to true and if you build this out you'll probably notice that if you remove this code that it looks kind of like it doesn't look that great and there probably are better workarounds than this but i think this is a fun you know way to kind of get around this for this tutorial all right so we have this loaded boolean um the next we want to create is an own change handler and this on-chain channeler will allow us to update the uh post content so we're going to have two form fields these form fields will allow the user to set the title and the content of the actual post and with that we can allow them to kind of do that um the next thing that we're going to do is have the functions for handling a file change as well as saving a post and saving a post to ipfs so i think the first thing we might want to do is go ahead and create the function for saving a post to ipfs so let's go ahead and create that so save post to ipfs is going to allow us to call client.ad and this is going to take the content that we have stored in our local state turn it into json upload it to ipfs and then it's going to return this path and then we can call this function whenever we want to save something to ipfs and we're going to be using this when we create a new post so we're going to now call we're going to now create a function called save post and then save posts is going to be called by a separate function called create new posts that will call both save posts to ipfs as well as save post and like hopefully after we write all this code it'll it won't be so confusing but basically this function is standalone just uploaded ipfs this function is standalone 2 taught to our smart contract so here we kind of check to make sure that the user is signed in we get a provider using the window.ethereum we create a signer we get a reference to the contract by using the contract address blog api and the signer and then we call contract.createpost passing in the post title and the hash that is coming in from uh from ipfs and again like the main idea here is we're like anchoring on updates and crea when we create a post we're also anchoring the hash for that post so using those two functions we can have our final function called create post and create posts is going to first check to see if there is a post title or post content it will then call save post ipfs and then we'll call save post passing in the hash that was returned from ipfs and then call router.push so we have all those but there's actually another function a couple of pieces of functionality we haven't talked about so how are we going to get this cover image uploaded well the way that we're going to do that is we're going to have a function that allows the user to upload a file and then when that file is uploaded we're going to save that file to ipfs and we're going to update the current local state for the post and we're going to set a cover image property here so using this handle file change function we can first get the file that's being uploaded off of the event by saying event.target.files the zeroth item out of that array we want to check to make sure that that exists because if they cancel then this will not exist and if it does exist we go ahead and up upload that to ipfs and then we update the current state with all the existing state so this will be the post title and the content and then we also add the cover image and the cover image is going to be the path for the ipfs hash and uh and then we call set image which is going to set the image locally so it can actually just render that and see what it looks like so with that being said we should be done now actually there's one more thing that we want to do and we we're using a ref here because we want to have a reference to a component that we want to trigger a click with without actually having to click directly on that and the reason that we're doing that is like when you're using a file input like an input like this it's really hard to style these file inputs so what a lot of times people do is they'll have like you know a button and then when you click the button the button triggers the file input and uh to be to be clicked and the way that you might do that is like using a ref and here we're going to be calling uh fileref.current.click and here we created that um did we create the ref oh we did not use to create the ref yet so let's go ahead and do that so here we're going to go ahead and say the file ref is going to be using use ref and we're going to start off with null and and then we should be able to use this in a couple of different ways um and then the last two things we want to do is we want to destructure the title and the content off of the post so we can just kind of like reference that from now on so here you see us like referencing the title and the content so the way that we're going to get that is we're going to destructure it here and then finally i think we're using the router here so in order to use that we want to go ahead and use use router to kind of get a an instance of the router so we have all that stuff set up now we can go ahead and create our user interface so to do that i'm just going to return all right so we're starting off with this class name of container uh the first thing we want to do is we want to say okay if there is a cover image we want to render that cover image so the way that we do that is we look and say okay if the image exists we want to go ahead and render that which is pretty pretty nice next we want to have a input for the user to type in the post title and we also want to have them the ability to create the post content so for the input we're setting the on change handler to be that on change function we created earlier but for the simple markdown editor um it's a little different so we don't need to deal with the event stuff with simplemde instead we can just get the value directly as a callback so in on change here we're getting the value and we're calling set post and we're setting the content as the value so when someone types in for the file i'm sorry for the form input for the title or for the markdown editor we're uploading we're updating that state and then finally we're going to use the loaded boolean that we created earlier and we want to say okay once this is loaded we want to show like these two buttons and one of the buttons is going to be to publish the blog post and the other button is going to be for adding the cover image and this is going to be calling this trigger on change so like how do we actually connect this to the ref for the file ref well we are going to now create one last component or one last html element i guess you could say and that's going to be this input so for the input we want to have some styling that's just going to basically hide this completely so this won't be visible at all this is going to be the button for for uh adding a cover image but we're going to basically be triggering this under the hood we're going to hide it and then when we want to trigger we just call this trigger on change function so one thing to note though is that like when we create a new post we're going to be re-routed back to the home screen so we have like this router.push so after we create a new post we uh we save the post we have like the save post function and then we reroute and then one last thing that you'll notice is that i have this commented out but we also have this function called await provider.wait for transaction and this is a way for you to actually wait for this transaction to process before rerouting this is kind of optional because like if you're working on a network like polygon which is fairly fast then it won't take very long for this to show up but let's say you wanted to wait to be rerouted until this transaction was was done then you might uncomment this and use this line of code i would say though like for working on a local host it's not really necessary because it's going to be instantaneous but you might consider this for when you deploy to the main network and then last thing that we're going to do is go ahead and get some of that styling done and this is a little less styling than what we've done in the past but still quite a bit so i'm going to start up here so we have this hidden input and this is this input so we're just basically saying display none because we don't want it to show up we have our cover image style and we're just setting a max width for that we have our markdown editor with some basic styling we have our title style we have our container button and that's it so i'm going to go ahead and save this and let's see if this actually renders so if i refresh and i connect i click create first post then we should see some nice user interface so now i should be able to test out this functionality so let's go ahead and give this a shot so i'll say hello world and i'm going to say this is my blog post all right i might add a cover image and let's go ahead and try to publish this all right there we go so we have our you know post creation stuff working if i refresh then we still see it show up but we see that we no longer have the nav item but if i connect then we can go back to create a post so we're getting there i think the next thing we want to do now is have the ability to like view a single post and then we want to have the ability to edit a post so let's go ahead and create a new folder called post and then here we want to have a new file called id.js and this is where we're going to be able to view a single post so like if i click on this post now we should see an error or something yeah because we don't really have a component there so we're going to go ahead and create that so um i'm going to go continue to go you know fairly quickly because we're kind of repeating some stuff but for the new stuff i'll definitely go in depth um we're inputting react react markdown for the first time this is going to be our markdown renderer so all we need to do is pass in a string of markdown and this will render our markdown which is pretty nice we're using use context again we're using use router again we're using next link again css ethers like all this stuff we've already used i will go ahead and import both the contract address and the owner address as well as the abi again we're going to be using that i'm going to set the ipfs uri there this is going to be something that we use to kind of like talk to ipfs i will create the post component here and the way that we called server side props or we were interacting with like some data fetching on the server for our index.js page we're going to be doing that similarly here so when this component is rendered we're going to have a function that's down here that's going to be called git static paths and also a function called get static props and to be quite honest like this isn't 100 necessary you could also do this data fetching on the client but you're going to see after we run and build how fast this is by doing it on the server but i get static pads and get static props are going to allow us to fetch first of all we're going to like fetch all the blog posts here and then we're going to like then pass each individual blog post will be passed here to create a single page for each post and then um each post will be passed in here and then we'll essentially have like the post dot id post like content whatever all this other stuff so that's kind of how this works so we're going to basically be getting that post as an argument there the next thing that we're going to do is in our post we're going to go ahead and get a reference to the current uh signed in account using context we're going to get a reference to the router and we're also going to use for the first time router.query and what this is going to do it's going to read the url here and it's going to say okay if we have like blah blah blah it's going to actually get that id off of there so it's going to assume that if we're at slash post slash id that the id is going to be the query value so then we can kind of uh we can reference that and we're going to also use this next.js specific thing called fallback route and this is a little bit advanced for me going into the details here but essentially if we run a build and then when someone creates a new post and you want to be able to continue rendering the new posts then you can use what's called a fallback route and this will basically recognize that that post hasn't been part of the build it will then fetch the data and then it will like wait for it to be returned and it will kind of show this loading indicator the next thing we'll do is go ahead and return our ui so we have div whoops all right so what we want to do is we want to say if the post exists we want to then render like our ui and stuff so i might do something like this so i'm unsure if we even need to have this check but let's let's stick with it for now because this is how i wrote my tutorial um next thing we're going to do is we're going to create a div to hold the post all right so we have that there and here we're going to go ahead and check to see if this is interesting because we want to allow the user to edit their posts right but we only want to allow the user to edit their posts if they created it so what we can now do is check to see if the owner address is equal to the account meaning that the user that is currently signed in is the owner and then we're going to render them a nice edit post button next we're going to check to see if there is a cover image and if there is go ahead and go back do that we're going to say like if there is a post cover image then we want to render that image and then finally there's only a few lines of code to render the markdown because simple uh react markdown editors is pretty nice so we're gonna have an h1 for the post title and then we're gonna say we want to have react markdown and for the content we're just gonna say post.content so that's all we need and now we need to work with these functions here um we're going to be doing something very similar to what we did earlier where we basically are going to check the environment variables that we have set up and we're going to create a provider based on what environment we're in and you know starting off we're going to be on the local host so we're going to be using this json rpc provider and we want to be able to switch networks as well later on and then we're going to call dot fetch post so we're going to get a reference to the contract that we want to interact with using the provider the contract address and the abi and we're going to call fetch posts now the next thing we're going to do is kind of like a little bit complex for um maybe this tutorial to kind of go into how next.js works but when we call getstatic or when git static props is invoked from git static paths expecting an object that looks kind of like this so it's expecting the object to have a params object with an id and this id needs to be like a number like one two three four five whatever so for us to do that we need to basically create an array of of these params and each array each item in the array needs to have this data structure so we're gonna just map over this data that came back from fetch posts and for each item we're going to create an object that has that data structure where we have a params object and then the id is going to be the id from this array that came back for each individual blog post item so each blog post you know post would be something like you know it would have like three items and then the third item is what we're passing in as the id so that might be a little complicated so don't worry about it just kind of like write the code if you're if you're not familiar with next gs again you could also do this data fetching on the client and it would probably make a little more sense to you but um you'd be kind of going around the reason why you would use next.js in the first place and then finally we want to return this array of paths and we also want to set that this is a fallback meaning that we want to implement this functionality for if we've run a build and we still want users to be able to continue to create posts which is a pretty nice piece of functionality so now we've we've created this get static pads functionality meaning we're going to fetch all the posts and we want to for every single item in the array of posts we want to create a new page and to create the page we're going to be using git static props and the params object is going to you know look like it's going to essentially have like um you know like an id whatever and this id is kind of what we're worried about so what we can do is just say okay we want to destructure the id off of the params and this is going to be the hash for ipfs so we can now say we can configure our ipfs url using that uri slash our hash and then this will allow us to then fetch the the information using the fetch api and we then call response.json because that's the way that the fetch api works we want to return the json from fetch and we then check to see if there is a cover image and if there is a cover image we want to go ahead and create the url uri or url for that and it's essentially going to be the same thing as as the response uri that we called ipfs with so it'll be like ipfs uri you know slash blah blah blah blah blah and then this will allow us to then render that in our um in our ui and we just have this object that is the data object that is essentially the post so like data will end up looking like the post with like an id cover image and whatever other metadata content whatever so we've uh we're kind of building up that that data so like we have the basic data and then if we have a cover image we update the cover image to be in the right format for us to use and then we just return a props object that has the posts set to the data and then again we should now be able to i'm just going to go back up here to say okay that post is coming in and this is where that post is coming from from all this functionality here and then the last thing we want to do is create a couple of pieces of styling for edit posts for cover image style for our container and for our content container so this is for viewing an individual post so um we should be able to go and test this functionality out as well so if i go here and i refresh and i click on hello world we see that this post has been rendered and if i click connect then i should see this edit post button now this is cool but if i click edit posts then this is going to break because we haven't created that page yet so let's go ahead and create that page so we're going to do something similar to how we did with viewing an individual post we're going to create a new folder called edit post and then here we're going to have a new file called id dot js and here we're going to go ahead and we're going to be mimicking a lot of the functionality that we've used so far because really what we want to do here is we want to navigate to [Music] like let me go ahead and try this one more time and show you the url structure so if i click edit post we're going to navigate to this url that is slash edit post slash this so what we need to do is read this ipfs hash off of the router and then we want to call and get that information and then we want to render it in the ui so instead of calling this on the server we're kind of like calling it on the client so for our imports we're going to import use state and use effect we're going to import use router import react markdown we're going to import css dynamic again because we're going to be rendering another markdown editor ethers and then create from ipfs http client we're going to do a lot of the same stuff we did before like having our contract address as well as the blog api and we're going to have our ipfs uri and our client for interacting with ipfs uploading we're going to also do the same thing we did before with our simple markdown editor we're going to be using the dynamic import with server side rendering set to false and then finally we're just going to have our default export and i've i've done this a few different ways i've just created the component and then you know export it later but here we're just saying export default function edit post and we'll go ahead and create a couple of pieces of state we're going to have a post variable and a set post function and we're going to have a variable for editing and also to stop editing so we can kind of like view how it would look while we're editing and then you know while we're not editing essentially and we can kind of like render our ui based on that that that boolean i guess you could say so what we're going to say is like if we're editing we want to show this and if we're not editing we want to show that we're going to use our router to get the id off of the route which again is going to be like this and then what we can do now is we can fetch the posts using that id and the way that that's all going to work is like when our use effect hook is is fired and this is going to be fired when the component loads as well as when this like if this id updates then we're going to have this fetch post function and it will look something like this we want to use that id to kind of get the data and we first might say okay if there is no id like if they hit this and they don't like give an id or whatever then we'll just gonna like return but next we want to go ahead and create a provider and we're going to use that same logic that we've been using so far where we're going to look at the environment variables and we're going to set the provider based on whether or not we're in local testnet or mainnet or some other network all right so we're going to go ahead and get a hold of the contract we're going to go ahead and call the contract by calling contract.fetchpost and then we are going to have that post id by getting the value that is returned from fetch posts and we're going to kind of like take the zeroth item out of that which is the id and we're going to say two number and then now that we have that we can call ipfs and we will call fetch and using that ipfs url which is a combination of the ipfs uri slash the id that we want to fetch we'll wait we'll turn that into some json and we'll check to see if this has a cover image similarly to how we did in the last component where we say okay if the data return from ipfs has a cover image we want to update the cover image path or we want to create in this case create a variable called cover image path that is a property of the data object that is a combination of the ipfs ura uri plus the cover image hash which is like the hash then we set the id and then we call setpost and now our post has been set and all of this functionality happened from us like reading the id off of the off of the the router we call our contract with that id we then get the information that we need to call ipfs and we kind of like set up everything from there we're next going to have a function called save post ipfs and this is going to be called from when we called update post so this function is going to be called from another function we're about to to create and this function just allows us to just upload you know our json metadata which is the post metadata to ipfs and then the update post function is going to be calling save post to ipfs and here we're going to be kind of like getting a signer we're going to be interacting with the contract we're going to call contract that update post and here we're actually making sure we pass in all the different values here and i'm kind of like hard coding true here because like i didn't actually implement this functionality for for the edit post button but you might want to like update this component to make it more extensible about giving the user the ability to publish and unpublish a post so by default all of these posts are going to be published but if you wanted to kind of like give them an option to set this boolean in the user interface that might make sense um before we render our ui we're just going to check to see if there is uh indeed a post and if there is no post we're just going to return null and if there is then this should continue to to go and we should be able to kind of return our user interface so the first thing we'll do is we'll go ahead and just have a div and we're going to have the editing state and we're going to have the state where no one is editing so we might say editing and and then this is going to be like a div and then we also might have the complete opposite where we say like editing with exclamation point meaning like we are editing and we're not editing and then here we also might want to have a div okay so if we are editing we want to implement a input for the user to be able to update the post title we want to give them a markdown editor for them to be able to update the markdown of their posts so we're kind of using a lot of the same stuff that we use for create post here where we have like this on change handler that's setting the post and then we have this on change handler here that's setting the um so this is setting the post title up here and this is setting the post markdown content and then we have a button that just allows the user to kind of like update the post and this will call the update post function up here all right now if they are editing i'm sorry if they're not editing we want to just render the post cover image so here i will say if there is a post cover image we want to render that image and below that we want to render the post title and the post content and then finally we're gonna have this last little button here that allows the user to toggle between whether they're editing or they're not editing and if they're editing you know we're going to show one view and if they're not editing we're going to show the other view this way they can kind of like preview the different changes as they're being made so the last thing we want for this component is our styling so here we have our button we have our title style we have our markdown editor we have our cover image style we have our container we have our content container all right so with that being said we should be able to go ahead and test this out so i'm going to go back to localhost and i save that so i should be able to connect click on this post here here i can go ahead and click on edit post and there we go we see that we have the ability to you know view the post we have the ability to edit the posts and we have the ability to say updated click update post and there we go we see that the content has indeed been updated so that is actually the end of the basic stuff that we wanted to to go over now we want to deploy this to polygon and we want to then build a subgraph on top of it so let's go ahead and get started doing that to work with polygon we need a couple of things first of all we need to add polygon as a network to our list of networks and we also need to receive some polygon now this tutorial isn't going to cover how to actually get polygon but you can buy polygon off of a lot of the exchanges out there and there are even bridges that allow you to bridge other currencies to polygon so um i already have some polygon in my wallet um so we're going to kind of like skip that step but we what we do want to show is how to kind of deploy to a real live network so to find out how to add polygon to metamask i need to kind of get the rpc endpoint and all the other stuff like the chain id so if i just google polygon network metamask you should come on the polygon docs docs.polygon.technology and here we have information around how to add to metamask so what i want to do is i want to go ahead and click here and i want to go to networks add network and i want to start off with all this information so here i can say i want to copy this rpc url paste it here network name polygon chain id is going to be 137 and the currency symbol is like matic i believe and for the block explorer we just use polygonscan.com and if i save that then here we see that i have matic set up and if i jump back to one of my other accounts i see that i have a little bit of matic here and this is what i'm going to be using to kind of deploy and i'm going to just go ahead and go to advanced settings and reset this account all right cool so we're set up with matic in our wallet we have the account on polygon and we have some matic in our wallet so what we want to do now is go to our hard hat configuration and i want to set up polygon as one of my networks so i'm going to just uncomment here and here i'm going to set my url as well as my environment variable for my private key so for my url i'm actually going to use infura because i already set up that inferior account earlier i can now just go to my dashboard i can go down here go to project settings and i can click on polygon and i can copy this in points to my clipboard and i can set that here and then for my environment variable for my private key you know you need to kind of find out uh your private key and set this preferably as an environment variable you never really want to hard code this value into your application because if you ever accidentally pushed it up to source control then your entire account will be compromised fairly quickly so how do you get this private key well you go to meta mask here you go to your account details right here and you click on export private key and then you pass you you type in your password so i'm going to go ahead and do that in a separate window and i'm going to go ahead and set this environment variable and then i will come back here and continue on in just a moment once the private key is set we should be able to go back to our command line here and we should be able to deploy to polygon now if i look at my current balance it's sitting at about point 8.24 so after i deploy we should see that go down so i should be able to say npx hardhat uh run scripts slash deploy and then i should say network polygon all right and if our application and our contract and everything deployed successfully we should get that address here and it should also be obviously kind of logged out or written here so there we go we have our address that's been deployed here and one way to kind of like see that this actually is indeed there we can go to polygon explorer i think it's polygon scan and we should be able to paste in our address here and see that 39 seconds ago a contract creation was was actually you know triggered so that's cool um we should also maybe see that we have like less matic so there we go 8.19 so that means it all works so if we want to test this out in our front end if i refresh then maybe this would give us an error or something that's because we've uh switched from our local network to this other network so what i want to do is i want to set this to polygon and i want to go ahead and start this over and i want to say npm run dev again and this will re-read our environment variables and if i refresh now then this should work so now we are on polygon and if i connect um i should from the address or i need to to change addresses i should be able to connect from the address from which i deployed which is this address and then be able to create a post so um i will go ahead and create a post because we want to then after this we want to be able to deploy this to the graph and i need to go ahead and create a couple of posts so i'll say post one create a second posts and as i'm creating these you'll notice that when i come back here that maybe they're not showing up yet um as quickly as they did earlier and that's because it takes some time for these to go through but remember what we talked about in createpost.js we can actually use this line of code here to wait for the transaction to confirm before rerouting so if i just uncomment that code here and i go back here and i click create post i'll just say third post maybe i'll actually add a cover image this time this time after i click publish it's actually going to take a little longer because we're going to wait for this transaction to actually be written to the network before we navigate all right and there we go so after we have our last post confirmed on the network we we're re-navigated now back here so if i click on one of these posts you might notice that it takes a little time to kind of navigate between each post if we want to make that faster we can actually just we're kind of running in a development environment on xjs so before we deploy to the graph let's go ahead and run a production build so to do that i'm going to go ahead and get off of the localhost and i'm going to run a build by running npx actually i should be able to say npm run build after the build is complete we should be able to say npm start and if we go back to localhost and we go home and we refresh we should see that this is very very fast so now we're clicking between we see that next.js is indeed extremely quick and yeah so it's really fast when you're actually running a production build so what we want to do next is we want to take this smart contract that we've deployed to polygon and we want to build an api on top of it using the graph so why would we do something like this well there's a lot of reasons but if you look at our smart contract what we basically have done is like we just have a single function in here for how we're going to read this data so we have this fetch post function but like as our blog expands let's say we added more users we took off that permission for only owner we allow anyone to create posts and we now have like you know dozens or hundreds of posts how would we create a different user interface on top of that without kind of like fetching all the posts and doing that stuff on the client well we would need a more flexible api you know on our back end and the traditional world databases and apis do that but in the blockchain world we're kind of limited by just connecting directly to the network so the graph protocol allows you as a developer to take the contract that you've created build a more flexible api on top of it and deploy this contract and this api to the decentralized network or the graph protocol network and we index all of the data we create a more flexible api on top of your data and then you can do stuff like full text search you can do stuff like filtering sorting and all the different more powerful queries that you typically need for a modern application so some of those queries that we might want in this example would be we want to query only posts created by a certain user or we might want to do a full text search where we can kind of search our blog for different things again filtering and sorting and all that stuff are also very powerful and important so let's go ahead and build out this subgraph so the way that we're going to do that is we first need to have the graph cli installed so we're kind of maybe done with most of the local network stuff so let's just go back here and what i want to do is i want to go ahead and install the graph cli and i can do that by running npm install g at graph protocol slash graph cli and if i hit enter it'll like start you know installing but i already have it installed and once you have it installed you should be able to just run the graph command and see that the binary is installed and you could say something like graph version or something like that and this will just kind of give you the version so what we want to do next is i might go ahead and for now just do that what we want to do now is we want to initialize a new subgraph and we can do that using the graph cli so i can say graph net dash dash from dash contract and here i want to paste in my contract address and the contract address is going to be wherever if i go to config here the contract addresses this here so we already have it like ready ready to go contract address is is from contract that's and then i'm going to just do a new line here and i'm going to say dash dash network polygon i'm not sure if it's polygon automatic uh in our in our api but for now i'll just use polygon and we can update it later if we have to for the contract name i'm going to set this as blog and then i'm going to also say i want to index events and remember when we created our events in our smart contract the graph cli will basically allow us to create a lot of nice boilerplate for us based on those events because that's kind of how the graph works is we listen for those events and we allow you to store the data that's coming into the function calls from which those events are triggered or the event calls from which those are triggered so when we when we walk through this setup we're going to actually need to go ahead and create a subgraph boilerplate in the graph ui so if i go back here to my browser i'm going to go to the graph.com and i'm going to go to products i'm going to go to hosted service and we're going to be going ahead and saying we're going to my dashboard and we're going to go ahead and click add a subgraph and here is where we're going to go ahead and create our first sub graph so the sub graph name is going to be something like um you know matters blog or something like that and then the subtitle is going to be just whatever and this will go ahead and allow us to go ahead i'm going to go ahead and hide it because this is kind of like an example and i'm going to click create sub graph now that we've created this sub graph we have our access token which is something that we're going to be using later to deploy our subgraph and we also have this uri scheme here so it's our username slash the blog and this is what we're going to need back on our cli so if i go back to our cli here we have like the protocol i'm going to set this as ethereum i'm going to set the hosted service is where we want to initialize the subgraph name is whoops it's going to be actually that information that we just i thought copied to our clipboard so debit three slash matters blog and the directory to where to create this subgraph it's up to you but like i like to use the naming convention like subgraph just because this automatically just lets me know you know what this is you can use whatever you like it's not really going to make a difference so um i think i had chosen polygon as the network but i think we still have it under the name of matic because they rebranded from polygon or informatic to polygon so we're going to use thematic network the contract address should already be in there now what it normally does it's going to go to polygon scan or ether scanner where or wherever the the explorer is for that network and it's going to look for the abi because typically when you deploy your smart contract to these networks you kind of upload your api but if it's not there you can kind of just reference the local path for that and luckily we know exactly where our abi is because again we've been using that abi all along from our artifacts directory contracts slash blog.json so if i go ahead and just copy this relative path to my clipboard by doing that and i go back here i should be able to just like reference it this way so it should be artifact slash contracts slash blog.soul blog.json and that looks like that worked for the contract name we already set blog and now we should be kind of good to go so this should go ahead and scaffold out our um subgraph so once the subgraph has been initialized we should see you know some good output like this where everything looks looks nice and we should be able to see in our directory we have this new subgraph directory and if i go in there i should be able to go ahead and see that we have our boilerplate kind of created for us so the three files that we're going to be working with are going to be schema.graphql we're going to be working with subgraph.yaml and we're going to be working in src slash mappings.ts so i'll go ahead and open those and the first thing we're going to do is we're going to go into our schema.graphql and what we're going to do here is this is going to be where we define kind of our data model and the only data model that we need to deal with in our in our application is this post type and this kind of might map fairly well to the struct that we created in our smart contract so the post has an id it has a title i'm kind of setting this value called content hash which is you know our the content hash or whatever the post content uh the published boolean as well as created at timestamp and updated at time stamp and we're going to kind of like look at how these values are set and how they're created in just a moment but this is going to be kind of our basic data model we're also going to have this additional feature where we set full text search and to add full text search all we need to do is kind of define the entity that we want to add full text search to so us we want to be able to search posts so in this includes array we set the entity as post we also are kind of setting the name for the query itself so like how do you actually use this full text search query well we're going to have this new query called post search so anyway we set the entity and we set the fields so the two fields that we want to be made searchable are the post content and the title so the title is going to be the title obviously but the post content is going to be the content that was uploaded to ipfs so like when we created the actual markdown we want to be able to search that markdown so the way that we're going to actually make this work is that from within the graph from within our subgraph we're going to be calling ipfs getting that post content and setting it as a field here and then we're going to make it searchable so this is pretty powerful so now that we have our data model set up we're going to need to actually update our subgraph main configuration but we can go ahead and close this so our subgraph.yaml this is kind of like where your main configuration is so here is um you know where you might think of as kind of like the description of all the different properties of a subgraph and then the data model is the graphql schema which we just looked at and then the business logic is going to be in these mappings which we haven't yet done yet but um to get started let's think about the entities that we want to work with so the entities are like going to be the items that you won't save and for us we really just have one entity which is that post so we created that post type in our graphql schema earlier and that entity should map one to one directly the other thing we might want to set is a start block so here if i go to the source i have the smart contract address i have the api but the start block will allow us to start indexing this directly from when the sub graph was deployed i'm sorry from when the smart contract was deployed so if i copy if i copy this address i can show you how to get that start block so what we're going to do is we're going to go back to polygon scan i think it was here and we can see that this this smart contract was deployed at this start block so i can actually just copy this block and set the star block as that i just want to make sure i have this right yep so we have this the address is right the start block is right and that's really all we have to do so the only thing we really did was to set the entity and we set the start block um i will just like reference the fact that we have these two event handlers that were created for us by the graph cli and when we used the index events flag the cli looked into our abis and it noticed that we had two events that were described in our smart contract the create i'm sorry the post created and the post updated events and it's gone ahead and created like these references to event handlers and the way that we're going to actually be able to save information is we're going to be calling functions when these event handlers are fired and the functions that we're going to be calling are going to be done in this mappings.cs now before we do that we can actually generate some helper code using the graph cli by going to our command line and running graph cogen and this oops i need to do this from uh the subgraph folder actually so if i go here and i run graph code gen then this should go ahead and generate a bunch of code for us that we can now import in our in our mappings and this code is going to be in this generated folder here so we should now see we have the schema.ts that uh maps closely with our graphql schema and this blog folder we don't really need to kind of like go into that right now but just figure out kind of like show you that that existed so the two ways that you're going to be interacting with the outside world i would say are the two interactions that you would have from within a mapping are going to be talking to the network itself so this could be ethereum but for our for us it's going to be polygon and you're also going to be talking to the graph node so for for talking to the graph node that's kind of like your database we're going to be storing data but you can also read data from it and then for the network that's just going to be the blockchain so for whatever reason you want to call that you're going to see how we're going to do that in just a moment so the two functions that we're going to have are going to be let's post handle posts created and handle posts updated and these are going to be fairly similar to each other the first thing we're going to do in handle posts creators we're going to first make sure to see if that post has been created actually no we don't have to do that because we know for sure that this is going to be a brand new post so we just actually create a new post passing in the id that comes in through the params we then set the title and we also set the content hash because we know based on the event how it was defined in our smart contract that we have this title we have this hash and we have this id that's going to be coming in as arguments what we want to now do though is actually talk to ipfs so to do that we import this ipfs helper from the graph protocol graph typescript library and we can now call the ipfs.cat which is going to allow us to call the ipfs network passing in that hash and then what we want to do here is we want to see if the data exists we want to do some some logic here so we're going to say okay like if this data came back from ipfs we want to go ahead and turn this data into an object and then we're also going to do another null check to see if that value exists we're going to now get the content off of that object and this is kind of like how assembly script works which is what we're working in um this is probably a lot different than maybe what you've used as far as you know maybe typescript or even javascript um and then we're gonna do one more null check we're gonna say okay if the content exists then we want to set the post content as the content and set it to a string so um you know the entire logic that we have going on here is like null checks and then um getting that data that we've gotten from ipfs and like you know manipulating it a little bit so um we have the value coming from ipfs we get the content value off of that object we check to see if the content is there and we set the post content so this post content is going to be our actual markdown you know it's going to be a string of markdown i set the post created timestamp as the timestamp coming from the block and then i go ahead and save it and then calling post.save just saves that to the node um what we do here is we go ahead and we call post.load passing in the post id and then we say like if the post exists then we're going to go ahead and do some more stuff and here we're going to do some similar a lot of similar stuff is what we did above we're going to go ahead and set the title content and published values similar to how we did here um and i guess we haven't set the published value here maybe we should do that so let me go to yeah so let's go ahead and say post published it's true i guess we know that's going to be true right um maybe i can just do this actually which should also be true oh okay maybe we don't get that okay so let's just leave that off for now um so we have the published value we're going to go ahead and get the data from ipfs like we did before and we're going to kind of have almost the exact same logic where we check to see if the data exists then we're going to get the value from the data turn it to an object we're going to see if that exists if it does we're going to get the content if the content exists then we set the post content and then we now set the updated at time stamp and then we go ahead and save that post and that's all done within this if statement here all right so that was quite a bit but you know and this is slightly advanced from just creating a basic application uh this is more graph specific but that's the whole point of this guide is kind of to be in depth so we're done now with the graph and we can now deploy this and we can test it out so we can go ahead and close this close this and we can go to our cli and we might want to just run a build to see if it works if it does then we can now deploy so to run a build we can run graph build when you run graph deploy it's actually going to or actually yarn deploy it's going to run a build for you anyway so let's go ahead and try this out so the build looks like it completed successfully meaning we don't really have any errors so what i want to do next is i want to say graph off because we need to authenticate our cli and this is going to allow us to set the authentication for the hosted service which is what we're working with and i'm going to go get my deploy key off of here and the dashboard and then once the deploy key is set we should be able to say yarn deploy and this is going to go ahead and take all of that code we just wrote it's going to deploy it to the graph network it's going to start indexing all of the different blog posts that we have and it should give us now a nice api for us to then query both using the basic queries that you might expect from like a graphql endpoint but also like full text search and stuff like that which is specifically what we set up just a moment ago so if everything goes smoothly you should get this output and then we should go here and we should refresh and you should now see that we have this graphql you know entity set up here so it looks like it's it's still syncing but um what i should be able to do now is like set up a couple of queries so let's go ahead and test that out so if i go to posts here i see that we have three posts coming back which is great i can also do and i'm kind of just pasting in some code but like you know with graphql you can ask only for the data that you want back so i could just say post id and then how do you actually know which fields are available where well it's pretty nice because like graphql schema introspection over here tells you so i can say okay i want to get the id the title and the post content okay then we get all that which is nice i can even order by creating that time stamp and set the order directions descending so here we're seeing that they're coming back in the reverse order from three two to one and then um the last thing i might want to do is a full text search so i have that that post search query and here we just enter in some text and we can return the same values like id title content or whatever so i might say okay i want to look for testing and there we go we have like that content um [Music] i forgot what some other stuff was but like third i guess first cool so um if i go back to just posts there we go so we have post one post two third post so our full text search is working now like if we wanted to implement this query in our client application you can go to the graph docs but you can also go to the graph youtube and see how you can just grab this endpoint and drop it in your app and you would then be replacing some of those contract calls that we were making to the network instead we would just call this graphql endpoint so it's pretty simple replacement in fact i think the api would be even simpler than what we did so now that we have all this set up we want to maybe deploy our code base to a repo open source to kind of let other people like use it or collaborate on it so one really great project is a radical so radical is a decentralized web 3 git hosting protocol and they recently released the radical cli and what we can basically do is use the radical cli to deploy our code to the radical network so if i go to the web client i can see oops it looks like the network might be down right now which is actually unfortunate well let me see oh i'm in the wrong network so let me just switch to ethereum try that perfect yeah and it doesn't matter because like uh that we deployed to polygon because we're just deploying our code to radical so we're on radical right now and the radical cli just allows you to open source your code and share and collaborate on your apps without using a centralized provider like github so what i would recommend is like installing the radical cli using one of these different commands so i use this one here that just uses cargo you can also use the home brew or whatever depending on your environment so once you have the radical cli installed you should be able to like run this command called rad and what we want to do now is deploy to radical network so i can do that i can first say git add and i want to go ahead and add all of you know what i need to [Music] actually update some code real quick i think in the sub graph i want to add a git ignore and here i want to set node modules i think which is something we should probably do by default but in the graph i don't want to obviously send my node modules up there and then i want to back up one directory and here we want to say you know git status get add all this is our initial commit and now we should be able to initialize a new radical project by running rat in it here we can set the name of the project the description default branch and now that we've set this up we should be able to say rad push and enter our password this password is set when you initialize your radical local setup by running rad auth by the way so we'll go ahead and type that in choose the seed node to sync it with give this a few seconds and this should go ahead and deploy so we've deployed this to i believe pine so if i go to radical here and i refresh i go to pine i should see that we have the web3 blog right there so now our entire code base is ready to go we can share this other people can can view it and they can actually download it so they can go to clone and they can clone it using either radical cli or they get cli by running git clone passing in the address there and now our code is running on or it's kind of deployed and ready to be used in a completely decentralized and censorship resistance place and manner which is really nice and i'm a big fan of radical and the radical cli so i definitely suggest checking that out adding it to your workflow especially if you're in the web3 space so um i think that we've come to an end here so i think that we're kind of wrapping up this entire uh tutorial and if you've hung around this long i appreciate it and i appreciate the fact that you've like been able to kind of get through all this because it's been a lot that's for sure now um again i kind of want to reiterate that this was a lot of content to cover so um typically what happens is like apis change and things like that uh get updated over time and these videos end up getting a little bit out of date so what i would like to just recommend is that if you're following along i would 100 recommend going back to the tutorial because the tutorial is the written tutorial something that i can kind of keep up to date and i will continue trying to kind of like iterate on that and prove it and uh add changes as apis maybe break or they change so um if you're following along and you see a little difference there i would probably tend to go with the written tutorial and yeah so with that being said i want to kind of go back to the complete guide to full stack web3 development and reference a couple of other tutorials that i've written so if you're interested in this type of stuff i would also check out the complete guide to full stack ethereum development which is a video in a blog post the com building a full stack nfc marketplace on ethereum with polygon which is a video and a blog post i'll plan on making an updated video for that one soon and then if you're also interested in solano development i would check out the solana complete guide to full stack solana development as well these are all very similar guides and then finally if you're interested in radical i have a video on my youtube channel that you can also check out to learn how to use radical so that wraps up this comprehensive web 3 guide thank you for checking it out and i'm going to be releasing this on glass protocol so i'm excited about that so if you're on glass just a shout out to anyone that's checking this out there i want to make it completely free of course but trying out some new strategies for distribution and monetization so i hope everyone learned a lot and subscribed to my youtube channel i am going to kind of link to all of the the information in the comments here hopefully so thanks for checking us out and see you in the metaverse
Up Next

Build an Ethereum Dapp with Scaffold-ETH: Fast Solidity Development
@MoralisWeb3
13.2K views•2021-06-12

IFS Therapy Demonstration: Complete Session with Unburdening
@IFSCA
95.9K views•2021-01-13

FastAPI vs Flask vs Django: Choosing the Right Python Web Framework
@TechWithTim
302.5K views•2024-05-26

Game of Thrones Opening Credits: A Cinematic Analysis
@gameofthrones
46.3M views•2011-04-18
Related Study Plans & Knowledge Roadmaps
Structured learning paths in General & Interdisciplinary Studies











































