> ## Documentation Index
> Fetch the complete documentation index at: https://docs.story.foundation/llms.txt
> Use this file to discover all available pages before exploring further.

# IP Asset

> IPAssetClient allows you to create, get, and list IP Assets within Story.

## IPAssetClient

### Methods

* registerIpAsset
* registerDerivativeIpAsset
* linkDerivative

### registerIpAsset

Register your IP as an [🧩 IP Asset](/concepts/ip-asset). It supports the following workflows:

1. Register an IP Asset
   1a. register an existing NFT as an IP Asset
   1b. mint a new NFT and register as an IP Asset
2. Attach license terms to the IP Asset
3. Distribute royalty tokens

<Note title="NFT Metadata">
  Note that this function will also set the underlying NFT's `tokenUri` to
  whatever is passed under `ipMetadata.nftMetadataURI`.
</Note>

| Method            | Type                                                                    |
| ----------------- | ----------------------------------------------------------------------- |
| `registerIpAsset` | `(request: RegisterIpAssetRequest) => Promise<RegisterIpAssetResponse>` |

Parameters:

* `request.nft`: You have two options here
  * `{ type: "minted", nftContract: Address, tokenId: number | bigint }`: Register an existing NFT as an IP Asset. This is typically the harder option because you need to already have an NFT minted.
  * `{ type: "mint", spgNftContract: Address, recipient?: Address, allowDuplicates?: boolean }`: Mint a new NFT and register as an IP Asset. This is typically the easier option because you don't need to worry about already having an NFT minted. Just create an spgNftContract, or use a default one, to mint for you.
* `request.licenseTermsData`: If you want to attach license terms.
  * `request.licenseTermsData.terms`: The [license terms](/concepts/programmable-ip-license/pil-terms) to attach to the IP Asset.
  * `request.licenseTermsData.licensingConfig`: The [licensing config](/concepts/licensing-module/license-config) to attach to the IP Asset.
  * `request.licenseTermsData.maxLicenseTokens`: The max number of license tokens that can be minted from this license term.
* `request.royaltyShares`: If you want to distribute royalty tokens out.
  * `request.royaltyShares.recipient`: The address of the recipient of the royalty shares.
  * `request.royaltyShares.percentage`: The percentage of the royalty shares.
* `request.ipMetadata`: The metadata of the IP Asset
  * `request.ipMetadata.ipMetadataURI`: The URI of the metadata for the IP.
  * `request.ipMetadata.ipMetadataHash`: The hash of the metadata for the IP.
  * `request.ipMetadata.nftMetadataURI`: The URI of the metadata for the NFT.
  * `request.ipMetadata.nftMetadataHash`: The hash of the metadata for the IP NFT.
* `request.deadline`: The deadline for the signature in milliseconds. **Defaults to 1000**.

