๐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
Copyright and license under [GNU GPLv2 or later]
๐ Extension: ReservableTokenEnumerable
๐ฆ This abstract contract extends
ReservableTokento include enumerable reservation capabilities usingEnumerableSet.
โจ 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 rangesEnumerableSetfrom 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
AppStoragestruct patternKeep separation of concerns between reservation management, token core, and marketplace logic
๐ Recommended Setup
Use
ReservableTokenas the base facet with core reservation functionalityExtend with
ReservableTokenEnumerableif enumeration or querying capabilities are neededShare storage using
LibAppStoragewith theDiamondStoragepatternInteract through
delegatecallto 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:
DiamondCutFacetmanages upgrades, whileReservableFacethandles ERC-721 reservations using interval trees and enumerable sets.
Last updated