Standards

ERC4907 Rental NFT, an Extension of EIP-721

Understand ERC4907, the EIP-721 rental NFT upgrade supporting timed access, lending functionality and permissioned asset usage.

Last updated: 12/4/2025
Improve this page

ERC4907, called the Rental Token Standard, extends ERC721 to add native rental functionality. Instead of transferring full ownership, the standard introduces a separate user role with an expiration timestamp, allowing an NFT holder to grant temporary usage rights without giving up ownership. The contract tracks who currently has access through userOf and when that access ends through userExpires. Once the rental period is over, control automatically returns to the owner, and any user-restricted calls revert if the lease is still active.

The standard was created to fix a common gap in ERC721: basic NFTs don’t handle rentals, lending, or temporary rights well, which led projects to implement custom leasing systems with high costs and inconsistent logic. ERC4907 provides a minimal, plug-and-play way for marketplaces, games, metaverse platforms, and rental protocols to manage leases directly on-chain while retaining compatibility with existing ERC721 infrastructure.

It builds directly on ERC721 and ERC165, with optional metadata support. In real-world asset designs, ERC4907 is especially useful for time-bound access or usage rights, such as temporary control over tokenized real estate, equipment, storage units, or property income windows. It can be paired with ERC3643 to ensure that only compliant users are eligible to rent, and with ERC7765 where rental access also includes redeemable privileges like booking rights, yield claims, or delivery of services during the active lease period.

Use of ERC4907 in RWA Contexts

ERC4907 enables real-world assets to be rented, leased, or temporarily delegated without transferring ownership. The owner remains the legal holder of the NFT, while another party is assigned as the temporary user with an expiration timestamp. This allows rental access, income participation, or usage rights to be granted for a defined duration while keeping asset title, tax responsibility, and compliance tied to the owner. It also creates clean on-chain signals that off-chain systems like property managers, custodians, or equipment controllers can use to activate or deactivate access.

Key Applications in RWA Development

Time-Bound Asset Leasing Physical assets such as machinery, vehicles, or industrial equipment can be tokenized as NFTs and rented out. The renter becomes userOf for the defined period, enabling digital access controls or smart lock integration, while ownership and legal responsibility stay with the issuer.

Fractional Yield Rentals In tokenized real estate structures, the renter can be assigned as user to receive rental yield or fee distributions during the lease term. When paired with ERC4626 vaults, distributions can route automatically until the expiration date.

Compliance-Controlled Delegation When combined with ERC3643 or other compliance layers, only verified and approved lessees can be assigned as user. This is especially relevant in regulated instruments such as carbon credits or restricted property rentals where usage rights are not equivalent to ownership.

Metaverse and Hybrid Access Rights For assets with mixed physical and digital utility, such as tokenized venues, event passes, or virtual land tied to real properties, userExpires cleanly enforces end dates without extra negotiation or manual checks.

Developer Advantages in RWA Builds

Compatibility Without Custom Leasing Logic Because the standard extends ERC721 directly, wallets, DEXs, and NFT marketplaces understand it without extra integrations. UIs can differentiate owners from renters using userOf.

Lightweight and Cost-Efficient Assigning a user uses a single transaction, and checking expiration is a simple view call. This works well for short rental cycles or platforms with frequent access changes.

Flexible Extensions Developers can add custom enforcement hooks, fee capture logic, or cross-asset batching. Multi-asset rental markets can extend the model through ERC1155 wrappers.

Regulatory and Accounting Alignment Because ownership is never transferred, rentals avoid creating taxable transfers or securities-like permanent rights. Events provide clear audit logs and timelines, supporting both compliance reviews and dispute resolution.

The following sequence diagram depicts leasing an RWA NFT (e.g., tokenized equipment), from setup to expiration and reversion. It highlights the dual owner/user model for developer orchestration.

Rental NFT.svg

Core Specification

ERC4907 tokens must fully implement ERC721 and add rental logic on top of it. The core change is that transfers must account for active leases: transferFrom and safeTransferFrom are overridden so that when a lease is in effect, the user role is respected and expiration rules are enforced. The primary state-changing function is setUser, which assigns or clears a temporary user and sets an expiration time. The owner remains the true holder of the token, while the user is only granted temporary rights until the timestamp expires. Once that time passes, access automatically reverts without requiring an additional transaction.

