Smart Contracts
On-chain architecture
The protocol is composed by three main entities: the Factory, the Smart Account and the Market Place. The Factory
is a smart contract that handles account creation and it is called every time a user opens a new account. The SmartAccount
is also a contract and is deployed by the factory when a new account should be created. The MarketPlace
is a smart contract that handles specific types of transaction involving Smart Accounts, namely NFT rental transactions. To enable a fully functioning protocol all three types of contracts need to communicate with each other.
Factory
As hinted above we use a factory pattern. That means that this contract, the Factory
, is a singleton that is called every time a new account should be created. To be able to do that, it has a method for instantiating and deploying a new Smart Account. The account implementation is stored inside Factory
and every Smart Account has the same implementation.
Smart Account
SmartAccount
is the implementation that each account generated by the Factory
uses. In theory it is also a singleton deployed by the Factory
in its constructor upon its own deployment. Each new account is a ERC1967Proxy
pattern that uses the singleton as its implementation. That is convenient from a user perspective because it allows for upgrades to be had. Once new features and functionalities are developed, either by our team or by the very community, users can opt in on the upgrade without having to create a new account.
Our Smart Account main feature is the enablement of safe and trustless NFT rental transactions. That is done by blocking certain types of operations conditioned on some state circumstances. In simple terms, if a given asset held by the account is a rental, it cannot be transferred, approved or have operators set to its contract. Of course that if the asset is not a rental it is not subject to the same conditions, i.e., the account can do whatever with it.
In order to retrieve a rental NFT from an account, pullAsset
method should be called.
Anyone can call this method for any rented asset. The asset will be returned only if the rental period is expired. This means that the method checks for the current timestamp before making the transfer. The target address of the transfer is always the address who held the NFT when rent was made. The asset is identified by a internal id (index
) stored inside the wallet contract. This index can be accessed using the function below:
Market Place
The main role of the Market Place is to be an intermediary between the NFT owners who want to put their assets out for rent, and Smart Account users who want to rent them. Any NFT market place platform can make itself compatible with this functionality. The compatibility requirements can be seen in a subsequent section.
Listing and De-Listing
Our implementation, MarketPlace,
uses a deposit format. This means that NFT owners have to deposit their NFTs in order to list them. Upon listing an NFT, the caller receives a receipt-NFT that tracks the listed NFT's metadata, so it looks like a replica of it. This receipt is used as a claim to the deposited NFT. So if the user sells a receipt-NFT, he is effectively selling ownership rights to the authentic one. This format gives more freedom to NFT owners to negotiate the asset while it is being rented, making it possible to sell them, putting it out as colateral, etc. Secondly it makes sure a listed NFT will be available to rentees while listed. Once the NFT is retrieved by or returned to the current receipt holder, the receipt is burned.
Listings are qualified by price
(the rent value) and maxDuration
(the maximum duration of future potential rentals). These parameters can be changed at any time. Off course that if an NFT is being rented at the moment of the change, it will only take effect once the current rental ends. Only holders of the related receipt-NFT can change these two parameters (that is what is meant by NFT owners in this context).
NFT owners can delist at any time. If the NFT is available, meaning it is either not rented out or the current rent has expired, it will be sent to the owner's account. Otherwise it will get flagged as unavailable and sent to the owner's account once it is retrieved from the rentee's account. Delisting is also restricted to receipt holders.
Renting
Renting listed NFTs is restricted to SmartAccount
implementations. It is also required that the account has no operators set to the contract of the NFT being rented. It is trivial to check this because SmartAccount
carries internal logic to take stock of this variable.
The duration of the rent is specified as an argument in the call and has to be less than or equal to the current maxDuration
for the listing, which can be accessed by calling getMaxDuration
.
Searchers and Retrievals
We also implement a pullAsset
method to retrieve expired rentals from Smart Accounts. This method is totally permissionless and pays a pull-fee to the caller. This means players looking for profit opportunity can monitor the protocol in search for expired rentals and execute retrievals and get paid for doing it! We call this players Searchers. They will provide a better user experience for NFT owners who won't have to take this step themselves. Off course that the very NFT owners can always execute the retrieval if no one else does, absorbing the pull-fee in the process.
If the NFT was delisted prior to the retrieval, it is sent to the account currently holding the receipt. This is why NFT owners need to be wary of staking receipts, because it is possible they loose their NFTs by doing so. If the listing is still on, the NFT is returned to the MarketPlace
as available. If an NFT owner delists an NFT that is currently an expired rental before anyone executes a retrieval, it is automatically pulled from the rentee's account and sent to the owner's account in a single tx. The owner absorbs the pull-fee in this case.
The pull-fee is taken out of the service-fee charged upon the rental call. It sits idle in a untouchable pool, so the amount of funds needed to cover retrievals will always be available.
Rental metadata can be accessed via Rental event emitted on every successful rent call.
The pull-fee can alternatively be accessed by feeding the receipt id to getPullFee
. The receipt id can be accessed by feeding contract address and token id to getReceipt
. An NFT
struct (below) is obtained by giving a receipt id to getNFTbyReceipt
.
The contracts will undergo further adaptation to integrate ERC-1155 tokens among other features. So be forewarned that some specifications may change in the coming future.