@ckb-ccc/ssri

CKB 智能合约的 SSRI(脚本源生富信息)协议支持。

在 GitHub 上编辑

@ckb-ccc/ssri 实现了 脚本源生富信息(Script-Sourced Rich Information,简称 SSRI)协议。SSRI 定义了一套标准,用于调用 CKB 脚本上的具名方法并接收结构化响应——使智能合约能够通过链下 RPC 服务器暴露丰富的元数据和操作接口。

安装

@ckb-ccc/ssri npm version@ckb-ccc/ssri npm downloads per week

如果你使用的是 @ckb-ccc/shellssri 命名空间已作为 ccc.ssri 内置其中。

npm install @ckb-ccc/ssri
yarn add @ckb-ccc/ssri
pnpm add @ckb-ccc/ssri

SSRI 简介

CKB 脚本(Lock / Type Script)本质上是纯粹的验证函数——默认无法暴露元数据或提供可调用接口。SSRI 通过以下机制解决了这一问题:

  1. 智能合约按照命名约定实现具名方法(例如 UDT.nameSSRI.version)。
  2. 链下 SSRI 服务器在沙箱环境中运行脚本,执行这些方法。
  3. 客户端代码通过 JSON-RPC 调用 SSRI 服务器,传入脚本代码的 OutPoint、方法名和参数。

@ckb-ccc/ssri 为上述模式提供 TypeScript 抽象层。

导出

导出说明
Trait所有 SSRI Trait 的基类(继承此类以实现自定义 Trait)
ExecutorSSRI 执行后端的抽象基类
ExecutorJsonRpc通过 JSON-RPC 调用 SSRI 服务器的具体执行器
ExecutorResponse<T>响应包装类,携带执行结果和已解析的 Cell 依赖
ExecutorErrorUnknown错误:服务器未知错误
ExecutorErrorExecutionFailed错误:脚本执行失败
ExecutorErrorDecode错误:响应解码失败
ContextCode执行上下文:无上下文(代码层级)
ContextScript执行上下文:脚本层级
ContextCell执行上下文:Cell 层级
ContextTransaction执行上下文:交易层级
getMethodPath计算方法名对应的 8 字节方法路径哈希

核心类

Trait

所有兼容 SSRI 的合约接口的基类。继承它即可为链上脚本构建带类型的封装:

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

class MyContract extends ssri.Trait {
  async myMethod(): Promise<ssri.ExecutorResponse<string>> {
    const res = await this.assertExecutor().runScript(
      this.code,
      "MyContract.my_method",
      [],
    );
    return res.map((bytes) => ccc.bytesTo(bytes, "utf8"));
  }
}

Trait 内置方法:

// 列出脚本暴露的方法
trait.getMethods(offset?, limit?): Promise<ExecutorResponse<ccc.Hex[]>>

// 检查指定方法名是否存在
trait.hasMethods(methodNames: string[]): Promise<ExecutorResponse<boolean[]>>

// 查询脚本的 SSRI 版本
trait.version(): Promise<ExecutorResponse<ccc.Num>>

// 安全执行调用,执行失败时返回 undefined 而非抛出异常
trait.tryRun(call): Promise<ExecutorResponse<T | undefined>>

ExecutorJsonRpc

通过 HTTP JSON-RPC 连接 SSRI 服务器:

const executor = new ssri.ExecutorJsonRpc("https://your-ssri-server.example.com");

ExecutorResponse<T>

所有 SSRI 调用均返回 ExecutorResponse<T>,携带解码后的结果以及需要加入交易的 Cell 依赖:

const response: ssri.ExecutorResponse<string> = await trait.myMethod();

response.res;      // 解码后的值
response.cellDeps; // ccc.OutPoint[]——需添加至交易的 Cell 依赖
response.map(fn);  // 转换结果

使用示例

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

const executor = new ssri.ExecutorJsonRpc("https://ssri.example.com");

const trait = new ssri.Trait(
  { txHash: "0x...", index: 0 }, // 代码 OutPoint
  executor,
);

// 查询 SSRI 版本
const { res: version, cellDeps } = await trait.version();
console.log("Version:", version);

// 列出可用方法
const { res: methods } = await trait.getMethods();
console.log("Methods:", methods);

执行上下文

SSRI 方法支持四个层级的执行上下文,控制脚本可访问的链上数据范围:

上下文类型适用场景
ContextCode(默认)纯代码层级查询——不传入 Cell 或交易数据
ContextScript向执行器传入脚本(例如查询脚本级别的元数据)
ContextCell传入完整 Cell(输出 + 数据),执行 Cell 级别的脚本
ContextTransaction传入完整交易,执行交易级别的脚本
const res = await executor.runScript(
  codeOutPoint,
  "UDT.balance",
  [encodedArgs],
  {
    script: { codeHash: "0x...", hashType: "type", args: "0x..." },
  },
);

@ckb-ccc/udt 构建于 @ckb-ccc/ssri 之上,是 SSRI 模式的完整实现示例。

参考资料

最后更新于

目录