@ckb-ccc/core 1.9.1 → 1.11.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 +50 -0
- package/dist/ckb/hash.d.ts +18 -0
- package/dist/ckb/hash.d.ts.map +1 -0
- package/dist/ckb/hash.js +19 -0
- package/dist/ckb/index.d.ts +2 -0
- package/dist/ckb/index.d.ts.map +1 -1
- package/dist/ckb/index.js +2 -0
- package/dist/ckb/script.d.ts +12 -0
- package/dist/ckb/script.d.ts.map +1 -1
- package/dist/ckb/script.js +17 -0
- package/dist/ckb/transaction.d.ts +326 -25
- package/dist/ckb/transaction.d.ts.map +1 -1
- package/dist/ckb/transaction.js +354 -79
- package/dist/ckb/transactionErrors.d.ts +15 -0
- package/dist/ckb/transactionErrors.d.ts.map +1 -0
- package/dist/ckb/transactionErrors.js +21 -0
- package/dist/client/cache/cache.d.ts +7 -0
- package/dist/client/cache/cache.d.ts.map +1 -1
- package/dist/client/cache/cache.js +11 -0
- package/dist/client/cache/memory.advanced.d.ts +36 -3
- package/dist/client/cache/memory.advanced.d.ts.map +1 -1
- package/dist/client/cache/memory.advanced.js +53 -25
- package/dist/client/cache/memory.d.ts +10 -1
- package/dist/client/cache/memory.d.ts.map +1 -1
- package/dist/client/cache/memory.js +13 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +6 -9
- package/dist/client/clientTypes.advanced.d.ts +0 -1
- package/dist/client/clientTypes.advanced.d.ts.map +1 -1
- package/dist/client/clientTypes.advanced.js +0 -1
- package/dist/hasher/hasherCkb.d.ts +0 -16
- package/dist/hasher/hasherCkb.d.ts.map +1 -1
- package/dist/hasher/hasherCkb.js +0 -18
- package/dist/molecule/codec.d.ts +30 -10
- package/dist/molecule/codec.d.ts.map +1 -1
- package/dist/molecule/codec.js +46 -13
- package/dist/signer/ckb/signerCkbScriptReadonly.d.ts +18 -6
- package/dist/signer/ckb/signerCkbScriptReadonly.d.ts.map +1 -1
- package/dist/signer/ckb/signerCkbScriptReadonly.js +18 -6
- package/dist/signer/signer/index.d.ts +11 -1
- package/dist/signer/signer/index.d.ts.map +1 -1
- package/dist/signer/signer/index.js +23 -0
- package/dist.commonjs/ckb/hash.d.ts +18 -0
- package/dist.commonjs/ckb/hash.d.ts.map +1 -0
- package/dist.commonjs/ckb/hash.js +22 -0
- package/dist.commonjs/ckb/index.d.ts +2 -0
- package/dist.commonjs/ckb/index.d.ts.map +1 -1
- package/dist.commonjs/ckb/index.js +2 -0
- package/dist.commonjs/ckb/script.d.ts +12 -0
- package/dist.commonjs/ckb/script.d.ts.map +1 -1
- package/dist.commonjs/ckb/script.js +17 -0
- package/dist.commonjs/ckb/transaction.d.ts +326 -25
- package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
- package/dist.commonjs/ckb/transaction.js +353 -78
- package/dist.commonjs/ckb/transactionErrors.d.ts +15 -0
- package/dist.commonjs/ckb/transactionErrors.d.ts.map +1 -0
- package/dist.commonjs/ckb/transactionErrors.js +26 -0
- package/dist.commonjs/client/cache/cache.d.ts +7 -0
- package/dist.commonjs/client/cache/cache.d.ts.map +1 -1
- package/dist.commonjs/client/cache/cache.js +11 -0
- package/dist.commonjs/client/cache/memory.advanced.d.ts +36 -3
- package/dist.commonjs/client/cache/memory.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/cache/memory.advanced.js +54 -26
- package/dist.commonjs/client/cache/memory.d.ts +10 -1
- package/dist.commonjs/client/cache/memory.d.ts.map +1 -1
- package/dist.commonjs/client/cache/memory.js +12 -1
- package/dist.commonjs/client/client.d.ts.map +1 -1
- package/dist.commonjs/client/client.js +5 -8
- package/dist.commonjs/client/clientTypes.advanced.d.ts +0 -1
- package/dist.commonjs/client/clientTypes.advanced.d.ts.map +1 -1
- package/dist.commonjs/client/clientTypes.advanced.js +1 -2
- package/dist.commonjs/hasher/hasherCkb.d.ts +0 -16
- package/dist.commonjs/hasher/hasherCkb.d.ts.map +1 -1
- package/dist.commonjs/hasher/hasherCkb.js +2 -21
- package/dist.commonjs/molecule/codec.d.ts +30 -10
- package/dist.commonjs/molecule/codec.d.ts.map +1 -1
- package/dist.commonjs/molecule/codec.js +46 -13
- package/dist.commonjs/signer/ckb/signerCkbScriptReadonly.d.ts +18 -6
- package/dist.commonjs/signer/ckb/signerCkbScriptReadonly.d.ts.map +1 -1
- package/dist.commonjs/signer/ckb/signerCkbScriptReadonly.js +18 -6
- package/dist.commonjs/signer/signer/index.d.ts +11 -1
- package/dist.commonjs/signer/signer/index.d.ts.map +1 -1
- package/dist.commonjs/signer/signer/index.js +23 -0
- package/package.json +1 -1
- package/prettier.config.mjs +1 -1
- package/src/ckb/hash.ts +28 -0
- package/src/ckb/index.ts +2 -0
- package/src/ckb/script.ts +20 -0
- package/src/ckb/transaction.ts +436 -80
- package/src/ckb/transactionErrors.ts +36 -0
- package/src/client/cache/cache.ts +14 -1
- package/src/client/cache/memory.advanced.ts +57 -30
- package/src/client/cache/memory.ts +18 -1
- package/src/client/client.ts +5 -10
- package/src/client/clientTypes.advanced.ts +0 -1
- package/src/hasher/hasherCkb.ts +0 -26
- package/src/molecule/codec.ts +50 -13
- package/src/signer/ckb/signerCkbScriptReadonly.ts +24 -8
- package/src/signer/signer/index.ts +34 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { fixedPointToString } from "../fixedPoint/index.js";
|
|
2
|
+
import { Num, numFrom, NumLike } from "../num/index.js";
|
|
3
|
+
import { Script, ScriptLike } from "./script.js";
|
|
4
|
+
|
|
5
|
+
export class ErrorTransactionInsufficientCapacity extends Error {
|
|
6
|
+
public readonly amount: Num;
|
|
7
|
+
public readonly isForChange: boolean;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
amountLike: NumLike,
|
|
11
|
+
reason?: {
|
|
12
|
+
isForChange?: boolean;
|
|
13
|
+
},
|
|
14
|
+
) {
|
|
15
|
+
const amount = numFrom(amountLike);
|
|
16
|
+
const isForChange = reason?.isForChange ?? false;
|
|
17
|
+
super(
|
|
18
|
+
`Insufficient CKB, need ${fixedPointToString(amount)} extra CKB${isForChange ? " for the change cell" : ""}`,
|
|
19
|
+
);
|
|
20
|
+
this.amount = amount;
|
|
21
|
+
this.isForChange = isForChange;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ErrorTransactionInsufficientCoin extends Error {
|
|
26
|
+
public readonly amount: Num;
|
|
27
|
+
public readonly type: Script;
|
|
28
|
+
|
|
29
|
+
constructor(amountLike: NumLike, typeLike: ScriptLike) {
|
|
30
|
+
const amount = numFrom(amountLike);
|
|
31
|
+
const type = Script.from(typeLike);
|
|
32
|
+
super(`Insufficient coin, need ${amount} extra coin`);
|
|
33
|
+
this.amount = amount;
|
|
34
|
+
this.type = type;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
TransactionLike,
|
|
7
7
|
} from "../../ckb/index.js";
|
|
8
8
|
import { HexLike } from "../../hex/index.js";
|
|
9
|
-
import { NumLike } from "../../num/index.js";
|
|
9
|
+
import { numFrom, NumLike } from "../../num/index.js";
|
|
10
10
|
import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
|
|
11
11
|
import {
|
|
12
12
|
ClientBlock,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
ClientTransactionResponse,
|
|
17
17
|
ClientTransactionResponseLike,
|
|
18
18
|
} from "../clientTypes.js";
|
|
19
|
+
import { DEFAULT_CONFIRMED_BLOCK_TIME } from "./memory.advanced.js";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* @public
|
|
@@ -185,4 +186,16 @@ export abstract class ClientCache {
|
|
|
185
186
|
async getBlockByNumber(_number: NumLike): Promise<ClientBlock | undefined> {
|
|
186
187
|
return;
|
|
187
188
|
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Checks if a block header is considered confirmed.
|
|
192
|
+
* The default implementation compares the header's timestamp against the current time
|
|
193
|
+
* and a configured confirmation time. Override this method for custom confirmation logic.
|
|
194
|
+
* @param header
|
|
195
|
+
*/
|
|
196
|
+
hasHeaderConfirmed(header: ClientBlockHeader): boolean {
|
|
197
|
+
return (
|
|
198
|
+
numFrom(Date.now()) - header.timestamp >= DEFAULT_CONFIRMED_BLOCK_TIME
|
|
199
|
+
);
|
|
200
|
+
}
|
|
188
201
|
}
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
} from "../clientTypes.advanced.js";
|
|
9
9
|
import { ClientIndexerSearchKey } from "../clientTypes.js";
|
|
10
10
|
|
|
11
|
+
export const DEFAULT_CONFIRMED_BLOCK_TIME = numFrom(1000 * 10 * 50); // 50 blocks * 10s
|
|
12
|
+
|
|
11
13
|
// [isLive, Cell | OutPoint]
|
|
12
14
|
export type CellRecord =
|
|
13
15
|
| [
|
|
@@ -142,49 +144,74 @@ export function filterCell(
|
|
|
142
144
|
return true;
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
/**
|
|
148
|
+
* A Least Recently Used (LRU) cache implemented using a Map.
|
|
149
|
+
*
|
|
150
|
+
* This class extends the built-in Map to provide an LRU cache with a fixed capacity.
|
|
151
|
+
* When the cache is full, the least recently used entry is automatically evicted.
|
|
152
|
+
*
|
|
153
|
+
* @template K The type of the keys in the cache.
|
|
154
|
+
* @template V The type of the values in the cache.
|
|
155
|
+
*/
|
|
145
156
|
export class MapLru<K, V> extends Map<K, V> {
|
|
146
|
-
|
|
147
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Constructs a new MapLru instance.
|
|
159
|
+
*
|
|
160
|
+
* @param capacity The maximum number of entries the cache can hold. Must be a positive integer.
|
|
161
|
+
* @throws {Error} If the capacity is not a positive integer.
|
|
162
|
+
*/
|
|
148
163
|
constructor(private readonly capacity: number) {
|
|
149
164
|
super();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
get(key: K) {
|
|
153
|
-
const val = super.get(key);
|
|
154
|
-
if (val === undefined) {
|
|
155
|
-
return;
|
|
165
|
+
if (!Number.isInteger(capacity) || capacity < 1) {
|
|
166
|
+
throw new Error("Capacity must be a positive integer");
|
|
156
167
|
}
|
|
168
|
+
}
|
|
157
169
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Retrieves a value from the cache.
|
|
172
|
+
*
|
|
173
|
+
* If the key is present in the cache, the value is moved to the most-recently-used position.
|
|
174
|
+
*
|
|
175
|
+
* @param key The key of the value to retrieve.
|
|
176
|
+
* @returns The value associated with the key, or undefined if the key is not present.
|
|
177
|
+
*/
|
|
178
|
+
override get(key: K): V | undefined {
|
|
179
|
+
// Check if the key exists. If not, return undefined.
|
|
180
|
+
if (!super.has(key)) {
|
|
181
|
+
return undefined;
|
|
166
182
|
}
|
|
167
183
|
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
set(key: K, value: V) {
|
|
172
|
-
this.get(key);
|
|
184
|
+
const value = super.get(key) as V;
|
|
173
185
|
|
|
186
|
+
// Move to most-recently-used position
|
|
187
|
+
super.delete(key);
|
|
174
188
|
super.set(key, value);
|
|
175
|
-
|
|
189
|
+
|
|
190
|
+
return value;
|
|
176
191
|
}
|
|
177
192
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Inserts a new value into the cache, or updates an existing value.
|
|
195
|
+
*
|
|
196
|
+
* If the key is already present in the cache, it is first deleted so that the re-insertion
|
|
197
|
+
* moves it to the most-recently-used position.
|
|
198
|
+
* If the cache is over capacity after the insertion, the least recently used entry is evicted.
|
|
199
|
+
*
|
|
200
|
+
* @param key The key of the value to insert or update.
|
|
201
|
+
* @param value The value to associate with the key.
|
|
202
|
+
* @returns This MapLru instance.
|
|
203
|
+
*/
|
|
204
|
+
override set(key: K, value: V): this {
|
|
205
|
+
// Delete and re-insert to move key to the end (most-recently-used)
|
|
206
|
+
super.delete(key);
|
|
207
|
+
super.set(key, value);
|
|
182
208
|
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
|
|
209
|
+
// Evict oldest if over capacity
|
|
210
|
+
if (super.size > this.capacity) {
|
|
211
|
+
const oldestKey = super.keys().next().value!;
|
|
212
|
+
super.delete(oldestKey);
|
|
186
213
|
}
|
|
187
214
|
|
|
188
|
-
return
|
|
215
|
+
return this;
|
|
189
216
|
}
|
|
190
217
|
}
|
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
ClientTransactionResponseLike,
|
|
12
12
|
} from "../clientTypes.js";
|
|
13
13
|
import { ClientCache } from "./cache.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
CellRecord,
|
|
16
|
+
DEFAULT_CONFIRMED_BLOCK_TIME,
|
|
17
|
+
filterCell,
|
|
18
|
+
MapLru,
|
|
19
|
+
} from "./memory.advanced.js";
|
|
15
20
|
|
|
16
21
|
export class ClientCacheMemory extends ClientCache {
|
|
17
22
|
/**
|
|
@@ -37,10 +42,18 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
37
42
|
Pick<ClientBlock, "header"> | ClientBlock
|
|
38
43
|
>;
|
|
39
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @param maxCells - Maximum number of cells to store in the cache. Defaults to 512.
|
|
47
|
+
* @param maxTxs - Maximum number of transactions to store in the cache. Defaults to 256.
|
|
48
|
+
* @param maxBlocks - Maximum number of blocks to store in the cache. Defaults to 128.
|
|
49
|
+
* @param confirmedBlockTime - Time in milliseconds after which a block is considered confirmed.
|
|
50
|
+
* Defaults to DEFAULT_CONFIRMED_BLOCK_TIME (50 blocks * 10s).
|
|
51
|
+
*/
|
|
40
52
|
constructor(
|
|
41
53
|
private readonly maxCells = 512,
|
|
42
54
|
private readonly maxTxs = 256,
|
|
43
55
|
private readonly maxBlocks = 128,
|
|
56
|
+
private readonly confirmedBlockTime = DEFAULT_CONFIRMED_BLOCK_TIME,
|
|
44
57
|
) {
|
|
45
58
|
super();
|
|
46
59
|
|
|
@@ -216,4 +229,8 @@ export class ClientCacheMemory extends ClientCache {
|
|
|
216
229
|
}
|
|
217
230
|
return this.getBlockByHash(hash);
|
|
218
231
|
}
|
|
232
|
+
|
|
233
|
+
hasHeaderConfirmed(header: ClientBlockHeader): boolean {
|
|
234
|
+
return numFrom(Date.now()) - header.timestamp >= this.confirmedBlockTime;
|
|
235
|
+
}
|
|
219
236
|
}
|
package/src/client/client.ts
CHANGED
|
@@ -14,7 +14,6 @@ import { reduceAsync, sleep } from "../utils/index.js";
|
|
|
14
14
|
import { ClientCache } from "./cache/index.js";
|
|
15
15
|
import { ClientCacheMemory } from "./cache/memory.js";
|
|
16
16
|
import {
|
|
17
|
-
CONFIRMED_BLOCK_TIME,
|
|
18
17
|
ClientCollectableSearchKeyLike,
|
|
19
18
|
DEFAULT_MAX_FEE_RATE,
|
|
20
19
|
DEFAULT_MIN_FEE_RATE,
|
|
@@ -38,10 +37,6 @@ import {
|
|
|
38
37
|
} from "./clientTypes.js";
|
|
39
38
|
import { KnownScript } from "./knownScript.js";
|
|
40
39
|
|
|
41
|
-
function hasHeaderConfirmed(header: ClientBlockHeader): boolean {
|
|
42
|
-
return numFrom(Date.now()) - header.timestamp >= CONFIRMED_BLOCK_TIME;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
40
|
/**
|
|
46
41
|
* @public
|
|
47
42
|
*/
|
|
@@ -112,7 +107,7 @@ export abstract class Client {
|
|
|
112
107
|
verbosity,
|
|
113
108
|
withCycles,
|
|
114
109
|
);
|
|
115
|
-
if (res && hasHeaderConfirmed(res.header)) {
|
|
110
|
+
if (res && this.cache.hasHeaderConfirmed(res.header)) {
|
|
116
111
|
await this.cache.recordBlocks(res);
|
|
117
112
|
}
|
|
118
113
|
return res;
|
|
@@ -132,7 +127,7 @@ export abstract class Client {
|
|
|
132
127
|
verbosity,
|
|
133
128
|
withCycles,
|
|
134
129
|
);
|
|
135
|
-
if (res && hasHeaderConfirmed(res.header)) {
|
|
130
|
+
if (res && this.cache.hasHeaderConfirmed(res.header)) {
|
|
136
131
|
await this.cache.recordBlocks(res);
|
|
137
132
|
}
|
|
138
133
|
return res;
|
|
@@ -147,7 +142,7 @@ export abstract class Client {
|
|
|
147
142
|
}
|
|
148
143
|
|
|
149
144
|
const res = await this.getHeaderByNumberNoCache(blockNumber, verbosity);
|
|
150
|
-
if (res && hasHeaderConfirmed(res)) {
|
|
145
|
+
if (res && this.cache.hasHeaderConfirmed(res)) {
|
|
151
146
|
await this.cache.recordHeaders(res);
|
|
152
147
|
}
|
|
153
148
|
return res;
|
|
@@ -162,7 +157,7 @@ export abstract class Client {
|
|
|
162
157
|
}
|
|
163
158
|
|
|
164
159
|
const res = await this.getHeaderByHashNoCache(blockHash, verbosity);
|
|
165
|
-
if (res && hasHeaderConfirmed(res)) {
|
|
160
|
+
if (res && this.cache.hasHeaderConfirmed(res)) {
|
|
166
161
|
await this.cache.recordHeaders(res);
|
|
167
162
|
}
|
|
168
163
|
return res;
|
|
@@ -636,7 +631,7 @@ export abstract class Client {
|
|
|
636
631
|
const tx = await this.cache.getTransactionResponse(txHash);
|
|
637
632
|
if (tx?.blockHash) {
|
|
638
633
|
const header = await this.getHeaderByHash(tx.blockHash);
|
|
639
|
-
if (header && hasHeaderConfirmed(header)) {
|
|
634
|
+
if (header && this.cache.hasHeaderConfirmed(header)) {
|
|
640
635
|
return {
|
|
641
636
|
transaction: tx,
|
|
642
637
|
header,
|
|
@@ -2,7 +2,6 @@ import { ScriptLike } from "../ckb/index.js";
|
|
|
2
2
|
import { HexLike } from "../hex/index.js";
|
|
3
3
|
import { Num, numFrom, NumLike } from "../num/index.js";
|
|
4
4
|
|
|
5
|
-
export const CONFIRMED_BLOCK_TIME = numFrom(1000 * 10 * 50); // 50 blocks * 10s
|
|
6
5
|
export const DEFAULT_MAX_FEE_RATE = numFrom(10000000);
|
|
7
6
|
export const DEFAULT_MIN_FEE_RATE = numFrom(1000);
|
|
8
7
|
|
package/src/hasher/hasherCkb.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { blake2b } from "@noble/hashes/blake2b";
|
|
2
2
|
import { BytesLike, bytesFrom } from "../bytes/index.js";
|
|
3
|
-
import { CellInput, CellInputLike } from "../ckb/index.js";
|
|
4
3
|
import { Hex, hexFrom } from "../hex/index.js";
|
|
5
|
-
import { NumLike, numLeToBytes } from "../num/index.js";
|
|
6
4
|
import { CKB_BLAKE2B_PERSONAL } from "./advanced.js";
|
|
7
5
|
import { Hasher } from "./hasher.js";
|
|
8
6
|
|
|
@@ -81,27 +79,3 @@ export function hashCkb(...data: BytesLike[]): Hex {
|
|
|
81
79
|
data.forEach((d) => hasher.update(d));
|
|
82
80
|
return hasher.digest();
|
|
83
81
|
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Computes the Type ID hash of the given data.
|
|
87
|
-
* @public
|
|
88
|
-
*
|
|
89
|
-
* @param cellInputLike - The first cell input of the transaction.
|
|
90
|
-
* @param outputIndex - The output index of the Type ID cell.
|
|
91
|
-
* @returns The hexadecimal string representation of the hash.
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```typescript
|
|
95
|
-
* const hash = hashTypeId(cellInput, outputIndex); // Outputs something like "0x..."
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
98
|
-
|
|
99
|
-
export function hashTypeId(
|
|
100
|
-
cellInputLike: CellInputLike,
|
|
101
|
-
outputIndex: NumLike,
|
|
102
|
-
): Hex {
|
|
103
|
-
return hashCkb(
|
|
104
|
-
CellInput.from(cellInputLike).toBytes(),
|
|
105
|
-
numLeToBytes(outputIndex, 8),
|
|
106
|
-
);
|
|
107
|
-
}
|
package/src/molecule/codec.ts
CHANGED
|
@@ -459,34 +459,71 @@ type UnionDecoded<
|
|
|
459
459
|
: never;
|
|
460
460
|
|
|
461
461
|
/**
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
*
|
|
462
|
+
* Constructs a union codec that can serialize and deserialize values tagged with a type identifier.
|
|
463
|
+
*
|
|
464
|
+
* If all variants have the same fixed size, the resulting union codec is fixed-size (header + payload).
|
|
465
|
+
* Otherwise, it falls back to a dynamic-size codec.
|
|
466
|
+
*
|
|
467
|
+
* Serialization format:
|
|
468
|
+
* 1. 4-byte little-endian unsigned integer for the variant index.
|
|
469
|
+
* 2. Encoded bytes of the selected variant.
|
|
470
|
+
*
|
|
471
|
+
* @typeParam T
|
|
472
|
+
* A record mapping variant names to codecs.
|
|
473
|
+
* @param codecLayout
|
|
474
|
+
* An object whose keys are variant names and values are codecs for each variant.
|
|
475
|
+
* @param fields
|
|
476
|
+
* Optional mapping from variant names to custom numeric IDs. If omitted, the index
|
|
477
|
+
* of each variant in `codecLayout` is used as its ID.
|
|
478
|
+
*
|
|
479
|
+
*
|
|
468
480
|
* @example
|
|
469
|
-
* // without custom
|
|
470
|
-
* union({ cafe: Uint8, bee:
|
|
471
|
-
*
|
|
472
|
-
*
|
|
481
|
+
* // Dynamic union without custom numeric IDs
|
|
482
|
+
* union({ cafe: Uint8, bee: Uint16 })
|
|
483
|
+
*
|
|
484
|
+
* // Dynamic union with custom numeric IDs
|
|
485
|
+
* union({ cafe: Uint8, bee: Uint16 }, { cafe: 0xcafe, bee: 0xbee })
|
|
486
|
+
*
|
|
487
|
+
* // Fixed-size union without custom numeric IDs
|
|
488
|
+
* const PaddedUint8 = struct({ data : u8, padding : u8 })
|
|
489
|
+
* union({ cafe: PaddedUint8, bee: Uint16 });
|
|
490
|
+
*
|
|
491
|
+
* // Fixed-size union with custom numeric IDs
|
|
492
|
+
* union({ cafe: PaddedUint8, bee: Uint16 }, { cafe: 0xcafe, bee: 0xbee })
|
|
473
493
|
*/
|
|
494
|
+
|
|
474
495
|
export function union<T extends Record<string, CodecLike<any, any>>>(
|
|
475
496
|
codecLayout: T,
|
|
476
497
|
fields?: Record<keyof T, number | undefined | null>,
|
|
477
498
|
): Codec<UnionEncodable<T>, UnionDecoded<T>> {
|
|
478
|
-
const
|
|
499
|
+
const entries = Object.entries(codecLayout);
|
|
500
|
+
|
|
501
|
+
// Determine if all variants have a fixed and equal byteLength.
|
|
502
|
+
let byteLength: number | undefined;
|
|
503
|
+
if (entries.length > 0) {
|
|
504
|
+
const firstLen = entries[0][1].byteLength;
|
|
505
|
+
if (
|
|
506
|
+
firstLen !== undefined &&
|
|
507
|
+
entries.every(([, { byteLength: len }]) => len === firstLen)
|
|
508
|
+
) {
|
|
509
|
+
// Add 4 bytes for the type header
|
|
510
|
+
byteLength = firstLen + 4;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
479
513
|
|
|
480
514
|
return Codec.from({
|
|
515
|
+
byteLength,
|
|
481
516
|
encode({ type, value }) {
|
|
482
517
|
const typeStr = type.toString();
|
|
483
518
|
const codec = codecLayout[typeStr];
|
|
484
519
|
if (!codec) {
|
|
485
520
|
throw new Error(
|
|
486
|
-
`union: invalid type, expected ${
|
|
521
|
+
`union: invalid type, expected ${entries.map((e) => e[0]).toString()}, but got ${typeStr}`,
|
|
487
522
|
);
|
|
488
523
|
}
|
|
489
|
-
const fieldId = fields
|
|
524
|
+
const fieldId = fields
|
|
525
|
+
? (fields[typeStr] ?? -1)
|
|
526
|
+
: entries.findIndex((e) => e[0] === typeStr);
|
|
490
527
|
if (fieldId < 0) {
|
|
491
528
|
throw new Error(`union: invalid field id ${fieldId} of ${typeStr}`);
|
|
492
529
|
}
|
|
@@ -4,31 +4,46 @@ import { Client } from "../../client/index.js";
|
|
|
4
4
|
import { Signer, SignerSignType, SignerType } from "../signer/index.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* A
|
|
8
|
-
* This
|
|
7
|
+
* A read-only signer for a CKB script. It can be used to get addresses,
|
|
8
|
+
* but not to sign transactions. This is useful when you want to watch an address
|
|
9
|
+
* without having the private key.
|
|
10
|
+
*
|
|
9
11
|
* @public
|
|
10
12
|
*/
|
|
11
13
|
export class SignerCkbScriptReadonly extends Signer {
|
|
14
|
+
/**
|
|
15
|
+
* The type of the signer.
|
|
16
|
+
*/
|
|
12
17
|
get type(): SignerType {
|
|
13
18
|
return SignerType.CKB;
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* The sign type of the signer.
|
|
23
|
+
* As this is a read-only signer, the sign type is {@link SignerSignType.Unknown}.
|
|
24
|
+
*/
|
|
16
25
|
get signType(): SignerSignType {
|
|
17
26
|
return SignerSignType.Unknown;
|
|
18
27
|
}
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The scripts associated with the signer.
|
|
31
|
+
*/
|
|
32
|
+
public readonly scripts: Script[];
|
|
21
33
|
|
|
22
34
|
/**
|
|
23
35
|
* Creates an instance of SignerCkbScriptReadonly.
|
|
24
36
|
*
|
|
25
37
|
* @param client - The client instance used for communication.
|
|
26
|
-
* @param
|
|
38
|
+
* @param scripts - The scripts associated with the signer. Can be a single script, an array of scripts, or multiple script arguments.
|
|
27
39
|
*/
|
|
28
|
-
constructor(client: Client,
|
|
40
|
+
constructor(client: Client, ...scripts: (ScriptLike | ScriptLike[])[]) {
|
|
29
41
|
super(client);
|
|
30
42
|
|
|
31
|
-
this.
|
|
43
|
+
this.scripts = scripts.flat().map(Script.from);
|
|
44
|
+
if (this.scripts.length === 0) {
|
|
45
|
+
throw new Error("SignerCkbScriptReadonly requires at least one script.");
|
|
46
|
+
}
|
|
32
47
|
}
|
|
33
48
|
|
|
34
49
|
/**
|
|
@@ -71,8 +86,9 @@ export class SignerCkbScriptReadonly extends Signer {
|
|
|
71
86
|
* const addressObjs = await signer.getAddressObjs(); // Outputs the array of Address objects
|
|
72
87
|
* ```
|
|
73
88
|
*/
|
|
74
|
-
|
|
75
89
|
async getAddressObjs(): Promise<Address[]> {
|
|
76
|
-
return
|
|
90
|
+
return this.scripts.map((script) =>
|
|
91
|
+
Address.fromScript(script, this.client),
|
|
92
|
+
);
|
|
77
93
|
}
|
|
78
94
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
Client,
|
|
7
7
|
ClientFindTransactionsGroupedResponse,
|
|
8
8
|
ClientFindTransactionsResponse,
|
|
9
|
+
ClientIndexerSearchKeyFilterLike,
|
|
9
10
|
} from "../../client/index.js";
|
|
10
11
|
import { Hex } from "../../hex/index.js";
|
|
11
12
|
import { Num } from "../../num/index.js";
|
|
@@ -239,6 +240,39 @@ export abstract class Signer {
|
|
|
239
240
|
);
|
|
240
241
|
}
|
|
241
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Find cells of this signer
|
|
245
|
+
*
|
|
246
|
+
* @param filter - The filter for the search key.
|
|
247
|
+
* @param withData - Whether to include cell data in the response.
|
|
248
|
+
* @param order - The order of the returned cells, can be "asc" or "desc".
|
|
249
|
+
* @param limit - The maximum number of cells for every querying chunk.
|
|
250
|
+
* @returns A async generator that yields all matching cells
|
|
251
|
+
*/
|
|
252
|
+
async *findCellsOnChain(
|
|
253
|
+
filter: ClientIndexerSearchKeyFilterLike,
|
|
254
|
+
withData?: boolean | null,
|
|
255
|
+
order?: "asc" | "desc",
|
|
256
|
+
limit?: number,
|
|
257
|
+
): AsyncGenerator<Cell> {
|
|
258
|
+
const scripts = await this.getAddressObjs();
|
|
259
|
+
for (const { script } of scripts) {
|
|
260
|
+
for await (const cell of this.client.findCellsOnChain(
|
|
261
|
+
{
|
|
262
|
+
script,
|
|
263
|
+
scriptType: "lock",
|
|
264
|
+
filter,
|
|
265
|
+
scriptSearchMode: "exact",
|
|
266
|
+
withData,
|
|
267
|
+
},
|
|
268
|
+
order,
|
|
269
|
+
limit,
|
|
270
|
+
)) {
|
|
271
|
+
yield cell;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
242
276
|
/**
|
|
243
277
|
* Find cells of this signer
|
|
244
278
|
*
|