The Business & Technology Network
Helping Business Interpret and Use Technology
S M T W T F S
 
 
 
 
 
1
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
9
 
10
 
11
 
12
 
13
 
14
 
15
 
16
 
17
 
18
 
19
 
20
 
21
 
22
 
23
 
24
 
25
 
26
 
27
 
28
 
29
 
30
 

Metaverse Domains vs. Traditional Domains: What’s the Difference?

DATE POSTED:August 14, 2024
What I learned while developing a decentralized House Rental Platform with Next.js, Redux, and Solidity.If you are new in this web3 space, this might interest you…Introduction

I have been immersed in the blockchain web3 space for a few months. Well, this has been an intriguing ride thus far. I wish I had begun this earlier in my professional career. I adore this new journey, and every morning I look forward to learning something new and trying something different. Part of that journey led me to develop a dApp (decentralized Application) for a house rental platform.

How it works

The application is a partial clone of the Airbnb website where users can list properties/rooms to rent out to travelers (i.e. a marketplace where people rent out their properties). As the owner of a property, you will be able to create, update, and delete a property, in the same way, customers will be able to view the listed property and if they like it, they can book and check in to the property when the time reach and can also request for a refund (perhaps, they don’t like it). If a user has successfully checked in to an apartment, they will be qualified to post a review of that property.

Technologies/tools

Next.js, Solidity, Redux, NodeJs, Hardhat, Ether.js

LESSONS LEARNTLesson 1: First, you need to design your application’s (dApp) front-end user interface.

As a frontend engineer, I am more interested in the front-end/user interface (UI) of the dApp, The front-end is the part of the dApp that users interact with directly. By focusing on the front-end design first, I can prioritize creating a user-friendly and intuitive interface. This ensures that users will have a positive experience, which is essential for the adoption and success of the dApp.

Also, designing the front end forces me to think through the core functionalities of the dApp. This facilitates early in the development process clarification and consolidation of the functional requirements. A well-thought-out front-end design can guide the development of the back-end (in this case, the smart contract). It provides a clear understanding of what needs to be built on the smart contract to support the front-end’s functionality, leading to a more efficient and aligned development process.

With a well-designed front end, integrating with the smart contract becomes more straightforward. You already know what data (or parameter) is needed, and how it should be presented, making the smart contract integration smoother. In summary, designing the front end first sets a solid foundation for the rest of the dApp development, ensuring that the end product is user-friendly, functional, and aligned with user needs.

Lesson 2: The need to use dummy data to populate the front-end components/UI.

As front-end engineers, dummy data allows us to see how our front-end UI will look and behave with real content. This visual feedback helps to ensure that our UI components are correctly displayed and function as expected. With dummy data, I can test how my design adapts to different screen sizes and devices. This ensures that the dApp is fully responsive and looks good across various platforms/screen sizes.

Meanwhile, dummy data gives me the privilege of simulating user interactions with the dApp, this ensures that the logic behind these interactions is sound before real data is introduced from the smart contract

Generally, using dummy data enables front-end developers to work independently of the back-end (smart contracts). While the back-end logic is still being developed, the front-end can be built and tested using placeholder data. This parallel development speeds up the overall process and when it’s time to integrate the smart contracts, having a front-end already populated with dummy data makes the process smoother. You can replace the dummy data with real data from the blockchain, ensuring that the front-end components are ready to handle the actual data structure and types. Examples of dummy data providers include DummyJson, JsonPlaceholder and you can get more from here

In summary, dummy data gives me the privilege to thoroughly test and refine the front end before integrating the smart contracts, ensuring a smooth and efficient development process with fewer surprises and issues during integration.

Lesson 3: The importance of using Redux (Redux toolkit) for state management and its importance on the UX.

Redux provides a single, centralized store for the entire application’s state. This is crucial in a dApp, where the state can be influenced by both on-chain data (from smart contracts) and off-chain data (from the UI or other external sources). Having a single source of truth ensures that all parts of the application are consistent and up-to-date.

Aside from this, Redux allows for optimized UI updates by controlling how and when components re-render based on state changes. It also enforces a predictable state management pattern by using pure functions (reducers) to update the state. In a dApp, where data integrity is critical, this predictability ensures that state changes are transparent, traceable, and can be easily debugged. This is important in a dApp to ensure that the UI remains responsive, even when dealing with large amounts of data or frequent updates.

In summary, Redux (most especially using the redux toolkit) provides a robust and scalable solution for managing the state in a dApp. It gives me the privilege of having a smooth UI update as soon as the state changes or when a new apartment/review is created/updated. It’s such a nice experience for the user.

Lesson 4: The use of Hardhat to compile, debug, deploy, and test Ethereum Smart contract

Hardhat is a development environment for Ethereum smart contracts that facilitates testing, debugging, deploying, and compilation. It has local testing, Solidity compilation, and easy contract deployment. Hardhat allows developers to run a local Ethereum network for testing and development. This network simulates the Ethereum blockchain, enabling developers to deploy, test, and debug smart contracts in an isolated environment.

Hardhat allows for detailed network configuration, letting developers easily switch between different Ethereum networks (local, testnet, mainnet) and manage multiple network environments in a single project. Hardhat can analyze and report on the gas usage of smart contract functions, helping developers optimize their contracts for lower gas costs. This is crucial for making dApps more cost-effective for users, especially in environments where gas prices can fluctuate significantly.

