@ickb/sdk 1000.0.82 → 9000.0.1
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/README.md +81 -32
- package/dist/constants.d.ts +13 -22
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +80 -76
- package/dist/constants.js.map +1 -1
- package/dist/conversion/estimate.d.ts +39 -0
- package/dist/conversion/estimate.d.ts.map +1 -0
- package/dist/conversion/estimate.js +117 -0
- package/dist/conversion/estimate.js.map +1 -0
- package/dist/conversion/maturity.d.ts +15 -0
- package/dist/conversion/maturity.d.ts.map +1 -0
- package/dist/conversion/maturity.js +112 -0
- package/dist/conversion/maturity.js.map +1 -0
- package/dist/conversion/plans.d.ts +20 -0
- package/dist/conversion/plans.d.ts.map +1 -0
- package/dist/conversion/plans.js +106 -0
- package/dist/conversion/plans.js.map +1 -0
- package/dist/conversion/projection.d.ts +22 -0
- package/dist/conversion/projection.d.ts.map +1 -0
- package/dist/conversion/projection.js +91 -0
- package/dist/conversion/projection.js.map +1 -0
- package/dist/conversion/types.d.ts +252 -0
- package/dist/conversion/types.d.ts.map +1 -0
- package/dist/conversion/types.js +2 -0
- package/dist/conversion/types.js.map +1 -0
- package/dist/conversion/withdrawal_ring.d.ts +36 -0
- package/dist/conversion/withdrawal_ring.d.ts.map +1 -0
- package/dist/conversion/withdrawal_ring.js +87 -0
- package/dist/conversion/withdrawal_ring.js.map +1 -0
- package/dist/dao.d.ts +86 -0
- package/dist/dao.d.ts.map +1 -0
- package/dist/dao.js +113 -0
- package/dist/dao.js.map +1 -0
- package/dist/index.d.ts +51 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/dist/logic.d.ts +85 -0
- package/dist/logic.d.ts.map +1 -0
- package/dist/logic.js +184 -0
- package/dist/logic.js.map +1 -0
- package/dist/order/cells.d.ts +207 -0
- package/dist/order/cells.d.ts.map +1 -0
- package/dist/order/cells.js +427 -0
- package/dist/order/cells.js.map +1 -0
- package/dist/order/conversion.d.ts +43 -0
- package/dist/order/conversion.d.ts.map +1 -0
- package/dist/order/conversion.js +123 -0
- package/dist/order/conversion.js.map +1 -0
- package/dist/order/fee.d.ts +9 -0
- package/dist/order/fee.d.ts.map +1 -0
- package/dist/order/fee.js +24 -0
- package/dist/order/fee.js.map +1 -0
- package/dist/order/fill.d.ts +36 -0
- package/dist/order/fill.d.ts.map +1 -0
- package/dist/order/fill.js +53 -0
- package/dist/order/fill.js.map +1 -0
- package/dist/order/info.d.ts +62 -0
- package/dist/order/info.d.ts.map +1 -0
- package/dist/order/info.js +99 -0
- package/dist/order/info.js.map +1 -0
- package/dist/order/master.d.ts +49 -0
- package/dist/order/master.d.ts.map +1 -0
- package/dist/order/master.js +27 -0
- package/dist/order/master.js.map +1 -0
- package/dist/order/matcher.d.ts +43 -0
- package/dist/order/matcher.d.ts.map +1 -0
- package/dist/order/matcher.js +123 -0
- package/dist/order/matcher.js.map +1 -0
- package/dist/order/order.d.ts +59 -0
- package/dist/order/order.d.ts.map +1 -0
- package/dist/order/order.js +239 -0
- package/dist/order/order.js.map +1 -0
- package/dist/order/order_data.d.ts +51 -0
- package/dist/order/order_data.d.ts.map +1 -0
- package/dist/order/order_data.js +64 -0
- package/dist/order/order_data.js.map +1 -0
- package/dist/order/ratio.d.ts +42 -0
- package/dist/order/ratio.d.ts.map +1 -0
- package/dist/order/ratio.js +82 -0
- package/dist/order/ratio.js.map +1 -0
- package/dist/order/relative.d.ts +43 -0
- package/dist/order/relative.d.ts.map +1 -0
- package/dist/order/relative.js +54 -0
- package/dist/order/relative.js.map +1 -0
- package/dist/owned_owner.d.ts +113 -0
- package/dist/owned_owner.d.ts.map +1 -0
- package/dist/owned_owner.js +280 -0
- package/dist/owned_owner.js.map +1 -0
- package/dist/sdk.d.ts +71 -42
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +388 -209
- package/dist/sdk.js.map +1 -1
- package/dist/send/sign_and_send_transaction.d.ts +46 -0
- package/dist/send/sign_and_send_transaction.d.ts.map +1 -0
- package/dist/send/sign_and_send_transaction.js +101 -0
- package/dist/send/sign_and_send_transaction.js.map +1 -0
- package/dist/send/wait_transaction.d.ts +41 -0
- package/dist/send/wait_transaction.d.ts.map +1 -0
- package/dist/send/wait_transaction.js +204 -0
- package/dist/send/wait_transaction.js.map +1 -0
- package/dist/udt.d.ts +123 -0
- package/dist/udt.d.ts.map +1 -0
- package/dist/udt.js +244 -0
- package/dist/udt.js.map +1 -0
- package/dist/utils/chain.d.ts +38 -0
- package/dist/utils/chain.d.ts.map +1 -0
- package/dist/utils/chain.js +20 -0
- package/dist/utils/chain.js.map +1 -0
- package/dist/utils/codec.d.ts +19 -0
- package/dist/utils/codec.d.ts.map +1 -0
- package/dist/utils/codec.js +66 -0
- package/dist/utils/codec.js.map +1 -0
- package/dist/utils/transaction_header.d.ts +17 -0
- package/dist/utils/transaction_header.d.ts.map +1 -0
- package/dist/utils/transaction_header.js +44 -0
- package/dist/utils/transaction_header.js.map +1 -0
- package/dist/utils/utils.d.ts +126 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +151 -0
- package/dist/utils/utils.js.map +1 -0
- package/package.json +19 -26
- package/src/constants.ts +84 -181
- package/src/conversion/estimate.ts +157 -0
- package/src/conversion/maturity.ts +159 -0
- package/src/conversion/plans.ts +144 -0
- package/src/conversion/projection.ts +128 -0
- package/src/conversion/types.ts +287 -0
- package/src/conversion/withdrawal_ring.ts +126 -0
- package/src/dao.ts +172 -0
- package/src/index.ts +89 -3
- package/src/logic.ts +295 -0
- package/src/order/cells.ts +520 -0
- package/src/order/conversion.ts +173 -0
- package/src/order/fee.ts +30 -0
- package/src/order/fill.ts +83 -0
- package/src/order/info.ts +178 -0
- package/src/order/master.ts +42 -0
- package/src/order/matcher.ts +191 -0
- package/src/order/order.ts +302 -0
- package/src/order/order_data.ts +128 -0
- package/src/order/ratio.ts +144 -0
- package/src/order/relative.ts +106 -0
- package/src/owned_owner.ts +394 -0
- package/src/sdk.ts +555 -440
- package/src/send/sign_and_send_transaction.ts +120 -0
- package/src/send/wait_transaction.ts +271 -0
- package/src/udt.ts +317 -0
- package/src/utils/chain.ts +43 -0
- package/src/utils/codec.ts +74 -0
- package/src/utils/transaction_header.ts +66 -0
- package/src/utils/utils.ts +237 -0
- package/dist/codec.d.ts +0 -3
- package/dist/codec.d.ts.map +0 -1
- package/dist/codec.js +0 -58
- package/dist/codec.js.map +0 -1
- package/src/codec.ts +0 -138
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ccc } from "@ckb-ccc/core";
|
|
2
|
+
|
|
3
|
+
/** Public CKB networks supported by Stack consumers. */
|
|
4
|
+
export type SupportedChain = "mainnet" | "testnet";
|
|
5
|
+
|
|
6
|
+
/** Canonical public identity of one supported CKB network. */
|
|
7
|
+
export interface ChainIdentity {
|
|
8
|
+
/** Stack network selector represented by this identity. */
|
|
9
|
+
readonly chain: SupportedChain;
|
|
10
|
+
/** CKB specification network name. */
|
|
11
|
+
readonly networkName: string;
|
|
12
|
+
/** Canonical genesis block hash. */
|
|
13
|
+
readonly genesisHash: ccc.Hex;
|
|
14
|
+
/** Canonical genesis message used by the CKB specification. */
|
|
15
|
+
readonly genesisMessage: string;
|
|
16
|
+
/** Public specification location from which the genesis identity was derived. */
|
|
17
|
+
readonly genesisSource: string;
|
|
18
|
+
/** Canonical address prefix for this network. */
|
|
19
|
+
readonly addressPrefix: "ckb" | "ckt";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The immutable canonical identity of each supported chain. */
|
|
23
|
+
export const chainIdentities = Object.freeze({
|
|
24
|
+
mainnet: Object.freeze({
|
|
25
|
+
chain: "mainnet",
|
|
26
|
+
networkName: "ckb",
|
|
27
|
+
genesisHash: "0x92b197aa1fba0f63633922c61c92375c9c074a93e85963554f5499fe1450d0e5",
|
|
28
|
+
genesisMessage:
|
|
29
|
+
"lina 0x18e020f6b1237a3d06b75121f25a7efa0550e4b3f44f974822f471902424c104",
|
|
30
|
+
genesisSource:
|
|
31
|
+
"https://raw.githubusercontent.com/nervosnetwork/ckb/develop/resource/specs/mainnet.toml",
|
|
32
|
+
addressPrefix: "ckb",
|
|
33
|
+
}),
|
|
34
|
+
testnet: Object.freeze({
|
|
35
|
+
chain: "testnet",
|
|
36
|
+
networkName: "ckb_testnet",
|
|
37
|
+
genesisHash: "0x10639e0895502b5688a6be8cf69460d76541bfa4821629d86d62ba0aae3f9606",
|
|
38
|
+
genesisMessage: "aggron-v4",
|
|
39
|
+
genesisSource:
|
|
40
|
+
"https://raw.githubusercontent.com/nervosnetwork/ckb/develop/resource/specs/testnet.toml",
|
|
41
|
+
addressPrefix: "ckt",
|
|
42
|
+
}),
|
|
43
|
+
} as const satisfies Record<SupportedChain, ChainIdentity>);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ccc } from "@ckb-ccc/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Codec for little-endian 32-bit signed integers.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* The encoder rejects numeric values outside the signed 32-bit range before
|
|
8
|
+
* writing bytes. Decoding reads a signed little-endian integer from the bytes
|
|
9
|
+
* after CCC byte normalization.
|
|
10
|
+
*/
|
|
11
|
+
export const CheckedInt32LE = ccc.Codec.from<ccc.NumLike, number>({
|
|
12
|
+
byteLength: 4,
|
|
13
|
+
encode: (numLike) => {
|
|
14
|
+
const normalized = normalizeInteger(numLike);
|
|
15
|
+
if (normalized < -2147483648n || normalized > 2147483647n) {
|
|
16
|
+
throw new Error("NumLike out of int32 bounds");
|
|
17
|
+
}
|
|
18
|
+
const num = Number(normalized);
|
|
19
|
+
const encoded = new Uint8Array(4);
|
|
20
|
+
new DataView(encoded.buffer).setInt32(0, num, true);
|
|
21
|
+
return encoded;
|
|
22
|
+
},
|
|
23
|
+
decode: (bytesLike) => {
|
|
24
|
+
const bytes = ccc.bytesFrom(bytesLike);
|
|
25
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getInt32(
|
|
26
|
+
0,
|
|
27
|
+
true,
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** Checked codec for 8-bit unsigned integers. */
|
|
33
|
+
export const CheckedUint8 = checkedUintLE(1);
|
|
34
|
+
|
|
35
|
+
/** Checked codec for little-endian 32-bit unsigned integers. */
|
|
36
|
+
export const CheckedUint32LE = checkedUintLE(4);
|
|
37
|
+
|
|
38
|
+
/** Checked codec for little-endian 64-bit unsigned integers. */
|
|
39
|
+
export const CheckedUint64LE = checkedUintLE(8);
|
|
40
|
+
|
|
41
|
+
/** Checked codec for little-endian 128-bit unsigned integers. */
|
|
42
|
+
export const CheckedUint128LE = checkedUintLE(16);
|
|
43
|
+
|
|
44
|
+
function checkedUintLE(byteLength: number): ccc.Codec<ccc.NumLike, ccc.Num> {
|
|
45
|
+
const bitLength = BigInt(byteLength * 8);
|
|
46
|
+
const max = (1n << bitLength) - 1n;
|
|
47
|
+
return ccc.Codec.from({
|
|
48
|
+
byteLength,
|
|
49
|
+
encode: (numLike: ccc.NumLike) => {
|
|
50
|
+
const num = normalizeInteger(numLike);
|
|
51
|
+
if (num < 0n || num > max) {
|
|
52
|
+
throw new Error(`NumLike out of uint${String(bitLength)} bounds`);
|
|
53
|
+
}
|
|
54
|
+
return ccc.numLeToBytes(num, byteLength);
|
|
55
|
+
},
|
|
56
|
+
decode: ccc.numFromBytes,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeInteger(numLike: ccc.NumLike): ccc.Num {
|
|
61
|
+
if (typeof numLike === "number") {
|
|
62
|
+
if (!Number.isFinite(numLike) || !Number.isInteger(numLike)) {
|
|
63
|
+
throw new TypeError("NumLike must be a finite integer");
|
|
64
|
+
}
|
|
65
|
+
if (!Number.isSafeInteger(numLike)) {
|
|
66
|
+
throw new TypeError("NumLike number must be a safe integer");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return ccc.numFrom(numLike);
|
|
71
|
+
} catch {
|
|
72
|
+
throw new TypeError("NumLike must be a finite integer");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ccc } from "@ckb-ccc/core";
|
|
2
|
+
import { jsonRpcRequestor, rawTransactionStatus } from "./utils.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The header of the block that committed `txHash`, without the transaction body, which no
|
|
6
|
+
* caller reads. A client with a JSON-RPC requestor, the connector's composed client
|
|
7
|
+
* included, asks the node for the status only (verbosity 1) and then the header by number,
|
|
8
|
+
* which CCC caches once confirmed; a cold read of the pool then moves a few bytes per
|
|
9
|
+
* deposit instead of every deposit transaction. Any other client keeps the typed lookup.
|
|
10
|
+
*/
|
|
11
|
+
export async function getTransactionHeader(
|
|
12
|
+
client: ccc.Client,
|
|
13
|
+
txHash: ccc.Hex,
|
|
14
|
+
): Promise<ccc.ClientBlockHeader | undefined> {
|
|
15
|
+
const requestor = jsonRpcRequestor(client);
|
|
16
|
+
if (requestor === undefined) {
|
|
17
|
+
return (await client.getTransactionWithHeader(txHash))?.header;
|
|
18
|
+
}
|
|
19
|
+
const { blockNumber } = rawTransactionStatus(
|
|
20
|
+
await requestor.request("get_transaction", [txHash, "0x1"]),
|
|
21
|
+
);
|
|
22
|
+
return blockNumber === undefined ? undefined : client.getHeaderByNumber(blockNumber);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The committing headers of a batch of transactions, each hash read once. A batch is one
|
|
27
|
+
* coherent read: the cells came from one scan, so every header must exist.
|
|
28
|
+
*/
|
|
29
|
+
export async function transactionHeaders(
|
|
30
|
+
client: ccc.Client,
|
|
31
|
+
txHashes: Iterable<ccc.Hex>,
|
|
32
|
+
): Promise<Map<ccc.Hex, ccc.ClientBlockHeader>> {
|
|
33
|
+
const distinct = [...new Set(txHashes)];
|
|
34
|
+
const headers = await Promise.all(
|
|
35
|
+
distinct.map(async (txHash) => getTransactionHeader(client, txHash)),
|
|
36
|
+
);
|
|
37
|
+
return new Map(
|
|
38
|
+
distinct.map((txHash, index) => {
|
|
39
|
+
const header = headers[index];
|
|
40
|
+
if (header === undefined) {
|
|
41
|
+
throw new Error(`Header not found for txHash ${txHash}`);
|
|
42
|
+
}
|
|
43
|
+
return [txHash, header];
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The headers of a batch of block numbers, each read once; every block must exist. */
|
|
49
|
+
export async function headersByNumber(
|
|
50
|
+
client: ccc.Client,
|
|
51
|
+
blockNumbers: Iterable<ccc.Num>,
|
|
52
|
+
): Promise<Map<ccc.Num, ccc.ClientBlockHeader>> {
|
|
53
|
+
const distinct = [...new Set(blockNumbers)];
|
|
54
|
+
const headers = await Promise.all(
|
|
55
|
+
distinct.map(async (blockNumber) => client.getHeaderByNumber(blockNumber)),
|
|
56
|
+
);
|
|
57
|
+
return new Map(
|
|
58
|
+
distinct.map((blockNumber, index) => {
|
|
59
|
+
const header = headers[index];
|
|
60
|
+
if (header === undefined) {
|
|
61
|
+
throw new Error(`Header not found for block number ${String(blockNumber)}`);
|
|
62
|
+
}
|
|
63
|
+
return [blockNumber, header];
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { ccc } from "@ckb-ccc/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The default page size used when querying cells from the chain.
|
|
5
|
+
*
|
|
6
|
+
* This page size is aligned with Nervos CKB's pull request #4576
|
|
7
|
+
* (https://github.com/nervosnetwork/ckb/pull/4576) to avoid excessive paging.
|
|
8
|
+
*/
|
|
9
|
+
export const defaultCellPageSize = 400;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reads every committed cell matching the key, page by page, without touching
|
|
13
|
+
* CCC's cell cache. The scan ends on the first short page.
|
|
14
|
+
*
|
|
15
|
+
* @remarks A full page must advance the cursor; otherwise the read throws so a faulty
|
|
16
|
+
* endpoint in the app's public node pool cannot keep the scan looping forever.
|
|
17
|
+
* The cursor continues ordering, not a coherent snapshot. There is no aggregate budget:
|
|
18
|
+
* a large book costs a slower read rather than a partial result.
|
|
19
|
+
*/
|
|
20
|
+
export async function findCells(
|
|
21
|
+
client: ccc.Client,
|
|
22
|
+
keyLike: ccc.ClientIndexerSearchKeyLike,
|
|
23
|
+
): Promise<ccc.Cell[]> {
|
|
24
|
+
const key = ccc.ClientIndexerSearchKey.from(keyLike);
|
|
25
|
+
const cells: ccc.Cell[] = [];
|
|
26
|
+
let after: string | undefined;
|
|
27
|
+
for (;;) {
|
|
28
|
+
const page = await client.findCellsPagedNoCache(
|
|
29
|
+
key,
|
|
30
|
+
"asc",
|
|
31
|
+
defaultCellPageSize,
|
|
32
|
+
after,
|
|
33
|
+
);
|
|
34
|
+
cells.push(...page.cells);
|
|
35
|
+
if (page.cells.length < defaultCellPageSize) {
|
|
36
|
+
return cells;
|
|
37
|
+
}
|
|
38
|
+
if (page.lastCursor === after) {
|
|
39
|
+
throw new Error("Cell scan cursor did not advance");
|
|
40
|
+
}
|
|
41
|
+
after = page.lastCursor;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Local transaction inclusion metadata.
|
|
47
|
+
*/
|
|
48
|
+
export interface TransactionHeader {
|
|
49
|
+
/**
|
|
50
|
+
* The block header used for inclusion-dependent calculations.
|
|
51
|
+
*/
|
|
52
|
+
header: ccc.ClientBlockHeader;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The transaction hash when the caller has resolved it for the header.
|
|
56
|
+
*/
|
|
57
|
+
txHash?: ccc.Hex;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* CKB and UDT amounts carried by a cell, order, or planned value.
|
|
62
|
+
*/
|
|
63
|
+
export interface ValueComponents {
|
|
64
|
+
/** CKB-side amount as a `ccc.FixedPoint`. */
|
|
65
|
+
ckbValue: ccc.FixedPoint;
|
|
66
|
+
|
|
67
|
+
/** UDT-side amount as a `ccc.FixedPoint`. */
|
|
68
|
+
udtValue: ccc.FixedPoint;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Integer scale pair for comparing or converting CKB-side and UDT-side values.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* CKB-to-UDT conversions multiply by `ckbScale` and divide by `udtScale`.
|
|
76
|
+
* UDT-to-CKB conversions swap the scales. Callers choose the rounding policy.
|
|
77
|
+
*/
|
|
78
|
+
export interface ExchangeRatio {
|
|
79
|
+
/** Numerator scale for CKB-side values. */
|
|
80
|
+
ckbScale: ccc.Num;
|
|
81
|
+
|
|
82
|
+
/** Numerator scale for UDT-side values. */
|
|
83
|
+
udtScale: ccc.Num;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Script plus cell dependencies needed to build transactions that use it.
|
|
88
|
+
*/
|
|
89
|
+
export interface ScriptDeps {
|
|
90
|
+
/**
|
|
91
|
+
* The lock or type script.
|
|
92
|
+
*/
|
|
93
|
+
script: ccc.Script;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Cell dependencies required to resolve the script code.
|
|
97
|
+
*/
|
|
98
|
+
cellDeps: ccc.CellDep[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* True when a cell has no type script and no data payload.
|
|
103
|
+
*
|
|
104
|
+
* @remarks
|
|
105
|
+
* This is a structural filter for plain capacity cells. Spendability still
|
|
106
|
+
* depends on the lock script, live cell state, and transaction context.
|
|
107
|
+
*/
|
|
108
|
+
export function isPlainCapacityCell(cell: ccc.Cell): boolean {
|
|
109
|
+
return cell.cellOutput.type === undefined && cell.outputData === "0x";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Performs asynchronously a binary search to find the smallest index `i` in the range [0, n)
|
|
114
|
+
* such that the function `f(i)` returns true. It is assumed that for the range
|
|
115
|
+
* [0, n), if `f(i)` is true, then `f(i+1)` is also true. This means that there
|
|
116
|
+
* is a prefix of the input range where `f` is false, followed by a suffix where
|
|
117
|
+
* `f` is true. If no such index exists, the function returns `n`.
|
|
118
|
+
*
|
|
119
|
+
* The function `f` is only called for indices in the range [0, n).
|
|
120
|
+
*
|
|
121
|
+
* @param n - The non-negative integer upper bound of the search range (exclusive).
|
|
122
|
+
* @param f - An async function that takes an index `i` and returns a boolean value.
|
|
123
|
+
* @returns The smallest index `i` such that `f(i)` is true, or `n` if no such index exists.
|
|
124
|
+
*
|
|
125
|
+
* @remarks Adapted from Go's standard library search implementation:
|
|
126
|
+
* {@link https://go.dev/src/sort/search.go}
|
|
127
|
+
*/
|
|
128
|
+
export async function asyncBinarySearch(
|
|
129
|
+
n: number,
|
|
130
|
+
f: (i: number) => Promise<boolean>,
|
|
131
|
+
): Promise<number> {
|
|
132
|
+
// Define f(-1) == false and f(n) == true.
|
|
133
|
+
// Invariant: f(i-1) == false, f(j) == true.
|
|
134
|
+
let [i, j] = [0, n];
|
|
135
|
+
while (i < j) {
|
|
136
|
+
const h = Math.trunc((i + j) / 2);
|
|
137
|
+
// i ≤ h < j
|
|
138
|
+
if (!(await f(h))) {
|
|
139
|
+
i = h + 1; // preserves f(i-1) == false
|
|
140
|
+
} else {
|
|
141
|
+
j = h; // preserves f(j) == true
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
|
|
145
|
+
return i;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The client's JSON-RPC requestor, when it has one. The connector hands the interface a
|
|
150
|
+
* composition proxy over the public client (`ClientWithFeeRate`, a `ccc.Client` but not a
|
|
151
|
+
* `ccc.ClientJsonRpc`), so `instanceof` misses it; the proxy forwards the property.
|
|
152
|
+
*/
|
|
153
|
+
export function jsonRpcRequestor(client: ccc.Client): ccc.RequestorJsonRpc | undefined {
|
|
154
|
+
if (!("requestor" in client)) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
const { requestor } = client;
|
|
158
|
+
return requestor instanceof ccc.RequestorJsonRpc ? requestor : undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** A node's raw `get_transaction` status record (verbosity 1), the fields the stack reads. */
|
|
162
|
+
export function rawTransactionStatus(response: unknown): {
|
|
163
|
+
status: string | undefined;
|
|
164
|
+
reason: string | undefined;
|
|
165
|
+
blockNumber: ccc.Num | undefined;
|
|
166
|
+
} {
|
|
167
|
+
const record =
|
|
168
|
+
typeof response === "object" &&
|
|
169
|
+
response !== null &&
|
|
170
|
+
"tx_status" in response &&
|
|
171
|
+
typeof response.tx_status === "object" &&
|
|
172
|
+
response.tx_status !== null
|
|
173
|
+
? response.tx_status
|
|
174
|
+
: {};
|
|
175
|
+
return {
|
|
176
|
+
status:
|
|
177
|
+
"status" in record && typeof record.status === "string" ? record.status : undefined,
|
|
178
|
+
reason:
|
|
179
|
+
"reason" in record && typeof record.reason === "string" ? record.reason : undefined,
|
|
180
|
+
blockNumber:
|
|
181
|
+
"block_number" in record && typeof record.block_number === "string"
|
|
182
|
+
? ccc.numFrom(record.block_number)
|
|
183
|
+
: undefined,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function minBigInt(left: bigint, right: bigint): bigint {
|
|
188
|
+
return left < right ? left : right;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function maxBigInt(left: bigint, right: bigint): bigint {
|
|
192
|
+
return left > right ? left : right;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** `numerator / denominator` rounded up; the denominator is positive. */
|
|
196
|
+
export function ceilDiv(numerator: bigint, denominator: bigint): bigint {
|
|
197
|
+
return (numerator + denominator - 1n) / denominator;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Compares two bigint values using sort-compatible ordering.
|
|
202
|
+
*
|
|
203
|
+
* @returns `-1` when `left` is smaller, `1` when `left` is larger, and `0` when equal.
|
|
204
|
+
*/
|
|
205
|
+
export function compareBigInt(left: bigint, right: bigint): number {
|
|
206
|
+
if (left < right) {
|
|
207
|
+
return -1;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (left > right) {
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Yields unique items from the given iterable based on their hex representation.
|
|
219
|
+
*
|
|
220
|
+
* The function uses a Set to track the hex-string keys of items that have already been yielded.
|
|
221
|
+
* Only the first occurrence of each unique key is yielded.
|
|
222
|
+
*
|
|
223
|
+
* @typeParam T - A type that extends ccc.Entity.
|
|
224
|
+
* @param items - An iterable collection of items of type T.
|
|
225
|
+
* @returns A generator that yields items from the iterable, ensuring that each item's
|
|
226
|
+
* hex representation (via toHex()) is unique.
|
|
227
|
+
*/
|
|
228
|
+
export function* unique<T extends ccc.Entity>(items: Iterable<T>): Generator<T> {
|
|
229
|
+
const set = new Set<string>();
|
|
230
|
+
for (const i of items) {
|
|
231
|
+
const key = i.toHex();
|
|
232
|
+
if (!set.has(key)) {
|
|
233
|
+
set.add(key);
|
|
234
|
+
yield i;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
package/dist/codec.d.ts
DELETED
package/dist/codec.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codec.d.ts","sourceRoot":"../src/","sources":["codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,GAAG,EAAE,MAAM,eAAe,CAAC;AAgBzC,eAAO,MAAM,YAAY,+BAkDvB,CAAC"}
|
package/dist/codec.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { ccc, mol } from "@ckb-ccc/core";
|
|
2
|
-
import { max } from "@ickb/utils";
|
|
3
|
-
const N = 1024;
|
|
4
|
-
export const PoolSnapshot = mol.Codec.from({
|
|
5
|
-
encode: (bins) => {
|
|
6
|
-
if (bins.length !== N) {
|
|
7
|
-
throw new Error("Expected 1024 bins");
|
|
8
|
-
}
|
|
9
|
-
const bitsPerBin = computeBits(bins);
|
|
10
|
-
const buffer = new Uint8Array((bitsPerBin * N) >> 3);
|
|
11
|
-
let bitOffset = 0;
|
|
12
|
-
for (const count of bins) {
|
|
13
|
-
packBits(buffer, bitOffset, bitsPerBin, count);
|
|
14
|
-
bitOffset += bitsPerBin;
|
|
15
|
-
}
|
|
16
|
-
return buffer;
|
|
17
|
-
},
|
|
18
|
-
decode: (bufferLike) => {
|
|
19
|
-
const buffer = ccc.bytesFrom(bufferLike);
|
|
20
|
-
const bitsPerBin = (buffer.byteLength * 8) / N;
|
|
21
|
-
if (!Number.isInteger(bitsPerBin)) {
|
|
22
|
-
throw new Error("Invalid buffer length for 1024 bins");
|
|
23
|
-
}
|
|
24
|
-
const bins = new Array(N);
|
|
25
|
-
let bitOffset = 0;
|
|
26
|
-
for (let i = 0; i < N; i++) {
|
|
27
|
-
bins[i] = unpackBits(buffer, bitOffset, bitsPerBin);
|
|
28
|
-
bitOffset += bitsPerBin;
|
|
29
|
-
}
|
|
30
|
-
return bins;
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
function computeBits(bins) {
|
|
34
|
-
return Math.ceil(Math.log2(1 + max(1, ...bins)));
|
|
35
|
-
}
|
|
36
|
-
function packBits(buffer, bitOffset, width, value) {
|
|
37
|
-
let offset = bitOffset;
|
|
38
|
-
for (let i = 0; i < width; i++) {
|
|
39
|
-
const byteIndex = offset >> 3;
|
|
40
|
-
const bitInByte = offset % 8;
|
|
41
|
-
const bit = (value >> i) & 1;
|
|
42
|
-
buffer[byteIndex] |= bit << bitInByte;
|
|
43
|
-
offset++;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function unpackBits(buffer, bitOffset, width) {
|
|
47
|
-
let value = 0;
|
|
48
|
-
let offset = bitOffset;
|
|
49
|
-
for (let i = 0; i < width; i++) {
|
|
50
|
-
const byteIndex = offset >> 3;
|
|
51
|
-
const bitInByte = offset % 8;
|
|
52
|
-
const bit = (buffer[byteIndex] >> bitInByte) & 1;
|
|
53
|
-
value |= bit << i;
|
|
54
|
-
offset++;
|
|
55
|
-
}
|
|
56
|
-
return value;
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=codec.js.map
|
package/dist/codec.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"../src/","sources":["codec.ts"],"names":[],"mappings":"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"}
|
package/src/codec.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { ccc, mol } from "@ckb-ccc/core";
|
|
2
|
-
import { max } from "@ickb/utils";
|
|
3
|
-
|
|
4
|
-
const N = 1024;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Codec for encoding and decoding a pool snapshot.
|
|
8
|
-
*
|
|
9
|
-
* The PoolSnapshotCodec encodes an array of 1024 numbers representing event counts for bins,
|
|
10
|
-
* where the number of bits used per bin is dynamically computed as the ceiling of log2(max + 1)
|
|
11
|
-
* across all bins. The codec provides methods to encode the array into a Uint8Array and decode
|
|
12
|
-
* a Uint8Array back to the original array of numbers.
|
|
13
|
-
*
|
|
14
|
-
* @remarks The total number of bits for encoding all the bins is computed as bitsPerBin * 1024. The codec
|
|
15
|
-
* does not have a fixed byteLength since it depends on the data.
|
|
16
|
-
*/
|
|
17
|
-
export const PoolSnapshot = mol.Codec.from<number[]>({
|
|
18
|
-
/**
|
|
19
|
-
* Encodes an array of 1024 bin counts into a Uint8Array.
|
|
20
|
-
*
|
|
21
|
-
* @param bins - An array of 1024 numbers. Each number represents the event count for a bin.
|
|
22
|
-
* @returns A Uint8Array containing the packed bit representation of the bin counts.
|
|
23
|
-
* @throws Error if the input array does not contain exactly 1024 elements.
|
|
24
|
-
*/
|
|
25
|
-
encode: (bins) => {
|
|
26
|
-
if (bins.length !== N) {
|
|
27
|
-
throw new Error("Expected 1024 bins");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const bitsPerBin = computeBits(bins);
|
|
31
|
-
const buffer = new Uint8Array((bitsPerBin * N) >> 3);
|
|
32
|
-
|
|
33
|
-
let bitOffset = 0;
|
|
34
|
-
for (const count of bins) {
|
|
35
|
-
packBits(buffer, bitOffset, bitsPerBin, count);
|
|
36
|
-
bitOffset += bitsPerBin;
|
|
37
|
-
}
|
|
38
|
-
return buffer;
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Decodes a buffer into an array of 1024 bin counts.
|
|
43
|
-
*
|
|
44
|
-
* The function automatically computes the number of bits per bin from the buffer length,
|
|
45
|
-
* expecting that the total number of bits in the buffer is a multiple of 1024.
|
|
46
|
-
*
|
|
47
|
-
* @param bufferLike - The input that can be converted into a Uint8Array.
|
|
48
|
-
* @returns An array of 1024 numbers representing the decoded bin counts.
|
|
49
|
-
* @throws Error if the buffer length is invalid (i.e., its total bit count is not divisible by 1024).
|
|
50
|
-
*/
|
|
51
|
-
decode: (bufferLike) => {
|
|
52
|
-
const buffer = ccc.bytesFrom(bufferLike);
|
|
53
|
-
// Determine bitsPerBin from the fixed structure (totalBits divided by N).
|
|
54
|
-
const bitsPerBin = (buffer.byteLength * 8) / N;
|
|
55
|
-
if (!Number.isInteger(bitsPerBin)) {
|
|
56
|
-
throw new Error("Invalid buffer length for 1024 bins");
|
|
57
|
-
}
|
|
58
|
-
const bins = new Array<number>(N);
|
|
59
|
-
let bitOffset = 0;
|
|
60
|
-
for (let i = 0; i < N; i++) {
|
|
61
|
-
bins[i] = unpackBits(buffer, bitOffset, bitsPerBin);
|
|
62
|
-
bitOffset += bitsPerBin;
|
|
63
|
-
}
|
|
64
|
-
return bins;
|
|
65
|
-
},
|
|
66
|
-
// Note: The byteLength is not fixed as it depends on the data (i.e., the maximum bin count).
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Computes the minimal number of bits required to represent the maximum number in the bins.
|
|
71
|
-
*
|
|
72
|
-
* Given an array of numbers that represent counts for each bin, this function calculates
|
|
73
|
-
* the number of bits required to represent the maximum bin count. A minimum of 1 bit is
|
|
74
|
-
* always returned.
|
|
75
|
-
*
|
|
76
|
-
* @param bins - An array of numbers, each representing a bin's value.
|
|
77
|
-
* @returns The minimal number of bits required to represent the highest value among the bins.
|
|
78
|
-
*/
|
|
79
|
-
function computeBits(bins: number[]): number {
|
|
80
|
-
return Math.ceil(Math.log2(1 + max(1, ...bins)));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Packs a given numeric value into a Uint8Array (bit array) at the specified bit offset and width.
|
|
85
|
-
*
|
|
86
|
-
* The function encodes the given number into the provided buffer, using the specified number of bits (width)
|
|
87
|
-
* starting from the specified bit offset. Each bit of the value is written into the buffer.
|
|
88
|
-
*
|
|
89
|
-
* @param buffer - The Uint8Array into which the value will be packed.
|
|
90
|
-
* @param bitOffset - The starting bit index in the array where the value should be packed.
|
|
91
|
-
* @param width - The number of bits to use for packing the value.
|
|
92
|
-
* @param value - The numeric value to pack.
|
|
93
|
-
*/
|
|
94
|
-
function packBits(
|
|
95
|
-
buffer: Uint8Array,
|
|
96
|
-
bitOffset: number,
|
|
97
|
-
width: number,
|
|
98
|
-
value: number,
|
|
99
|
-
): void {
|
|
100
|
-
let offset = bitOffset;
|
|
101
|
-
for (let i = 0; i < width; i++) {
|
|
102
|
-
const byteIndex = offset >> 3;
|
|
103
|
-
const bitInByte = offset % 8;
|
|
104
|
-
const bit = (value >> i) & 1;
|
|
105
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
106
|
-
buffer[byteIndex]! |= bit << bitInByte;
|
|
107
|
-
offset++;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Unpacks a numeric value from a Uint8Array (bit array) starting at a given bit offset with a specified width.
|
|
113
|
-
*
|
|
114
|
-
* The function reads bits from the buffer starting at the bit offset and reconstructs a numeric value
|
|
115
|
-
* using the specified number of bits (width).
|
|
116
|
-
*
|
|
117
|
-
* @param buffer - The Uint8Array from which the value will be unpacked.
|
|
118
|
-
* @param bitOffset - The starting bit index in the buffer.
|
|
119
|
-
* @param width - The number of bits to read for unpacking the value.
|
|
120
|
-
* @returns The numeric value resulting from decoding the specified bits.
|
|
121
|
-
*/
|
|
122
|
-
function unpackBits(
|
|
123
|
-
buffer: Uint8Array,
|
|
124
|
-
bitOffset: number,
|
|
125
|
-
width: number,
|
|
126
|
-
): number {
|
|
127
|
-
let value = 0;
|
|
128
|
-
let offset = bitOffset;
|
|
129
|
-
for (let i = 0; i < width; i++) {
|
|
130
|
-
const byteIndex = offset >> 3;
|
|
131
|
-
const bitInByte = offset % 8;
|
|
132
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
133
|
-
const bit = (buffer[byteIndex]! >> bitInByte) & 1;
|
|
134
|
-
value |= bit << i;
|
|
135
|
-
offset++;
|
|
136
|
-
}
|
|
137
|
-
return value;
|
|
138
|
-
}
|