Standard-udt-contracts: A Standardized UDT Contract Suite for CKB

大家好,我想介绍一个 CKB 上的 UDT 合约项目:standard-udt-contracts: xcshuan/ckb-standard-udt-contracts

原始设计: Enhanced UDT Standard - English / CKB Development & Technical Discussion - Nervos Talk

先做一个说明:这个项目的合约开发过程中大量使用了 AI 辅助,包括代码实现、测试补充和文档整理。但合约核心逻辑、状态机路径、权限校验和关键安全边界我都已经人工逐项审阅过。AI 在这里主要承担的是实现和整理工作,最终的协议设计取舍和合约逻辑判断仍然由人工完成。

这个项目实现了一组围绕 sUDT、xUDT、元数据、供应量追踪、权限控制和访问控制构建的标准化合约。目标是提供一套更完整、更可组合、边界更清晰的 UDT 合约基础设施。

项目包含五个主要 type script:

  • sudt:sUDT token type script

  • sudt-meta:sUDT metadata type script

  • xudt:xUDT token type script

  • xudt-meta:xUDT metadata type script

  • access-list:xUDT 使用的 AccessList shard type script

同时项目还包含:

  • lib/types:共享 Molecule schema、生成类型和严格解析器

  • lib/script-utils:共享 no-std 脚本工具,包括权限验证、token delta 计算、cell 扫描等

  • tests:基于 ckb-testtool 的集成测试和测试插件

核心功能

这个项目支持:

  • 普通 UDT 转账

  • 授权 mint

  • 授权 protocol burn

  • 用户自行销毁 token cell

  • 可选的 total supply tracking

  • metadata cell 创建、更新和销毁

  • metadata authority 和 mint authority

  • xUDT pause mode

  • xUDT whitelist / blacklist access mode

  • AccessList 分片管理

  • 动态扩展插件,包括 dynamic linking 和 spawn 两种执行模式

Supply Tracking 设计

供应量追踪是可选的,并且在 token 创建后不可变。

如果启用 CONFIG_SUPPLY_TRACKED,metadata 中的 current_supply 必须和交易中的 token cell delta 对齐:

  • mint 增加 supply,需要 mint_authority

  • protocol burn 减少 supply,需要 mint_authority

  • user destruction 不减少 tracked supply

  • metadata 不能单独修改 current_supply

这里区分了 protocol burn 和 user destruction:

  • 如果交易消费了 metadata input cell,负 delta 被视为 protocol burn

  • 如果没有消费 metadata input cell,负 delta 被视为用户自行销毁 token cell

这样可以允许用户销毁自己的 token cell 回收 CKB,同时不要求 mint authority,也不影响协议层记录的 total supply。

metadata cell 本身也可以销毁以回收 CKB,但条件更严格:

  • 必须是 supply-tracked mode

  • current_supply 必须为 0

  • 必须由 mint_authority 授权

对于 xUDT,如果 access mode 仍然开启,销毁 metadata 时还要求:

  • input 中包含 full-domain AccessList

  • output 中不能再留下绑定到该 metadata 的 AccessList cell

AccessList 和访问控制

xUDT 支持三种 access state:

  • disabled

  • blacklist

  • whitelist

AccessList 使用 shard 结构覆盖 lock hash domain。每个 shard 有自己的 range 和 entries。entries 在类型层保证:

  • 在 shard range 内

  • 有序

  • 不重复

xUDT 在转账时根据 access mode 验证 input lock:

  • whitelist:必须提供 membership proof

  • blacklist:必须提供 non-membership proof

Access mode 的全局切换由 xudt-meta 管理:

  • disabled → active 需要 full-domain AccessList outputs

  • active → disabled 需要 full-domain AccessList inputs

  • whitelist ↔ blacklist 需要 full-domain inputs 和 outputs

普通 AccessList 更新不需要消费全域,只需要 input shards 和 output shards 覆盖同一段连续区间。在这段区间内,可以同时修改 entries、split shard、merge shard。

