DEV Community

Cover image for Casper CEP-78 Enhanced NFT Standard
Jonas Pauli for Casper Blockchain

Posted on

Casper CEP-78 Enhanced NFT Standard

Introduction
Most people only have experience with NFTs in the form of JPEGs and art collections, despite the wide variety of use-cases beyond this implementation. The new enhanced NFT standard on Casper is designed to support more than ordinary NFT collections and even allows for developers to associate real world objects with digital representations in the form of NFTs on the blockchain.

There are now three different "metadata_types":

Physical: The NFT represents a real-world physical item e.g a house.
Digital: The NFT represents a digital item, e.g a unique JPEG or a digital art.
Virtual: The NFT is the virtual representation of a physical notion, e.g a patent or copyright.

This article introduces the Casper Cep-78 token standard, which is an upgrade of the deprecated Cep-47 standard. Essentially, the Cep-78 token standard is more flexible and supports “modalities”.

Casper NFT Visualizer
Thanks to the casper-signer and the casper-javascript-sdk, building Dapps on Casper is achievable. To showcase this, I built a “Casper-Sandbox” demo application using React that is open source and can be found here. If you want to install and test the react app follow the setup guide. You will need React and Node.js to run the app.
example account on NFT Sandbox
The “Casper-Sandbox” is an open-source NFT visualizer built to demonstrate some of the capabilities of the Casper Blockchain and the CEP-78 Standard. The app is still under development but already supports minting of “digital” NFTs. The readme includes the latest documentation for the project.
Metadata
The structure of an NFTs metadata is defined by a json schema. Cep-78 supports both standardized and custom json schemes. Standardized schemes are easier to integrate, whilst custom schemes can be individualized to suit a projects needs best.
An example for a standardized json schema (CEP78):

{
  "name": "Example NFT",
  "token_uri": "https://SOME_BACKEND/id",
  "checksum":
"SOME_CHECKSUM"
}
Enter fullscreen mode Exit fullscreen mode

In this example the webserver at "token_uri" should return json data containing all relevant information regarding the NFT, such as a url to the image/jpg file, name and description.

Alternatively, one could define a custom metadata schema to store binary data instead of a weblink as the NFTs metadata.

An example of custom metadata:

{
   "properties":{
      "nft_name":{
         "name":"some_name",
         "description":"some_description",
         "required":true
      },
      "nft_binary_data":{
         "name":"some_binary_data",
         "description":"some_description",
         "required":true
      },
   }
}
Enter fullscreen mode Exit fullscreen mode

_More examples can be found in the readme of the enhanced NFT standard.
_
Deploy the Contract
In the following, I will explain how to deploy the enhanced NFT standard on Ubuntu.

Requirements:

**Dependencies**:
- libssl-dev
- curl
- cmake
- pkg-config
$ sudo apt install libssl-dev curl cmake pkg-config
Setup:
1. install Rust and default to nightly toolchain:
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env
$ rustup toolchain install nightly
$ rustup default nightly
2. install the casper-client
$ cargo install casper-client
Enter fullscreen mode Exit fullscreen mode

The next step is to compile the Rust smart contract to WebAssembly:

casper@jonas:~/Desktop/cep-78-enhanced-nft-dev$ make prepare
casper@jonas:~/Desktop/cep-78-enhanced-nft-dev$ make build-contract
the compiled contract.wasm will be in ./contract/target/wasm32-unknown-unknown/release
Enter fullscreen mode Exit fullscreen mode

Deploy the compiled contract.wasm to casper testnet:

$ casper-client put-deploy --node-address <NODE_ADDRESS> --chain-name casper-test --secret-key <PATH_TO_SECRET_KEY> --payment-amount <GAS_FEE_IN_MOTE> --session-path <PATH_TO_contract.wasm> --session-arg <see below>,
Enter fullscreen mode Exit fullscreen mode

Session Arguments:
A list of mandatory session arguments for an NFT contract on Casper:

  • "collection_name": The name of the NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.
  • "collection_symbol": The symbol representing a given NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.
  • "total_token_supply": The total number of NFTs that a specific instance of a contract will mint passed in as a U64 value. This parameter is required and cannot be changed post installation.
  • "ownership_mode": The OwnershipMode modality that dictates the ownership behavior of the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.
  • "nft_kind": The NFTKind modality that specifies the off-chain items represented by the on-chain NFT data. This argument is passed in as a u8 value and is required at the time of installation.
  • "json_schema": The JSON schema for the NFT tokens that will be minted by the NFT contract passed in as a String. This parameter is required if the metadata kind is set to CustomValidated(4) and cannot be changed post installation.
  • "nft_metadata_kind": The metadata schema for the NFTs to be minted by the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.
  • "identifier_mode": The NFTIdentifierMode modality dictates the primary identifier for NFTs minted by the contract. This argument is passed in as a u8 value and is required at the time of installation.
  • "metadata_mutability": The MetadataMutability modality dictates whether the metadata of minted NFTs can be updated. This argument is passed in as a u8 value and is required at the time of installation. More on session args Mint an NFT Before we can mint an NFT using our installed contract, we have to find the "contract_hash"of our deploy. In order to accomplish this, we will have to query the "state-root-hash" after our deploy has been successfully processed, use that "state-root-hash" to query our account and copy the "contract_hash" associated with the "contract_name". ( which in this case will be "nft_contract", as specified in constants.rs) Query your account:
