40 KiB
eip | title | description | author | discussions-to | status | type | category | created | requires |
---|---|---|---|---|---|---|---|---|---|
6065 | Real Estate Token | An interface for real estate NFTs that extends EIP-721 | Alex (@Alex-Klasma), Ben Fusek (@bfusek), Daniel Fallon-Cyr (@dfalloncyr) | https://ethereum-magicians.org/t/eip-6065-real-estate-token/11936 | Draft | Standards Track | ERC | 2022-11-29 | 721 |
Abstract
This proposal introduces an open structure for physical real estate and property to exist on the blockchain. This standard builds off of EIP-721, adding important functionality necessary for representing real world assets such as real estate. The three objectives this standard aims to meet are: universal transferability of the NFT, private property rights attached to the NFT, and atomic transfer of property rights with the transfer of the NFT. The token contains a hashed operating agreement component, the ability to transfer legal ownership of the property, a payment function, and a repossession function. In addition to the token component, there are legal requirements that have to be met, which are discussed in the specification.
Motivation
Real estate is the largest asset class in the world. By tokenizing real estate, barriers to entry are lowered, transaction costs are minimized, information asymmetry is reduced, ownership structures become more malleable, and a new building block for innovation is formed. However, in order to tokenize this asset class, a common standard is needed that accounts for its real world particularities while remaining flexible enough to adapt to various jurisdictions and regulatory environments.
Ethereum tokens involving real world assets are notoriously tricky. This is because Ethereum tokens exist on-chain, while real estate exists off-chain. As such, the two are subject to entirely different consensus environments. For Ethereum tokens, consensus is reached through a formalized process of distributed validators. When a purely-digital NFT is transferred, the new owner has a cryptographic guarantee of ownership. For real estate, consensus is supported by legal contracts, property law, and enforced by the court system. With existing asset-backed EIP-721 tokens, a transfer of the token to another individual does not necessarily have any impact on the legal ownership of the physical asset.
This standard attempts to solve the real world reconciliation issue, enabling real estate NFTs to function seamlessly on-chain, just like their purely-digital counterparts.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
In order to meet the above objectives and create an open standard for on-chain property ownership we have created a token structure that builds on the EIP-721 standard and coupled that with a set of legal requirements broad enough to adapt to various jurisdictions and regulatory environments.
Token Components:
- Inherits EIP-721 - Allows for backwards compatibility with the most widely accepted NFT token standard.
- Transferable Administrator of physical asset - Ability for NFT owner to initiate a transfer of the legal owner of the physical asset.
- Hashed operating agreement - Immutable legal agreement between Administrator and NFT owner that requires both parties to accept any proposed changes before they are made.
- Payment function - Ability for NFT Administrator to request payment for financing any payments made by the Administrator on behalf of the NFT owner (e.g. property taxes).
- Repossession function - Ability for Administrator to repossess the asset to ensure legally required payments are made whole (e.g. unpaid property taxes).
Token Legal Requirements (Outlined in Hashed Operating Agreement):
- Property held by the Administrator is self-contained, transferable, and bankruptcy remote.
- Transfer of property rights are atomic with the digital transfer of the NFT.
- The NFT owner Ethereum address has the right to change the Administrator (i.e. legal owner) of the property.
- The operating agreement for the legal entity which holds the property must be hashed to the NFT and cannot be changed without mutual approval from both the NFT owner and the Administrator.
- The operating agreement must contain the right for the NFT owner to hold, occupy, rent, alter, resell, or transfer the property.
- The Administrator has no usage right to the property and may not collateralize, use, or otherwise encumber the property attached to the NFT.
- The Administrator is the sole legal owner of the property, and responsible for facilitating mandatory filings and payments for the property.
- The Administrator is entitled to limited liability with regard to the property and has a right to require insurance on the property.
- Failure of the NFT owner to make required payments for the property (e.g. property taxes) triggers the Administrator’s right to repossess the property in order to make required payments.
Interfaces
We rely on the EIP-721 NFT token standard for all transfer and approval logic. All transfer and approval functions are inherited from this token standard without changes. This allows an NFT under this standard to become interoperable with preexisting NFT exchanges and services, however some care must be taken. Please refer to the Backwards Compatibility
section.
Administrator
/// @dev This event emits when a change of NFT Administrator is proposed.
/// Note that contracts can be init'ed with changes proposed without this event emitted.
event AdministratorChangeInit(uint256 indexed _tokenId, address indexed _owner, address indexed _from, address indexed _to, string _extradata);
/// @dev This event emits when a change of NFT Administrator is canceled.
/// When an EIP-721 transfer event emits, any proposed Administrator changes should be nulled and this event should also emit
event AdministratorChangeCanceled(uint256 indexed _tokenId, address indexed _owner, address indexed _from, address indexed _to, string _extradata);
/// @dev This event emits when a change of NFT Administrator is accepted. The new Administrator MUST accept this change for this event to emit.
/// This event MUST emit on any change, however, contracts can be init'ed with Administrators set and without emitting events.
event AdministratorChangeAccept(uint256 indexed _tokenId, address indexed _owner, address indexed _from, address indexed _to, string _extradata);
/// @dev MUST emit if cancelAdministratorAccept is called successfully
event AdministratorChangeAcceptCanceled(uint256 indexed _tokenId, address indexed _owner, address indexed _from, address indexed _to, string _extradata);
/// @dev MUST emit if finishAdministratorChange is called successfully
event AdministratorChangeFinish(uint256 indexed _tokenId, address indexed _owner, address indexed _from, address indexed _to, string _extradata);
/// @notice query current Administrator of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the Administrator of the NFT
function administratorOf(uint256 _tokenId) external view returns (address);
// STEP 1: Owner propose Administrator change, possible to cancel
/// @notice propose a change of an Administrator for an NFT, called by ownerOf(NFT)
/// @dev Throws unless msg.sender is the current ownerOf this NFT.
/// @param _tokenId The identifier for an NFT
/// @param _to The newly proposed Administrator of an NFT, if _to == address(0),
/// this can be interpreted as _to == msg.sender == ownerOf, and they want to self-custody.
/// @param _extradata An optional field for metadata
function initAdministratorChange(uint256 _tokenId, address _to, string calldata _extradata) external;
/// @notice query current proposed Administrator of an NFT
/// @dev NFTs assigned to zero addresses are considered invalid, and queries
/// about them do throw. On a EIP-721 transfer event emit, any proposed Administrator should be set to address(0)
/// @param _tokenId The identifier for an NFT
function proposedAdministratorOf(uint256 _tokenId) external view returns (address);
/// @notice ownerOf(NFT) can cancel Administrator change. After a period of time, you might allow anyone (or old administrator)
/// to cancel the change, as this blocks payment delinquency -> repossess logic. You can call this function as long as
/// Administrator change was not accepted/finalized by new Administrator
/// @dev throw if tokenId doesn't have an Administrator change.
/// also implement logic for who/when can Administrator change be canceled
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function cancelAdministratorChange(uint256 _tokenId, string calldata _extradata) external;
// STEP 2: New Administrator, accept Administrator change, possible to cancel
/// @notice new Administrator accept a change of Administrator of an NFT
/// @dev Throws unless msg.sender is proposedAdministratorOf this NFT. you may clear proposedAdministratorOf data
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function acceptAdministratorChange(uint256 _tokenId, string calldata _extradata) external;
/// @notice once the Administrator change is accepted as a new Administrator, this function needs to return their address
/// @dev on an EIP-721 transfer, this address remains, as the transfer is in progress.
/// @param _tokenId The identifier for an NFT
function pendingAdministratorOf(uint256 _tokenId) external view returns(address);
/// @notice allow a cancellation of the processing/pending Administrator change
/// @dev determine who is allowed to cancel this change, up to implementor,
/// msg.sender should be pendingAdministratorOf in most cases, but perhaps can be canceled by anyone after a period of time
/// throw if there's no pendingAdministratorOf
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function cancelAdministratorChangeAccept(uint256 _tokenId, string calldata _extradata) external;
// STEP 3: Finalize Administrator change, cannot cancel. This occurs after the "real world legal steps" to change Administrator have taken place off-chain.
/// @notice finalize the change in Administrator of the NFT
/// @dev throws if msg.sender is not pendingAdministratorOf. now administratorOf(NFT) will return the new Administrator address, you may clear pendingAdministratorOf()
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function finishAdministratorChange(uint256 _tokenId, string calldata _extradata) external;
Operating Agreement Updates
/// @dev emit this event if there's a successful call of initOperatingAgreementChange
/// @param _proposer is the msg.sender of the init
event OperatingAgreementChangeInit(uint256 indexed _tokenId, address indexed _proposer, string _updatedAgreementHash, string _extradata);
/// @dev emit this event if there's a successful call of cancelOperatingAgreementChange
/// also emit this if there is a owner proposed change but the owner transfers to new owner
/// also emit if there is a Administrator proposed change, but the Administrator transfers to a new owner
event OperatingAgreementChangeCancel(uint256 indexed _tokenId, address indexed _proposer, string _extradata);
// @dev emit if there's a successful call of finishOperatingAgreementChange
// @param _proposer is the msg.sender of the init
// @param _agreer is the msg.sender of the finishOperatingAgreementChange
// @param _updatedAgreementHash must be == the _updatedAgreementHash from the OperatingAgreementChangeInit event
event OperatingAgreementChangeFinish(uint256 indexed _tokenId, address indexed _proposer, address indexed _agreer, string _updatedAgreementHash, string _extradata);
/// @notice query the current operating agreement, this is recommended to be an IPFS link
/// or some other URL or reference. see best practices for NFT metadata.
/// @dev if tokenId doesn't exist, throw
/// @param _tokenId The identifier for an NFT
/// @returns some string, likely to an external resource as a legal document is very expensive to store on-chain
function operatingAgreementOf(uint256 _tokenId) external view returns(string);
/// @notice propose a change to the operating agreement
/// @dev throw is msg.sender is not ownerOf(NFT) or is not administratorOf(NFT). update needs to be accepted by the other party
/// (owner if Administrator proposed, Administrator if owner proposed)
/// @param _tokenId The identifier for an NFT
/// @param _updatedAgreementHash Is the proposed new agreement
/// @param _extradata An optional field for metadata
function initOperatingAgreementChange(uint256 _tokenId, string calldata _updatedAgreementHash, string calldata _extradata) external;
/// @notice view a pending change for _tokenId
/// @dev if _tokenId doesn't exist then throw, if there is not an update proposed then throw
/// also note that if the Administrator has made a proposal, but the Administrator is changed to a new Administrator (finished change)
/// then any update proposals should be nulled
/// also note that is the owner has made a proposal, but the owner changes (EIP-721 transfer), then any update proposals should be nulled as well
/// @param _tokenId The identifier for an NFT
/// @returns _proposer is either the Administrator or owner who proposed the update
/// @returns _updatedAgreementHash is the proposed agreement to be update
function pendingOperatingAgreementOf(uint256 _tokenId) external view returns(address _proposer, string _updatedAgreementHash);
/// @notice allow proposer to cancel agreement
/// @dev throw if tokenId doesn't exist, or if there is no proposal for this agreement, or if msg.sender was not the proposer of the change
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function cancelOperatingAgreementChange(uint256 _tokenId, string calldata _extradata) external;
/// @notice accept a change to the operating agreement
/// @dev msg.sender must be ownerOf(NFT) if AdministratorOf(NFT) proposed change, OR must be AdministratorOf(NFT) if ownerOf(NFT) proposed change, ELSE throw
/// also throw if _updatedAgreementHash does not match the originally proposed agreement
/// @param _tokenId The identifier for an NFT
/// @param _updatedAgreementHash hash that MUST match the prior submitted change suggestion hash to confirm the agreement
/// @param _extradata An optional field for metadata
function finishOperatingAgreementChange(uint256 _tokenId, string calldata _updatedAgreementHash, string calldata _extradata) external;
Payments
/// @dev emit this event when initPayment is called successfully
event PaymentInit(uint256 indexed _tokenId, address indexed _administrator, address indexed _paymentToken, uint256 _amount, bool _decreaseAmtOwed, uint256 _oldestTimestamp, string _extradata);
/// @dev This event emits when a finishPayment is successful. The payment MUST be completed for this event to emit, and
/// this event MUST emit if the payment is completed and funds are transferred from msg.sender address
event PaymentFinish(uint256 indexed _tokenId, address indexed _administrator, address indexed _paymentToken, uint256 _amount, string _extradata);
/// @notice Administrator assess payment on the NFT owner
/// @dev throw if msg.sender is not the current administratorOf(_tokenId), you may store payments by token to be paid, and you may sum the values of all other
/// prior unpaid payments. store the timestamp of the oldest unpaid payment for this payment type, if this is a new token with no prior payments
/// then store block.timestamp for this payment, this will be used for delinquent payments
/// if payments are _decreaseAmtOwed, the total amount owed can never be negative, if this will happen null payment storage for this _paymentToken
/// if a new Administrator is adding/decreasing a payment token outstanding by an old Administrator, overwrite the Administrator name in storage
/// you might want to change the timestamp of old Administrator payments to be a new/current timestamp
/// @param _tokenId The identifier for an NFT
/// @param _paymentToken the EIP-20 token address to define the payment
/// @param _amount the amount of EIP-20 token payment due
/// @param _decreaseAmtOwed this decreases any payment by the _amount, this can be used to revise or adjust down any payments, basically adding a negative sign to _amount
/// @param _extradata An optional field for metadata
function initPayment(uint256 _tokenId, address _paymentToken, uint256 _amount, bool _decreaseAmtOwed, string calldata _extradata) external;
/// @notice query an existing unpaid payment
/// @dev queries about non-existent _tokenId, _token pairings are considered invalid, and queries
/// about them do throw. This can include already completed payments (where the blockchain reference is deleted)
/// @param _tokenId The identifier for an NFT
/// @param _paymentToken the EIP-20 token address to define the payment
/// @returns _amount the amount of _paymentToken that needs to be paid to fulfill payment
/// @returns _receiver is the Administrator of the specific tokenId, who will receive payment
/// @returns _timestamp of the oldest non-completed payment in this _paymentToken
function pendingPaymentOf(uint256 _tokenId, address _paymentToken) external view returns (uint256 _amount, address _receiver, uint256 _timestamp);
/// @notice NFT owner make payment that was invoiced by Administrator
/// @dev do NOT throw if msg.sender isn't ownerOf(_tokenId), anyone can fulfill a payment if they desire
/// allow msg.sender to make a partial payment for an amount, if _amount > total payments outstanding, then pay their total, do not pay extra
/// also note the Administrator the payment is supposed to go to, we recommend ignoring payments to an old Administrator, or throwing
/// @param _tokenId The identifier for an NFT
/// @param _paymentToken The EIP-20 token address to define the payment
/// @param _amount The amount user desires to pay
/// @param _extradata An optional field for metadata
function finishPayment(uint256 _tokenId, address _paymentToken, uint256 _amount, string calldata _extradata) external;
/// @notice query if a payment is delinquent, a payment considered to be delinquent is defined by implementor
/// it's recommended that a payment cannot be delinquent if there is a proposedAdministratorOf || pendingAdministratorOf
/// if payments are delinquent, then the underlying physical asset is liable to be repossessed
/// we recommend ignoring payments to an old Administrator in a delinquency determination
/// @dev queries about non-existent payments are considered invalid and queries about them do throw.
/// this can include already completed payments (where the blockchain reference is deleted)
/// @param _tokenId The identifier for an NFT
/// @param _paymentToken The EIP-20 token address to define the payment
/// @returns false if there is no delinquent payment for this payment id, EIP-20 payment token, true if there is
function paymentIsDelinquent(uint256 _tokenId, address _paymentToken) external view returns (bool);
Repossess/Foreclosure
/// @dev this event emits when a initRepossess is successful, only emit if initRepossess is successful
event RepossessInit(uint256 indexed _tokenId, address indexed _administrator, address _token, string _extradata);
/// @dev this event emits when a cancelRepossess is successful, only emit if there is successful canceled repossess
event RepossessCancel(uint256 indexed _tokenId, address indexed _administrator, string _extradata);
/// @dev this event emits when finishRepossess is successfully called, only emit if there is a successfully finished repossess
/// @param _amount is the amount of ETH paid back to user after a repossess is complete
event RepossessFinish(uint256 indexed _tokenId, address indexed _administrator, uint256 _amount, string _extradata);
/// @dev this event emits when claimRepossess is called, only emit if it's successfully called
/// @param _amount is the amount of ETH sent to the user
event RepossessClaim(uint256 indexed _tokenId, address indexed _owner, uint256 _amount)
/// @notice if this function returns true, then the underlying physical asset has been repossessed
/// due to the user not paying required fees for the asset. if true, then the asset only contains
/// the second return value in wei, and this amount of ETH can be withdrawn at any time by ownerOf NFT.
/// @param _tokenId The identifier for an NFT
/// @returns _repossessed true if the asset has finished repossessing, else false
/// @returns _amount, the amount of ETH that was returned after the repossess took place, zero if claimed (below)
function isRepossessed(uint256 _tokenId) external view returns(bool _repossessed, uint256 _amount);
/// @notice initialize repossess underlying RWA asset that backs NFT if a payment is delinquent
/// @dev paymentIsDelinquent(_tokenId, _token) must return true, else this function reverts.
/// is msg.sender is not the Administrator, this function reverts.
/// if the Administrator is in transfer state, we recommend not letting a repossess happen as it could be malicious
/// (see paymentIsDelinquent logic)
/// however we also recommend forcing Administrator transfers to happen within a certain period of time to prevent griefing
/// and allowing a repossess after a certain time has elapsed without an Administrator accepting the proposed Administrator change
/// @param _tokenId The identifier for an NFT
/// @param _token The payment token that a payment was delinquent
/// @param _extradata An optional field for metadata
function initRepossess(uint256 _tokenId, address _token, string calldata _extradata) external;
/// @notice view if a payment has a repossess pending on the asset, this will warn any prospective buyer that the asset is in question
/// @dev true if there is a pending repossess, false otherwise, if tokenId doesn't exist, then throw
/// @param _tokenId The identifier for an NFT
/// @returns true if there is a repossess pending, false if not
function pendingRepossess(uint256 _tokenID) external view returns(bool);
/// @notice cancel a prior initialized repossess, Administrator can cancel for any reason
/// @dev tokenId must have an initialized repossess, and msg.sender must be administratorOf(tokenId) or function reverts
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function cancelRepossess(uint256 _tokenId, string calldata _extradata) external;
/// @notice finish repossessing underlying physical asset that backs NFT, underlying asset sold/auctioned at fair value
/// and function is payable so that Administrator can send remaining auction proceeds to contract *in ETH*
/// @dev if msg.sender is not the Administrator, this function reverts
/// @param _tokenId The identifier for an NFT
/// @param _extradata An optional field for metadata
function finishRepossess(uint256 _tokenId, string calldata _extradata) external payable;
/// @notice after an asset is repossessed, ownerOf(NFT) can claim the proceeds of the repossession
/// @dev throw is ownerOf(_tokenId) != msg.sender, otherwise send amount of ETH from finishRepossess() to caller
/// @param _tokenId The identifier for an NFT
function claimRepossess(uint256 _tokenId) external;
Rationale
Introduction
Real world assets operate in messy, non-deterministic environments. Because of this, validating the true state of an asset can be murky, expensive, or time-consuming. For example, in the U.S., change of property ownership is usually recorded at the County Recorder’s office, sometimes using pen and paper. It would be infeasible to continuously update this manual record every time an NFT transaction occurs on the blockchain. Additionally, since real world property rights are enforced by the court of law, it is essential that property ownership be documented in such a way that courts are able to interpret and enforce ownership if necessary.
For these reasons, it is necessary to have a trusted party tasked with the responsibility of ensuring the state of the on-chain property accurately mirrors its physical counterpart. By having an Administrator for the property who issues a legally-binding digital representation of the physical property, we are able to solve for both the atomic transfer of the property rights with the transfer of the NFT, as well as institute a seamless process for making the necessary payments and filings associated with property ownership.
There are various ways to meet the legal requirements of this standard, especially considering different property ownership laws and regulations between various jurisdictions. Therefore, we do not prescribe a specific legal structure. However, an example structure implemented by Klasma Inc. for property tokenization in the U.S. is provided in the Reference Implementation.
Guiding Objectives
We have designed this EIP to achieve three primary objectives necessary for creating an NFT representation of physical real estate:
1. Real Estate NFTs are universally transferable
A key aspect to private property is the right to transfer ownership to any legal person or entity that has the capacity to own that property. Therefore, an NFT representation of physical property should maintain that universal freedom of transfer.
2. All rights associated with property ownership are maintained
The rights associated with private property ownership are the right to hold, occupy, rent, alter, resell, or transfer the property. It is essential that these same rights are maintained in an NFT representation of real estate.
3. Property rights are transferred atomically with the transfer of the NFT.
Token ownership on any blockchain is atomic with the transfer of the digital token. To ensure the digital representation of a physical property is able to fully integrate the benefits of blockchain technology, it is essential the rights associated with the property are passed atomically with the transfer of the digital token representation. For this reason, the legal ownership of the property must be packaged in such a way that allows for the atomic transfer of rights with the transfer of the digital token.
This EIP proposes a way to mesh the transfers of off-chain assets (in a legal sense) with on-chain Ethereum blockchain transfers and state-transitions. The following section specifies the technological and legal requirements needed to accomplish this.
Administrator, Legal Entity, & Administrator Transferability
The Administrator is the legal owner of a singular legal entity special purpose vehicle (SPV) which holds the title to an individual physical property and issues the corresponding NFT. It is the duty of the Administrator to make all necessary filings and payments for the legal entity and corresponding property (e.g. tax filings, property tax payments & required utility payments). In addition to ensuring the property is in good standing with the government, the Administrator is tasked with ensuring the rightful occupancy of the home, signing documents on behalf of the NFT owner when necessary, and posting up-to-date information regarding the condition of the property to the NFT.
Within the token components exists a function to transfer the Administrator of the asset. Any owner of the physical property NFT can transfer legal ownership of the asset by calling this function. This action kicks off the pen and paper process whereby the Administrator changes ownership of the legal entity. This process also allows the NFT owner to bridge the asset off-chain by transferring ownership of the entity to themselves and taking legal ownership of the title to the property.
Trusted roles are antithetical to crypto. Ideally, the Administrator role eventually becomes obsolete. However, currently, this function is essential to providing enforceable property rights to the NFT owner. There are various avenues to explore for making the role of Administrators trust-minimized, including reputation systems and financial/game theory incentives, but they are outside the scope of this standard.
Hashed Operating Agreement
The hashed operating agreement is a legal document issued by the Administrator that contains the rights to the physical property, as well as terms and conditions. This document is hashed to the NFT to ensure the immutability of these rights. In order to make changes to this contract, either the Administrator or NFT owner must submit a change request via the legal entity and it must be approved by the corresponding side. Upon transfer of the NFT, these legal rights are transferred to the new owner.
As this standard is adopted and developed further, we anticipate a collection of particular operating requirements to become common across different Administrators and asset types. These requirements will be componentized into referenceable hashes that can be easily understood and verified when interacting with a digital representation of a property.
Payment Function
Payments are a necessary part of owning real estate. Owners must pay for property taxes, basic utilities, and other required costs. Because the Administrator is the legal owner of the entity that holds the title to the property, it is the Administrator’s responsibility to make any and all required payments. Administrators will issue all anticipated fees and payments to the NFT owner using the payment function. Owners are then able to make the necessary payments for the property directly through their NFT. Administrators are strongly encouraged to submit any bills or invoices in “paper form” using the _extradata
field and attach a link to a PDF or other documentation, as well as group payments by time period to ensure simplicity for the owners.
Repossession Function
If the payments mentioned in the previous section go unpaid, the property is at risk of having silent liens placed against it or in extreme circumstances, being repossessed by the state. In order to ensure Administrators are able to provide reliable and clean transfers of a property, the Administrator must have the means to make payments without being subject to payment liability risk. If the Administrator makes payments for a property on behalf of a NFT owner and then needs to be reimbursed, the Administrator is exposed to risk of financial loss in the event the NFT owner sells the NFT without reimbursing the Administrator. For this reason all payments need to be funded directly from the NFT owner through the smart contract.
If the NFT owner fails to pay the invoice, the Administrator has the right to repossess the property, sell it in order to generate the required funds for payment, and then replace the physical asset backing the original NFT with the remaining funds from the sale in ETH. Any proceeds from the repossession/foreclosure sale must be converted to ETH in order to be returned to the original owner. It is up to the implementer to determine what criterion for payment delinquency triggers a repossession.
Backwards Compatibility
Although this standard is backwards compatible with EIP-721, there are important security and implementation considerations to take into account before any smart contract integration. These considerations primarily surround the built-in payment function of the token. While treating NFTs under this standard as identical to EIP-721 NFTs is technically possible, we recommend considering additional logic to support fee payment and recognize any unpaid obligations.
Specific applications that incorporate these NFTs can suffer losses from incorrect implementation. See Integration Checks and Considerations
for more details.
Reference Implementation
This section details an implementation of the legal standard by Klasma Inc. specifically for property tokenization in the U.S. in the 2022 regulatory environment.
The Klasma Inc. legal structure for U.S. real estate and property is as follows:
- Klasma Inc., a parent company and property Administrator, owns a bankruptcy remote LLC for each individual property they act as Administrator for.
- This LLC owns a DAO LLC, which issues the NFT for the property and holds the title and deed to the property.
- This structure enables the following three outcomes:
- Homeowners are shielded from any financial stress or bankruptcy their physical asset Administrator encounters. In the event of an Administrator bankruptcy or dissolution the owner of the NFT is entitled to transfer of the DAO LLC, or the sale and distribution of proceeds from the property.
- Transfer of the rights to the property are atomic with the transfer of the NFT. The rights to the property are issued and controlled by a DAO LLC, a legally recognized entity that can be algorithmically managed, (e.g. managed by smart contract). This enables the enforceable rights to the physical property to be passed digitally with the transfer of the NFT without having to update the legal owner of the property with each transfer.
- Each real estate NFT is universally transferable. The DAO LLC will be taxed as a corporation to limit any pass-through tax benefits that could put the token at risk of being deemed a security in the U.S. The DAO LLC will always operate in a tax neutral or negative status thus not requiring any tax payments to be made on behalf of the LLC. Additionally, it is important to note that the NFT associated with a particular property merely provides a means of digital transfer for the private ownership rights to the property. Therefore, there is no action by the Administrator that could increase the value of the asset, ensuring the NFT is deemed a commodity, the same as any other home or property.
Security Considerations
This standard attempts to strike a balance between the crypto ethos of “code is law” and the understanding that a stolen home with no possibility of recourse for the owner is a non-starter for almost all users. On a risk-adjusted basis, the benefits of using a decentralized finance protocol are unlikely to offset the possibility of a catastrophic loss of the property via a protocol exploit. Losing your home in a DeFi hack is unacceptable.
On the other hand, granting the Administrator full control of the NFTs through backdoor access to the smart contracts is also unacceptable. Given the complex nature of many exploits, requiring Administrators to act as judge and jury in defining a hack and determining the rightful owner is sub-optimal. The following sections define how private key loss and protocol hacks are addressed, as well as provide important checks and considerations for smart contract integrations, particularly for lending protocols.
Private Key Loss and Theft
While DeFi protocol hacks leave an immutable trail on-chain, private key hacks do not. A private key transferring an asset legitimately or maliciously looks identical in any blockchain analysis. As such, Administrators should not be tasked with arbitrating or remedying private key hacks or loss.
Secure private key storage is a fundamental requirement to be able to interact with the crypto ecosystem. Users unable to do so should either pay for an NFT custody solution, or refrain from owning digital assets altogether.
Protocol Hacks and Exploits
A protocol hack or exploit occurs within the confines of a smart contract integration and thus is reviewable on-chain, via specific transaction hashes and block explorer level evidence. A respectable Administrator should lay out their process for classifying and addressing protocol exploits in the Operating Agreement.
To remedy a hack, the Administrator may issue a charge against the NFT to the new owner of the NFT for the full market value of the underlying asset via the initPayment()
function. If the new owner does nothing, the Administrator will repossess this asset and return it to the original owner or protocol. To contest the classification of a hack, the new owner may start the initAdministratorChange()
workflow to change the Administrator or self-custody the asset. Since all Administrators must be legal entities, the original owner may now bring this case to the traditional legal system if they desire.
Through leveraging the existing payment and Administrator change flow, a safety mechanism against protocol exploits is provided without inserting a smart contract backdoor. In the event that an exploit is contestable (e.g. a hack, versus an economic exploit, versus a well timed trade), this system provides an avenue for the new asset owner to make her case through the jurisdictional legal system.
Integration Checks and Considerations
The following are checks and recommendations for protocols integrating NFTs under this standard. These are of particular relevance to applications which lend against any asset utilizing this standard.
- Lending protocol integrators are recommended to pay any payments on behalf of their NFT depositors by calling
finishPayment()
and adding this balance to their users outstanding debt position. This avoids repossession by the Administrator, which may lead to loans becoming undercollateralized or undefined behavior in the protocol. - Before accepting NFT deposits, a protocol integrator should check any
pendingPaymentOf()
the asset. A protocol may decide not accept an asset until all payments are cleared, or mark down the fair market value of the asset. - Protocol integrators should also check if the function
paymentIsDelinquent()
returnstrue
for any payments. If so, they should reject the asset as it is at risk of being repossessed. - Protocol integrators are recommended to implement a time-delay before performing irreversible actions. This is to protect against future to-be-assessed payments that may occur if a hacked NFT is deposited into the protocol.
- For example, a protocol should implement a waiting period before issuing stablecoins as part of a collateralized mortgage on the NFT. If another DeFi protocol can be hacked, and a hacker can immediately run to a different protocol to receive an 80% LTV loan on the asset, it is likely that this second protocol will take a loss when this hack is resolved by the Administrator billing the NFT via
initPayment()
for it’s entire market value. Now this second protocol is stuck with valueless collateral, but already issued a 80% LTV loan. - Because there is no standardized waiting period, DeFi protocols should specifically whitelist Administrator addresses for deposit into their protocols. Administrators may have specialized descriptor smart contracts to give an upper bound on wait-time recommendations. For example, Administrator A could state that one should wait 7 days for any of their assets, and after 7 days it is guaranteed that there will be no
initPayments()
for any prior malicious activity or hacks of the asset, and the asset is now safe to accept as collateral as its value is simply value(asset) without any possible liabilities.
- For example, a protocol should implement a waiting period before issuing stablecoins as part of a collateralized mortgage on the NFT. If another DeFi protocol can be hacked, and a hacker can immediately run to a different protocol to receive an 80% LTV loan on the asset, it is likely that this second protocol will take a loss when this hack is resolved by the Administrator billing the NFT via
- It is recommended that protocol integrators expose
initAdministratorChange()
logic in their smart contracts in order to change the Administrator in the future, if necessary. Protocol integrators may decide to only accept assets with certain operating agreement hashes, viewable by callingoperatingAgreementOf()
. This ensures that all legal clauses and terms in this off-chain contract have been reviewed prior. - More advanced protocol integrators may decide to expose
initOperatingAgreementChange()
functionality, in case a better legal agreement standard is designed in order to upgrade their assets to the best possible protections.
Copyright
Copyright and related rights waived via CC0.