๐ŸŒERC-XXXX: Reservable Token Standard

๐Ÿ“ Draft proposal for a new ERC extension to ERC-721 enabling time-based reservation of non-fungible tokens. โš ๏ธ Not finished โš ๏ธ .

โœจ Simple Summary

A standard interface for ERC-721 tokens that allows owners to list their tokens for reservation during specified time intervals, enabling decentralized booking, rentals, and time-slot management.

๐Ÿ“œ Abstract

This standard proposes an extension to the ERC-721 Non-Fungible Token Standard to support reservable NFTs. It enables the reservation of NFTs for specific time intervals, supporting use cases such as decentralized rentals, lab/equipment booking, and access control based on time. The standard introduces reservation states, calendar conflict prevention, and lifecycle events for decentralized time-bound token usage.

โš ๏ธ This proposal serves as a refined and complete alternative to previous proposals like ERC-809 and ERC-1201, which did not reach final standard status. It addresses missing functionality, unification of terminology, and broader applicability.

๐ŸŽฏ Motivation

Use cases for NFTs increasingly include real-world and digital assets requiring time-bound access โ€” such as booking shared resources, event tickets, or property rentals. This extension enables standardized reservation and scheduling functionality, avoiding ad hoc implementations and enabling interoperable reservation-based systems.

๐Ÿงฉ Specification

Interfaces

interface IReservableToken {
    /// @notice Lists a token, making it available for reservation
    /// @param _tokenId The ID of the token to list
    function listToken(uint256 _tokenId) external;

    /// @notice Unlists a token, removing it from the reservation system
    /// @param _tokenId The ID of the token to unlist
    function unlistToken(uint256 _tokenId) external;

    /// @notice Requests a reservation for a specific time range
    /// @param _tokenId The ID of the token to reserve
    /// @param _start The start timestamp of the reservation
    /// @param _end The end timestamp of the reservation
    function reservationRequest(uint256 _tokenId, uint32 _start, uint32 _end) external;

    /// @notice Cancels a pending reservation request
    /// @param _reservationKey The unique key identifying the reservation
    function cancelReservationRequest(bytes32 _reservationKey) external;

    /// @notice Confirms a pending reservation request
    /// @param _reservationKey The unique key identifying the reservation
    function confirmReservationRequest(bytes32 _reservationKey) external;

    /// @notice Denies a pending reservation request
    /// @param _reservationKey The unique key identifying the reservation
    function denyReservationRequest(bytes32 _reservationKey) external;

    /// @notice Cancels an existing booking
    /// @param _reservationKey The unique key identifying the reservation
    function cancelBooking(bytes32 _reservationKey) external;

    /// @notice Retrieves reservation details by reservation key
    /// @param _reservationKey The unique key of the reservation
    /// @return Reservation struct containing reservation data
    function getReservation(bytes32 _reservationKey) external view returns (
        uint256 labId,
        address renter,
        uint96 price,
        uint32 start,
        uint32 end,
        uint status
    );

    /// @notice Checks if a reservation is actively booked by a user
    /// @param _reservationKey The reservation key to check
    /// @param _user The address of the user
    /// @return True if the user has an active booking
    function hasActiveBooking(bytes32 _reservationKey, address _user) external view returns (bool);

    /// @notice Returns the address of the user who owns the reservation
    /// @param _reservationKey The reservation key
    /// @return Address of the user
    function userOfReservation(bytes32 _reservationKey) external view returns (address);

    /// @notice Checks whether a token is listed as reservable
    /// @param _tokenId The token ID to check
    /// @return True if listed, false otherwise
    function isTokenListed(uint256 _tokenId) external view returns (bool);

    /// @notice Checks if a token is available for reservation in a given time range
    /// @param _tokenId The ID of the token
    /// @param _start The start time of the requested reservation
    /// @param _end The end time of the requested reservation
    /// @return True if the time range is available
    function checkAvailable(uint256 _tokenId, uint256 _start, uint256 _end) external view returns (bool);
}

๐Ÿค” Rationale

The interface provides essential functionality to:

  • โœ… List/unlist tokens as reservable

  • ๐Ÿ“† Request, confirm, and cancel reservations

  • ๐Ÿ—“๏ธ View reservation calendars per token

  • โ›” Avoid overlapping intervals using a time-interval library (e.g., AVL tree)

This encourages composability with marketplaces, decentralized identity, and access management.

๐Ÿ” Security Considerations

  • โ›“๏ธ Prevent time-slot collisions using interval trees

  • ๐Ÿ” Require authentication for token owner and reservation initiator

  • โš–๏ธ Handle overlapping and concurrent reservations gracefully

  • ๐Ÿ“ก Emit events to support transparent off-chain indexing

๐Ÿ› ๏ธ Reference Implementation

A full implementation is available at: DecentraLabsCom/Smart-Contracts

Copyright and license under [GNU GPLv2 or later]


๐Ÿ”„ Extension: ReservableTokenEnumerable

๐Ÿ“ฆ This abstract contract extends ReservableToken to include enumerable reservation capabilities using EnumerableSet.

โœจ Features Added

  • ๐Ÿ”ข Enumeration of reservations per token

  • ๐Ÿ“‡ Query reservations by renter or token

  • ๐Ÿ“ฌ Efficient indexing using EnumerableSet.Bytes32Set

  • ๐Ÿ•’ Precise time interval conflict detection using interval trees

๐Ÿ“ฆ Key Functions

This contract introduces new capabilities including (but not limited to):

๐Ÿ’ก Reservations are tracked internally using interval trees and sets of hashes or keys to allow enumeration and lookup efficiency.

๐Ÿงช Libraries Used

  • RivalIntervalTreeLibrary โ€” for managing overlapping time ranges

  • EnumerableSet from OpenZeppelin โ€” for indexed access to reservation identifiers

๐Ÿง  Use Cases Enhanced

  • Lab booking systems with user dashboards

  • NFT-based rental markets needing calendar views

  • Event space or asset scheduling where users need to see all their upcoming reservations


๐Ÿ“ฃ Events

These events enable off-chain services (e.g., UIs, analytics, or subgraphs) to track the lifecycle of a reservation and its associated status.

โ„น๏ธ These events are crucial for tracking reservation status transitions in decentralized booking systems, especially in UIs and indexing layers like The Graph.

๐Ÿ’Ž Compatibility: EIP-2535 Diamond Standard

This standard is designed to be fully compatible with EIP-2535 Diamonds, enabling modular deployment of facets that implement reservable functionality.

๐Ÿ—๏ธ Facet Architecture

The reservable token logic can be deployed as a facet within a Diamond proxy system. This allows developers to:

  • Add, replace, or remove reservation logic without redeploying the entire contract

  • Share state using a central AppStorage struct pattern

  • Keep separation of concerns between reservation management, token core, and marketplace logic

  • Use ReservableToken as the base facet with core reservation functionality

  • Extend with ReservableTokenEnumerable if enumeration or querying capabilities are needed

  • Share storage using LibAppStorage with the DiamondStorage pattern

  • Interact through delegatecall to preserve upgradeability and modular logic separation

๐Ÿ” Access Control & Security

  • Ensure facets verify caller permissions (owner, renter) properly

  • Emit standard events for off-chain indexing and UI syncing

  • All state modifications are performed via Diamond-compatible storage layout

๐Ÿงฉ Benefits of Diamond Integration

  • Gas-efficient modular upgrades

  • Composability with other facet-based systems

  • Code separation between UI/logic/data layers

๐Ÿ› ๏ธ Example: DiamondCutFacet manages upgrades, while ReservableFacet handles ERC-721 reservations using interval trees and enumerable sets.

Last updated