$ casper-client get-state-root-hash <node-address>
-> outputs "state-root-hash"
$ casper-client get-account-state --node-address<NODE_ADDRESS> --state-root-hash <STATE_ROOT_HASH> --key <account-hash-YOUR_ACCOUNT_HASH>
-> find "contract_hash" of deploy named "nft_contract" in output and copy it. 
Enter fullscreen mode Exit fullscreen mode

Use the "contract_hash"of the deploy to call the mint() and deploy your first NFT to the Casper Blockchain:

A copy of the command I used to mint a Cep-78 digital NFT on Casper, using the standard metadata schema and dummy metadata from the README:
$ casper-client put-deploy \
--node-address http://136.243.187.84:7777 \
--chain-name casper-test \
--secret-key ./private.pem \
--payment-amount 1000000000 \
--session-hash hash-b4b78992e0324be09f174637c3dda2d29cc5c21c44430b72a0943d3ba6d2c827 \
--session-entry-point mint \
--session-arg "token_owner:key='account-hash-5a54f173e71d3c219940dcb9dfec222b024cd81aa7e0672de59ba5fab296448b'" \
--session-arg "token_meta_data:string='{\"name\":\"John Doe\",\"token_uri\":\"https://www.barfoo.cong\",\"checksum\":\"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fc\"}'"
-> outputs a deploy hash.
Enter fullscreen mode Exit fullscreen mode

Get a List of all owned NFTs by Account
In order to access the Metadata of an NFT, it is necessary to know which NFTs are owned by a given account. The Cep-78 contract’s named_keys store contain a dictionary named “owned_tokens”.

Find the Ids or Hashs of NFTs owned by your account. Whether your NFT is identified by a hash identifier or numerical Id depends on the modalityNFTIdentifierModethat defaults to “Ordinal” (numerical instead of hash):

A copy of the command I used to query the NFTs owned by my Account:
$ casper-client get-dictionary-item \
-n http://136.243.187.84:7777 \
-s 256d0445121f1144a09394c739c9baf82b5624b66dced181a0c1c8b8e936652b \
--account-hash hash-b4b78992e0324be09f174637c3dda2d29cc5c21c44430b72a0943d3ba6d2c827 \
--dictionary-name owned_tokens \
--dictionary-item-key 5a54f173e71d3c219940dcb9dfec222b024cd81aa7e0672de59ba5fab296448b
where --dictionary-item-key is set to my account-hash and -s is a new state-root-hash.
A copy of the output:
{
  "id": 6249115604543280689,
  "jsonrpc": "2.0",
  "result": {
    "api_version": "1.4.6",
    "dictionary_key": "dictionary-6bded5cf061dd95463e0064996f24cb88d19a6a7b24962a1347a5392356a35a0",
    "merkle_proof": "[38054 hex chars]",
    "stored_value": {
      "CLValue": {
        "bytes": "[280 hex chars]",
        "cl_type": {
          "List": "String"
        },
        "parsed": [
          "8bc73bf6cfdb48d0e88f16e0c02d5adff6c60a61a4b6bd65349d75fcb7b500d8",
          "0e557acd2b5a43a91c23c2f0e01687cc8a5342e105be22777b7bf97daf757c4f"
        ]
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The parsed value is a list of hash identifiers representing NFTs owned by the account:

"8bc73bf6cfdb48d0e88f16e0c02d5adff6c60a61a4b6bd65349d75fcb7b500d8",
          "0e557acd2b5a43a91c23c2f0e01687cc8a5342e105be22777b7bf97daf757c4f"
Enter fullscreen mode Exit fullscreen mode

Read NFT Metadata
The metadata that is passed as an argument when minting an NFT using CEP-78 is saved in a hashmap on the blockchain, where the key is the hash or numeric identifier, depending on theidentifier_mode modality. The name of the dictionary depends on the metadata_kind modality.
The NFT metadata can be found in the related dictionary:

1. "metadata_custom_validated"
2. "metadata_cep78"
3. "metadata_nft721"
4. "metadata_raw"
Enter fullscreen mode Exit fullscreen mode
  const client = await new CasperClient(node_addr);
  var product_contract = new Contracts.Contract(client);
  product_contract.setContractHash(cep78_contract_hash);
  const list = [YOUR_NFT_HASH_IDs];
  let meta = [];
  for (item in list) {
    console.log("Item is: ", list[item].toString());
    await product_contract.queryContractDictionary(
      "metadata_custom_validated",
      list[item]
    ).then(response => {
      meta.push(response.data);
    }).catch(error => {
      console.log(error);
    })
  }
Enter fullscreen mode Exit fullscreen mode

This example shows how a javascript application can query a deployed cep-78 instance with custom validated metadata as metadata_kind.

Youtube Workshop

  1. Learn to configure and install the CEP-78 smart contract here.
  2. Learn to use the Sandbox application here.

Summary
Minting NFTs on Casper is a straight forward process and the enhanced Token standard is a major improvement over the CEP47 Token standard. It’s a more flexible and future proof implementation, setting a metadata standard which allows for the integration of Casper NFTs in both on- and off-chain applications.

Tip: When passing metadata or json schemes using the casper-client, the json strings need to be escaped. When deploying a Cep-78 instance, I use this tool to escape my json schema.

Top comments (0)