跳到主要內容

Understanding NFTs

We use the term NFT and Asset interchangeably throughout this documentation because they mean the same thing on the ArcBlock chain. What is NFT? NFTs

Tip

We use the term NFT and Asset interchangeably throughout this documentation because they mean the same thing on the ArcBlock chain.

What is NFT?

NFTs (Non-fungible tokens) are cryptographic assets on a blockchain with unique identifiers and metadata that distinguish them from each other.

Unlike tokens, they cannot be traded or exchanged at equivalency. This differs from fungible tokens like cryptocurrencies, which are identical to each other and, therefore, can serve as a medium for commercial transactions.

  • NFTs can represent real-world items like artwork and real estate. "Tokenizing" these real-world tangible assets makes buying, selling, and trading them more efficient while reducing the probability of fraud.
  • NFTs can also function to represent individuals' identities, property rights, passports, and more.

On the ArcBlock chain, the essence of an NFT is data, any data that has actual value and needs to be recorded on the chain can be put on the chain in the form of NFTs. Each NFT is identified by a universal unique address, we call it DID.

NFT Use Cases?

The usage scenarios for NFTs are very extensive, when you need to make any records of the data, you can create NFTs and update them through transactions. There are many usage scenarios for NFTs, including but not limited to:

  • Create tickets: Alice needs to create tickets for her event so that participants can buy tickets to participate in the event. Alice can create ticket NFTs and store them on the chain.
  • Issue certificates: After the user of the online learning website finishes a course, he can create a course certificate for him, and then ask him to hold a certificate of a course when studying other courses.
  • Membership certificate: Paid subscription platform users pay for a passport, and check the pass that requires payment to view content.

NFT Structure

A typical NFT stored on ArcBlock chain has the following structure:

fieldtyperequireddefaultmemoupdatable
addressstringYes-NFT identifierNo
ownerstringYes-NFT owner identifierYes
issuerstringYes-NFT issuer identifierNo
parentstringYes-NFT Factory identifierNo
monikerstringYes-Human-readable nameNo
readonlybooleanYesfalseis the NFT immutableNo
transferrablebooleanYesfalsecan NFT be transferred after creationNo
consumedTimeDateNo-The consume date for the NFTYes
dataAnyYesfalsethe data that makes the NFT uniqueYes
displayobjectNonullthe NFT displayNo
endpointobjectNonullthe NFT endpointNo
tagsstring[]No[]List of tags for later filteringNo

NFT Extendability

NFTs on ArcBlock chain can either be mutable or immutable depending on the use case. To make NFTs more flexible in real-world applications we have another 2 layers that are totally customizable by developers:

  • NFT Display: used to define how the NFT will look like
  • NFT Endpoint: used to define dynamic attributes and actions of the NFT

Here is an example of how NFT Display and NFT Endpoint are parsed and displayed in DID Wallet:

Image

NFT Display

An NFT can have:

NFT display is defined with the following structure:

javascript
type NFTDisplay = {
  // Can be svg|url|uri
  type: string;

  // Varies according to the type
  // For svg type, content should be the svg itself
  // For url type, content should be the url to fetch the display content, this URL will be requested with the NFT or the NFT address for the display
  // For uri type, content should be the uri to resolve the display content, such as base64 encoded image
  content: string;
};

Developers can define NFT display in one of following ways:

  • Define display field in the CreateAssetTx
  • Define output.display field in CreateFactoryTx

NFT Endpoint

NFT endpoint enables developers to extend NFT capabilities off the chain, such as:

  • Display NFT status that may change over time
  • Display NFT action that may change over time

NFT endpoint is defined in the following structure:

javascript
type NFTEndpoint = {
  // the url that serve the endpoint, the url is requested with assetId and locale when displaying the NFT
  id: string;

  // can be public|private, private endpoints are requested with DID Connect
  scope: string;
};

A live NFT endpoint example form Blocklet Launcher.

TODO: how to create the response by NFT endpoint should be added

NFT Factory

Since some NFTs have standard formats, such as tickets sold in cinemas and parks, developers can use NFT factory to create vending machines on the blockchain: users send transactions to the NFT factory to pay and acquire NFTs that are defined by the NFT factory.

Just like a real-world factory that consumes some materials to produce standard products, the following diagram shows how NFT factory works:

Image

NFT Factory Transactions

There are a few transactions related to NFT Factory:

  • CreateFactoryTx: used by developers to create the factory
  • AcquireAssetV3Tx: used by users to acquire NFT with payment
  • MintAssetTx: used by factory owners to mint NFT without payment

NFT Factory Inputs

Users usually need to pay some tokens or consume some NFT to acquire a new NFT, the cost user paid on acquiring NFTs are called factory input, following is a factory input from Blocklet Launcher:

javascript
{
  "tokens": [
    {
      "address": "z35nNRvYxBoHitx9yZ5ATS88psfShzPPBLxYD",
      "value": "299000000000000000000"
    }
  ],
  "assets": [],
  "variables": [
    {
      "name": "plan",
      "value": "",
      "description": "",
      "required": true
    },
    {
      "name": "tag",
      "value": "",
      "description": "",
      "required": true
    }
  ]
}