Hardhat supports thorough testing of smart contracts using tools like Mocha and Chai. Developers can write unit tests to ensure that individual functions work as expected and integration tests to verify that smart contracts interact correctly with each other

Here is a quick guide to hardhat project structure after setup

Hardhat Project Structure

When you initialize a Hardhat project in your local environment, the structure includes the following important files/folders:

  1. /contracts: All of your .sol files
  2. /scripts: .js files for running scripts
  3. /artifacts: artifacts produced out of the contract compilation
  4. /test: .js files for using testing libraries
  5. hardhat.config.js: file with project configurations (very important!!!)

Please note: The hardhat.config.js file is the most important in your project!

In summary, Hardhat is crucial in dApp development because it provides a powerful, flexible, and user-friendly environment for building, testing, and deploying smart contracts. Its features are designed to streamline the development process, reduce errors, and ensure that the resulting dApp is secure, efficient, and ready for deployment on the Ethereum blockchain.

Lesson 5: The importance of testing your smart contract before front-end integration. [VERY IMPORTANT]

Testing a smart contract is the process of making sure its code functions as intended. Testing helps determine whether a certain smart contract meets the necessary standards for security, usability, and reliability.

Therefore:

TESTING SMART CONTRACTS IS A MUST !!!

So let’s talk about the dangers of not testing smart contracts.

  • Reentrancy: One of the most prevalent problems with smart contracts is reentrancy. Usually, it allows hackers to take money from balances several times and deplete the funds in your smart contract. A hacker employing a reentrancy vulnerability cost $25 million to the well-known decentralized exchange Uniswap in 2020. Reentrancy vulnerabilities are easy to miss, thus it’s critical to properly test your contract before deploying it. All state changes must be finished before invoking external contracts to avoid reentrancy attacks.
  • Frontrunning: Once a transaction is submitted as pending, it becomes publicly visible. Fraudulent traders can submit transactions with larger fees and ensure that their transaction is handled first. If writing arbitrage contracts is your intention, this approach may need to be revised because traders may copy your contract and raise the fee to take advantage of your arbitrage possibilities. Although it can be challenging to prevent these problems, you can at least undo your transactions by including a “transaction count” variable in your code. If the value of the transaction counter is less than the provided value, your transaction will be reversed. This amount indicates the most suitable transaction counter value. You should try this approach to make sure it suits your contract.
Smart contract testing is important for the following reasons.
  • To Avoid Bugs and Vulnerabilities: Smart contracts are immutable once deployed on the blockchain. If there’s a bug or vulnerability in the contract, it can lead to serious issues, including financial loss, security breaches, or even the need for contract redeployment. Thorough testing ensures that the contract behaves as expected, minimizing the risk of such problems.
  • For Accurate Business Logic: Testing verifies that the smart contract’s logic correctly implements the intended business rules and processes. This is crucial because any logical errors can lead to incorrect behavior, which
  • To Avoid High Deployment Costs: Deploying smart contracts on the Ethereum mainnet can be expensive due to gas fees. If a contract contains errors and needs to be redeployed, it can lead to significant additional costs. Testing the contract thoroughly in a local or testnet environment helps avoid unnecessary redeployment and associated costs.
  • To Optimize Gas Usage: Testing allows us to analyze and optimize the gas usage of smart contract functions. By identifying and addressing inefficiencies before deployment, you can reduce the cost of interacting with the contract for users.
  • Simplified Debugging: Testing smart contracts in isolation helps to identify issues directly related to the contract logic. If you integrate the front end before testing the contract, it becomes harder to determine whether an issue originates from the contract or the front-end code.
  • Clearer Error Diagnosis: By testing the smart contract independently, you can diagnose errors and edge cases specific to the contract, making it easier to understand and fix them without the added complexity of front-end interactions.
  • Preventing Regressions: When you add new features or update your smart contract, testing helps ensure that these changes do not introduce new bugs or regressions. This is particularly critical before front-end integration because untested modifications may cause unexpected behavior.
  • Consistent Data Flow: Testing guarantees that the data flow between the smart contract and the front end will be consistent and reliable. This is important because front-end components rely on accurate data from the blockchain to function correctly.
Sample test codedescribe('Apartment', () => {
beforeEach(async () => {
await contract
.connect(owner)
.createApartment(name, description, location, images.join(','), rooms, toWei(price))
})

it('Should confirm apartment in array', async () => {
result = await contract.getApartments()
expect(result).to.have.lengthOf(1)

result = await contract.getApartment(id)
expect(result.name).to.be.equal(name)
expect(result.description).to.be.equal(description)
expect(result.images).to.be.equal(images.join(','))
})
})

In summary, testing your smart contract before front-end integration is crucial for ensuring its correctness, security, and functionality. It saves time and costs in the long run, helps prevent serious issues, and provides a solid foundation for the rest of your dApp development.

The five points I listed above summarize the knowledge I gained while working on this project.

The source code for this project can be found here.

Disclaimer: I would like to say that, this is a tutorial done by Darlington Gospel and the full video can be found on his YouTube account, while the source code can be found here as well.

Useful Resources

What I learned while developing a decentralized House Rental Platform with Next.js, was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.