Key definitions:

  • User A temporary rights holder assigned to the token via setUser. This role is separate from ownerOf and does not confer ownership, only usage or access rights.
  • User Expiration A Unix timestamp that defines when the current rental or delegated usage period ends. A value of 0 indicates no active user.
  • Set User The function that assigns or removes a user and sets the lease duration. It can only be called by the owner or an approved operator, ensuring rentals cannot be assigned by unauthorized parties.
  • Transfer Enforcement Transfers initiated by the owner are unaffected by the presence of a user. However, a user cannot act beyond their expiration period, and any transfer attempt outside valid lease time must revert.

The standard supports ERC165 interface detection, with the specific interface identifier varying slightly by implementation (for example, type(IERC4907).interfaceId).

The standard defines a single extension interface. Below is the full ABI-compliant code from the EIP.

1pragma solidity ^0.8.0;
2
3import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
4import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
5
6interface IERC4907 is IERC721, IERC165 {
7    // Events
8    event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires);
9    event UserTransfer(uint256 indexed tokenId, address indexed from, address indexed to, uint64 expires);
10
11    // Functions
12    function setUser(uint256 _tokenId, address _user, uint64 _expires) external;
13    function userOf(uint256 _tokenId) external view returns (address);
14    function userExpires(uint256 _tokenId) external view returns (uint256);
15
16    // Overrides (implied in impl)
17    function transferFrom(address from, address to, uint256 tokenId) external override;
18    function safeTransferFrom(address from, address to, uint256 tokenId) external override;
19    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external override;
20}

Detailed Function Breakdown

setUser(uint256 _tokenId, address _user, uint64 _expires) Assigns or removes a temporary user. Passing address(0) clears the user and ends the lease early. Only the owner or an approved operator can call it. The function updates userExpires and emits UpdateUser. In RWA leasing models, issuers or property managers use this to grant lessee access for a fixed period. Setting _expires to zero revokes rights immediately when a tenant is removed or access is cancelled ahead of schedule. Edge case: the function reverts if called by anyone other than the owner or an approved operator. The uint64 expiration accommodates extremely long validity periods.

userOf(uint256 _tokenId) Returns the currently assigned user if an active lease exists, or the zero address when no rental is in place. RWA systems use this for front-end state checks, allowing property dashboards or equipment control interfaces to display who currently holds access rights.

userExpires(uint256 _tokenId) Reports the expiration timestamp of the active user assignment. The value is stored as uint64 but exposed as uint256. Interfaces typically compare this value to block.timestamp to decide when access ends and when user controls should automatically revert.

transferFrom(address from, address to, uint256 tokenId) Overrides the ERC721 implementation so user-based expiration rules are applied. If the caller is the assigned user, the transfer only proceeds if the current time is before userExpires. Transfers initiated by the owner continue normally, regardless of ongoing leases. If the new owner changes the effective user state, a UserTransfer event is emitted. In RWA terms, this allows sub-leasing under controlled conditions while ensuring that legal ownership transfers remain unaffected by temporary user assignments.

safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) Behaves like the standard ERC721 safe transfer, but includes the same expiration enforcement logic. Compliance is checked before delivery and the safe receiver logic runs afterward. For RWA implementations, this allows reliable callback flows such as triggering event confirmations, rental handover notices, or smart-lock access updates upon successful reassignment.

Reference Implementation

The EIP provides a reference Solidity implementation in the specification section. It extends a basic ERC721 contract with the required user mappings and overrides. This example is illustrative and not production-audited; developers should extend it with security best practices (e.g., from OpenZeppelin ERC721 base for unrelated features).

