NFT protocol draft

  1. Protocol

We go with same old PA IssueModes:

class IssueMode(Enum):

    NONE = 0x00
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L19
    # No issuance allowed.

    CUSTOM = 0x01
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L20
    # Custom issue mode, verified by client aware of this.

    ONCE = 0x02
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L21
    # A single card_issue transaction allowed.

    MULTI = 0x04
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L22
    # Multiple card_issue transactions allowed.

    MONO = 0x08
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L23
    # All card transaction amounts are equal to 1.

    UNFLUSHABLE = 0x10
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L24
    # The UNFLUSHABLE issue mode invalidates any card transfer transaction except for the card issue transaction.
    # Meaning that only the issuing entity is able to change the balance of a specific address.
    # To correctly calculate the balance of a PeerAssets addres a client should only consider the card transfer
    # transactions originating from the deck owner.

    SUBSCRIPTION = 0x34  # SUBSCRIPTION (34 = 20 | 4 | 10)
    # https://github.com/PeerAssets/rfcs/blob/master/0001-peerassets-transaction-specification.proto#L26
    # The SUBSCRIPTION issue mode marks an address holding tokens as subscribed for a limited timeframe. This timeframe is
    # defined by the balance of the account and the time at which the first cards of this token are received.
    # To check validity of a subscription one should take the timestamp of the first received cards and add the address' balance to it in hours.

    SINGLET = 0x0a  # SINGLET is a combination of ONCE and MONO (2 | 8)
    #  Singlet deck, one MONO card issunce allowed

For NFT, appropriate issue mode would be SINGLET=0x0a.
In ethereum world, NFTs with multiple issuance exist as well. No matter how silly that sounds.
That would be MONO=0x08.

For start we should just do singlets.

  1. Data format

This is an example of internal representation in python:

class Deck:

        version = version  # protocol version
        name = name  # deck name
        issue_mode = issue_mode  # deck issue mode
        number_of_decimals = number_of_decimals # sometime this is mandated by issue mode
        metadata = asset_specific_data  # optional metadata for the deck, for example link to a JPEG would go here
        issuer = issuer
  1. Announce

A PeerAssets transaction encodes it’s information in the transaction’s inputs (vin[]), outputs (vout[])
and a special meta-data output (OP_RETURN).

A txn where:

* `vin[0]`: The owner of the Asset. Ownership of the asset is proven by proving ownership over the Public Key Hash (PKH) or Script Hash (SH) originating `vin[0]`.
* `vout[0]`: Deck spawn tag using a P2TH output. This tag registers the assets as a PeerAsset so that it can be discovered by PeerAsset clients. This is a zero output.
* `vout[1]`: (`OP_RETURN`) Asset meta-data. A [protobuf3 encoded message][1] containing meta-data about the asset.
* all other in and outputs are free to be used in any way. `vout[2]` will typically be used as a change output.

Such txn is sent to a dedicated P2TH, this can be existing PAprodbYvZqf4vjhef49aThB9rSZRxXsM6 but we can also invent a new one just for NFTs.

Resulting txid becomes the ID of the asset.

  1. Send cards (NFT)

For the card transfer transaction, the following properties are specified:

  • vin[0]: The sending party of the transfer transaction.
  • vout[0]: Asset tag using a [P2TH] output based on the asset’s unique identifier.
    This tag makes it easy for nodes to follow transactions of a specific asset.
  • vout[1]: (OP_RETURN) Asset transfer data. [protobuf3 encoded message][1] containing the amount of transferred assets and optionally some meta-data
  • vout[n+2]: The receiving parties of the transfer transaction. vout[n+2] receives the n-th (starting with 0) amount specified in the asset transfer data message.
  • all other in and outputs are free to be used in any way. vout[2+receiver_cnt] will typically be used as a change output.
  1. Futher reading on announcing decks and sending cards
  1. Unresolved questions
  • Do we need to define the format for metadata? Specifically for links to external data like .jpegs/.gifs and so on.
  • Do we drop both hash and file link into the generic “metadata” field or we split it up into more fields?
  • Do we default to IPFS like Ethereum ecosystem or we allow more flexibility and allow standard HTTPS links or even .torrent?
  • Selling and buying these NFTs?
  • Do we give up on this deck announcement process, which allows light nodes to find all the decks? There is no such concept on any other protocol.