<CodeGroup>
  ```typescript Example theme={null}
  import { PILFlavor, WIP_TOKEN_ADDRESS } from "@story-protocol/core-sdk";
  import { toHex } from "viem";

  // an example of an SPG NFT contract address
  // you can create one via `client.nftClient.createNFTCollection`
  const spgNftContract = "0xc32A8a0FF3beDDDa58393d022aF433e78739FAbc";

  const response = await client.ipAsset.registerIpAsset({
    nft: { type: "mint", spgNftContract: spgNftContract },
    licenseTermsData: [
      {
        terms: PILFlavor.creativeCommonsAttribution({
          currency: WIP_TOKEN_ADDRESS,
          // RoyaltyPolicyLAP address from https://docs.story.foundation/docs/deployed-smart-contracts
          royaltyPolicy: "0xBe54FB168b3c982b7AaE60dB6CF75Bd8447b390E",
        }),
      },
      {
        terms: PILFlavor.commercialRemix({
          defaultMintingFee: 10000n,
          commercialRevShare: 20, // 20%
          currency: WIP_TOKEN_ADDRESS,
          // RoyaltyPolicyLAP address from https://docs.story.foundation/docs/deployed-smart-contracts
          royaltyPolicy: "0xBe54FB168b3c982b7AaE60dB6CF75Bd8447b390E",
        }),
        maxLicenseTokens: 100,
      },
    ],
    royaltyShares: [
      {
        recipient: "0x123...",
        percentage: 10,
      },
    ],
    ipMetadata: {
      ipMetadataURI:
        "https://ipfs.io/ipfs/bafkreiardkgvkejqnnkdqp4pamkx2e5bs4lzus5trrw3hgmoa7dlbb6foe",
      ipMetadataHash: toHex("test-metadata-hash", { size: 32 }),
      nftMetadataURI:
        "https://ipfs.io/ipfs/bafkreicexrvs2fqvwblmgl3gnwiwh76pfycvfs66ck7w4s5omluyhti2kq",
      nftMetadataHash: toHex("test-nft-metadata-hash", { size: 32 }),
    },
  });

  console.log(
    `Root IPA created at transaction hash ${response.txHash}, IPA ID: ${response.ipId}`
  );
  ```

  ```typescript RegisterIpAssetRequest theme={null}
  export type RegisterRequest = {
    nft: MintedNFT | MintNFT;
    // attach license terms
    licenseTermsData?: LicenseTermsDataInput[];
    // sent royalty tokens out
    royaltyShares?: RoyaltyShare[];
    // add metadata
    ipMetadata?: {
      ipMetadataURI: string;
      ipMetadataHash: Hex;
      nftMetadataURI: string;
      nftMetadataHash: Hex;
    };
    deadline?: number | bigint;
  };

  type MintedNFT = {
    type: "minted";
    /** The address of the NFT contract. */
    nftContract: Address;
    tokenId: number | bigint;
  };

  type MintNFT = {
    type: "mint";
    /**
     * The address of the SPG NFT contract.
     * You can create one via `client.nftClient.createNFTCollection`.
     */
    spgNftContract: Address;
    /**
     * The address to receive the NFT.
     * Defaults to client's wallet address if not provided.
     */
    recipient?: Address;
    /**
     * Set to true to allow minting an NFT with a duplicate metadata hash.
     * @default true
     */
    allowDuplicates?: boolean;
  };

  type LicenseTermsDataInput = {
    terms: LicenseTerms;
    licensingConfig?: LicensingConfig;
    /**
     * The max number of license tokens that can be minted from this license term.
     *
     * - When not specified, there is no limit on license token minting
     * - When specified, minting is capped at this value and the TotalLicenseTokenLimitHook
     *   is automatically configured as the licensingConfig.licensingHook
     */
    maxLicenseTokens?: number | bigint;
  };

  type RoyaltyShare = {
    recipient: Address;
    /**
     * The percentage of the total royalty share. For example, a
     * value of 10 represents 10% of max royalty shares, which is 10,000,000.
     * @example 10
     */
    percentage: number | bigint;
  };
  ```

  ```typescript RegisterIpAssetResponse theme={null}
  export type RegisterIpResponse = {
    txHash?: Hex;
    // ipId of the newly registered IP Asset
    ipId: Address;
    // if license terms were attached
    licenseTermsIds?: bigint[];
    // other fields based on input
    // ...
  };
  ```
</CodeGroup>

### registerDerivativeIpAsset

Register an IP as a derivative of another IP Asset. This function allows you to use an existing license token to register as derivative, or it will mint one for you. To register an IP as a derivative, it must be an IP Asset itself. So this function allows you to register an existing NFT as an IP Asset (which will be the derivative), or mint a new NFT for you (and register it as a derivative).

| Method                      | Type                                                                              |
| --------------------------- | --------------------------------------------------------------------------------- |
| `registerDerivativeIpAsset` | `(request: RegisterDerivativeIpRequest) => Promise<RegisterDerivativeIpResponse>` |

Parameters:

* `request.nft`: You have two options here
  * `{ type: "minted", nftContract: Address, tokenId: number | bigint }`: Register an existing NFT as an IP Asset. This is typically the harder option because you need to already have an NFT minted.
  * `{ type: "mint", spgNftContract: Address, recipient?: Address, allowDuplicates?: boolean }`: Mint a new NFT and register as an IP Asset. This is typically the easier option because you don't need to worry about already having an NFT minted. Just create an spgNftContract, or use a default one, to mint for you.
* `request.licenseTokenIds`: If you want to use a license token to register as derivative.
* `request.derivData`: If you want to mint a license token for you.
  * `request.derivData.parentIpIds`: The IDs of the parent IPs to link the registered derivative IP.
  * `request.derivData.licenseTermsIds`: The IDs of the license terms to be used for the linking.
* `request.royaltyShares`: If you want to distribute royalty tokens out.
  * `request.royaltyShares.recipient`: The address of the recipient of the royalty shares.
  * `request.royaltyShares.percentage`: The percentage of the royalty shares.
