Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions api-extractor.base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"apiReport": {
"enabled": false
},
"docModel": {
"enabled": false
},
"dtsRollup": {
"enabled": false
},
"tsdocMetadata": {
"enabled": false
},
"compiler": {
"overrideTsconfig": {
"compilerOptions": {
"target": "ES2024",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"customConditions": ["api-extractor"],
"skipLibCheck": true,
"preserveSymlinks": true
}
}
},
"messages": {
"compilerMessageReporting": {
"default": {
"logLevel": "warning"
}
},
"extractorMessageReporting": {
"default": {
"logLevel": "none"
},
"ae-forgotten-export": {
"logLevel": "error"
},
"ae-missing-release-tag": {
"logLevel": "error"
}
},
"tsdocMessageReporting": {
"default": {
"logLevel": "none"
}
}
}
}
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"private": true,
"type": "module",
"scripts": {
"build": "pnpm -r --filter !./apps/** --filter '!./forks/**' build",
"build:all": "pnpm -r --filter '!./forks/**' build",
Expand Down Expand Up @@ -33,20 +34,22 @@
"coworker:ask": "opencode run --pure --agent plan"
},
"engines": {
"node": ">=22"
"node": ">=22.19.0"
},
"devDependencies": {
"@eslint/js": "^9.39.3",
"@ickb/testkit": "workspace:*",
"@vitest/coverage-v8": "3.2.4",
"@microsoft/api-extractor": "^7.58.9",
"@typescript/native-preview": "latest",
"@vitest/coverage-v8": "4.1.8",
"eslint": "^9.39.3",
"eslint-plugin-react-compiler": "19.1.0-rc.2",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.24",
"madge": "^8.0.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.56.1",
"vitest": "^3.2.4"
"vitest": "^4.1.8"
},
"packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017"
}
2 changes: 1 addition & 1 deletion packages/node-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Private workspace utilities for Node-based iCKB apps.

`@ickb/node-utils` owns process and operator glue for Node-based iCKB apps such as `apps/tester`: environment parsing, public RPC client construction, signer account-lock collection, sleep loops, CKB log formatting, JSON-safe error/log serialization, elapsed-loop logging, and broadcast-timeout stop handling.
`@ickb/node-utils` owns process and operator glue for Node-based iCKB apps such as `apps/validation`: environment parsing, public RPC client construction, signer account-lock collection, sleep loops, CKB log formatting, JSON-safe error/log serialization, elapsed-loop logging, and broadcast-timeout stop handling.

This package is intentionally private and should not be used by the browser interface. Cross-runtime transaction lifecycle helpers, such as `sendAndWaitForCommit(...)`, stay in `@ickb/sdk`.

Expand Down
10 changes: 6 additions & 4 deletions packages/node-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
},
"sideEffects": false,
"type": "module",
"engines": {
"node": ">=22.19.0"
},
"main": "dist/index.js",
"types": "src/index.ts",
"exports": {
Expand All @@ -32,10 +35,9 @@
"scripts": {
"test": "vitest",
"test:ci": "vitest run",
"build": "tsc",
"lint": "eslint ./src",
"clean": "rm -fr dist",
"clean:deep": "rm -fr dist node_modules"
"build": "rm -fr dist && tsgo -p tsconfig.build.json && node ../../scripts/tooling/build/rewrite-dts-imports.ts dist",
"lint": "pnpm --workspace-root exec eslint --max-warnings=0 packages/node-utils/src packages/node-utils/test",
"clean": "rm -fr dist"
},
"dependencies": {
"@ckb-ccc/core": "catalog:",
Expand Down
80 changes: 80 additions & 0 deletions packages/node-utils/src/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { ccc } from "@ckb-ccc/core";
import { unique } from "@ickb/utils";

/**
* Returns the primary lock plus all signer address locks, deduplicated by script hash.
*/
export async function signerAccountLocks(
signer: ccc.Signer,
primaryLock: ccc.Script,
): Promise<ccc.Script[]> {
return [
...unique([
primaryLock,
...(await signer.getAddressObjs()).map(({ script }) => script),
]),
];
}

/**
* Sums currently live plain CKB capacity controlled by the account locks.
*/
export function accountPlainCkbBalance(
capacityCells: readonly ccc.Cell[],
accountLocks: readonly ccc.Script[],
): bigint {
const accountLockHexes = new Set(accountLocks.map((lock) => lock.toHex()));
return capacityCells.reduce(
(total, cell) =>
total + plainCapacity(cell.cellOutput, cell.outputData, accountLockHexes),
0n,
);
}

/**
* Projects account plain CKB capacity after applying a transaction's inputs and outputs.
*/
export function postTransactionAccountPlainCkbBalance(
tx: ccc.Transaction,
capacityCells: readonly ccc.Cell[],
accountLocks: readonly ccc.Script[],
): bigint {
const accountLockHexes = new Set(accountLocks.map((lock) => lock.toHex()));
const spentOutPoints = new Set(tx.inputs.map((input) => input.previousOutput.toHex()));
const unspentCapacity = capacityCells.reduce(
(total, cell) =>
spentOutPoints.has(cell.outPoint.toHex())
? total
: total + plainCapacity(cell.cellOutput, cell.outputData, accountLockHexes),
0n,
);
const outputCapacity = tx.outputs.reduce(
(total, output, index) =>
total + plainCapacity(output, tx.outputsData[index], accountLockHexes),
0n,
);

return unspentCapacity + outputCapacity;
}

function plainCapacity(
output: ccc.CellOutput,
outputData: string | undefined,
accountLockHexes: Set<string>,
): bigint {
return isAccountPlainCapacityOutput(output, outputData, accountLockHexes)
? output.capacity
: 0n;
}

function isAccountPlainCapacityOutput(
output: ccc.CellOutput,
outputData: string | undefined,
accountLockHexes: Set<string>,
): boolean {
return (
output.type === undefined &&
(outputData ?? "0x") === "0x" &&
accountLockHexes.has(output.lock.toHex())
);
}
Loading
Loading