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

# spore

> Create, transfer, melt, and query Spore Protocol on-chain NFTs using CCC.

`@ckb-ccc/spore` implements the [Spore Protocol](https://docs.spore.pro/) — CKB's standard for fully on-chain digital objects (DOBs). Spore cells store content entirely on-chain and encode ownership through CKB lock scripts, making them censorship-resistant and permanent.

The package exports functions for managing both **Spores** (individual NFTs) and **Clusters** (named collections that group Spores together).

## Installation

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npm install @ckb-ccc/spore
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add @ckb-ccc/spore
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @ckb-ccc/spore
    ```
  </Tab>
</Tabs>

```typescript theme={null}
import { spore } from "@ckb-ccc/shell"; // Node.js
// or
import { ccc } from "@ckb-ccc/connector-react"; // React (via ccc.spore)
```

If you install `@ckb-ccc/spore` directly, import from it:

```typescript theme={null}
import { createSpore, transferSpore, meltSpore } from "@ckb-ccc/spore";
```

## SporeDataView

Every Spore cell holds a `SporeDataView` payload that describes its content:

```typescript theme={null}
type SporeDataView = {
  contentType: string;   // MIME type, e.g. "image/png" or "text/plain"
  content: Uint8Array;   // Raw bytes of the content
  clusterId?: ccc.Hex;   // Optional cluster this Spore belongs to
};
```

## Spore functions

### createSpore

Create a new Spore cell and return the signed transaction along with the new Spore ID.

```typescript theme={null}
async function createSpore(params: {
  signer: ccc.Signer;
  data: SporeDataView;
  to?: ccc.ScriptLike;
  clusterMode?: "lockProxy" | "clusterCell" | "skip";
  tx?: ccc.TransactionLike;
  scriptInfo?: SporeScriptInfoLike;
  scriptInfoHash?: ccc.HexLike;
}): Promise<{ tx: ccc.Transaction; id: ccc.Hex }>
```

| Parameter     | Description                                                                                                                                                                                     |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `signer`      | The signer that pays fees and signs the transaction.                                                                                                                                            |
| `data`        | Content, MIME type, and optional cluster ID for the new Spore.                                                                                                                                  |
| `to`          | Lock script of the initial owner. Defaults to the signer's recommended lock.                                                                                                                    |
| `clusterMode` | How to handle the cluster cell when `data.clusterId` is set. Use `"clusterCell"` to include the cluster cell directly, `"lockProxy"` to use a proxy lock, or `"skip"` to omit cluster handling. |
| `tx`          | Optional transaction skeleton to extend.                                                                                                                                                        |

### transferSpore

Move an existing Spore to a new owner.

```typescript theme={null}
async function transferSpore(params: {
  signer: ccc.Signer;
  id: ccc.HexLike;
  to: ccc.ScriptLike;
  tx?: ccc.TransactionLike;
  scripts?: SporeScriptInfoLike[];
  scriptInfoHash?: ccc.HexLike;
}): Promise<{ tx: ccc.Transaction }>
```

### meltSpore

Destroy a Spore and reclaim its CKB capacity.

```typescript theme={null}
async function meltSpore(params: {
  signer: ccc.Signer;
  id: ccc.HexLike;
  tx?: ccc.TransactionLike;
  scripts?: SporeScriptInfoLike[];
  scriptInfoHash?: ccc.HexLike;
}): Promise<{ tx: ccc.Transaction }>
```

### findSpore

Look up a single Spore by its ID. Returns `undefined` if not found.

```typescript theme={null}
async function findSpore(
  client: ccc.Client,
  id: ccc.HexLike,
  scripts?: SporeScriptInfoLike[],
): Promise<{ cell: ccc.Cell; spore: ccc.Cell; sporeData: SporeDataView; scriptInfo: SporeScriptInfo } | undefined>
```

### assertSpore

Like `findSpore`, but throws if the Spore does not exist.

```typescript theme={null}
async function assertSpore(
  client: ccc.Client,
  args: ccc.HexLike,
  scripts?: SporeScriptInfoLike[],
): Promise<{ cell: ccc.Cell; scriptInfo: SporeScriptInfo }>
```

### findSpores

Async generator that streams all Spores matching an optional lock script and/or cluster ID.

```typescript theme={null}
async function* findSpores(params: {
  client: ccc.Client;
  lock?: ccc.ScriptLike;
  clusterId?: ccc.HexLike;
  scriptInfos?: SporeScriptInfoLike[];
  limit?: number;
  order?: "asc" | "desc";
}): AsyncGenerator<{ cell: ccc.Cell; spore: ccc.Cell; sporeData: SporeDataView; scriptInfo: SporeScriptInfo }>
```

### findSporesBySigner

Async generator that streams all Spores owned by a signer, with optional cluster filter.

```typescript theme={null}
async function* findSporesBySigner(params: {
  signer: ccc.Signer;
  order?: "asc" | "desc";
  limit?: number;
  clusterId?: ccc.HexLike;
  scriptInfos?: SporeScriptInfoLike[];
}): AsyncGenerator<{ cell: ccc.Cell; spore: ccc.Cell; sporeData: SporeDataView; scriptInfo: SporeScriptInfo }>
```

<Tip>
  Pass `clusterId: ""` to `findSpores` or `findSporesBySigner` to return only public Spores — those not belonging to any cluster.
</Tip>

## Cluster functions

Clusters group Spores into named collections. They are singleton cells that carry a name and description.

### createSporeCluster

```typescript theme={null}
async function createSporeCluster(params: {
  signer: ccc.Signer;
  data: ClusterDataView;      // { name: string; description: string }
  to?: ccc.ScriptLike;
  tx?: ccc.TransactionLike;
  scriptInfo?: SporeScriptInfoLike;
  scriptInfoHash?: ccc.HexLike;
}): Promise<{ tx: ccc.Transaction; id: ccc.Hex }>
```

### transferSporeCluster

```typescript theme={null}
async function transferSporeCluster(params: {
  signer: ccc.Signer;
  id: ccc.HexLike;
  to: ccc.ScriptLike;
  tx?: ccc.TransactionLike;
  scripts?: SporeScriptInfoLike[];
  scriptInfoHash?: ccc.HexLike;
}): Promise<{ tx: ccc.Transaction }>
```

### findCluster / assertCluster

```typescript theme={null}
async function findCluster(
  client: ccc.Client,
  id: ccc.HexLike,
  scripts?: SporeScriptInfoLike[],
): Promise<{ cell: ccc.Cell; cluster: ccc.Cell; clusterData: ClusterDataView; scriptInfo: SporeScriptInfo } | undefined>

async function assertCluster(
  client: ccc.Client,
  args: ccc.HexLike,
  scripts?: SporeScriptInfoLike[],
): Promise<{ cell: ccc.Cell; scriptInfo: SporeScriptInfo }>
```

### findSporeClustersBySigner / findSporeClusters

Async generators for enumerating clusters, equivalent to their Spore counterparts.

## Example: create and transfer a Spore

<Steps>
  <Step title="Create a Spore">
    ```typescript theme={null}
    import { createSpore } from "@ckb-ccc/spore";
    import { ccc } from "@ckb-ccc/shell";

    const client = new ccc.ClientPublicTestnet();
    const signer = new ccc.SignerCkbPrivateKey(client, "0x<private-key>");

    const { tx, id } = await createSpore({
      signer,
      data: {
        contentType: "text/plain",
        content: new TextEncoder().encode("Hello, Spore!"),
      },
    });

    // Complete capacity and fee, then send
    await tx.completeInputsByCapacity(signer);
    await tx.completeFeeBy(signer);
    const txHash = await signer.sendTransaction(tx);
    console.log("Spore created:", id, "TX:", txHash);
    ```
  </Step>

  <Step title="Transfer the Spore">
    ```typescript theme={null}
    import { transferSpore } from "@ckb-ccc/spore";

    const { script: newOwner } = await ccc.Address.fromString(
      "ckt1qzda0cr08m85hc8jlnfp3gp88t7re8he4qkd3he97k2tfe4ckb...",
      client,
    );

    const { tx: transferTx } = await transferSpore({
      signer,
      id,
      to: newOwner,
    });

    await transferTx.completeInputsByCapacity(signer);
    await transferTx.completeFeeBy(signer);
    const transferHash = await signer.sendTransaction(transferTx);
    console.log("Transferred:", transferHash);
    ```
  </Step>
</Steps>