1// SPDX-License-Identifier: CC0-1.0
2pragma solidity ^0.8.0;
3
4import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
5import "./IERC4907.sol";
6
7contract ERC4907 is ERC721, IERC4907 {
8    struct UserInfo
9    {
10        address user;   // address of user role
11        uint64 expires; // unix timestamp, user expires
12    }
13
14    mapping (uint256  => UserInfo) internal _users;
15
16    constructor(string memory name_, string memory symbol_)
17     ERC721(name_,symbol_)
18     {
19     }
20
21    /// @notice set the user and expires of a NFT
22    /// @dev The zero address indicates there is no user
23    /// Throws if `tokenId` is not valid NFT
24    /// @param user  Address of whom to set as user
25    /// @param expires  UNIX timestamp, The user expires when block.timestamp >= expires
26    function setUser(uint256 tokenId, address user, uint64 expires) public virtual override{
27        require(_isApprovedOrOwner(msg.sender, tokenId),"ERC721: transfer caller is not owner nor approved");
28        UserInfo storage info =  _users[tokenId];
29        info.user = user;
30        info.expires = expires;
31        emit UpdateUser(tokenId,user,expires);
32    }
33
34    /// @notice Get the user address of an NFT
35    /// @dev The zero address indicates that there is no user or the user is expired
36    /// @param tokenId NFT tokenId
37    /// @return The user address for this NFT
38    function userOf(uint256 tokenId)public view virtual override returns(address){
39        if( uint256(_users[tokenId].expires) >=  block.timestamp){
40            return  _users[tokenId].user;
41        }else{
42            return address(0);
43        }
44    }
45
46    /// @notice Get the user expires of an NFT
47    /// @dev The zero value indicates that there is no user
48    /// @param tokenId NFT tokenId
49    /// @return The user expires express in UNIX timestamp for this NFT
50    function userExpires(uint256 tokenId) public view virtual override returns(uint256){
51        return _users[tokenId].expires;
52    }
53
54    /// @dev See {IERC165-supportsInterface}.
55    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
56        return super.supportsInterface(interfaceId) || interfaceId == type(IERC4907).interfaceId;
57    }
58
59    function _beforeTokenTransfer(
60        address from,
61        address to,
62        uint256 tokenId,
63        uint256 batchSize
64    ) internal virtual override{
65        super._beforeTokenTransfer(from, to, tokenId, batchSize);
66
67        if (from != to && _users[tokenId].user != address(0)) {
68            delete _users[tokenId];
69            emit UpdateUser(tokenId, address(0), 0);
70        }
71    }
72}

This example uses a minimal ERC721 base. In real RWA deployments, developers often extend it with OpenZeppelin features such as EnumerableAccessControl, or URIStorage to support indexing, role constraints, and metadata.

Key Functions

setUser

1function setUser(uint256 tokenId, address user, uint64 expires) public virtual override{
2    require(_isApprovedOrOwner(msg.sender, tokenId),"ERC721: transfer caller is not owner nor approved");
3    UserInfo storage info =  _users[tokenId];
4    info.user = user;
5    info.expires = expires;
6    emit UpdateUser(tokenId,user,expires);
7}

This assigns or updates the active user for a token and sets the expiration timestamp. Only the owner or an approved operator can call it. In real-world asset rentals, platforms may override this to incorporate rental fee collection, escrow deposits, or payment verification before finalizing a user assignment.

userOf / userExpires

1function userOf(uint256 tokenId)public view virtual override returns(address){
2    if( uint256(_users[tokenId].expires) >=  block.timestamp){
3        return  _users[tokenId].user;
4    }else{
5        return address(0);
6    }
7}
8
9function userExpires(uint256 tokenId) public view virtual override returns(uint256){
10    return _users[tokenId].expires;
11}

These read functions report the current user and their expiration time. Once the lease period ends, userOf automatically returns the zero address, simplifying front-end display logic. For RWA integrations, this is often used by oracles and dashboards to track active leases, update access systems, or feed usage state into payout flows.

_beforeTokenTransfer

1function _beforeTokenTransfer(
2    address from,
3    address to,
4    uint256 tokenId,
5    uint256 batchSize
6) internal virtual override{
7    super._beforeTokenTransfer(from, to, tokenId, batchSize);
8
9    if (from != to && _users[tokenId].user != address(0)) {
10        delete _users[tokenId];
11        emit UpdateUser(tokenId, address(0), 0);
12    }
13}

