Mesh LogoMesh

Content Ownership

Manage ownership of digital content and assets

This contract allows you to create a content registry and users can create content that is stored in the registry.

It facilitates on-chain record of content (i.e. file on IPFS) ownership and transfer. While one cannot prefer others from obtaining a copy of the content, the app owner of the contract can serve the single source of truth of who owns the content. With the blockchain trace and record in place, it provides a trustless way to verify the ownership of the content and facilitates further application logics such as royalties, licensing, etc.

Install package

First you can to install the @meshsdk/contracts package:

npm install @meshsdk/contract

Initialize the contract

To initialize the contract, we need to initialize a provider, MeshTxBuilder and MeshContentOwnershipContract.

import { MeshContentOwnershipContract } from "@meshsdk/contract";
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";

const provider = new BlockfrostProvider('<Your-API-Key>');

const meshTxBuilder = new MeshTxBuilder({
  fetcher: provider,
  submitter: provider,
});

const contract = new MeshContentOwnershipContract(
  {
    mesh: meshTxBuilder,
    fetcher: provider,
    wallet: wallet,
    networkId: 0,
  },
  {
    operationAddress: operationAddress, // the address of the app owner, where most of the actions should be signed by the spending key of this address
    paramUtxo: { outputIndex: 0, txHash: "0000000000000000000000000000000000000000000000000000000000000000" }, // you can get this from the output of mintOneTimeMintingPolicy() transaction
    refScriptUtxos?: { // you can get these from the output of sendRefScriptOnchain() transactions
      contentRegistry: { outputIndex: 0, txHash: "0000000000000000000000000000000000000000000000000000000000000000" },
      contentRefToken: { outputIndex: 0, txHash: "0000000000000000000000000000000000000000000000000000000000000000" },
      ownershipRegistry: { outputIndex: 0, txHash: "0000000000000000000000000000000000000000000000000000000000000000" },
      ownershipRefToken: { outputIndex: 0, txHash: "0000000000000000000000000000000000000000000000000000000000000000" },
    },
  },
);

Both on-chain and off-chain codes are open-source and available on Mesh Github Repository.

Mint One Time Minting Policy

This is the first transaction you need to setup the contract.

This transaction mints the one-time minting policy (a NFT) for the contract.

It will be attached with the datum which serves as the single source of truth for the contract oracle.

Note: You must save the paramUtxo for future transactions.

Mint One Time Minting Policy

This transaction mints the one-time minting policy (a NFT) for the contract.

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

const { tx, paramUtxo } = await contract.mintOneTimeMintingPolicy();
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

Setup Oracle Utxo

This transaction send the NFT to a oracle contract locking the datum, which serves as the single source of truth for the contract oracle with data integrity.

This is the second transaction you need to setup the contract.

Note: You must provide the paramUtxo from the mintOneTimeMintingPolicy transaction.

Setup Oracle Utxo

This transaction send the NFT to a oracle contract locking the datum.

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02...f3f8bded3df2359"}

const tx = await contract.setupOracleUtxo();
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

Send Ref-Script Onchain

This are the next transactions you need to setup the contract. You need to run once for each script, and you would likely have to run one after the previous one is confirmed.

This transaction sends the reference scripts to the blockchain for later transactions, boosting efficiency and avoid exceeding 16kb of transaction size limits enforced by protocol parameter.

Note: You must provide the paramUtxo from the mintOneTimeMintingPolicy transaction.

Note: You must save txHash (after signed and submitted) for ContentRegistry, ContentRefToken, OwnershipRegistry,OwnershipRefToken transactions for future transactions.

Send Ref-Script Onchain

This transaction sends the reference scripts to the blockchain for later transactions.

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02...f3f8bded3df2359"}

Select script index OracleNFT

const tx = await contract.sendRefScriptOnchain('OracleNFT');
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

Create Content Registry

This is the next transaction you need to setup the contract after completing all the sendRefScriptOnchain transactions.

This transaction creates one content registry. Each registry should comes in pair with one ownership registry and each pair of registry serves around 50 records of content ownership. The application can be scaled indefinitely according to the number of parallelization needed and volumes of content expected to be managed.

Note: You must provide the paramUtxo from the mintOneTimeMintingPolicy transaction.

Note: You must provide the txHash forContentRegistry, ContentRefToken, OwnershipRegistry, OwnershipRefToken transactions.

Create Ownership Registry

This transaction creates one content registry

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02...f3f8bded3df2359"}

Content Registry Tx Hash dfd2a2616e6154a092807b1ceebb9ddcadc0f22cf5c8e0e6b0757815083ccb70

Content Ref Token Tx Hash 8f731be135171df172c07578a5d74589ec8fb30b37c12fdbe2639d69b7587f5e

Ownership Registry Tx Hash ec874b61eec4e5e8e395dead6c9bb18690e6d6ea64d773760c5e654ec9ff5f97

