Packages

@ckb-ccc/spore

Spore Protocol SDK for creating and managing on-chain digital objects(DOB).

Edit on GitHub

What is Spore?

@ckb-ccc/spore implements the Spore Protocol — CKB's on-chain digital object (DOB) standard. Each Spore is a Cell that holds its content (image, text, etc.) fully on-chain. Spores can optionally belong to a Cluster (similar to an NFT collection).

Installation

@ckb-ccc/spore npm version@ckb-ccc/spore npm downloads per week
npm install @ckb-ccc/spore
yarn add @ckb-ccc/spore
pnpm add @ckb-ccc/spore

If you are using @ckb-ccc/shell, spore is already included as ccc.spore.

Exports

The package exports the spore namespace from the barrel:

import { spore } from "@ckb-ccc/spore";
// or, when using @ckb-ccc/shell:
import { ccc } from "@ckb-ccc/shell";
// ccc.spore.createSpore(...)

Top-level exports:

ExportDescription
createSporeCreate a new Spore cell
transferSporeTransfer a Spore to a new owner
meltSporeDestroy a Spore and recover capacity
findSporeLook up a single Spore cell by ID
findSporesSearch Spore cells by lock or cluster
findSporesBySignerFind all Spores owned by a signer
createSporeClusterCreate a new Cluster
transferSporeClusterTransfer a Cluster to a new owner
findClusterLook up a Cluster by ID
findSporeClustersSearch Cluster cells
findSporeClustersBySignerFind all Clusters owned by a signer
dobDigital object encoding utilities

Key functions

createSpore

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 }>

transferSpore

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

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

createSporeCluster

async function createSporeCluster(params: {
  signer: ccc.Signer;
  data: ClusterDataView;
  to?: ccc.ScriptLike;
  tx?: ccc.TransactionLike;
  scriptInfo?: SporeScriptInfoLike;
  scriptInfoHash?: ccc.HexLike;
}): Promise<{ tx: ccc.Transaction; id: ccc.Hex }>

transferSporeCluster

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 }>

Usage examples

Create a Spore

import { spore } from "@ckb-ccc/spore";
import { ccc } from "@ckb-ccc/shell";

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

await tx.completeFeeBy(signer);
const txHash = await signer.sendTransaction(tx);
console.log("Spore ID:", id);

Create a Spore in a Cluster

const { tx: clusterTx, id: clusterId } = await spore.createSporeCluster({
  signer,
  data: {
    name: "My Collection",
    description: "A collection of digital objects",
  },
});

await clusterTx.completeFeeBy(signer);
await signer.sendTransaction(clusterTx);

// Create a Spore that belongs to the cluster
const { tx, id: sporeId } = await spore.createSpore({
  signer,
  data: {
    contentType: "image/png",
    content: pngBytes,
    clusterId,
  },
  clusterMode: "lockProxy",
});

await tx.completeFeeBy(signer);
await signer.sendTransaction(tx);

Find a Spore by ID

import { findSpore } from "@ckb-ccc/spore";

const result = await findSpore(client, "0xSPORE_ID...");
if (result) {
  console.log("Content type:", result.sporeData.contentType);
  console.log("Content:", ccc.bytesTo(result.sporeData.content, "utf8"));
}

Transfer a Spore

import { ccc } from "@ckb-ccc/core";
import { transferSpore } from "@ckb-ccc/spore";

// Transfer a Spore to a new owner
const { script: newOwner } = await ccc.Address.fromString(receiverAddress, client);

let { tx } = await transferSpore({
  signer,
  id: "0xSPORE_ID...",
  to: newOwner,
});

await tx.completeFeeBy(signer);
const txHash = await signer.sendTransaction(tx);

Search Spores by Owner

import { findSporesBySigner } from "@ckb-ccc/spore";

for await (const { sporeData, cell } of findSporesBySigner({ signer })) {
  console.log("Spore:", cell.outPoint.txHash);
  console.log("Content type:", sporeData.contentType);
}

Melt (Destroy) a Spore

import { meltSpore } from "@ckb-ccc/spore";

let { tx } = await meltSpore({
  signer,
  id: "0xSPORE_ID...",
});

await tx.completeFeeBy(signer);
const txHash = await signer.sendTransaction(tx);

DOB (digital object) encoding

The dob sub-namespace provides utilities for encoding Spore data following the DOB0/DOB1 specifications:

import { spore } from "@ckb-ccc/spore";

const encoded = spore.dob.encodeNativeRendererDob0({ /* DOB0 content */ });

Predefined script configurations

The package ships with predefined script info for both mainnet and testnet. These are selected automatically based on your client. You can also pass a custom scriptInfo to every function to target a different deployment.

On this page