Introduction
The hotel industry is constantly evolving, with the increasing need for secure and efficient booking systems. Traditional booking platforms often involve intermediaries, which can lead to higher costs, lack of transparency, and potential security risks. By leveraging the Celo blockchain, we can overcome these challenges and create a decentralized hotel booking system that provides enhanced trust, immutability, and efficiency.
This tutorial shows how to use smart contracts to create a decentralized and transparent hotel booking system on the Celo blockchain. By the end, you will know how to implement smart contracts for hotel booking and apply this knowledge to other decentralized applications.
Prerequisites:
These tutorials assume that you have some basic knowledge of solidity
This is a list of what we’ll cover
- Step 1: Creating a new project
- Step 2: Writing the smart contract
- Step 3: Compiling and deploying the smart contract
Requirements
Step 1: Creating a new project
-
Open the Remix IDE
-
Click on the File Explorer icon on the left side of the screen, then create a new workspace by clicking on the + icon
3.Chose a template for your project. For this tutorial, we will use the Basic template and name our project Booking Hotel, then click on Ok
You will see a structured project like this
Now, we will create a new file named BookingHotel.sol
by right-clicking on the contracts folder and selecting New File
Step 2: Writing the smart contract
Open the BookingHotel.sol
file and write the following code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract HotelBooking {
// Code goes here...
}
First, we need to define license for our smart contract. We will use the MIT license. Then, we define the version of solidity we will use. In this tutorial, we will use version 0.8.15.
uint256 public nextBookingId;
struct Booking {
uint256 roomId;
uint256 checkInDate;
uint256 checkOutDate;
address guest;
bool isActive;
}
mapping(uint256 => Booking) public bookings;
We will use a struct to store the booking information, and a mapping to store the booking ID and the booking information. We will also use a variable to store the next booking ID.
The Booking
struct is defined to represent a hotel booking, containing the room ID, check-in date, check-out date, guest address, and an isActive
flag.
The bookings
mapping is used to store all the bookings. The mapping key is the booking ID, and the value is the Booking
struct.
The nextBookingId
variable is used to keep track of the next booking ID to be assigned. It is initialized to 1 in the constructor.
event BookingCreated(
uint256 bookingId,
uint256 roomId,
uint256 checkInDate,
uint256 checkOutDate,
address guest
);
event BookingCanceled(uint256 bookingId);
Next, we define two events. The first event BookingCreated
will be emitted when a new booking is created. The second event BookingCanceled
will be emitted when a booking is canceled.
constructor() {
nextBookingId = 1;
}
We will use a constructor to initialize the next booking ID to 1.
function bookHotel(uint256 _roomId, uint256 _checkInDate, uint256 _checkOutDate) external {
require(_checkInDate < _checkOutDate, "Invalid date range");
require(_roomId > 0, "Invalid room ID");
require(!isRoomBooked(_roomId, _checkInDate, _checkOutDate), "Room is already booked");
Booking memory newBooking = Booking({
roomId: _roomId,
checkInDate: _checkInDate,
checkOutDate: _checkOutDate,
guest: msg.sender,
isActive: true
});
bookings[nextBookingId] = newBooking;
emit BookingCreated(nextBookingId, _roomId, _checkInDate, _checkOutDate, msg.sender);
nextBookingId++;
}
The bookHotel
function will be used to book a hotel room. It takes three parameters: the room ID, the check-in date, and the check-out date. It will check if the check-in date is before the check-out date, if the room ID is valid, and if the room is available. If all the checks pass, it will create a new booking and emit the BookingCreated
event.
function cancelBooking(uint256 _bookingId) external {
Booking storage booking = bookings[_bookingId];
require(booking.guest == msg.sender, "Only the guest can cancel the booking");
require(booking.isActive, "Booking is already canceled");
booking.isActive = false;
emit BookingCanceled(_bookingId);
}
The cancelBooking
function will be used to cancel a booking. It takes one parameter: the booking ID. It will check if the booking was made by the sender and if the booking is active. If all the checks pass, it will cancel the booking and emit the BookingCanceled
event.
function isRoomBooked(
uint256 _roomId,
uint256 _checkInDate,
uint256 _checkOutDate) internal view returns (bool) {
for (uint256 i = 1; i < nextBookingId; i++) {
Booking storage booking = bookings[i];
if (booking.isActive &&
booking.roomId == _roomId &&
(_checkInDate >= booking.checkInDate && _checkInDate < booking.checkOutDate ||
_checkOutDate > booking.checkInDate && _checkOutDate <= booking.checkOutDate)) {
return true;
}
}
return false;
}
The isRoomBooked
function will be used to check if a room is booked. It takes three parameters: the room ID, the check-in date, and the check-out date. It will iterate through all the bookings and check if the room is booked for the given date range. If the room is booked, it will return true. Otherwise, it will return false.
Full code of BookingHotel.sol
looks like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract HotelBooking {
struct Booking {
uint256 roomId;
uint256 checkInDate;
uint256 checkOutDate;
address guest;
bool isActive;
}
uint256 public nextBookingId;
mapping(uint256 => Booking) public bookings;
event BookingCreated(
uint256 bookingId,
uint256 roomId,
uint256 checkInDate,
uint256 checkOutDate,
address guest
);
event BookingCanceled(uint256 bookingId);
constructor() {
nextBookingId = 1;
}
function bookHotel(
uint256 _roomId,
uint256 _checkInDate,
uint256 _checkOutDate
) external {
require(_checkInDate < _checkOutDate, "Invalid date range");
require(_roomId > 0, "Invalid room ID");
require(
!isRoomBooked(_roomId, _checkInDate, _checkOutDate),
"Room is already booked"
);
Booking memory newBooking = Booking({
roomId: _roomId,
checkInDate: _checkInDate,
checkOutDate: _checkOutDate,
guest: msg.sender,
isActive: true
});
bookings[nextBookingId] = newBooking;
emit BookingCreated(
nextBookingId,
_roomId,
_checkInDate,
_checkOutDate,
msg.sender
);
nextBookingId++;
}
function cancelBooking(uint256 _bookingId) external {
Booking storage booking = bookings[_bookingId];
require(
booking.guest == msg.sender,
"Only the guest can cancel the booking"
);
require(booking.isActive, "Booking is already canceled");
booking.isActive = false;
emit BookingCanceled(_bookingId);
}
function isRoomBooked(
uint256 _roomId,
uint256 _checkInDate,
uint256 _checkOutDate
) internal view returns (bool) {
for (uint256 i = 1; i < nextBookingId; i++) {
Booking storage booking = bookings[i];
if (
booking.isActive &&
booking.roomId == _roomId &&
((_checkInDate >= booking.checkInDate &&
_checkInDate < booking.checkOutDate) ||
(_checkOutDate > booking.checkInDate &&
_checkOutDate <= booking.checkOutDate))
) {
return true;
}
}
return false;
}
}
Step 3: Compiling and deploying the smart contract
Now, we will compile the smart contract. Open BookingHotel.sol
file, and look compiler icon in left side of the editor.
Choose the compiler version 0.8.15
and in the contract dropdown, choose BookingHotel.sol
. Then click on the compile button.
To deploy the smart contract, click on the Ethereum
icon in the left sidebar of the editor.
In the environment dropdown, select Injected Web3. Then, in the contract dropdown, select BookingHotel.sol
. Finally, click on the Deploy button.
You should see contract deployed in the Deployed Contracts section.
Now, we can interact with the smart contract using the Remix IDE UI.
Conclusion
Congratulations on completing this tutorial! We built a decentralized hotel booking system using blockchain technology and smart contracts. The system is transparent and secure, and it eliminates the need for intermediaries. You can enhance the system with additional features like payment processing, rating systems, or integration with external APIs. Happy coding!
Next steps
I hope you learned from this tutorial. I also encourage you to further build your knowledge on smart contract writing by reading as many articles as you can find on the Celo community. The Celo community is a great resource for learning about smart contracts, and there are many articles and tutorials available that can help you improve your skills. In addition to reading articles, you can also participate in discussions and forums on the Celo community to learn from other developers and enthusiasts. By engaging with the Celo community, you can expand your knowledge and network, which will help you become a more proficient smart contract writer.
About the Author
Okoro Samuel Ogheneyole is a Web3 technical writer who has burning passion for technology and loves to share his knowledge for the benefit of other Web3 enthusiasts.
References
GithHub Repo
Solidity Documentation