Ownership Ref Token Tx Hash e1bdfc7ae6929f934cf9d418273dde143cbb65ec0eec23bdb6c342e4cd91dbd0

const tx = await contract.createContentRegistry();
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

Create Ownership Registry

This is the last transaction you need to setup the contract after completing all the sendRefScriptOnchain transactions.

This transaction creates one content registry. Each registry should comes in pair with one content registry and each pair of registry serves around 50 records of content ownership. The application can be scaled indefinitely according to the number of parallelization needed and volumes of content expected to be managed.

Note: You must provide the paramUtxo from the mintOneTimeMintingPolicy transaction.

Note: You must provide the txHash for ContentRegistry, ContentRefToken, OwnershipRegistry,OwnershipRefToken transactions.

Create Ownership Registry

This transaction creates one content registry

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02e4e2c8b7...ed3df2359"}

Content Registry Tx Hash dfd2a2616e6154a092807b1ceebb9ddcadc0f22cf5c8e0e6b0757815083ccb70

Content Ref Token Tx Hash 8f731be135171df172c07578a5d74589ec8fb30b37c12fdbe2639d69b7587f5e

Ownership Registry Tx Hash ec874b61eec4e5e8e395dead6c9bb18690e6d6ea64d773760c5e654ec9ff5f97

Ownership Ref Token Tx Hash e1bdfc7ae6929f934cf9d418273dde143cbb65ec0eec23bdb6c342e4cd91dbd0

const tx = await contract.createOwnershipRegistry();
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

Get Oracle Data

Getting the oracle data is essential to fetch the current state of the registry.

To facilitate this process, you must provide the paramUtxo that contains the output index and transaction hash of the NFT minting policy.

The getOracleData() function will return the current oracle data.

const oracleData = await contract.getOracleData();

For example:

{
  "contentNumber": 2,
  "ownershipNumber": 2
}

Mint User Token

This transaction mints a token that users can use to create content.

Note that you can actually use any tokens for createContent(), this mintUserToken() function is just helpful if you want to mint a token specifically for this purpose.

Note that you signTx with true to mint the token to enable partial signing.

Mint User Token

Mint a token that users can use to create content

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02e4e2c8b7...ed3df2359"}

const tx = await contract.mintUserToken("MeshContentOwnership", {
  name: "Mesh Content Ownership",
  description: "Demo at https://meshjs.dev/smart-contracts/content-ownership",
});
const signedTx = await wallet.signTx(tx, true);
const txHash = await wallet.submitTx(signedTx);

Create Content

This transaction creates a content attached to the registry reference by a token. You can use any token for ownerAssetHex and the contentHashHex is a string to identify the content.

Note: You must provide the paramUtxo from the mintOneTimeMintingPolicy transaction.

Note: You must provide the txHash for ContentRegistry, ContentRefToken, OwnershipRegistry,OwnershipRefToken transactions.

Create Content

For users to create a content attached to the registry reference by a token

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02e4e2c8b7...ed3df2359"}

Content Registry Tx Hash dfd2a2616e6154a092807b1ceebb9ddcadc0f22cf5c8e0e6b0757815083ccb70

Content Ref Token Tx Hash 8f731be135171df172c07578a5d74589ec8fb30b37c12fdbe2639d69b7587f5e

Ownership Registry Tx Hash ec874b61eec4e5e8e395dead6c9bb18690e6d6ea64d773760c5e654ec9ff5f97

Ownership Ref Token Tx Hash e1bdfc7ae6929f934cf9d418273dde143cbb65ec0eec23bdb6c342e4cd91dbd0

const asset = demoAsset;
const contentHashHex = "ipfs://contentHashHex";
const registryNumber = 0;

const tx = await contract.createContent(
  asset,
  contentHashHex,
  registryNumber,
);
const signedTx = await wallet.signTx(tx);
const txHash = await wallet.submitTx(signedTx);

Get Content

This transaction fetches the content data from the registry.

Get Oracle Data

Fetch the current oracle data

Operation address addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr

Param UTxO {"outputIndex":0,"txHash":"2aba4d6705cfe6405cf02e4e2c8b7...ed3df2359"}

Content Registry Tx Hash dfd2a2616e6154a092807b1ceebb9ddcadc0f22cf5c8e0e6b0757815083ccb70

Content Ref Token Tx Hash 8f731be135171df172c07578a5d74589ec8fb30b37c12fdbe2639d69b7587f5e

Ownership Registry Tx Hash ec874b61eec4e5e8e395dead6c9bb18690e6d6ea64d773760c5e654ec9ff5f97

Ownership Ref Token Tx Hash e1bdfc7ae6929f934cf9d418273dde143cbb65ec0eec23bdb6c342e4cd91dbd0

const content = await contract.getContent(0, 0);