AI agents: the machine-readable documentation index for this site is at https://docs.ckbccc.com/llms.txt. Append ".md" to any documentation page URL to fetch its canonical Markdown source, which is preferred over rendered HTML for retrieval, indexing, question answering, and code generation.

Product-specific agent operating guidance (read before generating CKB/CCC code): https://docs.ckbccc.com/skill.md

核心概念

Address

解析和构造 CKB 地址——地址中编码了 Lock 脚本和网络前缀。

Edit on GitHub

CKB 地址是一个 bech32m 编码的字符串,其中打包了两部分信息:

  1. Lock 脚本——决定谁可以花费该地址下 Cell 的链上判定逻辑(codeHash、hashType 和 args)。
  2. 网络前缀——主网用 ckb,测试网用 ckt。

由于 Lock 脚本已内嵌于地址中,向某个地址发送资产时,可以直接从地址还原出所需的脚本,无需额外元数据。

Address 类

ccc.Address 将 Script 与网络前缀绑定在一起:

export class Address {
  constructor(
    public script: Script,
    public prefix: string, // "ckb" | "ckt"
  ) {}
}

凡接受 AddressLike 的 API,都可以传入已有的 Address 实例或普通对象——Address.from() 会做归一化处理:

const address = ccc.Address.from({
  script: { codeHash: "0x...", hashType: "type", args: "0x..." },
  prefix: "ckb",
});

使用方法

解析地址字符串

Address.fromString 将编码后的 CKB 地址解析为结构化对象。如果字符串不是编码地址,client 上可选的 addressResolver 可以解析名称等其他表示形式:

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

const clientOwner = ccc.ClientPublicMainnet.open();
const client = clientOwner.value;
// 不再使用时调用 `await clientOwner.dispose()`。
const address = await ccc.Address.fromString(
  "ckb1qzda0cr08m85hc8jlnfp3sdrlalyatuqvqdveld...",
  client,
);

console.log(address.script.codeHash); // Lock 脚本 code hash
console.log(address.script.hashType); // "type" | "data"
console.log(address.script.args);     // Lock 脚本 args
console.log(address.prefix);          // "ckb"

对于编码地址,该方法会校验地址前缀与 client 所在网络是否匹配,不匹配时抛出异常(例如将 ckt 地址传给主网 client)。

传入以 prefix 为 key 的 client 对象字典已经 deprecated。如果同一段代码需要同时处理两个网络,应由调用方依次尝试各个 client 并处理失败:

const clientsOwner = ccc.OwnerAggregated.from([
  ccc.ClientPublicMainnet.open(),
  ccc.ClientPublicTestnet.open(),
] as const);
const [mainnetClient, testnetClient] = clientsOwner.value;
let address: ccc.Address;

try {
  try {
    address = await ccc.Address.fromString(someAddress, mainnetClient);
  } catch {
    address = await ccc.Address.fromString(someAddress, testnetClient);
  }
} finally {
  await clientsOwner.dispose();
}

解析名称及其他表示形式

如果应用接受编码后的 CKB 地址以外的表示形式,可以配置 AddressResolver:

const names: Record<string, ccc.ScriptLike> = {
  "alice.example": aliceLock,
};

const addressResolver: ccc.AddressResolver = {
  shouldResolve: (value) => value.endsWith(".example"),
  resolve: async (value) => names[value],
};

const clientOwner = ccc.ClientPublicMainnet.open({ addressResolver });
const address = await ccc.Address.fromString(
  "alice.example",
  clientOwner.value,
);
await clientOwner.dispose();

只有常规地址解析失败后才会调用 resolver。shouldResolve 用于判断该 resolver 是否负责给定的表示形式;如果返回 false,Address.fromString 会保留原始解析错误;如果 resolve 返回 undefined,则抛出 Address ... not found。解析得到的脚本会与传入 client 的网络前缀组合成 Address。

从脚本构造地址

直接由 Lock 脚本和 client 构造 Address:

const address = ccc.Address.fromScript(lockScript, client);
console.log(address.toString()); // "ckb1q..."