* `request.maxRts`: The maximum number of royalty tokens that can be distributed to the external royalty policies. Must be between 0 and 100,000,000. **Recommended for simplicity: 100\_000\_000**
* `request.ipMetadata`: The metadata of the IP Asset
  * `request.ipMetadata.ipMetadataURI`: The URI of the metadata for the IP.
  * `request.ipMetadata.ipMetadataHash`: The hash of the metadata for the IP.
  * `request.ipMetadata.nftMetadataURI`: The URI of the metadata for the NFT.
  * `request.ipMetadata.nftMetadataHash`: The hash of the metadata for the IP NFT.
* `request.deadline`: The deadline for the signature in milliseconds. **Defaults to 1000**.

<CodeGroup>
  ```typescript Example theme={null}
  import { toHex } from "viem";

  // an example of an SPG NFT contract address
  // you can create one via `client.nftClient.createNFTCollection`
  const spgNftContract = "0xc32A8a0FF3beDDDa58393d022aF433e78739FAbc";

  // an example of a parent IP ID
  const parentIpId = "0x456...";

  // an example of a commercial remix license terms ID
  const commercialRemixLicenseTermsId = 5;

  const response = await client.ipAsset.registerDerivativeIpAsset({
    nft: { type: "mint", spgNftContract },
    derivData: {
      parentIpIds: [parentIpId],
      licenseTermsIds: [commercialRemixLicenseTermsId],
    },
    ipMetadata: {
      ipMetadataURI:
        "https://ipfs.io/ipfs/bafkreiardkgvkejqnnkdqp4pamkx2e5bs4lzus5trrw3hgmoa7dlbb6foe",
      ipMetadataHash: toHex("test-metadata-hash", { size: 32 }),
      nftMetadataURI:
        "https://ipfs.io/ipfs/bafkreicexrvs2fqvwblmgl3gnwiwh76pfycvfs66ck7w4s5omluyhti2kq",
      nftMetadataHash: toHex("test-nft-metadata-hash", { size: 32 }),
    },
    royaltyShares: [
      {
        recipient: "0x123...",
        percentage: 10,
      },
    ],
  });

  console.log(
    `Derivative IPA linked to parent at transaction hash ${response.txHash}`
  );
  ```

  ```typescript Request Type theme={null}
  export type RegisterDerivativeIpRequest = {
    nft: MintedNFT | MintNFT;
    /** The IDs of the license tokens to be burned for linking the IP to parent IPs.
     * Must be provided together with `maxRts`.
     */
    licenseTokenIds?: number[] | bigint[];
    /**
     * The derivative data containing parent IP information and licensing terms.
     * This will be used to mint a license token for you.
     * @remarks
     * This should not be provided if you are using a license token to register as derivative.
     * Because the license token is already minted.
     */
    derivData?: DerivativeDataInput;
    /**
     * Authors of the IP and their shares of the royalty tokens.
     *
     * @remarks
     * Royalty shares can only be specified if `derivData` is also provided.
     * This ensures that royalty distribution is always associated with derivative IP registration.
     * The shares define how royalty tokens will be distributed among IP authors.
     */
    royaltyShares?: RoyaltyShare[];
    ipMetadata?: {
      ipMetadataURI: string;
      ipMetadataHash: Hex;
      nftMetadataURI: string;
      nftMetadataHash: Hex;
    };
    /**
     * The maximum number of royalty tokens that can be distributed to the external royalty policies (max: 100,000,000).
     * Must be provided together with `licenseTokenIds`.
     * Just use 100_000_000 for simplicity.
     */
    maxRts?: number;
    /**
     * The deadline for the signature in seconds.
     * @default 1000
     */
    deadline?: number | bigint;
  };

  type MintedNFT = {
    type: "minted";
    /** The address of the NFT contract. */
    nftContract: Address;
    tokenId: number | bigint;
  };

  type MintNFT = {
    type: "mint";
    /**
     * The address of the SPG NFT contract.
     * You can create one via `client.nftClient.createNFTCollection`.
     */
    spgNftContract: Address;
    /**
     * The address to receive the NFT.
     * Defaults to client's wallet address if not provided.
     */
    recipient?: Address;
    /**
     * Set to true to allow minting an NFT with a duplicate metadata hash.
     * @default true
     */
    allowDuplicates?: boolean;
  };

  export type DerivativeDataInput = {
    parentIpIds: Address[];
    /** The IDs of the license terms that the parent IP supports. */
    licenseTermsIds: bigint[] | number[];
    /**
     * The maximum minting fee that the caller is willing to pay. if set to 0 then no limit.
     * @default 0
     */
    maxMintingFee?: bigint | number;
    /**
     *  The maximum number of royalty tokens that can be distributed to the external royalty policies (max: 100,000,000).
     * @default 100_000_000
     */
    maxRts?: number;
    /**
     * The maximum revenue share percentage allowed for minting the License Tokens. Must be between 0 and 100 (where 100% represents 100_000_000).
     * @default 100
     */
    maxRevenueShare?: number;
    /**
     * The address of the license template.
     * @default Defaults to https://docs.story.foundation/developers/deployed-smart-contracts
     * PILicenseTemplate address if not provided.
     */
    licenseTemplate?: Address;
  };

  type RoyaltyShare = {
    recipient: Address;
    /**
     * The percentage of the total royalty share. For example, a
     * value of 10 represents 10% of max royalty shares, which is 10,000,000.
     * @example 10
     */
    percentage: number | bigint;
  };
  ```

  ```typescript Response Type theme={null}
  export type RegisterDerivativeIpResponse = {
    txHash?: Hex;
    ipId?: Address;
  };
  ```
