Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tut] Project – React dApp for Selling eBooks in a Decentralized Manner (1/4)

#1
Project – React dApp for Selling eBooks in a Decentralized Manner (1/4)

<div>
<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-top" data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;1055370&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;top&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;2&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (2 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;width&quot;:&quot;142.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
<div class="kksr-stars">
<div class="kksr-stars-inactive">
<div class="kksr-star" data-star="1" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="2" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="3" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="4" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="5" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
<div class="kksr-stars-active" style="width: 142.5px;">
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
</div>
<div class="kksr-legend" style="font-size: 19.2px;"> 5/5 – (2 votes) </div>
</p></div>
<p>Welcome to another project of a decentralized dapp with <a href="https://blog.finxter.com/learn-to-build-smart-contracts-in-react-with-web3-js-heres-how-1-2/" data-type="post" data-id="978706" target="_blank" rel="noreferrer noopener">React</a> and <code><a href="https://blog.finxter.com/i-created-a-counter-smart-contract-with-ether-js-heres-how/" data-type="post" data-id="1002304" target="_blank" rel="noreferrer noopener">ether.js</a></code>.</p>
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube"><a href="https://blog.finxter.com/project-react-dapp-for-selling-ebooks-in-a-decentralized-manner-1-4/"><img src="https://blog.finxter.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fk9FWq9hTYiA%2Fhqdefault.jpg" alt="YouTube Video"></a><figcaption></figcaption></figure>
<h2>Project Scenario</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="1019" height="679" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-122.png" alt="" class="wp-image-1055400" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-122.png 1019w, https://blog.finxter.com/wp-content/uplo...00x200.png 300w, https://blog.finxter.com/wp-content/uplo...68x512.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></figure>
</div>
<p>We will build an ebook stall from which anyone can buy an ebook on a monthly subscription basis. </p>
<p>The buyer will submit his name, the book’s name, and the writer’s name at the time of buying the subscription. When he pays for the subscription, the subscription fee will be added to the bookstall owner’s account, and at the same time, the system will debit the transaction fee from the buyer’s account. </p>
<p>Apart from this, the details info of the buyer will be displayed on the user interface. The information includes the buyer’s name, wallet address, transaction time, book, and writer’s name.</p>
<h2>Technology</h2>
<p>We will use <code>react.js</code> and tailwind CSS in the frontend, <a href="https://blog.finxter.com/solidity-crash-course/" data-type="post" data-id="445146" target="_blank" rel="noreferrer noopener">Solidity</a> for writing the smart contract, Ether.js for interacting with the smart contract, and the hardhat for smooth development.</p>
<h2>Initiate Hardhat</h2>
<p>Hardhat is arguably the best <a href="https://blog.finxter.com/ethereum-top-10-articles-to-get-started/" data-type="post" data-id="53284" target="_blank" rel="noreferrer noopener">Ethereum</a> development environment to compile your contracts and run them on a development network. To install the hardhat, open the <code>vscode</code> terminal and just type</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">npm install –save-dev hardhat</pre>
<p>Hardhat will be installed on the directory. Now run hardhat.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">npx hardhat</pre>
<p>The command prompt will ask for creating a <a rel="noreferrer noopener" href="https://blog.finxter.com/javascript-developer-income-and-opportunity/" data-type="post" data-id="191233" target="_blank">JavaScript</a> project. Approve it. You need to install some dependencies to run the project. Copy this from the terminal and run. All the extra dependencies will be installed.</p>
<p>Create a new <a href="https://blog.finxter.com/layout-of-a-solidity-source-file-spdx-license-identifier-and-version-pragmas/" data-type="post" data-id="703612" target="_blank" rel="noreferrer noopener">Solidity file</a> inside the contract folder. “<code>bookSell.sol</code>“. We will be writing all the code here.</p>
<h2>Build Solidity Smart Contract</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="1019" height="764" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-123.png" alt="" class="wp-image-1055401" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-123.png 1019w, https://blog.finxter.com/wp-content/uplo...00x225.png 300w, https://blog.finxter.com/wp-content/uplo...68x576.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></figure>
</div>
<p>I will create a simple and quick smart contract. This smart contract is basically for inputting the name, Book name, writer’s name, buyer address, the timing of issuing the order, etc.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pragma solidity >= 0.5.0 &lt; 0.9.0;
contract BookSell{ address payable owner; constructor(){ owner = payable(msg.sender); } struct Receipt{ uint256 timestamp ; string name; address buyer; string book; string writer; } Receipt[] receipts; function buyBook(string memory name, string memory book, string memory writer) public payable{ require(msg.value>0,"Payment is not acceptable"); owner.transfer(msg.value); receipts.push(Receipt(block.timestamp, name, msg.sender,book, writer)); } function getReceipts() public view returns(Receipt[] memory) { return receipts; }
}
</pre>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="624" height="336" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-116.png" alt="" class="wp-image-1055383" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-116.png 624w, https://blog.finxter.com/wp-content/uplo...00x162.png 300w" sizes="(max-width: 624px) 100vw, 624px" /></figure>
</div>
<p>First, we need to confirm the address of the owner of the bookstall. This address will be <code><a href="https://blog.finxter.com/what-is-payable-in-solidity/" data-type="post" data-id="37282" target="_blank" rel="noreferrer noopener">payable</a></code> cause it will receive the money of the buyers.</p>
<p>Create a constructor for the owner. “<code>msg.sender</code>” will be the owner in this case. <code>msg.sender</code> is normally the address that is used to deploy the contract. The person or the account that deploys the contract is normally the contract owner and will receive the transaction on his account.</p>
<p>Create a <a rel="noreferrer noopener" href="https://blog.finxter.com/solidity-reference-types-array-slices-and-structs/" data-type="post" data-id="829701" target="_blank">struct</a> “<code>Receipt</code>” with three strings, that is,</p>
<ul>
<li>“<code>name</code>” for the buyer’s name, </li>
<li>“<code>book</code>” for the book buyers want to buy, and </li>
<li>“<code>writer</code>” for the writer of the book. </li>
</ul>
<p>The timestamp would be an unsigned integer to note down the time and an address to collect the buyer’s account address.</p>
<p>To store the data of several buyers, I created a “<code>receipts</code>” <a href="https://blog.finxter.com/solidity-array-members-and-manipulation-techniques/" data-type="post" data-id="830098" target="_blank" rel="noreferrer noopener">array</a>. It is a dynamic array, which means whenever a new buyer inputs his information, the receipt will be added dynamically to the receipts array.</p>
<p><a href="https://blog.finxter.com/solidity-function-type-examples-a-simple-illustrated-guide/" data-type="post" data-id="830464" target="_blank" rel="noreferrer noopener">Create a function</a> to buy the book. This <code>buyBook</code> function will take the information of the buyer as the parameters. The information includes the buyer’s name, book, and writer’s name. This function will also be <code>payable</code> cause we will use this to transfer money to the owner’s address.</p>
<p>Buyers must not pay zero eth as an amount. That’s why we added a condition with the “<code>require</code>” method. “<code>msg.value</code>” is the amount the buyer spends to buy the book.</p>
<p>“<code>owner.transfer(msg.value)</code>” is used to transfer the fund to the stall owner’s account.</p>
<p>When the transaction is done, add the transaction receipt to the receipts array with the help of the push method. Since the receipts array is a struct type of array, you can input the required fields as the parameter of receipt.</p>
<p>To get the information from the receipts, we created a <code>getReceipts()</code> function. This returns the receipt of each buyer when we call the function.</p>
<h2>Test the Smart Contract</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="1019" height="679" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-124.png" alt="" class="wp-image-1055403" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-124.png 1019w, https://blog.finxter.com/wp-content/uplo...00x200.png 300w, https://blog.finxter.com/wp-content/uplo...68x512.png 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></figure>
</div>
<p>Before deploying the contract, we need to check if all the functionalities of the <a href="https://blog.finxter.com/smart-contracts-discover-how-to-create-them-directly-and-indirectly/" data-type="post" data-id="978963" target="_blank" rel="noreferrer noopener">smart contract</a> are working properly or not. Hardhat has its own node and tools for checking the smart contract. We will first deploy our smart contract on the hardhat node to check its functionality and then deploy it to our testnet.</p>
<p>Move inside the <code>deploy.js</code>. We will create several functions here for different purposes.</p>
<p>We need to generate some accounts for the transaction. Inside the <code>async main()</code> function, generate account addresses with the help of the <code>getSigners()</code> method of <code>ether.js</code>. One account is for the contract owner, and the other three are for different buyers.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const [owner, buyer1, buyer2, buyer3] = await hre.ethers.getSigners();</pre>
<p>Hardhat will generate four accounts with the help of ether modules. Each account will have 1000 eth by default. We can use that at the time of the transaction for testing purposes.</p>
<p>Create an addresses array to store all the addresses together.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const addresses = [ owner.address, buyer1.address, buyer2.address, buyer3.address, ];
</pre>
<p>Now to get the balances of those addresses, we will create <code>obtainBalance()</code> function outside the main <code>function()</code></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const obtainBalance = async (address) => { const balanceBigInt = await hre.ethers.provider.getBalance(address); return hre.ethers.utils.formatEther(balanceBigInt);
};
</pre>
<p>This <code>obtainBalance()</code> function will take an address from the addresses array, and it will use the <code>getBalance()</code> method of the <code>ethers.provider</code> to get the balance.</p>
<p>We will get the output as a Big Int object, and we need to convert it to get the actual number. The <code>formatEther()</code> method of the <code>utils</code> library converts the big int object into a readable format.</p>
<p><strong>Reference</strong>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt" target="_blank" rel="noreferrer noopener">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt</a></p>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="624" height="345" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-117.png" alt="" class="wp-image-1055385" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-117.png 624w, https://blog.finxter.com/wp-content/uplo...00x166.png 300w" sizes="(max-width: 624px) 100vw, 624px" /></figure>
</div>
<p>Now we will create another function to loop through the addresses, and it will also show the balances on the console.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const printBalances = async (addresses) => { let id = 0; for (const address of addresses) { console.log(`Account ${id} Balance:`, await obtainBalance(address)); id++; }
};
</pre>
<p>The “<code>for</code>” loop is used to loop through all the addresses of the array. While looping, the <code>obtainBalance()</code> function will get the balance from each account. An <code>id</code> variable is used to mark each account with a unique id.</p>
<p>Apart from that, we want to see the receipt for each buyer. Let’s create a <code>printReceipt()</code> function to get the receipt.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const printReceipts = async (receipts) => { for (const receipt of receipts) { const timestamp = receipt.timestamp; const name = receipt.name; const buyer = receipt.buyer; const book = receipt.book; const writer = receipt.writer; console.log( `Buyer Details: Name:${name},Book:${book},Writer:${writer},Address:${buyer},Time:${timestamp}` ); }
};
</pre>
</p>
<p>The <code>printReceipts()</code> function initiates a for loop that will loop through all the receipts of the receipts array. Then it will show all the buyer’s details from the receipt that will be called.</p>
<p>Now we need to call the receipts array from the smart contract. Otherwise, it won’t be possible to get data from the contract. Create an instance of the smart contract inside the <code>main()</code> function.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> const bookSell = await hre.ethers.getContractFactory("BookSell"); const contract = await bookSell.deploy(); //instance of the contract
</pre>
<p>With the first line of code, we called smart contract with the <code>getContractFactory()</code> method of the <code>ethers</code> library. Then we created an instance of the smart contract in the second line.</p>
<p>Now we can call the functions of the smart contract from here.</p>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="624" height="309" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-118.png" alt="" class="wp-image-1055386" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-118.png 624w, https://blog.finxter.com/wp-content/uplo...00x149.png 300w" sizes="(max-width: 624px) 100vw, 624px" /></figure>
</div>
<p>Let’s say we want to check the accounts’ balances first. Let’s <a href="https://blog.finxter.com/javascript-intro-how-to-see-your-code-output/" data-type="post" data-id="175068" target="_blank" rel="noreferrer noopener">console log</a> the balance on the terminal with the help of <code>printBalance()</code> method that we created earlier.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> console.log("Initial Balance:"); printBalances(addresses);
</pre>
<p>Assume we want to send some balance to the owner’s address for buying books. Fix the amount we want to transfer</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> const amount = { value: hre.ethers.utils.parseEther("1") }; await contract .connect(buyer1) .buyBook("Adam", "Miracle Morning", "Hal Elrod", amount); await contract .connect(buyer2) .buyBook("Mike", "The Slight Edge", "Jeff Olson", amount); await contract .connect(buyer3) .buyBook("Peter", "Loving what is", "Byron Katie", amount);
</pre>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="624" height="470" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-119.png" alt="" class="wp-image-1055387" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-119.png 624w, https://blog.finxter.com/wp-content/uplo...00x226.png 300w" sizes="(max-width: 624px) 100vw, 624px" /></figure>
</div>
<p>We fixed an amount, one eth, to transfer from all the buyer’s addresses. We used the <code>parseEther()</code> method of the <code>utils</code> library to fix the value.</p>
<p>In the next few lines, we called the contract and established a connection with the buyer’s address. We also called the <code>buyBook</code> method of the smart contract to buy the books.</p>
<p>Inside the <code>buyBook</code> function we passed the buyer address, the book name, the writer name, and the amount as the parameter. For simplicity, we are sending the same amount from all the buyer’s accounts.</p>
<p>To check the balances after buying the book, we will call the <code>printBalance()</code> method again. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> console.log("Last Balance:"); await printBalances(addresses);
</pre>
<p>We forgot to call the receipts array from the smart contract. We will use the <code>getReceipts()</code> methods from the smart contract to get the receipts.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> const receipts = await contract.getReceipts(); printReceipts(receipts);
}
</pre>
<p>Now. Let’s deploy the contract on the hardhat and check how it works.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> await contract.deployed(); console.log("Contract Address:", contract.address);
</pre>
<p>I deployed the contract in the first line and then asked for the contract address.</p>
<p>Let’s move to the terminal and run the script.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">npx hardhat run scripts/deploy.js</pre>
<p>Don’t forget to mention the directory of the file on the code.</p>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="624" height="186" src="https://blog.finxter.com/wp-content/uploads/2023/01/image-120.png" alt="" class="wp-image-1055388" srcset="https://blog.finxter.com/wp-content/uploads/2023/01/image-120.png 624w, https://blog.finxter.com/wp-content/uplo...300x89.png 300w" sizes="(max-width: 624px) 100vw, 624px" /></figure>
</div>
<p>I got these results on my terminal after running the scripts. You can see from here that initially, the balances of all the accounts were 10000 eth. But after the transaction, more than one eth was deducted from each of the last three accounts. </p>
<p>It took more than one eth because of the transaction fee. At the same time, we can see the owner’s account (Account 0) is credited with exactly three eth.</p>
<p>In the last part, we also gathered all the info from the buyer’s receipt, including the time of the transaction and the address of the buyer.</p>
<h2>Thanks for Reading <img src="https://s.w.org/images/core/emoji/14.0.0/72x72/2665.png" alt="♥" class="wp-smiley" style="height: 1em; max-height: 1em;" /></h2>
<p>That’s all for today. You have learned how to build and test a smart contract. In the next part, we will deploy the smart contract on a testnet.</p>
<p><strong>GitHub</strong>: <a rel="noreferrer noopener" href="https://github.com/yassesh/bookSell" target="_blank">https://github.com/yassesh/bookSell</a></p>
</div>


https://www.sickgaming.net/blog/2023/01/...anner-1-4/
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

Forum software by © MyBB Theme © iAndrew 2016