Factory inputs fall into 3 categories:

  • tokens: cryptocurrencies required to acquire NFT, a factory can require up to 8 tokens on acquiring, and each token input must specify its token address and price.
  • assets: NFT to be consumed to acquire NFT, can be NFT address or Factory address, all assets are marked consumed upon successful acquiring
  • variables: extra info required to acquire NFT, usually collected with a form before the acquiring

NFT Factory Output

Since all NFTs from a factory share a predefined format, developers define the format as output, a typical factory output is a mustache template that produces the same structure as CreateAssetTx upon rendering(acquiring).

Following is the factory output from Blocklet Launcher

javascript
{
  "moniker": "BlockletServerOwnershipNFT",
  "data": {
    "type": "json",
    "value": {
      "purchased": {
        "plan": "{{input.plan}}",
        "sku": {
          "name": "{{data.name}}",
          "type": "{{data.type}}",
          "period": "{{data.period}}"
        }
      }
    }
  },
  "readonly": false,
  "transferrable": true,
  "ttl": 0,
  "parent": "{{ctx.factory}}",
  "address": "",
  "issuer": "{{ctx.issuer.id}}",
  "endpoint": {
    "id": "http://1322c65c-znkqyck3vfnye4cyk3yrwfnydgvvkshr9cur.did.abtnet.io/api/nft/status",
    "scope": "public"
  },
  "display": {
    "type": "url",
    "content": "http://1322c65c-znkqyck3vfnye4cyk3yrwfnydgvvkshr9cur.did.abtnet.io/api/nft/display"
  },
  "tags": ["BlockletServerOwnershipNFT", "{{input.tag}}"]
}

Data that can be consumed in NFT factory output includes:

  • input.*: factory input variables, must be set when acquiring/minting
  • data.*factory data object, immutable since factory creation
  • ctx.* the context when acquiring/minting from the factory
    • ctx.factory: the factory address
    • ctx.id: the current mint sequence, set to factory.numMinted + 1 on each mint
    • ctx.issuer.id: address for NFT issuer
    • ctx.issuer.pk: public key for NFT issuer
    • ctx.issuer.name: name for NFT issuer(account moniker)
    • ctx.owner: address of NFT owner

NFT Factory Hooks

Developers can use hooks to add custom logic when a new NFT is acquired from a factory, for example:

  • Blocklet Store uses factory hooks to split revenue between the blocklet developer and store when users purchased a paid blocklet.
  • NFT minting tool use factory hooks to split revenue between the developer and NFT provider.

Factory hooks are set and immutable when sending CreateFactoryTxhooks from Blocklet Store:

javascript
[
  {
    "name": "mint",
    "type": "contract",
    "hook": "transferToken('z35nNRvYxBoHitx9yZ5ATS88psfShzPPBLxYD','z1gShFYDsiMfGtaerBTh2ydu75768xMYPQU','4662000000000000000');\ntransferToken('z35nNRvYxBoHitx9yZ5ATS88psfShzPPBLxYD','zNKXtdqz6Jbw5mKpojK2nP5gRNiEGJY3mNFF','1998000000000000000')"
  }
]

This mint hook uses the experimental contract of the chain:

javascript
transferToken(
  "z35nNRvYxBoHitx9yZ5ATS88psfShzPPBLxYD", // token address
  "z1gShFYDsiMfGtaerBTh2ydu75768xMYPQU", // receiver address
  "4662000000000000000" // token amount in big number
);

Token transfers in factory hooks must the following restrictions:

  • Revenue split must not exceed the factory input token amount
  • Token receivers must exist in the ledger
  • Token address must exist in the ledger

NFT Factory Data

The NFT factory can have data attached to it on creation, the data can be used in NFT output templates upon acquiring/minting.

  • NFT factory data is copied from the CreateFactoryTx
  • NFT factory data should be Any Type

NFT Security

Privacy considerations

Once the NFT is stored on the chain, anyone with the NFT address can view all the information stored in the NFT state. In theory, any data can be stored in the NFT. As for what kind of data is stored, the developer can choose according to the actual scenario:

  • If NFT data is weakly typed, no privacy protection is required: for example, the certificate data can be stored in plain JSON, so that is fully publicly verifiable.
  • If NFT data is strongly typed, some privacy protection requirements are required: NFT data can be saved in the serialized format of Any Type, no one can directly decode the NFT data without the NFT data proto-buffer, but technically it is possible to view some of the fields
  • If NFT data is sensitive: such as contracts, pay slips, etc., to protect the security of NFT data, the data should only contain the hash of the original data, the original data should go into an off-chain database

Prevent counterfeiting

ArcBlock chain has built-in NFT anti-counterfeiting logic, that is, 2 identical NFTs are not allowed. However, during the app development process, the developer may mistake the fake NFT for the correct NFT when the verification logic is not strict enough, one solution to this is attaching the issuer's signature on NFT creation so that it can be easily verified.

Move NFT Across ArcBridge

TODO: more about ArcBridge should be added here