Implementing Smart Contract for Hotel Booking on Celo

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 :spiral_notepad:

  • :white_check_mark: Step 1: Creating a new project
  • :white_check_mark: Step 2: Writing the smart contract
  • :white_check_mark: Step 3: Compiling and deploying the smart contract

Requirements

Step 1: Creating a new project

  1. Open the Remix IDE

  2. 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

3 Likes

@Celo_Academy Announcing This Week's Top Voted Proposals at Celo Academy | 06/15/2023. I will love to get started with this.

1 Like

I can’t wait to add this knowledge to my library of blockchain. I would appreciate.

1 Like

Thanks for your contributions this week! Approved and excited to see how this turns out. :mortar_board: :seedling:

2 Likes

I will review this

1 Like

Okay. Thanks @yafiabiyyu

1 Like