Register a Derivative

Learn how to register a derivative/remix IP Asset as a child of another in TypeScript.

This section demonstrates how to register an IP Asset as a derivative of another. Luckily there are many ways you can do this based on what is best for you, and it is up to you to choose which one you need.

Prerequisites

  • Setup the client object.
  • The parent IP Asset must be registered and have License Terms attached to it.

Existing Child IP + License Token

Additional Prerequisites

  • An already minted License Token from the parent IP Asset. Learn how to mint a License Token here.

If you already have a License Token, it is easier to register a derivative this way. We can register a child IPA as a derivative of a parent IPA by calling client.ipAsset.registerDerivativeWithLicenseTokens() like so:

const response = await client.ipAsset.registerDerivativeWithLicenseTokens({
  childIpId: "0xC92EC2f4c86458AFee7DD9EB5d8c57920BfCD0Ba",
  licenseTokenIds: ["5"], // array of license ids relevant to the creation of the derivative, minted from the parent IPA
  txOptions: { waitForTransaction: true }
});

console.log(`Derivative IPA linked to parent at transaction hash ${response.txHash}`)
export type RegisterDerivativeWithLicenseTokensRequest = {
  childIpId: Address;
  licenseTokenIds: string[] | bigint[] | number[];
  txOptions?: TxOptions;
};
export type RegisterDerivativeWithLicenseTokensResponse = {
  txHash?: string;
  encodedTxData?: EncodedTxData;
};

Existing Child IP + Parent IP

You can also register a derivative directly, without needing a License Token. There is no real difference between registerDerivativeWithLicenseTokens (above) and registerDerivative (below) except that the former requires an already minted License Token and the latter is a convenient function that handles it for you.

❓

"Why would I ever use a License Token then?"

There are a few times when you would need a License Token to register a derivative:

  • The License Token contains private license terms, so you would only be able to register if you had the License Token that was manually minted by the owner. More on that here.
  • The License Token (which is an NFT) costs a mintingFee to mint, and you were able to buy it on a marketplace for a cheaper price. Then it makes more sense to simply register with the License Token then have to pay the more expensive mintingFee.

πŸ“˜

Quick Note

Remember that once License Terms are attached to an IP Asset, it becomes public to register a derivative with those terms, which is why you don't necessarily need a License Token first. Read more on that here.

const response = await client.ipAsset.registerDerivative({
  childIpId: "0xC92EC2f4c86458AFee7DD9EB5d8c57920BfCD0Ba",
  parentIpIds: ["0xC92EC2f4c86458AFee7DD9EB5d8c57920BfCD0Ba"],
  licenseTermsIds: ["5"],
  txOptions: { waitForTransaction: true }
});

console.log(`Derivative IPA linked to parent at transaction hash ${response.txHash}`)
export type RegisterDerivativeRequest = {
  childIpId: Address;
  parentIpIds: Address[];
  licenseTermsIds: string[] | bigint[] | number[];
  licenseTemplate?: Address;
  txOptions?: TxOptions;
};
export type RegisterDerivativeResponse = {
  txHash?: string;
  encodedTxData?: EncodedTxData;
  childIpId?: Address;
};

Existing NFT, Register IP, and Link to Existing Parent IP

This function allows you to do all of the following: Register an NFT as an IP Asset ▢️ Register an IPA as a Derivative

import { toHex } from 'viem';

const response = await client.ipAsset.registerDerivativeIp({
  nftContract: "0x041B4F29183317Fd352AE57e331154b73F8a1D73", // your NFT contract address
  tokenId: '127',
  derivData: {
    parentIpIds: ['0x4c1f8c1035a8cE379dd4ed666758Fb29696CF721'],
    licenseTermsIds: ['13']
  },
  // https://docs.story.foundation/docs/ip-asset#adding-nft--ip-metadata-to-ip-asset
  ipMetadata: {
    ipMetadataURI: 'test-uri',
    ipMetadataHash: toHex('test-metadata-hash', { size: 32 }),
    nftMetadataHash: toHex('test-nft-metadata-hash', { size: 32 }),
    nftMetadataURI: 'test-nft-uri',
  },
  txOptions: { waitForTransaction: true }
});

console.log(`Completed at transaction hash ${response.txHash}, IPA ID: ${response.ipId}`);
export type RegisterIpAndMakeDerivativeRequest = {
  nftContract: Address;
  tokenId: string | number | bigint;
  deadline?: string | number | bigint;
  derivData: {
    parentIpIds: Address[];
    licenseTermsIds: string[] | bigint[] | number[];
    licenseTemplate?: Address;
  };
} & IpMetadataAndTxOption;

type IpMetadataAndTxOption = {
  ipMetadata?: {
    ipMetadataURI?: string;
    ipMetadataHash?: Hex;
    nftMetadataURI?: string;
    nftMetadataHash?: Hex;
  };
  txOptions?: TxOptions;
};
export type RegisterIpAndMakeDerivativeResponse = {
  txHash?: string;
  encodedTxData?: EncodedTxData;
  ipId?: Address;
};

Existing NFT, Register IP, and Link to Existing Parent IP w/ License Tokens

Additional Prerequisites

  • An already minted License Token from the parent IP Asset. Learn how to mint a License Token here.
import { toHex } from 'viem';

