So if you are starting your Web3.0 journey, understanding all the concepts by building the projects is the best thing you can do.
In this blog, we are going to build a simple App: Chain-Journey, it is going to be an application where users will drop a message about what they are learning and it will be stored on the blockchain and everyone can see what others are learning.
For this application, our tech-stack is
For Front-end
HTML
CSS
JavaScript
-For Smart-Contract we are using Solidity
-We will be using Ethers.JS for interacting with our smart contract.
Open your terminal and run the below command
1mkdir Chain-Journey 2cd Chain-Journey
Now open this folder in VS Code or your code Editor
After that make a file with the name index.html
.
After this, make a file with the name style.css
.
Now make another file named interact.js
, in this file we are writing all of our logic.
So our Setup for the front-end is done.
Before writing smart-contract let's understand what is smart-contract
A "smart contract" is simply a program that runs on the Ethereum blockchain. It's a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain.
For writing smart-contract, we are going to use Remix-IDE, Remix is an online, Web-based IDE for writing, compiling, testing, and deploying the Smart-Contract.
Just go to Remix-IDE
You should see the screen like this
Now from File-explorer Click on + Icon to create a new workspace and in the modal leave the Workspace name as default . Choose a template Select Blank
and hit enter.
Now from the file explorer click on File-Icon and Enter the file name ChainJourney.sol
.
Now in ChainJourney.sol
paste the below code.
This is our code which we will deploy on the blockchain.
1//SPDX-License-Identifier: Unlicense 2pragma solidity ^0.8.0; 3 4contract ChainJourney{ 5 6 struct Learner{ 7 address from; 8 string learning; 9 } 10 11 Learner[] allLearnes; 12 13 function getAllLearners() public view returns(Learner[] memory){ 14 return allLearnes; 15 } 16 17 function addLearner(string memory learning) public { 18 allLearnes.push(Learner(msg.sender,learning)); 19 } 20}
So Let's understand our code line-by-line:
1//SPDX-License-Identifier: Unlicense 2pragma solidity ^0.8.0;
The first line is a comment defining our license of the program and the second line declares that what solidity version we are using.
Note that the symbol ^0.8.0 defines that our program is compatible with a solidity version greater than 0.8.0
Solidity is a contract-oriented language, So our code resides in the contract ChainJourney{}
Here ChainJourney is the contract name.
1struct Learner{ 2 address from; 3 string learning; 4 }
Sometimes we need our own data type. In Solidity struct
is a keyword used to define custom data types. Here we are defining the struct with the name Learner
.
Inside this struct, we are having two members
address from
: address is data-type in the solidity that represents the public address of the user.
string learning
: it's a simple string storing what the user is learning.
1Learner[] alllearners;
Here, We are declaring an array of type Learner, this array will store all the user's address and what they are learning.
1function getAllLearners() public view returns(Learner[] memory){ 2 return allLearnes; 3 }
Now we are declaring a function named getAllLearners
Let's understand what is the meaning of public, view, and returns.
public
: Basically this function is public and can be called by anyone
view
: In Solidity, a view function is the function that does not changes the state of the contract.
returns
: Here, we are defining what our function is going to return, in our case the function getAllLearners
is returning an array type of Learner.
1function addLearner(string memory learning) public { 2 allLearnes.push(Learner(msg.sender,learning)); 3 }
Here we have another function named addLearner
.
When we want to add any user's data to the blockchain we will call this function.
Our function takes an argument learning whose type is a string.
Inside our function, we are pushing the incoming data in the allLearners
array by calling the push method.
Now our contract is ready.
At this point, your screen should look like this
![remix-2.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663043536492/vBhLf7V67.png align="left")
Now Click on Compile Tab
Here click on complete ChainJourney.sol
and should see the green tick.
Now Our Contract is ready for deployment on blockchain
Here we are deploying our contract on Ethereum's Goerli Testnet.
Make sure you are on Goerli Testnet before deploying the Contract.
For this, you need to have some Goerli Test Eth.
You can find your public address here
Now Click On Deploy Tab.
Now just Press the Deploy button and you will see a meta mask pop-up, just confirm the transaction and wait for a couple of seconds you see the contract address in Remix
So, Take time, You just deployed your first smart contract.
Now just copy that address and keep it for future reference.
We also need Contract ABI, Switch to Compile tab, copy the ABI keep it for future reference.
Now Open your index.html
file and paste the below code.
1<!DOCTYPE html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 <title>Chain Journey</title> 8 <link rel="STYLESHEET" href="./style.css" /> 9 <script 10 src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js" 11 type="application/javascript" 12 ></script> 13 </head> 14 <body> 15 <section class="form"> 16 <div id="caccount"></div> 17 <label>Enter What you are learning</label> 18 <input type="text" id="inputText" /> 19 <button onclick="addLearner()" id="addChain">Add to Chain</button> 20 <div id="txnhash"></div> 21 </section> 22 <div class="container"> 23 </div> 24 <script defer src="./interect.js"></script> 25 </body> 26</html>
In HTML We have only two sections
In the form section, we have one input field and one button and when the user will click on that button we are triggering a function addLearner()
.
And the div with container class is used to render all the data which is coming from the blockchain.
So let's add some CSS and style our page.
Open your style.css
and paste the below code.
1body { 2 background: #c2e59c; 3 background: -webkit-linear-gradient(to right, #64b3f4, #c2e59c); 4 background: linear-gradient(to right, #64b3f4, #c2e59c); 5 display: flex; 6 flex-direction: row; 7} 8.form { 9 flex: 0.5; 10 background-color: rgba(0, 0, 0, 0.1); 11 display: flex; 12 flex-direction: column; 13 justify-content: center; 14 border-radius: 15px; 15 padding: 15px; 16} 17#caccount { 18 color: white; 19 font-size: 1.3rem; 20} 21#inputText { 22 background-color: rgba(0, 0, 0, 0.1); 23 border: 2px solid transparent; 24 padding: 15px; 25 outline: none; 26 border-radius: 10px; 27 margin-block: 1rem; 28 color: white; 29 font-size: 1.2rem; 30} 31label { 32 font-size: 1.3rem; 33 color: aliceblue; 34 font-weight: 600; 35} 36#inputText:focus { 37 border: 2px solid aliceblue; 38} 39#addChain { 40 width: max-content; 41 align-self: center; 42 padding: 8px; 43 font-size: 1.2rem; 44 background-color: violet; 45 border: none; 46 outline: none; 47 border-radius: 8px; 48} 49.container { 50 flex: 0.5; 51 display: grid; 52 place-content: center; 53 row-gap: 5px; 54 max-height: 90vh; 55 overflow-y: auto; 56} 57.card { 58 background-color: rgba(0, 0, 0, 0.1); 59 padding: 10px; 60 font-size: 1.2rem; 61 font-weight: 600; 62 border-radius: 10px; 63 color: white; 64} 65@media (max-width: 688px) { 66 body { 67 flex-direction: column; 68 } 69}
Now open your index.html
with the browser or if you are using VS Code, install the extension Live Server
and in your index.html
file click right and select the option Open with live-server. It will open a local dev server at port 5500
Now go to Localhost
You should see the output like this.
Now open your interect.js
file.
Here we are going to write all the logic.
const CONTRACT_ADDRESS = "PASTE_YOUR_CONTRACT_ADDRESS_HERE";
const ABI = PASTE_YOUR_ABI_HERE
Now in the interect.js
file, we are declaring two variables.
Hint: The Address starts with
0x..
and is 42 characters long string.
2.ABI= Paste the ABI that you grab earlier in the tutorial.
Hint: ABI Is an Array and starts like this ABI: [
Now declare two variables
1const provider = new ethers.providers.Web3Provider(window.ethereum); 2let account = "0x";
The provider is one utility that gives us access to all Ethereum Methods.
Here I am assuming that you have Metamask installed, if not, download it from the Chrome extension store and complete the onboarding.
Paste the below code in the interect.js
file.
1async function connectWallet() { 2 let accountList = await provider.send("eth_requestAccounts", []); 3 account = accountList[0]; 4 document.getElementById("caccount").innerHTML = 5 "Current Account is :" + account; 6 getlearners(); 7} 8 9function getContract() { 10 let signer = provider.getSigner(account); 11 let contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer); 12 return contract; 13} 14
Here we are defining two functions
1.connectWallet()
: This function is used to connect the wallet(Metamask) with our Application.
Here we are seeing the request eth_requestAccounts
to get the account and it will return an Array of addresses.
After that, we are just displaying the address to our front end.
As soon as the wallet is connected we are calling the function getlearners()
.
getContract()
: This function creates the instance of our contractHere we have new ethersContract
: It takes three arguments:Contract Address
, Contract ABI
, and Signer
.
and this returns the contract instance
We can use this instance to call our contract methods.
Now in the interect.js
file paste the below code.
1 2async function getlearners() { 3 let contract = getContract(); 4 let learners = await contract.getAllLearners(); 5 for (const item of learners) { 6 appendCard(item); 7 } 8}
This function is used to retrieve all the data from the blockchain.
First, we are grabbing the contract instance by calling the getContract
method and after that, we are calling contract.getAllLearners()
method which will call our getAllLearners()
function and it will return all learners from the chain
and we are storing them in learners variables.
After that we are are iterating over all the learners and call the function appendCard()
So lets define appendCard()
function.
Hers's implementation of it:
1function appendCard(item) { 2 let container = document.getElementsByClassName("container")[0]; 3 let card = document.createElement("div"); 4 card.className = "card"; 5 card.innerHTML = 6 "Address " + item.card + "<br/>" + "Learning : " + item.learning; 7 container.append(card); 8}
This function is just creating one div
, then we are adding the classname card
to it and by using card.innerHTML method
we are actually writing the address of the learner and what the learner is learning.
After this, we are just appending this div to our container.
1async function addLearner() { 2 let learningtext = document.getElementById("inputText"); 3 if (learningtext.value === "") { 4 learningtext.style.border = "2px solid red"; 5 learningtext.setAttribute("placeholder", "This filed can not be blank"); 6 return; 7 } 8 let contract = getContract(); 9 let txn = await contract.addLearner(learningtext.value); 10 let showhash = document.getElementById("txnhash"); 11 let a = document.createElement("a"); 12 a.href = `https://goerli.etherscan.io/tx/${txn.hash}`; 13 a.innerHTML = "Follow your transaction here"; 14 showhash.append(a); 15 await txn.wait(); 16 history.go(0); 17}
This is the function that adds the user's address and what he/she is learning to block-chain.
First, we are grabbing the value of the input.
If the user has not entered some input we will show him/her an alert and return from the function.
If the user has entered some text we will call our contracts addLearner()
method.
After that, we are grabbing the div which will show the transaction hash to the user.
Here, we are creating an anchor element and setting the href
value to https://goerli.etherscan.io/tx/${txn.hash}
.
Here txn.hash is the transaction hash.
And after that, we are waiting for the transaction to confirm and
as soon as this resolves we are refreshing the page, so the data is updated.
In the interact.js
add this line
1window.addEventListener("load", connectWallet);
here we are adding the event listener to the window and when this event occurs, we are calling the function connectWallet
.
Here's the full code of interect.js
.
1 const CONTRACT_ADDRESS = "PASTE_YOUR_CONTRACT_ADDRESS_HERE"; 2const ABI = [ 3 { 4 inputs: [ 5 { 6 internalType: "string", 7 name: "learning", 8 type: "string", 9 }, 10 ], 11 name: "addLearner", 12 outputs: [], 13 stateMutability: "nonpayable", 14 type: "function", 15 }, 16 { 17 inputs: [], 18 name: "getAllLearners", 19 outputs: [ 20 { 21 components: [ 22 { 23 internalType: "address", 24 name: "card", 25 type: "address", 26 }, 27 { 28 internalType: "string", 29 name: "learning", 30 type: "string", 31 }, 32 ], 33 internalType: "struct ChainJourney.Learner[]", 34 name: "", 35 type: "tuple[]", 36 }, 37 ], 38 stateMutability: "view", 39 type: "function", 40 }, 41]; 42 43const provider = new ethers.providers.Web3Provider(window.ethereum); 44let account = "0x"; 45 46async function connectWallet() { 47 let accountList = await provider.send("eth_requestAccounts", []); 48 account = accountList[0]; 49 document.getElementById("caccount").innerHTML = 50 "Current Account is :" + account; 51 getlearners(); 52} 53 54function getContract() { 55 let signer = provider.getSigner(account); 56 let contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer); 57 return contract; 58} 59 60async function getlearners() { 61 let contract = getContract(); 62 let learners = await contract.getAllLearners(); 63 // console.log(learners); 64 for (const item of learners) { 65 appendCard(item); 66 } 67} 68 69function appendCard(item) { 70 let container = document.getElementsByClassName("container")[0]; 71 let card = document.createElement("div"); 72 card.className = "card"; 73 card.innerHTML = 74 "Address " + item.card + "<br/>" + "Learning : " + item.learning; 75 container.append(card); 76} 77 78async function addLearner() { 79 let learningtext = document.getElementById("inputText"); 80 if (learningtext.value === "") { 81 learningtext.style.border = "2px solid red"; 82 learningtext.setAttribute("placeholder", "This filed can not be blank"); 83 return; 84 } 85 let contract = getContract(); 86 let txn = await contract.addLearner(learningtext.value); 87 let showhash = document.getElementById("txnhash"); 88 let a = document.createElement("a"); 89 a.href = `https://goerli.etherscan.io/tx/${txn.hash}`; 90 a.innerHTML = "Follow your transaction here"; 91 showhash.append(a); 92 await txn.wait(); 93 history.go(0); 94} 95 96window.addEventListener("load", connectWallet);
Now open your localhost and you should see the output look like this.
Now type what are you learning in the input field and press the add to chain button.
A metamask pop-up will appear, confirm the transaction and wait for some time.
After roughly 10-15 seconds the page is refreshed and you will be able to see what you have typed in the text is now stored on the block-chain and it is retrieved and rendered on the front-end.
So if you have followed until here, just reward yourself.
And a big congratulations on building your first DApp.
Until next
Keep Coding, Keep Debugging.
Feel free to contact me.