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:

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

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

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.

This sounds an interesting idea worth pursuing!

1 Like

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.

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.

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);
}

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!

No you’re right, sorry my mistake!