Skip to main content

Gear Rentable Non-Fungible Token

Introduction

This is an extension of standard Non-Fungible token. It proposes an additional role (user) which can be granted to addresses, and a time where the role is automatically revoked (expires). The user role represents permission to "use" the NFT, but not the ability to transfer it or set users.

Motivation

Some NFTs have certain utilities. For example, virtual land can be "used" to build scenes, and NFTs representing game assets can be "used" in-game. In some cases, the owner and user may not always be the same. There may be an owner of the NFT that rents it out to a “user”. The actions that a “user” should be able to take with an NFT would be different from the “owner” (for instance, “users” usually shouldn’t be able to sell ownership of the NFT). In these situations, it makes sense to have separate roles that identify whether an address represents an “owner” or a “user” and manage permissions to perform actions accordingly.

Some projects already use this design scheme under different names such as “operator” or “controller” but as it becomes more and more prevalent, we need a unified standard to facilitate collaboration amongst all applications.

Furthermore, applications of this model (such as renting) often demand that user addresses have only temporary access to using the NFT. Normally, this means the owner needs to submit two on-chain transactions, one to list a new address as the new user role at the start of the duration and one to reclaim the user role at the end. This is inefficient in both labor and gas and so an “expires” function is introduced that would facilitate the automatic end of a usage term without the need of a second transaction.

Details

The default implementation of the NFT contract is provided in the gear library: gear-lib/non_fungible_token.

To use the default implementation you should include the packages into your Cargo.toml file:

gear-lib = { git = "https://github.com/gear-dapps/gear-lib.git" }
gear-lib-derive = { git = "https://github.com/gear-dapps/gear-lib.git" }
hashbrown = "0.13.1"

Rentable NFT contains regular NFT (gnft-721) and additional field users_info:

use hashbrown::HashMap;

#[derive(Debug, Default, NFTStateKeeper, NFTCore, NFTMetaState)]
pub struct Nft {
#[NFTStateField]
pub token: NFTState,
pub token_id: TokenId,
pub owner: ActorId,
pub transactions: HashMap<H256, NFTEvent>,
pub users_info: HashMap<TokenId, UserInfo>,
}

In all other cases, everything also corresponds to the usual non-fungible-token contract, except additional specific actions:

#[derive(Debug, Encode, Decode, TypeInfo)]
pub enum NFTAction {
// ... like a usual NFT contract
SetUser {
token_id: TokenId,
address: ActorId,
expires: u64, // unix timestamp
transaction_id: u64,
},
UserOf {
token_id: TokenId,
},
UserExpires {
token_id: TokenId,
},
}

And features specific events:

#[derive(Clone, Debug, Encode, Decode, TypeInfo)]
pub enum NFTEvent {
UpdateUser {
token_id: TokenId,
address: ActorId,
expires: u64,
},
UserOf {
address: ActorId,
},
UserExpires {
expires: u64,
},
}

Conclusion

Gear provides a reusable library with core functionality for the gNFT-4907 protocol. By using object composition, the library can be utilized within a custom NFT contract implementation in order to minimize duplication of community available code.

A source code of the Gear NFT smart contract example based on gear-lib is available on GitHub: gear-dapps/non-fungible-token.

See also an example of the smart contract testing implementation based on gtest: gear-dapps/non-fungible-token/tests.

For more details about testing smart contracts written on Gear, refer to this article: Program Testing.