1 Like

IPFS

This is a IPFS link:

https://ipfs.io/ipfs/QmSMfd3keETKC9ZCgXWPfLa42mni2iQensVut4RRvEgsQF?filename=blockchain.png

CID of this file (QmSMfd3keETKC9ZCgXWPfLa42mni2iQensVut4RRvEgsQF) is a multihash.
sha256 hash would be: f2fc142a6837699996ee72ae9f4b060482c73f89208f97ffd8405c88bc918d9c

It seems IPFS does some multihash thing:

Need to learn more about this.


When it comes to IPFS CID is enough to store IPFS CID, as the rest can be assembled by the end client. Everything but CID is static. This final argument, “filename” is optional.

Metadata is made usually to match OpenSea’s expectations (Metadata Standards). This may change with time which is why you can update the URI. Also depends if its a video/animation etc.

Depends on what the expectation of the front-end is. OpenSea reads whatever from expected fields + attributes

// https://ipfs.io/ipfs/Qma7FFgUmFv9ZNWXSkMWc6e7UvhsB9GxgVM5Y4rbDfhEt4/123
{
   "tokenId": 123,
   "hash": "EXAMPLEHASH000000000000000088c087d474e51171f5417ba59cddd519e2462e4daa679161",
   "image": "https://ipfs.io/ipfs/{CONTRACT}/123",
   "attributes": {
       {
            "trait_type": "Body",
            "value": "Blue Raspberry"
       },
   }
}

CryptoPunks uses google image hosting :upside_down_face: (https://lh3.googleusercontent.com/PWDq8erM2dMscd99OntjFRJFfvtvki7uxeYiBUT8e59Kdbn8s34dM59kCkVZ66b687B6i8KXMDspRfnU-JbLcB9Kc23EoSydJNkmgA=w600)

Many projects use IPFS. You can also do SVG generation in the contract but it is advised against. Not sure how compatible .torrent is but I’m sure it’s used and I’m sure we can test it

Once contract is deployed, items are visible after you submit the contract address
https://opensea.io/get-listed

OpenSea is #1 but I expect more competitors soon but you can be flexible because of the setURI function. I expect competitors to be compatible at a base level with additional features but similar base structure.

1 Like

This is good, better choice than IPFS.

BTW:

OpenSea is Ethereum (& ecosystem) thing. They will not support PA NFTs, ever. We do not have to conform to their standards.

To be clear, you are asking if we should remove P2TH? It can hypothetically be added back later for a ‘lite compatible’ version of PA. But ultimately, I don’t think we lose much by doing it, and you gain the lite import, so why not keep it?

P2TH is used all over actually, so you can never not use it.

What I talk about is this token discovery process which PA has and no other protocol does it. You announce every new deck onto a common P2TH, then every client can find all the decks with ease.

So yes, by dropping support for that we remove easy and fast deck discovery. We gain almost nothing, as that costs nearly nothing. We may save some trivial amount on fees though.

The price is only on deck creation, but we can give it as an approx. % of txn size. Outputs are cheap, inputs are expensive. I estimate ~5-10% bloat only on deck creation. Seems not too bad to me.

It’s probably less than 5% per deck creation. Easy to forget about honestly.

so when deck is spawned, how will you know that it’s nft, perhaps it would be a good idea to have a separate p2th announcement address. this way you will know that data in deck is ipfs cid.

i think storing any urls in deck creation is a bad idea, ipfs allows for much more flexibility and compatibility with other systems.

I was thinking about separate P2TH yeah.
Anyway client can parse the deck and figure out it’s NFT by it’s issue mode and presence of metadata.

But it also requires pinning, for example. To even work.