@ckb-ccc/spore
Spore Protocol SDK for creating and managing on-chain digital objects(DOB).
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
npm install @ckb-ccc/sporeyarn add @ckb-ccc/sporepnpm add @ckb-ccc/sporeIf 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:
| Export | Description |
|---|---|
createSpore | Create a new Spore cell |
transferSpore | Transfer a Spore to a new owner |
meltSpore | Destroy a Spore and recover capacity |
findSpore | Look up a single Spore cell by ID |
findSpores | Search Spore cells by lock or cluster |
findSporesBySigner | Find all Spores owned by a signer |
createSporeCluster | Create a new Cluster |
transferSporeCluster | Transfer a Cluster to a new owner |
findCluster | Look up a Cluster by ID |
findSporeClusters | Search Cluster cells |
findSporeClustersBySigner | Find all Clusters owned by a signer |
dob | Digital 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.