Manage Assets (NFTs)


This guide provides a comprehensive walkthrough of managing the entire lifecycle of Non-Fungible Tokens (NFTs), also known as assets, using the OCAP Client. You will learn how to create new assets from scratch, update their properties, establish an asset factory for standardized minting, and acquire new assets from that factory.

Create a New Asset#

You can create a unique, standalone asset on the blockchain using the createAsset method. Each asset is assigned a unique on-chain address derived from its initial properties.

const { wallet } = getWallet(); // User's wallet object

async function createNewAsset() {
  try {
    const [hash, address] = await client.createAsset({
      moniker: 'My Unique Digital Artwork',
      data: {
        typeUrl: 'json',
        value: { 
          description: 'A one-of-a-kind piece created by Artist X.',
          imageUrl: 'https://example.com/path/to/image.png',
        },
      },
      readonly: true,
      transferrable: true,
      wallet: wallet,
    });

    console.log(`Asset creation transaction sent: ${hash}`);
    console.log(`New asset address: ${address}`);
    return address;
  } catch (error) {
    console.error('Error creating asset:', error);
  }
}

See all 2 lines

Parameters#

moniker
string
required
The name of the asset.
parent
string
default:''
The address of a parent asset, if any.
data
object
required
The data payload for the asset, which must include a typeUrl and value.
readonly
boolean
default:false
If true, the asset cannot be updated after creation.
transferrable
boolean
default:true
If true, the asset can be transferred to another account.
ttl
number
default:0
Time-to-live in seconds after the asset's first consumption.
display
object
Object containing display information for the asset.
endpoint
object
Object containing endpoint details for the asset.
tags
string[]
default:[]
An array of strings to categorize the asset.
wallet
WalletObject
required
The wallet object of the asset's initial owner.
delegator
string
default:''
The address of the account that authorized this transaction via delegation.

Returns#

A Promise that resolves to an array containing the transaction hash and the new asset's on-chain address.

response
Promise<[string, string]>
[transactionHash, assetAddress]


Update an Existing Asset#

If an asset was created with readonly: false, you can modify its moniker and data fields using the updateAsset method. The asset is identified by its unique address.

const { wallet } = getWallet(); // User's wallet object
const assetAddress = 'z362...'; // Address of the asset to update

async function updateExistingAsset() {
  try {
    const hash = await client.updateAsset({
      address: assetAddress,
      moniker: 'My Updated Digital Artwork',
      data: {
        typeUrl: 'json',
        value: { 
          description: 'An updated description for my unique piece.',
          imageUrl: 'https://example.com/path/to/new_image.png',
        },
      },
      wallet: wallet,
    });

    console.log(`Asset update transaction sent: ${hash}`);
  } catch (error) {
    console.error('Error updating asset:', error);
  }
}

updateExistingAsset();

Parameters#

address
string
required
The on-chain address of the asset to update.
moniker
string
required
The new name for the asset.
data
object
required
The updated data payload for the asset.
wallet
WalletObject
required
The wallet object of the current asset owner.

Returns#

A Promise that resolves to the transaction hash.

response
Promise<string>
transactionHash


Create an Asset Factory#

An Asset Factory is a template for creating multiple, similar assets. It defines the structure, rules, and logic for minting new assets, which is more efficient than creating each one individually. This is ideal for use cases like issuing event tickets, certificates, or collectibles.

const { wallet } = getWallet(); // Factory owner's wallet

const factoryDefinition = {
  name: 'Conference Ticket Factory',
  description: 'Mints tickets for the 2024 Tech Conference.',
  limit: 1000, // Max 1000 tickets can be minted
  input: {
    // Defines what data is required to mint an asset
    type: 'object',
    properties: {
      attendeeName: { type: 'string' },
      ticketType: { type: 'string', enum: ['General', 'VIP'] },
    },
  },
  output: {
    // Defines the structure of the minted asset
    moniker: 'Ticket for {{attendeeName}}',
    description: '{{ticketType}} admission for the 2024 Tech Conference.',
    transferrable: false, // Tickets are non-transferrable
  },
  hooks: [],
};