也可以从内置的 KnownScript 派生:

const address = await ccc.Address.fromKnownScript(
  client,
  ccc.KnownScript.Secp256k1Blake160,
  "0xPublicKeyHash...",
);

从 Signer 获取地址

在 dApp 中,最便捷的方式是直接从已连接的 Signer 获取地址:

// 推荐地址的字符串形式
const addressStr = await signer.getRecommendedAddress();

// 推荐地址的 Address 对象(包含 Lock 脚本)
const addressObj = await signer.getRecommendedAddressObj();
const { script: lock } = addressObj;

// 该 Signer 控制的所有地址
const allAddresses = await signer.getAddresses(); // string[]

需要 Lock 脚本时(例如将其设为交易输出的接收方),优先使用 getRecommendedAddressObj,而不是先调用 getRecommendedAddress 再对结果执行 Address.fromString。

将地址转换为字符串

对任意 Address 实例调用 toString(),得到 bech32m 编码的地址字符串:

const str = address.toString(); // "ckb1q..." | "ckt1q..."

toString() 始终生成当前推荐的长(Full)地址格式。CCC 为了向后兼容可以解析旧版(legacy)格式,但不会生成它们。

地址格式

CCC 支持四种地址格式,由首字节(format byte)区分。toString() 只输出 Full 格式,其余格式仅用于兼容 2021 年前的旧版地址。

格式编码Payload 结构备注
Fullbech32m[0x00, codeHash(32), hashType(1), args]当前标准格式,由 toString() 输出。
FullDatabech32[0x02, codeHash(32), args],hashType 为 "data"2019 年旧版格式。
FullTypebech32[0x04, codeHash(32), args],hashType 为 "type"2019 年旧版格式。
Shortbech32[0x01, scriptIndex(1), args(20)]通过脚本索引(scriptIndex)而非完整 code hash 编码脚本。

Short 格式通过脚本索引而非完整 codeHash 来标识脚本,支持以下脚本:

scriptIndex脚本
0KnownScript.Secp256k1Blake160
1KnownScript.Secp256k1Multisig
2KnownScript.AnyoneCanPay

解析 Short 格式地址需要 Client,用于查找索引对应脚本当前的 codeHash 和 cellDeps。

网络前缀

前缀网络
ckb主网
ckt测试网

运行时可从 client 读取前缀:

const clientOwner = ccc.ClientPublicTestnet.open();
const client = clientOwner.value;
// 不再使用时调用 `await clientOwner.dispose()`。
console.log(client.addressPrefix); // "ckt"

不要混用主网和测试网地址。将 ckt 地址传给主网 client 会抛出异常。使用 Address.fromString 时,务必配合正确网络的 client。

进阶:底层解析

绝大多数应用场景,Address.fromString 和 Address.fromScript 已经足够。如果需要在不发起 Client 请求的情况下检查或转换地址,可以使用 cccA 进阶命名空间中暴露的底层步骤:

import { cccA } from "@ckb-ccc/ccc/advanced";

addressPayloadFromString

解码 bech32/bech32m 封装,返回原始的 format byte 和 payload——不解析任何 KnownScript:

const { prefix, format, payload } = cccA.addressPayloadFromString(
  "ckb1qzda0cr08m85hc8jlnfp3sdrlalyatuqvqdveld...",
);
// prefix:  "ckb"
// format:  cccA.AddressFormat.Full
// payload: number[](codeHash + hashType + args 字节)

优先尝试 bech32m 解码,失败后回退到旧版 bech32。两者均不匹配时,抛出 Unknown address format。

addressFromPayload

将解码后的 payload 还原为 AddressLike,并通过 client 解析 Short 格式的脚本索引:

const addressLike = await cccA.addressFromPayload(prefix, format, payload, client);
const address = ccc.Address.from(addressLike);

对于编码地址,Address.fromString 会依次执行 addressPayloadFromString、前缀校验和 addressFromPayload。如果第一步失败,则可能改由 client.addressResolver 解析。

Last updated on

On this page