Idea: Standard digital receipts using ERC-721

I hadnt thought too deep into that side of things! But love it!

Like a nft recovery method!

Drafted up a long form introduction to ERC5570 - Digital Receipts:

1 Like

Have published a video demonstrating the usage of the demo application here:

PEEPanEIP #95: EIP-5570: Digital Receipt Non-Fungible Tokens with @darcys22

1 Like

There are two main improvements that need to be made:

  • You need to be able to put the items in an array.

  • The items should be able to be NFTs themselves. Therefore each item should have a property for smart contract and tokenId.

Another improvement would be to make the price queryable so it would be a module you can add to the smart contract so things like oracles can read the price. If the price data is only in the metadata then it cannot be integrated into smart contracts.

1 Like

This sounds an interesting idea worth pursuing!

2 Likes

Could you clarify your point on putting items in an array? They already are in an array:

       "items": {
          "title": "Items",
          "description": "Items included into the receipt",
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "$ref": "item.json#"
          }
        },

I like the idea that the items themselves could be NFTs, If the NFT was issued in the same transaction as the receipt you would be able to find the NFT easily enough but i guess if the receipts was copied you would lose this link. It sorta falls into the same category as serial numbers for product so I think it would need to be general enough to handle both here.

1 Like

This is also an interesting idea! Did you have an example use cases where a smart contract would query the price of an item receipt?

Echoing above. Why does this need to be an nft issued on chain? You could accomplish the above by simply emitting an event with the data you need (signed and encrypted receipt data along with the uri string), which would be much cheaper than creating an nft. Systems can observe and index these events.

1 Like

Ok for the items array I think you just have a syntax error in the json. There should be a bracket instead of a curly brach after the colon or at least thatā€™s what I was looking for when I scanned the json so:

"items": {
          "title": "Items",
          "description": "Items included into the receipt",
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": [{
            "$ref": "item.json#"
          }, ...]
        },

Iā€™m not sure I understand what you mean that if the receipt was copied you would lose the link. A smart contract and an NFT ID on that contract will always point to the same NFT. The only case it could be different would be if it was on another blockchain so you could put the NFT ID (int), smart contract (string: address) and blockchain (string) to really triangulate an NFT. You donā€™t have to include any prefix or anything. Software can use that data to find the meta data of any NFT you have those 3 items for.

I made this code snipped: receipt-standard/eip-5570-solidity.sol at main Ā· Ownerfy/receipt-standard Ā· GitHub

Itā€™s inspired by: EIP-2981: NFT Royalty Standard

The idea is that blockchain apps can then also query this data. This can be very useful for DAOs, accounting, royalties, defi and all kinds of financial services.

pragma solidity ^0.8.0;
import "./IERC165.sol";

///
/// @dev Interface for eip-5570 Receipt Standard
///
interface IERC5570 is IERC165 {
    /// ERC165 bytes to add to interface array - set in parent contract
    /// implementing this standard
    ///
    /// Below needs to be calculated depending on final interface
    /// bytes4(keccak256("receipt(uint256,uint256)")) == 0xUNSET
    /// bytes4 private constant _INTERFACE_ID_ERC5570 = 0xUNSET;
    /// _registerInterface(_INTERFACE_ID_ERC5570);

    function paid(
        uint256 _tokenId,
    ) external view returns (
        uint256 goodsAndServices,
        uint256 fees,
        uint256 tax,
        bytes8 symbol
    );
    
    function buyer(
        uint256 _tokenId,
    ) external view returns (
        address buyerAddress
    );
    
    function seller(
        uint256 _tokenId,
    ) external view returns (
        address seller
    );
    
    // Optional - Used for the sale of things represented by NFTs
    // Returns all the tokenIds that were sold, their contracts, and prices 
    // The price should be in the symbol designated above.
    // It might be useful to have an NFT reference the receipt it was sold in 
    // and the reference receipt NFT would have to conform to this standard
    function purchasedItems(
        uint256 _tokenId,
    ) external view returns (
        uint256[] tokenId,
        address[] contract,
        uint256[] price
    );
}

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
1 Like

Could you confirm what the bracket recommendation is based off? As far as I can see the syntax that is in the schema is correct according to array ā€” Understanding JSON Schema 2020-12 documentation

