Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ckb-devrel/ccc/llms.txt

Use this file to discover all available pages before exploring further.

CKB supports User Defined Tokens (UDT) — fungible tokens that live in the data field of cells. The @ckb-ccc/ccc package includes first-class UDT support via the ccc.udt namespace.

xUDT vs basic UDT

Basic sUDTxUDT
StandardCKB RFC 25CKB RFC 52
Extension supportNoYes (owner-mode, RCE rules)
KnownScript value— (not in CCC)ccc.KnownScript.XUdt
Production useLegacyRecommended
The Udt class in CCC supports both. By default it uses the SSRI execution model (on-chain script execution), and falls back gracefully to off-chain construction for legacy xUDT tokens.

Installation

npm install @ckb-ccc/ccc
UDT support is bundled in the main package — no extra install is required.

Import

import { ccc } from "@ckb-ccc/ccc";
The Udt class is available as ccc.udt.Udt.

Construct a Udt instance

A Udt instance is defined by two pieces of information:
  • code — the OutPoint of the cell that holds the UDT script code
  • script — the type script that identifies this specific token
const type = await ccc.Script.fromKnownScript(
  signer.client,
  ccc.KnownScript.XUdt,
  // The args uniquely identify this token (issuer lock hash)
  "0xf8f94a13dfe1b87c10312fb9678ab5276eefbe1e0b2c62b4841b1f393494eff2",
);

const code = (
  await signer.client.getCellDeps(
    (await signer.client.getKnownScript(ccc.KnownScript.XUdt)).cellDeps,
  )
)[0].outPoint;

const udt = new ccc.udt.Udt(code, type);

Transfer tokens

This example is from packages/examples/src/transferUdt.ts. It sends 1 token unit to the signer’s own address:
1

Build the initial transfer output

udt.transfer creates a transaction with the output cells you want. It does not yet balance inputs.
const receiver = await signer.getRecommendedAddress();
const { script: lock } = await ccc.Address.fromString(receiver, signer.client);

let { res: tx } = await udt.transfer(signer, [
  { to: lock, amount: ccc.fixedPointFrom(1) },
]);
2

Fill UDT inputs

udt.completeBy collects the signer’s UDT cells until there is enough token balance to cover the outputs. Any surplus is sent back as a change cell.
tx = await udt.completeBy(tx, signer);
3

Fill capacity inputs

After UDT inputs are set, fill capacity inputs for the CKB needed to hold the cells.
await tx.completeInputsByCapacity(signer);
4

Pay fee and broadcast

await tx.completeFeeBy(signer);
const txHash = await signer.sendTransaction(tx);
console.log("UDT transfer hash:", txHash);

Mint tokens

Minting works identically to transfer — it just creates new token outputs without requiring existing UDT inputs. The UDT script must grant the signer mint authority (typically through owner-mode in xUDT):
const { script: to } = await ccc.Address.fromString(receiver, signer.client);

let { res: tx } = await udt.mint(signer, [
  { to, amount: ccc.fixedPointFrom(1000) },
]);

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

Read token metadata (SSRI tokens)

For SSRI-compliant UDTs, the Udt class can fetch on-chain metadata:
const { res: name }     = await udt.name();
const { res: symbol }   = await udt.symbol();
const { res: decimals } = await udt.decimals();
const { res: icon }     = await udt.icon();

console.log(`${name} (${symbol}), ${decimals} decimals`);
These methods return undefined for legacy sUDT/xUDT tokens that do not implement the SSRI UDT interface. Check the return value before using it.

API reference

MethodDescription
new ccc.udt.Udt(code, script)Construct a UDT instance
udt.transfer(signer, transfers, tx?)Build transfer outputs
udt.mint(signer, mints, tx?)Build mint outputs
udt.completeBy(tx, signer)Fill UDT inputs and add change
udt.completeChangeToLock(tx, signer, lock)Fill UDT inputs with a specific change lock
udt.name()Token name (SSRI only)
udt.symbol()Token symbol (SSRI only)
udt.decimals()Token decimals (SSRI only)
udt.icon()Token icon URI (SSRI only)

Build docs developers (and LLMs) love