Skip to main content

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.

javascript
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);
  }
}

createNewAsset();

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.

javascript
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.

javascript
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 {
    const [hash, factoryAddress] = await client.createAssetFactory({
      factory: factoryDefinition,
      wallet: wallet,
    });

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

createFactory();

Parameters

  • factory object (required) — An object defining the factory's properties and minting logic.
    • name string (required) — Name of the factory.
    • description string (required) — Description of the factory's purpose.
    • limit number (default: 0) — The maximum number of assets that can be minted from this factory. 0 means unlimited.
    • trustedIssuers string[] — A list of account addresses authorized to mint from this factory.
    • input object (required) — Defines the required input data for minting an asset.
    • output object (required) — Defines the structure and properties of the asset that will be minted.
    • hooks object[] — A list of hooks to execute during the minting process.
    • data object — Additional arbitrary data to store with the factory.
  • 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.

javascript
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.

javascript
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.

javascript
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.

javascript
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