Yeah this is an awesome suggestion, instead of an NFT it could define a standard event structure. @Pandapip1 raised similar concerns.

At this point in time I canā€™t think of any real advantages as to why an NFT would be better than an Event being emitted.

Itā€™s like maybe you could use the NFT in another smart contract, but Nicks suggestion that the receipt should contain a field to link to another NFT (or serial number) makes more sense for that too.

Iā€™m going to shoot some messages out to the people I know who were building things using this and see if changing this would affect them.

Thanks for the feedback!

1 Like

No youā€™re right, sorry my mistake!

So I have been sending messages to people who have reached out and shown interest in this EIP so far and have been discussing their thoughts on whether this digital receipt format should stay as an NFT or whether changing to an event would be better for their purposes.

The conclusion I have reached is that it should stay as an NFT even if this means more on chain data and gas. The reasons I have collected so far are as follows:

  1. Simplicity: NFTs are well understood by the community and end users. When discussing the idea of a digital receipt as an NFT almost everyone immediately recognises how the transaction leads to an NFT and this NFT leads to some data. Although the usage of an event would contain a similar workflow this is not something many users have done before and most reactions Iā€™ve had to using an event are whether its even possible (It definitely is, but the workflow for how this would work is foreign most users).
  2. Versatility: When suggesting a receipt as an NFT people appear excited about the ideas of what can be built on top of this. Things like warranty claims and review websites have been suggested to me where a smart contract can check if you own the NFT. I believe a lot of these are still possible using events, but would be more difficult cause you would need to analyse blocks to see if it the receipt exists for this person.
  3. Consistency: Ethereum as a whole uses tokens to do things, almost all of the things that have been built are done by moving tokens around. An NFT receipt is consistent with how ethereum end users do things. This is contrasted to events which are typically used by devs when doing tests and by analysts looking over the blockchain. End users donā€™t usually touch events so to make them follow an event here would be inconsistent.
  4. Gas: The primary argument for events is that it would save on gas. Obviously the current proposal on L1 would be too expensive, even right now when gas prices are quite low the price of $2- $5 for a receipt is unfeasible. So L2s are almost immediately a requirement for this proposal where gas prices and block space is cheap enough for this to exist. So optimising this proposal for Gas I believe would be incorrect here.

Overall the tradeoff here is to save gas vs usability for users and I donā€™t believe the savings in gas justify the increase in difficulty for end users. So I have kept the structure as an NFT rather than adjusting to an event and keeping it entirely off chain.

1 Like

Iā€™ve also pushed 2 changes to the schema today,

  1. A field in the line items to link to a contract; and
  2. A field in the line items to reference a serial number

Providing a optional serial number in the receipt seems like an obvious addition, and a link to an external document containing a contract might be useful here.

But this also allows us to link the line item to another NFT if we wanted, by referencing the smart contract hash in the contract field and the ID number in the serial number field.

1 Like

And have moved this to Final Call. Last call deadline set for 1 April 2023

1 Like

Hi @darcys22 , When I first started reading this thread I was not necessarily fond of using an NFT in this manner. But I am now convinced that this is definitely a unique and useful idea. Not only could this serve as a receipt and warranty, it could also serve as a maintenance record, recall system and much more. Kudos on your hard work with this, I am in hopes that it will be implemented. I feel it would not be the proper method for some items, with a price say < $300 or some amount. That could even be a choice made by the purchaser. It those cases the emitted event method could be more useful and save on gas. One last thought would be an additional field for a purchase order number when used in a business setting and/or a comment field.

1 Like

@Pandapip1 has raised an interesting point about privacy aspects of the data contained in the digital receipts.

The schema contains significant private information about the items a user has purchased, aswell as identifying information about the vendor (ie Name, Telephone, Email, Address).

This information should not be conveyed in clear text over any medium, and the full intent is for the information contained in this ERC to be encrypted. My first draft contained some details on how one would go about doing this encryption, but it quickly became apparent that it deserved its own ERC to describe a method for ā€œencrypted NFTsā€.

Essentially the encryption method is out of scope for this ERC.

Discussions already exist in ERC-5630 on how one would go about encrypting using ethereum keys, I personally am a big fan in this case of how it would allow the vendor to encrypt the metadata using the purchasers ethereum address, and only the purchaser would be able to decrypt.