const response = await client.ipAsset.registerIpAndMakeDerivativeWithLicenseTokens({
  nftContract: "0x041B4F29183317Fd352AE57e331154b73F8a1D73", // your NFT contract address
  tokenId: '127',
  licenseTokenIds: ['10'],
  // https://docs.story.foundation/docs/ip-asset#adding-nft--ip-metadata-to-ip-asset
  ipMetadata: {
    ipMetadataURI: 'test-uri',
    ipMetadataHash: toHex('test-metadata-hash', { size: 32 }),
    nftMetadataHash: toHex('test-nft-metadata-hash', { size: 32 }),
    nftMetadataURI: 'test-nft-uri',
  },
  txOptions: { waitForTransaction: true }
});

console.log(`Completed at transaction hash ${response.txHash}, IPA ID: ${response.ipId}`);
export type RegisterIpAndMakeDerivativeWithLicenseTokensRequest = {
  nftContract: Address;
  tokenId: string | number | bigint;
  licenseTokenIds: string[] | bigint[] | number[];
  deadline?: string | number | bigint;
} & IpMetadataAndTxOption;

type IpMetadataAndTxOption = {
  ipMetadata?: {
    ipMetadataURI?: string;
    ipMetadataHash?: Hex;
    nftMetadataURI?: string;
    nftMetadataHash?: Hex;
  };
  txOptions?: TxOptions;
};
export type RegisterIpResponse = {
  txHash?: string;
  encodedTxData?: EncodedTxData;
  ipId?: Address;
  tokenId?: bigint;
};

Mint NFT, Register IP, and Link to Existing Parent IP

This function allows you to do all of the following: Mint an NFT ▢️ Register an NFT as an IP Asset ▢️ Register an IPA as a Derivative

πŸ“˜

Before You Use this Function

The address of nftContract must implement ISPGNFT in order to work.

An easy way to create a collection that implements ISPGNFT is to call the createCollection function in the SPG contract.

πŸ“˜

NFT Metadata

Note that this function will also set the underlying NFT's tokenUri to whatever is passed under ipMetadata.nftMetadataURI.

import { PIL_TYPE } from '@story-protocol/core-sdk';
import { toHex } from 'viem';

const response = await client.ipAsset.mintAndRegisterIpAndMakeDerivative({
  // an NFT contract address created by the SPG
  spgNftContract: "0xfE265a91dBe911db06999019228a678b86C04959",
  derivData: {
    parentIpIds: ['0x4c1f8c1035a8cE379dd4ed666758Fb29696CF721'],
    licenseTermsIds: ['13']
  },
  // https://docs.story.foundation/docs/ip-asset#adding-nft--ip-metadata-to-ip-asset
  ipMetadata: {
    ipMetadataURI: 'test-uri',
    ipMetadataHash: toHex('test-metadata-hash', { size: 32 }),
    nftMetadataHash: toHex('test-nft-metadata-hash', { size: 32 }),
    nftMetadataURI: 'test-nft-uri',
  },
  txOptions: { waitForTransaction: true }
});

console.log(`Completed at transaction hash ${response.txHash}, IPA ID: ${response.ipId}, Token ID: ${response.tokenId}`);
export type MintAndRegisterIpAndMakeDerivativeRequest = {
  nftContract: Address;
  derivData: {
    parentIpIds: Address[];
    licenseTermsIds: string[] | bigint[] | number[];
    licenseTemplate?: Address;
  };
  nftMetadata?: string;
  recipient?: Address;
} & IpMetadataAndTxOption;

type IpMetadataAndTxOption = {
  ipMetadata?: {
    ipMetadataURI?: string;
    ipMetadataHash?: Hex;
    nftMetadataURI?: string;
    nftMetadataHash?: Hex;
  };
  txOptions?: TxOptions;
};
export type RegisterDerivativeResponse = {
  txHash?: string;
  encodedTxData?: EncodedTxData;
  childIpId?: Address;
  tokenId?: bigint;
};

Mint NFT, Register IP, and Link to Existing Parent IP w/ License Tokens

Additional Prerequisites

  • An already minted License Token from the parent IP Asset. Learn how to mint a License Token here.
import { toHex } from 'viem';

const response = await client.ipAsset.mintAndRegisterIpAndMakeDerivativeWithLicenseTokens({
  spgNftContract: "0xfE265a91dBe911db06999019228a678b86C04959", // your NFT contract address
  licenseTokenIds: ['10'],
  // https://docs.story.foundation/docs/ip-asset#adding-nft--ip-metadata-to-ip-asset
  ipMetadata: {
    ipMetadataURI: 'test-uri',
    ipMetadataHash: toHex('test-metadata-hash', { size: 32 }),
    nftMetadataHash: toHex('test-nft-metadata-hash', { size: 32 }),
    nftMetadataURI: 'test-nft-uri',
  },
  txOptions: { waitForTransaction: true }
});

console.log(`Completed at transaction hash ${response.txHash}, IPA ID: ${response.ipId}, Token ID: ${response.tokenId}`);
export type MintAndRegisterIpAndMakeDerivativeWithLicenseTokensRequest = {
  spgNftContract: Address;
  licenseTokenIds: string[] | bigint[] | number[];
  recipient?: Address;
} & IpMetadataAndTxOption;

type IpMetadataAndTxOption = {
  ipMetadata?: {
    ipMetadataURI?: string;
    ipMetadataHash?: Hex;
    nftMetadataURI?: string;
    nftMetadataHash?: Hex;
  };
  txOptions?: TxOptions;
};
export type RegisterIpResponse = {
  txHash?: string;
  encodedTxData?: EncodedTxData;
  ipId?: Address;
  tokenId?: bigint;
};