Live NFT example

This examples shows how to create a collection where token properties can be changed, mint a token and then change it.

import {Sdk} from '@unique-nft/sdk'
import {KeyringProvider} from '@unique-nft/accounts/keyring'
import {AttributeType, COLLECTION_SCHEMA_NAME, SchemaTools, UniqueCollectionSchemaToCreate} from '@unique-nft/schemas'

const SDK_BASE_URL = 'https://rest.unique.network/opal/v1'
const MNEMONIC = 'electic suit...'

const sdk = new Sdk({baseUrl: SDK_BASE_URL})

const main = async () => {
  const account = await KeyringProvider.fromMnemonic(MNEMONIC)

  ////////////////////////////////////////
  // Creating collection in Unique schema
  // Part 1: creating the schema
  ////////////////////////////////////////

  const collectionSchema: UniqueCollectionSchemaToCreate = {
    schemaName: COLLECTION_SCHEMA_NAME.unique,
    schemaVersion: '1.0.0',
    image: {urlTemplate: 'https://ipfs.unique.network/ipfs/QmcAcH4F9HYQtpqKHxBFwGvkfKb8qckXj2YWUrcc8yd24G/image{infix}.png'},
    coverPicture: {urlInfix: '1'},
    // important:
    // attributes are virtual thing which exists only in the Unique schema
    // it can be encoded and decoded and read only with collection schema encoded in Unique format
    // it's like traits in cryptopunks
    // actually every attribute is stored as token's property
    // and token property is a real on-chain record with access controlled by blockchain
    // so, the attribute - is just a value stored in property
    attributesSchemaVersion: '1.0.0',
    attributesSchema: {
      0: {
        name: {_: "colour"},
        type: AttributeType.string,
        optional: false,
        isArray: false,
        enumValues: {
          0: {_: 'red'},
          1: {_: 'green'},
          2: {_: 'blue'},
        }
      },
      1: {
        name: {_: 'this attr is some free form string'},
        type: AttributeType.string,
        optional: true,
        isArray: false,
      }
    }
  }

  ////////////////////////////////////////
  // Creating collection in Unique schema
  // Part 2: creating the collection
  ////////////////////////////////////////

  const collectionResult = await sdk.collections.creation.submitWaitResult({
    address: account.getAddress(),
    name: 'Test collection',
    description: 'Test collection description',
    tokenPrefix: "TEST",
    schema: collectionSchema as any, // temporary typing mismatch
    tokenPropertyPermissions: [
      // we need manually set token property permissions
      // because by default it's set with mutable: false flag
      {
        key: 'a.0', // 'a.0' corresponds to the attribute from 'schema.attributesSchema.0'
        permission: {
          tokenOwner: true,
          collectionAdmin: true,
          mutable: true,
        },
      },
      {
        key: 'a.1', // 'a.0' corresponds to the attribute from 'schema.attributesSchema.1'
        permission: {
          tokenOwner: true,
          collectionAdmin: true,
          mutable: true,
        },
      },
    ]
  }, {
    signer: account
  })
  const {collectionId} = collectionResult.parsed!
  console.log(collectionId)

  ////////////////////////////////////////
  // Minting a token
  ////////////////////////////////////////

  const tokenProperties = SchemaTools.encodeUnique.token({
    image: {
      urlInfix: '1',
    },
    encodedAttributes: {
      0: 0, // red by default
      1: {_: 'test value'},
    }
  }, collectionSchema)

  const tokenMintResult = await sdk.tokens.create.submitWaitResult({
    address: account.getAddress(),
    collectionId,
    properties: tokenProperties,
  }, {
    signer: account
  })

  console.log(tokenMintResult)
  const tokenId = tokenMintResult.parsed!.tokenId

  ////////////////////////////////////////
  // Getting the token from the chain
  // the colour attr value should be 'red'
  ////////////////////////////////////////

  const token = await sdk.tokens.get({
    collectionId,
    tokenId,
  })
  console.dir(token, {depth: 100})
  
  const color = token.attributes[0].value._
  if (color !== 'red') {
    throw new Error(`token color should be red, got ${color}`)
  }

  ////////////////////////////////////////
  // Changing the token property
  ////////////////////////////////////////

  const tokenChangeResult = await sdk.tokens.setProperties.submitWaitResult({
    address: account.getAddress(),
    collectionId,
    tokenId,
    properties: [{
      key: 'a.0',
      value: '2',
    }]
  }, {
    signer: account
  })

  /////////////////////////////////////////
  // Getting the token from the chain
  // the colour attr value should be 'blue'
  /////////////////////////////////////////

  const tokenAfterChange = await sdk.tokens.get({
    collectionId,
    tokenId,
  })
  console.dir(tokenAfterChange, {depth: 100})

  const colorAfterChange = tokenAfterChange.attributes[0].value._
  if (colorAfterChange !== 'blue') {
    throw new Error(`token color should be blue, got ${colorAfterChange}`)
  }

}

main().catch(err => console.error(err))