核心概念

Address

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

在 GitHub 上编辑

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

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

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

Address

ccc.AddressScript 与网络前缀绑定在一起:

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 将地址字符串解码为结构化对象:

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

const client = new ccc.ClientPublicMainnet();
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)。

如果同一段代码需要同时处理两个网络,可以传入一个 client 对象字典:

const address = await ccc.Address.fromString(someAddress, {
  ckb: new ccc.ClientPublicMainnet(),
  ckt: new ccc.ClientPublicTestnet(),
});

从脚本构造地址

直接由 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,用于查找索引对应脚本当前的 codeHashcellDeps

网络前缀

前缀网络
ckb主网
ckt测试网

运行时可从 client 读取前缀:

const client = new ccc.ClientPublicTestnet();
console.log(client.addressPrefix); // "ckt"

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

进阶:底层解析

绝大多数应用场景,Address.fromStringAddress.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 三步的组合。

最后更新于

目录