forked from ethereum/ERCs
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merged by EIP-Bot.
- Loading branch information
Showing
1 changed file
with
276 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
--- | ||
eip: 7578 | ||
title: Physical Asset Redemption | ||
description: Provides the holder of physical asset backed NFTs readily available real-world information on the underlying physical asset. | ||
author: Lee Vidor (@V1d0r) <vidor@emergentx.org>, David Tan <david@emergentx.org>, Lee Smith <lee@emergentx.org> | ||
discussions-to: https://ethereum-magicians.org/t/erc-7578-physical-asset-redemption/17556 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2023-08-01 | ||
requires: 165, 721 | ||
--- | ||
|
||
## Abstract | ||
|
||
This proposal is an extension of [ERC-721](./eip-721.md) and implements additional functionality and information pertaining to the NFT’s underlying physical asset by capturing information that enables the holder of physical asset backed NFTs to verify authenticity and facilitate redemption of the underlying physical assets. This proposal is primarily aimed at providing transparency by disclosing details of involved parties and provides opportunity to define and make readily available relevant legal relationship between NFT holder and the owner/holder of the respective underlying physical asset. This proposal makes the token issuer accountable to embed accurate information on a set of standardized information about the underlying physical asset and the involved key parties. | ||
|
||
## Motivation | ||
|
||
The first wave of NFT use cases encompass predominately the representation of ownership of digital assets. In view of the anticipated trend to tokenize any real-world asset, it is to be expected that the use cases of NFTs will rapidly grow and expand around physical assets. The absence of an embedded standardized set of information pertaining to the underlying physical asset together with lack of transparency of involved key parties, creates an unnecessary hurdle for NFT holders and potential users which might, as a result, hinder mass adoption of NFTs that are used as ownership representation of a specific physical asset. | ||
|
||
Addressing the lack of readily available information and paving the way for mass adoption for a tokenized economy, this proposal requires that each minted token includes a defined number of predefined variables enabling verification of authenticity and facilitating redemption of the underlying physical asset. | ||
|
||
* `[TOKEN ISSUER]` **Identification of individual or entity minting the NFT (Issuer)**: [NAME], [UNIQUE IDENTIFICATION NUMBER] OR [NETWORK IDENTIFICATION] | ||
<br> *The token issuer is the key person connecting the physical asset and the digital representation. By identifying and disclosing the token issuer, a reference point is made instantly available to the NFT holder which allows them to conduct a due diligence on the NFT issuer and assessment of the NFT issuer’s trustworthiness. At the same time, it creates accountability for the token issuer which leads to overall improvement and standardisation of the NFT minting process. Token issuers will compete for best practices and recognition to gain advantages over competitors. A reputable NFT issuer will e.g. keep information on the legal owner of the physical asset prior to the minting of the underlying physical asset to satisfy any AML and KYC concerns. Ideally the NFT issuer is identified by a name but may also be identifiable via unique identification number or network ID that is issued by a service provider who stores relevant information on the NFT issuer.* | ||
|
||
* `[LEGAL OWNER OF UNDERLYING PHYSICAL ASSET]` **Identification of legal owner of underlying physical asset:** [NAME], [UNIQUE IDENTIFICATION NUMBER] OR [NETWORK ID] | ||
<br> *In view of a redemption of the underlying physical asset and enforcing of legal rights, it is (from a legal perspective) essential for the NFT holder to identify the legal owner of the underlying physical asset. It allows the NFT holder to consider the legal counterparty risk. It cannot be assumed that the NFT issuer is the legal owner of the underlying physical asset, therefore it is vital for the NFT holder to have instant access to this additional information. Same as with the NFT issuer’s identity, the legal owner is ideally identified by a name but may also be identifiable via unique identification number or network ID that is issued by a service provider who stores relevant information on the legal owner.* | ||
|
||
* `[STORAGE LOCATION]` **Identification of storage location of underlying physical asset:** [PHYSICAL ADDRESS OR JURISDICTION] | ||
<br> *Certain physical assets require specific storage conditions. A digital representation of an inappropriately stored physical asset may impact the value of the NFT significantly. Disclosing the storage location and making it directly accessible to the NFT holder, allows them to evaluate the storage risk of the underlying physical asset. In addition, it provides the NFT holder with a second point of contact for the enforcement of the redemption of the underlying physical asset.* | ||
|
||
* `[LEGAL CONTRACT]` **Type of legal relationship:** [WITH LINK TO DOCUMENT IPSF] | ||
<br> *The disclosure and accessibility of the legal basis of the relationship between NFT holder and legal owner of the underlying physical asset promotes token issuers to stipulate and define the legal rights of the involved key parties. It furthermore allows the NFT Holder to conduct a legal risk and enforcement assessment. Ideally, the information is provided by embedding a link to the actual legal documentation such as an agreement or terms. The more information is accessible via the NFT, the better the NFT holder can assess the legal risks associated with enforcement of the redemption of the underlying physical asset.* | ||
|
||
* `[APPLICABLE LAW]` **Governing Law and Jurisdiction:** [JURISDICTION] | ||
<br> *The applicable law is an extension of the legal contract disclosure and makes instantly available to the NFT holder or smart contract under what jurisdiction an enforcement would be governed without the need to review the details legal contract. This allows for an instant assessment of jurisdiction risk.* | ||
|
||
* `[DECLARED VALUE]` **Value of the underlying asset:** [VALUE] | ||
<br> *Certain auxiliary services such as insurance are tied to a value of the NFT and underlying physical asset. By defining a declared value, NFTs are able to be categorised in certain ways while the declared value provides an indication regarding the underlying asset’s value. The declared value of the underlying physical asset does not necessarily represent the market value.* | ||
|
||
|
||
## Specification | ||
|
||
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. | ||
|
||
|
||
`Properties` MUST be set before a token can be minted. | ||
|
||
The `tokenId` MUST be greater than 0. | ||
|
||
The `terms` parameter MUST be a link to a document that is stored on IPFS. | ||
|
||
When a token has no `properties` set mint reverts. | ||
|
||
When a token has a valid properties, if the token burns, the properties MUST be deleted. | ||
|
||
|
||
### Contract Interface | ||
|
||
```solidity | ||
pragma solidity ^0.8.21; | ||
/** | ||
* @notice A struct containing data for redemption properties | ||
* @param tokenId Set when properties are created | ||
* @param tokenIssuer The network or entity minting the tokens | ||
* @param legalOwner The legal owner of the physical asset | ||
* @param storedLocation The physical storage location | ||
* @param terms Link to IPFS contract, agreement or terms | ||
* @param jurisdiction The legal justification set out in the terms | ||
* @param declaredValue The declared value at time of token minting | ||
*/ | ||
struct Properties { | ||
uint256 tokenId; | ||
string tokenIssuer; | ||
string assetHolder; | ||
string storedLocation; | ||
string terms; | ||
string jurisdiction; | ||
Amount declaredValue; | ||
} | ||
/** | ||
* @notice A struct for amount values | ||
* @param currency The currency of the amount | ||
* @param value The value of the amount | ||
*/ | ||
struct Amount { | ||
string currency; | ||
uint256 value; | ||
} | ||
/** | ||
* @notice Interface for the PhysicalAssetRedemption contract | ||
*/ | ||
interface IPhysicalAssetRedemption { | ||
/** | ||
* @notice Emitted when properties are set | ||
* @param properties The properties of the token | ||
*/ | ||
event PropertiesSet(Properties properties); | ||
/** | ||
* @notice Emitted when properties are removed | ||
* @param properties The properties of the token | ||
*/ | ||
event PropertiesRemoved(Properties properties); | ||
/** | ||
* @notice function to get the properties of a token | ||
* @param tokenId The token id of the minted token | ||
*/ | ||
function properties( | ||
uint256 id | ||
) | ||
external | ||
view | ||
returns ( | ||
uint256 tokenId, | ||
string memory tokenIssuer, | ||
string memory assetHolder, | ||
string memory storedLocation, | ||
string memory terms, | ||
string memory jurisdiction, | ||
Amount memory declaredValue | ||
); | ||
/** | ||
* @notice Properties required to be set when minting a token | ||
* @param id The token id of the minted token | ||
* @param tokenIssuer The network or entity minting the tokens | ||
* @param assetHolder The legal owner of the physical asset | ||
* @param storedLocation The physical storage location | ||
* @param terms HTTP Link to IPFS contract, agreement or terms | ||
* @param jurisdiction The legal justification set out in the terms | ||
* @param declaredValueCurrency The declared value currency at time of token minting | ||
* @param declaredValueAmount The declared value amount at time of token minting | ||
*/ | ||
function setProperties( | ||
uint256 id, | ||
string memory tokenIssuer, | ||
string memory assetHolder, | ||
string memory storedLocation, | ||
string memory terms, | ||
string memory jurisdiction, | ||
string memory declaredValueCurrency, | ||
uint256 declaredValueAmount | ||
) external; | ||
} | ||
``` | ||
|
||
The `setProperties(uint256 id, string memory tokenIssuer, string memory assetHolder, string memory storedLocation, string memory terms, string memory jurisdiction, string memory declaredValueCurrency, uint256 declaredValueAmount)` function is called before minting a token. | ||
|
||
The `properties(uint256 id)` function MUST return the unique `properties` for a token. | ||
|
||
When `properties` are set, the `PropertiesSet(Properties properties)` event is emitted. | ||
|
||
When `properties` are removed, the `PropertiesRemoved(Properties properties)` event is emitted. | ||
|
||
|
||
## Rationale | ||
|
||
The `tokenId` must be greater than 0 so the `properties` can be checked before minting. | ||
|
||
The mint function is overridden to check if the `properties` are set before minting. | ||
|
||
The `terms` parameter is a HTTP link to a document that is stored on IPFS. This is to ensure that the document is immutable and can be verified by the NFT holder. | ||
|
||
Contract level validation is not used on the properties as we believe the accuracy of the data declared is the responsibility of the token issuer. This builds trust in the token issuer and the token itself. | ||
|
||
|
||
## Backwards Compatibility | ||
|
||
This standard is compatible with ERC-721. | ||
|
||
## Reference Implementation | ||
|
||
An example of an ERC-721 that includes the Physical Asset Redemption: | ||
|
||
```solidity | ||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | ||
import "./IPhysicalAssetRedemption.sol"; | ||
/** | ||
* @title Physical Asset Redemption Contract | ||
* @notice Contract for Physical Asset Redemption Standard | ||
**/ | ||
contract PhysicalAssetRedemption is IPhysicalAssetRedemption, ERC721 { | ||
/** | ||
* @notice Constructor for the PhysicalAssetRedemption contract | ||
* @param _name The name of the token | ||
* @param _symbol The symbol of the token | ||
*/ | ||
constructor( | ||
string memory _name, | ||
string memory _symbol | ||
) ERC721(_name, _symbol) {} | ||
mapping(uint256 => Properties) public properties; | ||
/** | ||
* @notice Properties required to be set when minting a token | ||
* @param id The token id of the initialized token. Should be greater than 0. | ||
* @param tokenIssuer The network or entity minting the tokens | ||
* @param assetHolder The legal owner of the physical asset | ||
* @param storedLocation The physical storage location | ||
* @param terms Link to IPFS contract, agreement or terms | ||
* @param jurisdiction The legal justification set out in the terms | ||
* @param declaredValueCurrency The declared value currency at time of token minting | ||
* @param declaredValueAmount The declared value amount at time of token minting | ||
*/ | ||
function setProperties( | ||
uint256 id, | ||
string memory tokenIssuer, | ||
string memory assetHolder, | ||
string memory storedLocation, | ||
string memory terms, | ||
string memory jurisdiction, | ||
string memory declaredValueCurrency, | ||
uint256 declaredValueAmount | ||
) public { | ||
require(id > 0, "Token id must be greater than 0"); | ||
properties[id] = Properties({ | ||
tokenId: id, | ||
tokenIssuer: tokenIssuer, | ||
assetHolder: assetHolder, | ||
storedLocation: storedLocation, | ||
terms: terms, | ||
jurisdiction: jurisdiction, | ||
declaredValue: Amount({ | ||
currency: declaredValueCurrency, | ||
value: declaredValueAmount | ||
}) | ||
}); | ||
emit PropertiesSet(properties[id]); | ||
} | ||
/** | ||
* @notice internal function to remove the properties of a token | ||
* @param _tokenId The token id of the minted token | ||
*/ | ||
function _removeProperties(uint256 _tokenId) internal { | ||
delete properties[_tokenId]; | ||
emit PropertiesRemoved(properties[_tokenId]); | ||
} | ||
/** | ||
* @notice override of the _safeMint function to check if properties are set | ||
* @param to The address to mint the token to | ||
* @param id The token id of the token to mint | ||
*/ | ||
function _safeMint(address to, uint256 id) internal virtual override { | ||
require(properties[id].tokenId > 0, "Properties not initialized"); | ||
super._safeMint(to, id); | ||
} | ||
/** | ||
* @notice override of the _burn function to remove properties | ||
* @param id The token id of the minted token | ||
*/ | ||
function _burn(uint256 id) internal virtual override { | ||
_removeProperties(id); | ||
super._burn(id); | ||
} | ||
} | ||
``` | ||
|
||
## Security Considerations | ||
|
||
For further discussion. <!-- TODO --> | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |