Description
Preamble
EIP: <to be assigned>
Title: Renting Standard for Rival, Non-Fungible Tokens
Author: Steven Lee <[email protected]>
Type: Standard
Category: ERC
Status: Draft
Created: 2017-12-26
Summary
A standard interface for renting rival non-fungible tokens.
Definitions
Rival good: a good is rival if its consumption by one individual prevents simultaneous consumption by other individuals. For example, driving a car is rival but watching the sunset is non-rival.
Non-Fungible good: a good is non-fungible if it is not interchangeable. For example, cars are non-fungible but Ether is fungible.
Abstract
The following suggests a standard API for renting access to rival non-fungible tokens within smart contracts.
Motivation
A standard interface would allow for any rival non-fungible token (rival NFT) on Ethereum to be handled by general purpose applications for renting purposes. Specifically, this would allow an owner to rent access to their rival NFTs using a standard set of commands, thus allowing users to view all past and current rental agreements from a single wallet interface.
Specifications
ERC-721 Compatibility
This section taken from ERC721. Follow link for a more detailed description of the ERC721 methods.
name
function name() constant returns (string name)
OPTIONAL - It is recommend that this method is implemented for enhanced usability with wallets and exchanges, but interfaces and other contracts MUST NOT depend on the existence of this method.
symbol
function symbol() constant returns (string symbol)
OPTIONAL - It is recommend that this method is implemented for enhanced usability with wallets and exchanges, but interfaces and other contracts MUST NOT depend on the existence of this method.
totalSupply
function totalSupply() public view returns (uint256 total)
Returns the total number of NFTs currently tracked by this contract.
balanceOf
function balanceOf(address _owner) public view returns (uint256 balance)
Returns the number of NFTs assigned to address _owner
.
ownerOf
function ownerOf(uint256 _tokenId) external view returns (address owner);
Returns the address currently marked as the owner of _tokenID
.
approve
function approve(address _to, uint256 _tokenId) external
Grants approval for address _to
to take possession of the NFT with ID _tokenId
.
transferFrom
function transferFrom(address _from, address _to, uint256 _tokenId) external
Assigns ownership of the NFT with ID _tokenId
to _to
if and only if _from
has been previously granted approval
transfer
function transfer(address _to, uint256 _tokenId) external
Assigns the ownership of the NFT with ID _tokenId
to _to
if and only if msg.sender == ownerOf(_tokenId)
. A successful transfer MUST fire the Transfer event (defined below).
Basic Renting
reserve
reserve(uint256 _tokenId, uint256 _start, uint256 _stop) external returns (bool success)
Reserve access to token (_tokenId
) from time _start
to time _stop
. A successful reservation must ensure each time slot in the range _start
to _stop
is not previously reserved (by calling the function checkAvailable()
described below) and then emit a Reserve event. For example, this could be implemented through a double mapping given by,
mapping(uint256 -> mapping(uint256 -> address)) reservations
In this case, we could map _tokenId
to a range of time slots, and each time slot to an address. If each time in the range _start
to _stop
returns address(0), then add reservations[_tokenId][_time] = msg.sender
for every _time
in range _start
to _stop
.
Further considerations include adding a reservation price, although this may not be necessary in the case of an auction for rental price.
access
access(uint256 _tokenId) external returns (bool success)
If msg.sender == reservations[_tokenId][now]
then grant access. Due to the possibility of different units of time preferred in the reservation (i.e. reserving by the second, hour, day, week, and so on), now
may need to be checked to the nearest reservation unit. This is to say that access must ensure that msg.sender
has a reservation for that time slot.
settle
settle(uint256 _tokenId, address _renter, uint256 _stop) external returns (bool success)
Removes _renter
access to _tokenId
and transfers any agreed upon funds only if _renter == reservations[_tokenId][_stop]
. Analogous to checking out of a hotel room or returning a rental car.
This function should be callable by either the owner of _tokenId
or _renter
, however, the owner should only be able to call this function if now >= _stop
to prevent premature settlement of funds.
checkAvailable
checkAvailable(uint256 _tokenId, uint256 _time) public view returns (bool available)
Returns true if reservations[_tokenId][_time] == address(0)
and false otherwise.
cancelReservation
cancelReservation(uint256 _tokenId, uint256 _start, uint256 _stop) external returns (bool success)
Returns true if msg.sender == reservations[_tokenId][_time]
for every _time
in range _start
to _stop
and deletes reservation.
Events
Transfer
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId)
Consistent with ERC721.
Approval
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId)
Consistent with ERC721.
Reserve
event Reserve(address indexed _renter, uint256 _tokenId, uint256 _start, uint256 _stop)
Must trigger on any successful call to reservation.
Cancel
event CancelReservation(address indexed _renter, uint256 _tokenId, uint256 _start, uint256 _stop)
Must trigger on any successful call to cancelReservation.
Rationale
The Ethereum blockchain provides the opportunity for reimagined distribution systems in asset rental markets (i.e. the travel industry). A community standard would help encourage secure rental contracts with common interfaces, thus allowing renters and owners alike to view all of their rental agreements from a single application.