@ckb-ccc/ssri 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # @ckb-ccc/ssri
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#130](https://github.com/ckb-devrel/ccc/pull/130) [`8c97c85`](https://github.com/ckb-devrel/ccc/commit/8c97c851db4a2d940c7e59116ca7620cfd0afae1) Thanks [@Hanssen0](https://github.com/Hanssen0)! - feat: SSRI & UDT SDK
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`4dbf4fd`](https://github.com/ckb-devrel/ccc/commit/4dbf4fd8021cf14d05282706a7667ea7d108fb09), [`4c76f9e`](https://github.com/ckb-devrel/ccc/commit/4c76f9e2a93a226fcfc4c32a5378bb531bfff08f), [`c2c4c26`](https://github.com/ckb-devrel/ccc/commit/c2c4c264e04461948e4b913b2f22054e6032ddc8), [`b6a73fa`](https://github.com/ckb-devrel/ccc/commit/b6a73fa9628ebdff51cb8f246309654cd53e36f2), [`8c97c85`](https://github.com/ckb-devrel/ccc/commit/8c97c851db4a2d940c7e59116ca7620cfd0afae1)]:
12
+ - @ckb-ccc/core@1.3.0
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ <p align="center">
2
+ <a href="https://app.ckbccc.com/">
3
+ <img alt="Logo" src="https://raw.githubusercontent.com/ckb-devrel/ccc/master/assets/logoAndText.svg" style="height: 8rem; max-width: 90%; padding: 0.5rem 0;" />
4
+ </a>
5
+ </p>
6
+
7
+ <h1 align="center" style="font-size: 48px;">
8
+ CCC's Support for SSRI
9
+ </h1>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@ckb-ccc/ssri"><img
13
+ alt="NPM Version" src="https://img.shields.io/npm/v/%40ckb-ccc%2Fssri"
14
+ /></a>
15
+ <img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/ckb-devrel/ccc" />
16
+ <img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/ckb-devrel/ccc/master" />
17
+ <img alt="GitHub branch check runs" src="https://img.shields.io/github/check-runs/ckb-devrel/ccc/master" />
18
+ <a href="https://live.ckbccc.com/"><img
19
+ alt="Playground" src="https://img.shields.io/website?url=https%3A%2F%2Flive.ckbccc.com%2F&label=Playground"
20
+ /></a>
21
+ <a href="https://app.ckbccc.com/"><img
22
+ alt="App" src="https://img.shields.io/website?url=https%3A%2F%2Fapp.ckbccc.com%2F&label=App"
23
+ /></a>
24
+ <a href="https://docs.ckbccc.com/"><img
25
+ alt="Docs" src="https://img.shields.io/website?url=https%3A%2F%2Fdocs.ckbccc.com%2F&label=Docs"
26
+ /></a>
27
+ </p>
28
+
29
+ <p align="center">
30
+ CCC - CKBers' Codebase is a one-stop solution for your CKB JS/TS ecosystem development.
31
+ <br />
32
+ Empower yourself with CCC to discover the unlimited potential of CKB.
33
+ <br />
34
+ Interoperate with wallets from different chain ecosystems.
35
+ <br />
36
+ Fully enabling CKB's Turing completeness and cryptographic freedom power.
37
+ </p>
38
+
39
+ ### Script-Sourced Rich Information
40
+
41
+ Read more about SSRI on [[EN/CN] Script-Sourced Rich Information - 来源于 Script 的富信息](https://talk.nervos.org/t/en-cn-script-sourced-rich-information-script/8256).
42
+
43
+ NOTE: This is the base package for interaction with SSRI-Compliant scripts.
44
+
45
+ If you are looking for UDT support, please refer directly to [@ckb-ccc/udt](https://www.npmjs.com/package/@ckb-ccc/udt) which supports both SSRI-compliant UDT and falling back to xUDT.
46
+
47
+ ### Related Projects
48
+
49
+ - [`ssri-server`](https://github.com/ckb-devrel/ssri-server): Server for calling SSRI methods.
50
+ - [`ckb_ssri_sdk`](https://github.com/ckb-devrel/ckb_ssri_sdk): A toolkit to help developers build SSRI-Compliant scripts on CKB with production level example script `pausable-udt` for reference.
51
+
52
+ <h3 align="center">
53
+ Read more about CCC on <a href="https://docs.ckbccc.com">our website</a> or <a href="https://github.com/ckb-devrel/ccc">GitHub Repo</a>.
54
+ </h3>
@@ -0,0 +1,4 @@
1
+ export * from "./executor.js";
2
+ export * from "./trait.js";
3
+ export * from "./utils.js";
4
+ //# sourceMappingURL=barrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
package/dist/barrel.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./executor.js";
2
+ export * from "./trait.js";
3
+ export * from "./utils.js";
@@ -0,0 +1,51 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export type ContextTransaction = {
3
+ script?: ccc.ScriptLike | null;
4
+ cell?: Omit<ccc.CellLike, "outPoint"> | null;
5
+ tx: ccc.TransactionLike;
6
+ };
7
+ export type ContextCell = {
8
+ script?: ccc.ScriptLike | null;
9
+ cell: Omit<ccc.CellLike, "outPoint">;
10
+ tx?: undefined | null;
11
+ };
12
+ export type ContextScript = {
13
+ script: ccc.ScriptLike;
14
+ cell?: undefined | null;
15
+ tx?: undefined | null;
16
+ };
17
+ export type ContextCode = undefined | {
18
+ script?: undefined | null;
19
+ cell?: undefined | null;
20
+ tx?: undefined | null;
21
+ };
22
+ export declare class ExecutorResponse<T> {
23
+ readonly res: T;
24
+ readonly cellDeps: ccc.OutPoint[];
25
+ constructor(res: T, cellDeps: ccc.OutPoint[]);
26
+ static new<T>(res: T, cellDeps?: ccc.OutPointLike[] | null): ExecutorResponse<T>;
27
+ map<U>(fn: (res: T) => U): ExecutorResponse<U>;
28
+ }
29
+ export declare class ExecutorErrorExecutionFailed extends Error {
30
+ constructor(msg?: string);
31
+ }
32
+ /**
33
+ * Represents an SSRI executor.
34
+ */
35
+ export declare abstract class Executor {
36
+ abstract runScript(codeOutPoint: ccc.OutPointLike, method: string, args: ccc.HexLike[], context?: ContextCode | ContextScript | ContextCell | ContextTransaction): Promise<ExecutorResponse<ccc.Hex>>;
37
+ runScriptTry(codeOutPoint: ccc.OutPointLike, method: string, args: ccc.HexLike[], context?: ContextCode | ContextScript | ContextCell | ContextTransaction): Promise<ExecutorResponse<ccc.Hex> | undefined>;
38
+ }
39
+ export declare class ExecutorJsonRpc extends Executor {
40
+ readonly requestor: ccc.RequestorJsonRpc;
41
+ /**
42
+ * Creates an instance of SSRI executor through Json RPC.
43
+ * @param {string} [url] - The external server URL.
44
+ */
45
+ constructor(url: string, config?: ccc.RequestorJsonRpcConfig & {
46
+ requestor?: ccc.RequestorJsonRpc;
47
+ });
48
+ get url(): string;
49
+ runScript(codeOutPoint: ccc.OutPointLike, method: string, args: ccc.HexLike[], context?: ContextCode | ContextScript | ContextCell | ContextTransaction): Promise<ExecutorResponse<ccc.Hex>>;
50
+ }
51
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { cccA } from "@ckb-ccc/core/advanced";
3
+ import { getMethodPath } from "./utils.js";
4
+ export class ExecutorResponse {
5
+ constructor(res, cellDeps) {
6
+ this.res = res;
7
+ this.cellDeps = cellDeps;
8
+ }
9
+ static new(res, cellDeps) {
10
+ return new ExecutorResponse(res, cellDeps?.map(ccc.OutPoint.from) ?? []);
11
+ }
12
+ map(fn) {
13
+ return new ExecutorResponse(fn(this.res), this.cellDeps);
14
+ }
15
+ }
16
+ export class ExecutorErrorExecutionFailed extends Error {
17
+ constructor(msg) {
18
+ super(msg);
19
+ }
20
+ }
21
+ /**
22
+ * Represents an SSRI executor.
23
+ */
24
+ export class Executor {
25
+ async runScriptTry(codeOutPoint, method, args, context) {
26
+ try {
27
+ return await this.runScript(codeOutPoint, method, args, context);
28
+ }
29
+ catch (err) {
30
+ if (err instanceof ExecutorErrorExecutionFailed) {
31
+ return undefined;
32
+ }
33
+ throw err;
34
+ }
35
+ }
36
+ }
37
+ export class ExecutorJsonRpc extends Executor {
38
+ /**
39
+ * Creates an instance of SSRI executor through Json RPC.
40
+ * @param {string} [url] - The external server URL.
41
+ */
42
+ constructor(url, config) {
43
+ super();
44
+ this.requestor =
45
+ config?.requestor ??
46
+ new ccc.RequestorJsonRpc(url, config, (errAny) => {
47
+ if (typeof errAny !== "object" ||
48
+ errAny === null ||
49
+ !("code" in errAny) ||
50
+ typeof errAny.code !== "number") {
51
+ throw errAny;
52
+ }
53
+ if (errAny.code === 1003 || errAny.code === 1004) {
54
+ if ("message" in errAny && typeof errAny.message === "string") {
55
+ throw new ExecutorErrorExecutionFailed(errAny.message);
56
+ }
57
+ throw new ExecutorErrorExecutionFailed();
58
+ }
59
+ throw errAny;
60
+ });
61
+ }
62
+ get url() {
63
+ return this.requestor.url;
64
+ }
65
+ /* Calls a method on the SSRI executor through SSRI Server.
66
+ * @param codeOutPoint - The code OutPoint.
67
+ * @param method - The SSRI method.
68
+ * @param args - The arguments for the method.
69
+ * @param context - The SSRI context for the method.
70
+ * @param context.script - The script level parameters.
71
+ * @param context.cell - The cell level parameters. Take precedence over script.
72
+ * @param context.transaction - The transaction level parameters. Take precedence over cell.
73
+ * @returns The result of the call.
74
+ */
75
+ async runScript(codeOutPoint, method, args, context) {
76
+ const code = ccc.OutPoint.from(codeOutPoint);
77
+ const [rpcMethod, rpcContext] = (() => {
78
+ if (context?.tx) {
79
+ const tx = ccc.Transaction.from(context.tx);
80
+ return [
81
+ "run_script_level_transaction",
82
+ [
83
+ {
84
+ inner: cccA.JsonRpcTransformers.transactionFrom(tx),
85
+ hash: tx.hash(),
86
+ },
87
+ ],
88
+ ];
89
+ }
90
+ if (context?.cell) {
91
+ return [
92
+ "run_script_level_cell",
93
+ [
94
+ {
95
+ cell_output: cccA.JsonRpcTransformers.cellOutputFrom(ccc.CellOutput.from(context.cell.cellOutput)),
96
+ hex_data: ccc.hexFrom(context.cell.outputData),
97
+ },
98
+ ],
99
+ ];
100
+ }
101
+ if (context?.script) {
102
+ return [
103
+ "run_script_level_script",
104
+ [cccA.JsonRpcTransformers.scriptFrom(context.script)],
105
+ ];
106
+ }
107
+ return ["run_script_level_code", []];
108
+ })();
109
+ const { content, cell_deps } = (await this.requestor.request(rpcMethod, [
110
+ code.txHash,
111
+ Number(code.index),
112
+ [getMethodPath(method), ...args.map(ccc.hexFrom)],
113
+ ...rpcContext,
114
+ ]));
115
+ return ExecutorResponse.new(content, cell_deps.map(cccA.JsonRpcTransformers.outPointTo));
116
+ }
117
+ }
@@ -0,0 +1,2 @@
1
+ export * as ssri from "./barrel.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * as ssri from "./barrel.js";
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,35 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { Executor, ExecutorResponse } from "./executor.js";
3
+ /**
4
+ * Abstract class representing an SSRI trait. Should be used as the base of all SSRI traits.
5
+ */
6
+ export declare abstract class Trait {
7
+ readonly code: ccc.OutPoint;
8
+ readonly executor?: Executor;
9
+ /**
10
+ * Creates an instance of SSRI trait.
11
+ * @param code - The cell dependency.
12
+ * @param executor - The SSRI executor instance.
13
+ */
14
+ constructor(code: ccc.OutPointLike, executor?: Executor | null);
15
+ assertExecutor(): Executor;
16
+ /**
17
+ * Retrieves a list of methods.
18
+ * @param offset - The offset for the methods.
19
+ * @param limit - The limit for the methods.
20
+ * @returns {Promise<Bytes[]>} A promise that resolves to a list of methods.
21
+ */
22
+ getMethods(offset?: ccc.NumLike, limit?: ccc.NumLike): Promise<ExecutorResponse<ccc.Hex[]>>;
23
+ /**
24
+ * Checks if the specified methods exist.
25
+ * @param methodNames - The methods to check.
26
+ * @returns A promise that resolves to an array of booleans indicating if methods exist.
27
+ */
28
+ hasMethods(methodNames: string[], extraMethodPaths?: ccc.HexLike[]): Promise<ExecutorResponse<boolean[]>>;
29
+ /**
30
+ * Retrieves the version of the trait.
31
+ * @returns A promise that resolves to the version number.
32
+ */
33
+ version(): Promise<ExecutorResponse<ccc.Num>>;
34
+ }
35
+ //# sourceMappingURL=trait.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trait.d.ts","sourceRoot":"","sources":["../src/trait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAG3D;;GAEG;AACH,8BAAsB,KAAK;IACzB,SAAgB,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC;IACnC,SAAgB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpC;;;;OAIG;gBACS,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI;IAK9D,cAAc;IAQd;;;;;OAKG;IACG,UAAU,CACd,MAAM,GAAE,GAAG,CAAC,OAAW,EACvB,KAAK,GAAE,GAAG,CAAC,OAAW,GACrB,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAUvC;;;;OAIG;IACG,UAAU,CACd,WAAW,EAAE,MAAM,EAAE,EACrB,gBAAgB,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,GAC/B,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IAcvC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAQpD"}
package/dist/trait.js ADDED
@@ -0,0 +1,52 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { getMethodPath } from "./utils.js";
3
+ /**
4
+ * Abstract class representing an SSRI trait. Should be used as the base of all SSRI traits.
5
+ */
6
+ export class Trait {
7
+ /**
8
+ * Creates an instance of SSRI trait.
9
+ * @param code - The cell dependency.
10
+ * @param executor - The SSRI executor instance.
11
+ */
12
+ constructor(code, executor) {
13
+ this.code = ccc.OutPoint.from(code);
14
+ this.executor = executor ?? undefined;
15
+ }
16
+ assertExecutor() {
17
+ if (!this.executor) {
18
+ throw new Error("SSRI executor is not set");
19
+ }
20
+ return this.executor;
21
+ }
22
+ /**
23
+ * Retrieves a list of methods.
24
+ * @param offset - The offset for the methods.
25
+ * @param limit - The limit for the methods.
26
+ * @returns {Promise<Bytes[]>} A promise that resolves to a list of methods.
27
+ */
28
+ async getMethods(offset = 0, limit = 0) {
29
+ const res = await this.assertExecutor().runScript(this.code, "SSRI.get_methods", [ccc.numToBytes(offset ?? 0, 8), ccc.numToBytes(limit ?? 0, 8)]);
30
+ return res.map((res) => ccc.mol.Byte8Vec.decode(res));
31
+ }
32
+ /**
33
+ * Checks if the specified methods exist.
34
+ * @param methodNames - The methods to check.
35
+ * @returns A promise that resolves to an array of booleans indicating if methods exist.
36
+ */
37
+ async hasMethods(methodNames, extraMethodPaths) {
38
+ const methodPaths = ccc.mol.Byte8Vec.encode(methodNames
39
+ .map(getMethodPath)
40
+ .concat(extraMethodPaths?.map(ccc.hexFrom) ?? []));
41
+ const res = await this.assertExecutor().runScript(this.code, "SSRI.has_methods", [methodPaths]);
42
+ return res.map((res) => ccc.mol.BoolVec.decode(res));
43
+ }
44
+ /**
45
+ * Retrieves the version of the trait.
46
+ * @returns A promise that resolves to the version number.
47
+ */
48
+ async version() {
49
+ const res = await this.assertExecutor().runScript(this.code, "SSRI.version", []);
50
+ return res.map((res) => ccc.numFrom(res));
51
+ }
52
+ }
@@ -0,0 +1,3 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export declare function getMethodPath(method: string): ccc.Hex;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,CAErD"}
package/dist/utils.js ADDED
@@ -0,0 +1,4 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export function getMethodPath(method) {
3
+ return ccc.hashCkb(ccc.bytesFrom(method, "utf8")).slice(0, 18);
4
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./executor.js";
2
+ export * from "./trait.js";
3
+ export * from "./utils.js";
4
+ //# sourceMappingURL=barrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./executor.js"), exports);
18
+ __exportStar(require("./trait.js"), exports);
19
+ __exportStar(require("./utils.js"), exports);
@@ -0,0 +1,51 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export type ContextTransaction = {
3
+ script?: ccc.ScriptLike | null;
4
+ cell?: Omit<ccc.CellLike, "outPoint"> | null;
5
+ tx: ccc.TransactionLike;
6
+ };
7
+ export type ContextCell = {
8
+ script?: ccc.ScriptLike | null;
9
+ cell: Omit<ccc.CellLike, "outPoint">;
10
+ tx?: undefined | null;
11
+ };
12
+ export type ContextScript = {
13
+ script: ccc.ScriptLike;
14
+ cell?: undefined | null;
15
+ tx?: undefined | null;
16
+ };
17
+ export type ContextCode = undefined | {
18
+ script?: undefined | null;
19
+ cell?: undefined | null;
20
+ tx?: undefined | null;
21
+ };
22
+ export declare class ExecutorResponse<T> {
23
+ readonly res: T;
24
+ readonly cellDeps: ccc.OutPoint[];
25
+ constructor(res: T, cellDeps: ccc.OutPoint[]);
26
+ static new<T>(res: T, cellDeps?: ccc.OutPointLike[] | null): ExecutorResponse<T>;
27
+ map<U>(fn: (res: T) => U): ExecutorResponse<U>;
28
+ }
29
+ export declare class ExecutorErrorExecutionFailed extends Error {
30
+ constructor(msg?: string);
31
+ }
32
+ /**
33
+ * Represents an SSRI executor.
34
+ */
35
+ export declare abstract class Executor {
36
+ abstract runScript(codeOutPoint: ccc.OutPointLike, method: string, args: ccc.HexLike[], context?: ContextCode | ContextScript | ContextCell | ContextTransaction): Promise<ExecutorResponse<ccc.Hex>>;
37
+ runScriptTry(codeOutPoint: ccc.OutPointLike, method: string, args: ccc.HexLike[], context?: ContextCode | ContextScript | ContextCell | ContextTransaction): Promise<ExecutorResponse<ccc.Hex> | undefined>;
38
+ }
39
+ export declare class ExecutorJsonRpc extends Executor {
40
+ readonly requestor: ccc.RequestorJsonRpc;
41
+ /**
42
+ * Creates an instance of SSRI executor through Json RPC.
43
+ * @param {string} [url] - The external server URL.
44
+ */
45
+ constructor(url: string, config?: ccc.RequestorJsonRpcConfig & {
46
+ requestor?: ccc.RequestorJsonRpc;
47
+ });
48
+ get url(): string;
49
+ runScript(codeOutPoint: ccc.OutPointLike, method: string, args: ccc.HexLike[], context?: ContextCode | ContextScript | ContextCell | ContextTransaction): Promise<ExecutorResponse<ccc.Hex>>;
50
+ }
51
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExecutorJsonRpc = exports.Executor = exports.ExecutorErrorExecutionFailed = exports.ExecutorResponse = void 0;
4
+ const core_1 = require("@ckb-ccc/core");
5
+ const advanced_1 = require("@ckb-ccc/core/advanced");
6
+ const utils_js_1 = require("./utils.js");
7
+ class ExecutorResponse {
8
+ constructor(res, cellDeps) {
9
+ this.res = res;
10
+ this.cellDeps = cellDeps;
11
+ }
12
+ static new(res, cellDeps) {
13
+ return new ExecutorResponse(res, cellDeps?.map(core_1.ccc.OutPoint.from) ?? []);
14
+ }
15
+ map(fn) {
16
+ return new ExecutorResponse(fn(this.res), this.cellDeps);
17
+ }
18
+ }
19
+ exports.ExecutorResponse = ExecutorResponse;
20
+ class ExecutorErrorExecutionFailed extends Error {
21
+ constructor(msg) {
22
+ super(msg);
23
+ }
24
+ }
25
+ exports.ExecutorErrorExecutionFailed = ExecutorErrorExecutionFailed;
26
+ /**
27
+ * Represents an SSRI executor.
28
+ */
29
+ class Executor {
30
+ async runScriptTry(codeOutPoint, method, args, context) {
31
+ try {
32
+ return await this.runScript(codeOutPoint, method, args, context);
33
+ }
34
+ catch (err) {
35
+ if (err instanceof ExecutorErrorExecutionFailed) {
36
+ return undefined;
37
+ }
38
+ throw err;
39
+ }
40
+ }
41
+ }
42
+ exports.Executor = Executor;
43
+ class ExecutorJsonRpc extends Executor {
44
+ /**
45
+ * Creates an instance of SSRI executor through Json RPC.
46
+ * @param {string} [url] - The external server URL.
47
+ */
48
+ constructor(url, config) {
49
+ super();
50
+ this.requestor =
51
+ config?.requestor ??
52
+ new core_1.ccc.RequestorJsonRpc(url, config, (errAny) => {
53
+ if (typeof errAny !== "object" ||
54
+ errAny === null ||
55
+ !("code" in errAny) ||
56
+ typeof errAny.code !== "number") {
57
+ throw errAny;
58
+ }
59
+ if (errAny.code === 1003 || errAny.code === 1004) {
60
+ if ("message" in errAny && typeof errAny.message === "string") {
61
+ throw new ExecutorErrorExecutionFailed(errAny.message);
62
+ }
63
+ throw new ExecutorErrorExecutionFailed();
64
+ }
65
+ throw errAny;
66
+ });
67
+ }
68
+ get url() {
69
+ return this.requestor.url;
70
+ }
71
+ /* Calls a method on the SSRI executor through SSRI Server.
72
+ * @param codeOutPoint - The code OutPoint.
73
+ * @param method - The SSRI method.
74
+ * @param args - The arguments for the method.
75
+ * @param context - The SSRI context for the method.
76
+ * @param context.script - The script level parameters.
77
+ * @param context.cell - The cell level parameters. Take precedence over script.
78
+ * @param context.transaction - The transaction level parameters. Take precedence over cell.
79
+ * @returns The result of the call.
80
+ */
81
+ async runScript(codeOutPoint, method, args, context) {
82
+ const code = core_1.ccc.OutPoint.from(codeOutPoint);
83
+ const [rpcMethod, rpcContext] = (() => {
84
+ if (context?.tx) {
85
+ const tx = core_1.ccc.Transaction.from(context.tx);
86
+ return [
87
+ "run_script_level_transaction",
88
+ [
89
+ {
90
+ inner: advanced_1.cccA.JsonRpcTransformers.transactionFrom(tx),
91
+ hash: tx.hash(),
92
+ },
93
+ ],
94
+ ];
95
+ }
96
+ if (context?.cell) {
97
+ return [
98
+ "run_script_level_cell",
99
+ [
100
+ {
101
+ cell_output: advanced_1.cccA.JsonRpcTransformers.cellOutputFrom(core_1.ccc.CellOutput.from(context.cell.cellOutput)),
102
+ hex_data: core_1.ccc.hexFrom(context.cell.outputData),
103
+ },
104
+ ],
105
+ ];
106
+ }
107
+ if (context?.script) {
108
+ return [
109
+ "run_script_level_script",
110
+ [advanced_1.cccA.JsonRpcTransformers.scriptFrom(context.script)],
111
+ ];
112
+ }
113
+ return ["run_script_level_code", []];
114
+ })();
115
+ const { content, cell_deps } = (await this.requestor.request(rpcMethod, [
116
+ code.txHash,
117
+ Number(code.index),
118
+ [(0, utils_js_1.getMethodPath)(method), ...args.map(core_1.ccc.hexFrom)],
119
+ ...rpcContext,
120
+ ]));
121
+ return ExecutorResponse.new(content, cell_deps.map(advanced_1.cccA.JsonRpcTransformers.outPointTo));
122
+ }
123
+ }
124
+ exports.ExecutorJsonRpc = ExecutorJsonRpc;
@@ -0,0 +1,2 @@
1
+ export * as ssri from "./barrel.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ssri = void 0;
27
+ exports.ssri = __importStar(require("./barrel.js"));
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,35 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { Executor, ExecutorResponse } from "./executor.js";
3
+ /**
4
+ * Abstract class representing an SSRI trait. Should be used as the base of all SSRI traits.
5
+ */
6
+ export declare abstract class Trait {
7
+ readonly code: ccc.OutPoint;
8
+ readonly executor?: Executor;
9
+ /**
10
+ * Creates an instance of SSRI trait.
11
+ * @param code - The cell dependency.
12
+ * @param executor - The SSRI executor instance.
13
+ */
14
+ constructor(code: ccc.OutPointLike, executor?: Executor | null);
15
+ assertExecutor(): Executor;
16
+ /**
17
+ * Retrieves a list of methods.
18
+ * @param offset - The offset for the methods.
19
+ * @param limit - The limit for the methods.
20
+ * @returns {Promise<Bytes[]>} A promise that resolves to a list of methods.
21
+ */
22
+ getMethods(offset?: ccc.NumLike, limit?: ccc.NumLike): Promise<ExecutorResponse<ccc.Hex[]>>;
23
+ /**
24
+ * Checks if the specified methods exist.
25
+ * @param methodNames - The methods to check.
26
+ * @returns A promise that resolves to an array of booleans indicating if methods exist.
27
+ */
28
+ hasMethods(methodNames: string[], extraMethodPaths?: ccc.HexLike[]): Promise<ExecutorResponse<boolean[]>>;
29
+ /**
30
+ * Retrieves the version of the trait.
31
+ * @returns A promise that resolves to the version number.
32
+ */
33
+ version(): Promise<ExecutorResponse<ccc.Num>>;
34
+ }
35
+ //# sourceMappingURL=trait.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trait.d.ts","sourceRoot":"","sources":["../src/trait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAG3D;;GAEG;AACH,8BAAsB,KAAK;IACzB,SAAgB,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC;IACnC,SAAgB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpC;;;;OAIG;gBACS,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI;IAK9D,cAAc;IAQd;;;;;OAKG;IACG,UAAU,CACd,MAAM,GAAE,GAAG,CAAC,OAAW,EACvB,KAAK,GAAE,GAAG,CAAC,OAAW,GACrB,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAUvC;;;;OAIG;IACG,UAAU,CACd,WAAW,EAAE,MAAM,EAAE,EACrB,gBAAgB,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,GAC/B,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IAcvC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAQpD"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Trait = void 0;
4
+ const core_1 = require("@ckb-ccc/core");
5
+ const utils_js_1 = require("./utils.js");
6
+ /**
7
+ * Abstract class representing an SSRI trait. Should be used as the base of all SSRI traits.
8
+ */
9
+ class Trait {
10
+ /**
11
+ * Creates an instance of SSRI trait.
12
+ * @param code - The cell dependency.
13
+ * @param executor - The SSRI executor instance.
14
+ */
15
+ constructor(code, executor) {
16
+ this.code = core_1.ccc.OutPoint.from(code);
17
+ this.executor = executor ?? undefined;
18
+ }
19
+ assertExecutor() {
20
+ if (!this.executor) {
21
+ throw new Error("SSRI executor is not set");
22
+ }
23
+ return this.executor;
24
+ }
25
+ /**
26
+ * Retrieves a list of methods.
27
+ * @param offset - The offset for the methods.
28
+ * @param limit - The limit for the methods.
29
+ * @returns {Promise<Bytes[]>} A promise that resolves to a list of methods.
30
+ */
31
+ async getMethods(offset = 0, limit = 0) {
32
+ const res = await this.assertExecutor().runScript(this.code, "SSRI.get_methods", [core_1.ccc.numToBytes(offset ?? 0, 8), core_1.ccc.numToBytes(limit ?? 0, 8)]);
33
+ return res.map((res) => core_1.ccc.mol.Byte8Vec.decode(res));
34
+ }
35
+ /**
36
+ * Checks if the specified methods exist.
37
+ * @param methodNames - The methods to check.
38
+ * @returns A promise that resolves to an array of booleans indicating if methods exist.
39
+ */
40
+ async hasMethods(methodNames, extraMethodPaths) {
41
+ const methodPaths = core_1.ccc.mol.Byte8Vec.encode(methodNames
42
+ .map(utils_js_1.getMethodPath)
43
+ .concat(extraMethodPaths?.map(core_1.ccc.hexFrom) ?? []));
44
+ const res = await this.assertExecutor().runScript(this.code, "SSRI.has_methods", [methodPaths]);
45
+ return res.map((res) => core_1.ccc.mol.BoolVec.decode(res));
46
+ }
47
+ /**
48
+ * Retrieves the version of the trait.
49
+ * @returns A promise that resolves to the version number.
50
+ */
51
+ async version() {
52
+ const res = await this.assertExecutor().runScript(this.code, "SSRI.version", []);
53
+ return res.map((res) => core_1.ccc.numFrom(res));
54
+ }
55
+ }
56
+ exports.Trait = Trait;
@@ -0,0 +1,3 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ export declare function getMethodPath(method: string): ccc.Hex;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,CAErD"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMethodPath = getMethodPath;
4
+ const core_1 = require("@ckb-ccc/core");
5
+ function getMethodPath(method) {
6
+ return core_1.ccc.hashCkb(core_1.ccc.bytesFrom(method, "utf8")).slice(0, 18);
7
+ }
package/jest.config.js ADDED
@@ -0,0 +1,5 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: "ts-jest",
4
+ testEnvironment: "node",
5
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@ckb-ccc/ssri",
3
+ "version": "0.1.0",
4
+ "description": "SSRI",
5
+ "author": "Alive24 <xct24@live.com>",
6
+ "license": "MIT",
7
+ "private": false,
8
+ "homepage": "https://github.com/ckb-devrel/ccc",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git://github.com/ckb-devrel/ccc.git"
12
+ },
13
+ "main": "./dist.commonjs/index.js",
14
+ "module": "./dist/index.js",
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/index.js",
18
+ "default": "./dist.commonjs/index.js"
19
+ },
20
+ "./barrel": {
21
+ "import": "./dist/barrel.js",
22
+ "default": "./dist.commonjs/barrel.js"
23
+ }
24
+ },
25
+ "devDependencies": {
26
+ "@eslint/js": "^9.1.1",
27
+ "@types/jest": "^29.5.12",
28
+ "@types/node": "^22.10.2",
29
+ "copyfiles": "^2.4.1",
30
+ "eslint": "^9.1.0",
31
+ "eslint-config-prettier": "^9.1.0",
32
+ "eslint-plugin-prettier": "^5.1.3",
33
+ "jest": "^29.7.0",
34
+ "prettier": "^3.2.5",
35
+ "prettier-plugin-organize-imports": "^3.2.4",
36
+ "rimraf": "^5.0.5",
37
+ "ts-jest": "^29.1.4",
38
+ "typescript": "^5.4.5",
39
+ "typescript-eslint": "^7.7.0"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "dependencies": {
45
+ "@ckb-ccc/core": "1.3.0"
46
+ },
47
+ "scripts": {
48
+ "test": "jest",
49
+ "build": "rimraf ./dist && rimraf ./dist.commonjs && tsc && tsc --project tsconfig.commonjs.json && copyfiles -u 2 misc/basedirs/**/* .",
50
+ "lint": "eslint ./src",
51
+ "format": "prettier --write . && eslint --fix ./src"
52
+ }
53
+ }
package/src/barrel.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./executor.js";
2
+ export * from "./trait.js";
3
+ export * from "./utils.js";
@@ -0,0 +1,184 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { cccA } from "@ckb-ccc/core/advanced";
3
+ import { getMethodPath } from "./utils.js";
4
+
5
+ export type ContextTransaction = {
6
+ script?: ccc.ScriptLike | null;
7
+ cell?: Omit<ccc.CellLike, "outPoint"> | null;
8
+ tx: ccc.TransactionLike;
9
+ };
10
+
11
+ export type ContextCell = {
12
+ script?: ccc.ScriptLike | null;
13
+ cell: Omit<ccc.CellLike, "outPoint">;
14
+ tx?: undefined | null;
15
+ };
16
+
17
+ export type ContextScript = {
18
+ script: ccc.ScriptLike;
19
+ cell?: undefined | null;
20
+ tx?: undefined | null;
21
+ };
22
+
23
+ export type ContextCode =
24
+ | undefined
25
+ | {
26
+ script?: undefined | null;
27
+ cell?: undefined | null;
28
+ tx?: undefined | null;
29
+ };
30
+
31
+ export class ExecutorResponse<T> {
32
+ constructor(
33
+ public readonly res: T,
34
+ public readonly cellDeps: ccc.OutPoint[],
35
+ ) {}
36
+
37
+ static new<T>(res: T, cellDeps?: ccc.OutPointLike[] | null) {
38
+ return new ExecutorResponse(res, cellDeps?.map(ccc.OutPoint.from) ?? []);
39
+ }
40
+
41
+ map<U>(fn: (res: T) => U): ExecutorResponse<U> {
42
+ return new ExecutorResponse(fn(this.res), this.cellDeps);
43
+ }
44
+ }
45
+
46
+ export class ExecutorErrorExecutionFailed extends Error {
47
+ constructor(msg?: string) {
48
+ super(msg);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Represents an SSRI executor.
54
+ */
55
+ export abstract class Executor {
56
+ abstract runScript(
57
+ codeOutPoint: ccc.OutPointLike,
58
+ method: string,
59
+ args: ccc.HexLike[],
60
+ context?: ContextCode | ContextScript | ContextCell | ContextTransaction,
61
+ ): Promise<ExecutorResponse<ccc.Hex>>;
62
+
63
+ async runScriptTry(
64
+ codeOutPoint: ccc.OutPointLike,
65
+ method: string,
66
+ args: ccc.HexLike[],
67
+ context?: ContextCode | ContextScript | ContextCell | ContextTransaction,
68
+ ): Promise<ExecutorResponse<ccc.Hex> | undefined> {
69
+ try {
70
+ return await this.runScript(codeOutPoint, method, args, context);
71
+ } catch (err) {
72
+ if (err instanceof ExecutorErrorExecutionFailed) {
73
+ return undefined;
74
+ }
75
+ throw err;
76
+ }
77
+ }
78
+ }
79
+
80
+ export class ExecutorJsonRpc extends Executor {
81
+ public readonly requestor: ccc.RequestorJsonRpc;
82
+
83
+ /**
84
+ * Creates an instance of SSRI executor through Json RPC.
85
+ * @param {string} [url] - The external server URL.
86
+ */
87
+ constructor(
88
+ url: string,
89
+ config?: ccc.RequestorJsonRpcConfig & { requestor?: ccc.RequestorJsonRpc },
90
+ ) {
91
+ super();
92
+
93
+ this.requestor =
94
+ config?.requestor ??
95
+ new ccc.RequestorJsonRpc(url, config, (errAny) => {
96
+ if (
97
+ typeof errAny !== "object" ||
98
+ errAny === null ||
99
+ !("code" in errAny) ||
100
+ typeof errAny.code !== "number"
101
+ ) {
102
+ throw errAny;
103
+ }
104
+
105
+ if (errAny.code === 1003 || errAny.code === 1004) {
106
+ if ("message" in errAny && typeof errAny.message === "string") {
107
+ throw new ExecutorErrorExecutionFailed(errAny.message);
108
+ }
109
+ throw new ExecutorErrorExecutionFailed();
110
+ }
111
+
112
+ throw errAny;
113
+ });
114
+ }
115
+
116
+ get url() {
117
+ return this.requestor.url;
118
+ }
119
+
120
+ /* Calls a method on the SSRI executor through SSRI Server.
121
+ * @param codeOutPoint - The code OutPoint.
122
+ * @param method - The SSRI method.
123
+ * @param args - The arguments for the method.
124
+ * @param context - The SSRI context for the method.
125
+ * @param context.script - The script level parameters.
126
+ * @param context.cell - The cell level parameters. Take precedence over script.
127
+ * @param context.transaction - The transaction level parameters. Take precedence over cell.
128
+ * @returns The result of the call.
129
+ */
130
+ async runScript(
131
+ codeOutPoint: ccc.OutPointLike,
132
+ method: string,
133
+ args: ccc.HexLike[],
134
+ context?: ContextCode | ContextScript | ContextCell | ContextTransaction,
135
+ ): Promise<ExecutorResponse<ccc.Hex>> {
136
+ const code = ccc.OutPoint.from(codeOutPoint);
137
+ const [rpcMethod, rpcContext] = (() => {
138
+ if (context?.tx) {
139
+ const tx = ccc.Transaction.from(context.tx);
140
+ return [
141
+ "run_script_level_transaction",
142
+ [
143
+ {
144
+ inner: cccA.JsonRpcTransformers.transactionFrom(tx),
145
+ hash: tx.hash(),
146
+ },
147
+ ],
148
+ ];
149
+ }
150
+ if (context?.cell) {
151
+ return [
152
+ "run_script_level_cell",
153
+ [
154
+ {
155
+ cell_output: cccA.JsonRpcTransformers.cellOutputFrom(
156
+ ccc.CellOutput.from(context.cell.cellOutput),
157
+ ),
158
+ hex_data: ccc.hexFrom(context.cell.outputData),
159
+ },
160
+ ],
161
+ ];
162
+ }
163
+ if (context?.script) {
164
+ return [
165
+ "run_script_level_script",
166
+ [cccA.JsonRpcTransformers.scriptFrom(context.script)],
167
+ ];
168
+ }
169
+ return ["run_script_level_code", []];
170
+ })();
171
+
172
+ const { content, cell_deps } = (await this.requestor.request(rpcMethod, [
173
+ code.txHash,
174
+ Number(code.index),
175
+ [getMethodPath(method), ...args.map(ccc.hexFrom)],
176
+ ...rpcContext,
177
+ ])) as { content: ccc.Hex; cell_deps: cccA.JsonRpcOutPoint[] };
178
+
179
+ return ExecutorResponse.new(
180
+ content,
181
+ cell_deps.map(cccA.JsonRpcTransformers.outPointTo),
182
+ );
183
+ }
184
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * as ssri from "./barrel.js";
package/src/trait.ts ADDED
@@ -0,0 +1,83 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+ import { Executor, ExecutorResponse } from "./executor.js";
3
+ import { getMethodPath } from "./utils.js";
4
+
5
+ /**
6
+ * Abstract class representing an SSRI trait. Should be used as the base of all SSRI traits.
7
+ */
8
+ export abstract class Trait {
9
+ public readonly code: ccc.OutPoint;
10
+ public readonly executor?: Executor;
11
+
12
+ /**
13
+ * Creates an instance of SSRI trait.
14
+ * @param code - The cell dependency.
15
+ * @param executor - The SSRI executor instance.
16
+ */
17
+ constructor(code: ccc.OutPointLike, executor?: Executor | null) {
18
+ this.code = ccc.OutPoint.from(code);
19
+ this.executor = executor ?? undefined;
20
+ }
21
+
22
+ assertExecutor() {
23
+ if (!this.executor) {
24
+ throw new Error("SSRI executor is not set");
25
+ }
26
+
27
+ return this.executor;
28
+ }
29
+
30
+ /**
31
+ * Retrieves a list of methods.
32
+ * @param offset - The offset for the methods.
33
+ * @param limit - The limit for the methods.
34
+ * @returns {Promise<Bytes[]>} A promise that resolves to a list of methods.
35
+ */
36
+ async getMethods(
37
+ offset: ccc.NumLike = 0,
38
+ limit: ccc.NumLike = 0,
39
+ ): Promise<ExecutorResponse<ccc.Hex[]>> {
40
+ const res = await this.assertExecutor().runScript(
41
+ this.code,
42
+ "SSRI.get_methods",
43
+ [ccc.numToBytes(offset ?? 0, 8), ccc.numToBytes(limit ?? 0, 8)],
44
+ );
45
+
46
+ return res.map((res) => ccc.mol.Byte8Vec.decode(res));
47
+ }
48
+
49
+ /**
50
+ * Checks if the specified methods exist.
51
+ * @param methodNames - The methods to check.
52
+ * @returns A promise that resolves to an array of booleans indicating if methods exist.
53
+ */
54
+ async hasMethods(
55
+ methodNames: string[],
56
+ extraMethodPaths?: ccc.HexLike[],
57
+ ): Promise<ExecutorResponse<boolean[]>> {
58
+ const methodPaths = ccc.mol.Byte8Vec.encode(
59
+ methodNames
60
+ .map(getMethodPath)
61
+ .concat(extraMethodPaths?.map(ccc.hexFrom) ?? []),
62
+ );
63
+ const res = await this.assertExecutor().runScript(
64
+ this.code,
65
+ "SSRI.has_methods",
66
+ [methodPaths],
67
+ );
68
+ return res.map((res) => ccc.mol.BoolVec.decode(res));
69
+ }
70
+
71
+ /**
72
+ * Retrieves the version of the trait.
73
+ * @returns A promise that resolves to the version number.
74
+ */
75
+ async version(): Promise<ExecutorResponse<ccc.Num>> {
76
+ const res = await this.assertExecutor().runScript(
77
+ this.code,
78
+ "SSRI.version",
79
+ [],
80
+ );
81
+ return res.map((res) => ccc.numFrom(res));
82
+ }
83
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { ccc } from "@ckb-ccc/core";
2
+
3
+ export function getMethodPath(method: string): ccc.Hex {
4
+ return ccc.hashCkb(ccc.bytesFrom(method, "utf8")).slice(0, 18) as ccc.Hex;
5
+ }
package/typedoc.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "entryPoints": ["./src/index.ts"],
4
+ "extends": ["../../typedoc.base.json"],
5
+ "name": "@ckb-ccc ssri"
6
+ }