This hook ensures that whenever ownership changes, any active user assignment is cleared. The new owner receives the token without inheriting an ongoing rental arrangement. In RWA implementations, this hook is commonly expanded to include compliance checks, such as KYC validation for incoming owners or conditions tied to location, license status, or asset category.

Security Considerations

ERC4907 introduces separate ownership and usage roles, which creates unique security risks during rental periods, lease expirations, and operator approvals. Because RWAs often involve legal rentals, access rights, and income streams, state drift or timestamp disputes can escalate beyond technical failures and become contractual conflicts.

Expiration Enforcement Gaps

If expiration checks are incomplete or poorly implemented, a user may retain effective control beyond the intended lease period, especially in edge cases like timestamp manipulation or delayed state updates. Mitigation includes strict block.timestamp validation in every transfer and privilege hook, plus off-chain indexing of lease windows for audit and dispute resolution.

Operator Abuse and Overextended Leases

Approved operators can set excessively long user assignments or delegate access to unauthorized addresses if approvals are too permissive. Mitigation includes limiting operator scopes, using granular isApprovedForAll configurations, and applying identity-based controls such as ERC3643 to ensure only verified lessees can be assigned.

Reentrancy Exposure in Transfer Hooks

If callbacks or fee-collection logic are embedded in _beforeTokenTransfer, a reentrancy window may open that allows rental state manipulation or balance drains. Mitigation includes applying checks-effects-interactions ordering, isolating rental logic from external calls, and using tools like ReentrancyGuard when fee side effects are required.

Event Reliability and Integrity

Off-chain systems rely heavily on UpdateUser logs to trigger lease activation, revoke access, or settle payouts. If these events are missed, overwritten, or forged via shadow forks, state could diverge. Mitigation includes redundant indexing through subgraphs, oracle witnesses, event nonces, and legal fallback records for high-value or regulated rentals.

Security Considerations

ERC4907 introduces separate ownership and usage roles, which creates unique security risks during rental periods, lease expirations, and operator approvals. Because RWAs often involve legal rentals, access rights, and income streams, state drift or timestamp disputes can escalate beyond technical failures and become contractual conflicts.

Expiration Enforcement Gaps

If expiration checks are incomplete or poorly implemented, a user may retain effective control beyond the intended lease period, especially in edge cases like timestamp manipulation or delayed state updates. Mitigation includes strict block.timestamp validation in every transfer and privilege hook, plus off-chain indexing of lease windows for audit and dispute resolution.

Operator Abuse and Overextended Leases

Approved operators can set excessively long user assignments or delegate access to unauthorized addresses if approvals are too permissive. Mitigation includes limiting operator scopes, using granular isApprovedForAll configurations, and applying identity-based controls such as ERC3643 to ensure only verified lessees can be assigned.

Reentrancy Exposure in Transfer Hooks

If callbacks or fee-collection logic are embedded in _beforeTokenTransfer, a reentrancy window may open that allows rental state manipulation or balance drains. Mitigation includes applying checks-effects-interactions ordering, isolating rental logic from external calls, and using tools like ReentrancyGuard when fee side effects are required.

Event Reliability and Integrity

Off-chain systems rely heavily on UpdateUser logs to trigger lease activation, revoke access, or settle payouts. If these events are missed, overwritten, or forged via shadow forks, state could diverge. Mitigation includes redundant indexing through subgraphs, oracle witnesses, event nonces, and legal fallback records for high-value or regulated rentals.

ERC7518 Dynamic Compliant Interop Security Token
ERC7208 On-Chain Data Containers

WE SECURE EVERYTHING YOU BUILD.

From day-zero risk mapping to exchange-ready audits — QuillAudits helps projects grow with confidence. Smart contracts, dApps, infrastructure, compliance — secured end-to-end.

DeFi SecurityplumeUniswap FoundationAethiropt-collectivePolygon SPNBNB Chain Kickstart

Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654

[email protected]

All Rights Reserved. © 2026. QuillAudits - LLC

Privacy Policy