async function createFactory() {
  try {

See all 13 lines

Parameters#

factory
object
required
An object defining the factory's properties and minting logic.
8 subfields
wallet
WalletObject
required
The wallet object of the factory's owner.

Returns#

A Promise that resolves to an array containing the transaction hash and the new factory's on-chain address.

response
Promise<[string, string]>
[transactionHash, factoryAddress]


Acquire an Asset from a Factory#

Acquiring an asset from a factory is a two-step process. First, you prepare the minting data, which allows you to preview the asset that will be created. Second, you submit the transaction to the blockchain to officially acquire the asset.

This separation is useful because it allows an application to show a user what they are about to receive before they sign and submit the final transaction.

Step 1: Prepare the Asset Data#

The preMintAsset method takes the factory address and user-provided inputs to generate the final asset data. This happens off-chain and does not require a transaction.

const factoryAddress = 'z2...'; // Address of the factory created previously
const { wallet: issuerWallet } = getIssuerWallet(); // The factory owner or a trusted issuer
const { wallet: userWallet } = getUserWallet(); // The user who will own the new asset

async function prepareAssetForMinting() {
  try {
    const mintingData = await client.preMintAsset({
      factory: factoryAddress,
      inputs: {
        attendeeName: 'John Doe',
        ticketType: 'VIP',
      },
      owner: userWallet.address,
      wallet: issuerWallet,
    });

    console.log('Prepared asset data for minting:', mintingData);
    return mintingData;
  } catch (error) {
    console.error('Error preparing asset:', error);
  }
}

Step 2: Send the Transaction#

Once the minting data is prepared, the user (the future asset owner) signs and sends the acquireAsset transaction. The itx object from preMintAsset is used as the payload.

async function acquireNewAsset() {
  // First, get the minting data from Step 1
  const itx = await prepareAssetForMinting();
  if (!itx) return;

  try {
    const hash = await client.acquireAsset({
      itx: itx,
      wallet: userWallet, // The user's wallet signs the transaction
    });

    console.log(`Asset acquisition transaction sent: ${hash}`);
    console.log(`New asset will be available at address: ${itx.address}`);
  } catch (error) {
    console.error('Error acquiring asset:', error);
  }
}

acquireNewAsset();

Parameters for acquireAsset#

itx
object
required
The inner transaction object returned from the `preMintAsset` method.
wallet
WalletObject
required
The wallet of the user who is acquiring the asset.
delegator
string
default:''
The address of the account that authorized this transaction via delegation.

Returns#

A Promise that resolves to the transaction hash for the acquireAsset operation.

response
Promise<string>
transactionHash


Mint an Asset from a Factory#

In addition to the user-led acquireAsset flow, an authorized issuer (such as the factory owner or a trusted issuer) can mint an asset and send it directly to a user's account. This process also uses preMintAsset to prepare the data, but the final transaction is mintAsset, signed by the issuer.

This flow is useful for scenarios like airdrops, awarding certificates, or any case where the receiving user does not need to initiate the final transaction.

Step 1: Prepare the Asset Data#

This step is identical to the acquisition flow. The issuer calls preMintAsset to generate the transaction payload (itx) off-chain.

const factoryAddress = 'z2...'; // Address of the factory
const { wallet: issuerWallet } = getIssuerWallet(); // The factory owner or a trusted issuer
const userAddress = 'z1...'; // The address of the user who will receive the asset

async function prepareAssetForMinting() {
  try {
    const mintingData = await client.preMintAsset({
      factory: factoryAddress,
      inputs: {
        attendeeName: 'Jane Smith',
        ticketType: 'General',
      },
      owner: userAddress,
      wallet: issuerWallet, // Issuer's wallet is used here
    });

    console.log('Prepared asset data for minting:', mintingData);
    return mintingData;
  } catch (error) {
    console.error('Error preparing asset:', error);
  }
}

Step 2: Send the Mint Transaction#

The issuer uses the prepared itx object to call mintAsset. The transaction is signed with the issuer's wallet, and the newly created asset is assigned to the owner specified in the previous step.

async function mintNewAsset() {
  // First, get the minting data from Step 1
  const itx = await prepareAssetForMinting();
  if (!itx) return;

  try {
    // The issuer's wallet signs the transaction
    const hash = await client.mintAsset({
      itx: itx,
      wallet: issuerWallet,
    });

    console.log(`Asset minting transaction sent: ${hash}`);
    console.log(`New asset for ${userAddress} will be available at address: ${itx.address}`);
  } catch (error) {
    console.error('Error minting asset:', error);
  }
}

mintNewAsset();

Parameters for mintAsset#

itx
object
required
The inner transaction object returned from the `preMintAsset` method.
wallet
WalletObject
required
The wallet of the issuer who is minting the asset.

Returns#

A Promise that resolves to the transaction hash for the mintAsset operation.

response
Promise<string>
transactionHash