</CodeGroup>

### linkDerivative

Link an existing derivative IP to a parent IP.

| Method           | Type                                                                  |
| ---------------- | --------------------------------------------------------------------- |
| `linkDerivative` | `(request: LinkDerivativeRequest) => Promise<LinkDerivativeResponse>` |

Parameters:

<Tabs>
  <Tab title="Without License Tokens">
    * `request.childIpId`: The ID of the child IP.
    * `request.licenseTermIds`: The IDs of the license terms to be used for the linking.
    * `request.parentIpIds`: The IDs of the parent IPs.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const response = await client.ipAsset.linkDerivative({
        childIpId: "0xC92EC2f4c86458AFee7DD9EB5d8c57920BfCD0Ba",
        parentIpIds: ["0xC92EC2f4c86458AFee7DD9EB5d8c57920BfCD0Ba"],
        licenseTermsIds: [5],
      });

      console.log(
        `Derivative IPA linked to parent at transaction hash ${response.txHash}`
      );
      ```

      ```typescript Request Type theme={null}
      export type LinkDerivativeRequest = {
        parentIpIds: Address[];
        childIpId: Address;
        /** The IDs of the license terms that the parent IP supports. */
        licenseTermsIds: number[] | bigint[];
        /**
        * The maximum minting fee that the caller is willing to pay. if set to 0 then no limit.
        * @default 0
        */
        maxMintingFee?: bigint | number;
        /**
        *  The maximum number of royalty tokens that can be distributed to the external royalty policies (max: 100,000,000).
        * @default 100_000_000
        */
        maxRts?: number;
        /**
        * The maximum revenue share percentage allowed for minting the License Tokens. Must be between 0 and 100 (where 100% represents 100_000_000).
        * @default 100
        */
        maxRevenueShare?: number;
        /**
        * The address of the license template.
        * Defaults to {@link https://docs.story.foundation/docs/programmable-ip-license | License Template} address if not provided.
        */
        licenseTemplate?: Address;
      };
      ```

      ```typescript Response Type theme={null}
      export type LinkDerivativeResponse = {
        txHash?: Hex;
      };
      ```
    </CodeGroup>
  </Tab>

  <Tab title="With License Tokens">
    * `request.childIpId`: The ID of the child IP.
    * `request.licenseTokenIds`: The IDs of the license tokens to be used for the linking.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      const response = await client.ipAsset.linkDerivative({
        childIpId: "0xC92EC2f4c86458AFee7DD9EB5d8c57920BfCD0Ba",
        licenseTokenIds: [1115],
      });

      console.log(
        `Derivative IPA linked to parent at transaction hash ${response.txHash}`
      );
      ```

      ```typescript Request Type theme={null}
      export type LinkDerivativeRequest = {
        /** The derivative IP ID. */
        childIpId: Address;
        /** The IDs of the license tokens. */
        licenseTokenIds: number[] | bigint[];
        /**
        * The maximum number of royalty tokens that can be distributed to the external royalty policies (max: 100,000,000).
        * @default 100_000_000
        */
        maxRts?: number;
      };
      ```

      ```typescript Response Type theme={null}
      export type LinkDerivativeResponse = {
        txHash?: Hex;
      };
      ```
    </CodeGroup>
  </Tab>
</Tabs>