权限模型

metadata 中可以配置多种 authority:

  • InputLock

  • InputType

  • OutputType

  • DynamicLinking

  • Spawn

其中 mint_authority 是最高权限,控制:

  • mint

  • protocol burn

  • supply-changing metadata update

  • mint authority 修改

  • extension list 修改

  • metadata/access authority 的 fallback 授权

项目中把权限验证逻辑抽到了共享的 AuthorityVerifier。同一条验证路径会复用 verifier,并缓存重复 authority check,避免重复扫描 cell 或重复执行动态权限代码。

即使是 no-op update,只要消费 metadata 或 AccessList state cell,也必须通过相应 authority 验证。状态 cell 的 unlock 权限不依赖 lock script,而由 type script 中的 authority 规则控制。

技术边界

项目强调 type script 的职责边界:

  • token script 负责 token movement

  • metadata script 负责 metadata state

  • access-list script 负责 AccessList shard lifecycle

  • shared libs 只提供解析和底层机制,不拥有业务规则

例如:

  • token script 不验证 metadata lifecycle

  • metadata script 不验证 token ownership

  • xUDT 只消费 AccessList proof,不负责 AccessList shard 状态机

  • AccessList script 不关心 token 转账语义

这种拆分让协议更容易测试、组合和审计。

一个需要注意的索引问题

这里还有一个实际工程问题需要说明:CKB 原生节点 RPC 本身不适合按 script 检索 live cell。通常要查找“使用某个 script 的 cell”,需要使用 CKB Indexer RPC 的 get_cells。现在 indexer 已经可以集成在 CKB node 里,CKB v0.106.0 之后也推荐直接启用 node 内置 indexer。

get_cells 的查询入口主要是完整的 Script 结构:


{

"script": {

"code_hash": "...",

"hash_type": "type",

"args": "..."

},

"script_type": "lock"

}

或者:


{

"script": {

"code_hash": "...",

"hash_type": "type",

"args": "..."

},

"script_type": "type"

}

也就是说,常规 get_cells 查询是按 code_hash + hash_type + args 组成的完整 Script 查询,并指定查 lock 还是 type,而不是直接传 script_hash

这对 xUDT 有一个影响:xUDT type args 中保存的是 metadata type script hash。拼装转账交易时,钱包或应用可以从 xUDT args 得到 meta type hash,但现有 indexer RPC 不能直接用这个 script hash 定位对应的 metadata cell。实际集成时需要额外处理:

  • 钱包、SDK 或应用自己缓存 token → metadata cell 的映射;

  • 提供额外的服务接口,通过 meta type hash 查询 metadata cell;

  • 或者推动 indexer 增加按 type script hash 定位 cell 的查询接口。

这个问题不影响链上合约验证逻辑,但会影响钱包、SDK 和应用侧的交易构建体验,是后续标准化和工具链支持里需要解决的一环。

测试

项目包含较完整的 ckb-testtool 集成测试,覆盖:

  • sUDT / xUDT mint、burn、transfer、user destruction

  • metadata 创建、更新、销毁

  • supply tracking

  • access mode transition

  • AccessList shard lifecycle

  • whitelist / blacklist proof

  • authority fallback

  • dynamic linking / spawn extension

  • debug/release 差异

目前 debug 集成测试覆盖 160+ 个用例。

总结

standard-udt-contracts 的目标不是只实现一个简单 UDT,而是提供一套完整的标准 UDT 合约框架:

  • 可选供应量追踪

  • 可治理 metadata

  • 可回收 CKB 的 state cell cleanup

  • xUDT access control

  • 可扩展插件系统

  • 明确的权限模型

  • 清晰的脚本职责边界

希望这个项目能为 CKB 上更复杂的 token、资产和应用协议提供基础组件,也欢迎大家 review 设计、提出建议或参与讨论。

6 Likes