Skip to content
Open
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
1 change: 0 additions & 1 deletion .npmrc

This file was deleted.

55 changes: 4 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,64 +44,17 @@ Packages:
- `packages/testkit`: Private test helpers and fixtures for workspace tests.
- `packages/utils`: Shared low-level utilities such as complete-scan enforcement, binary search, collection helpers, and bounded subset selection.

## Local CCC Workflow
## Dependencies

The shared CCC baseline lives in `forks/ccc/pin/` and materializes into `forks/ccc/repo/`.

Prerequisites: `git` and `jq`.

From a plain checkout:

```bash
git clone git@github.com:ickb/stack.git && cd stack
pnpm forks:bootstrap
pnpm install
pnpm forks:ccc
pnpm check
```
CCC packages are normal package dependencies resolved through `pnpm-workspace.yaml` catalog entries and `pnpm-lock.yaml`. From a plain checkout, run `pnpm install`; no local CCC fork, build step, or workspace alias is required.

`pnpm check` is the validation gate. It always runs with `CI=true`.

`pnpm forks:ccc` computes the local CCC build surface from the stack's direct `@ckb-ccc/*` dependencies and their current CCC dependency closure, so it avoids rebuilding unrelated packages like `ckb-ccc`, `@ckb-ccc/connector`, `@ckb-ccc/connector-react`, and `@ckb-ccc/lumos-patches`.

To inspect that current CCC surface without building anything:

```bash
pnpm forks:ccc:plan
```

For machine-readable inspection, use `pnpm -s forks:ccc --json`.

For active CCC work, keep built output fresh with:

```bash
pnpm forks:ccc --watch
```

Watch mode keeps the ESM `dist/` output fresh for the closure's `tsc` packages, including `@ckb-ccc/spore`, and prebuilds `@ckb-ccc/did-ckb` plus `@ckb-ccc/type-id` once so `@ckb-ccc/shell` and `@ckb-ccc/ccc` keep resolving against built output. If you change either `tsdown` package, rerun `pnpm forks:ccc`.

For quick consumer-context sanity checks after rebuilding CCC:

```bash
pnpm forks:ccc:smoke
```

That smoke path verifies the current direct Stack import surface through real consumers: `@ckb-ccc/core` from `@ickb/utils`, `@ckb-ccc/udt` from `@ickb/core`, and `@ckb-ccc/ccc` from `apps/interface`.

If you add a new direct `@ckb-ccc/*` dependency to any stack package, add the matching root override in `pnpm-workspace.yaml`. `pnpm check:ccc-overrides` enforces this.

If you need to update or save the shared CCC baseline, use `forks/phroi_forker/repo/` directly. `forks/ccc/pin/manifest` is the source of truth for the shared upstream refs.

## Live Testnet Supervisor

Build the local CCC fork, shared packages, live apps, and supervisor, provide ignored bounded configs, then run the supervisor from the repo root:
Provide ignored bounded configs, then run the supervisor from the repo root:

```bash
pnpm forks:ccc
pnpm --filter @ickb/utils --filter @ickb/dao --filter @ickb/core --filter @ickb/order --filter @ickb/sdk --filter @ickb/node-utils build
pnpm --filter ./apps/bot build
pnpm --filter ./apps/tester build
pnpm --filter @ickb/supervisor build
pnpm live:supervisor
```

Expand All @@ -117,7 +70,7 @@ For repeated bounded invocations, keep loop-owned options before `--` and superv
pnpm live:supervisor:loop --max-runs 1 -- --scenario standard-cycle --max-cycles 1
```

By default the loop prebuilds the local CCC fork plus bot, tester, and supervisor runtime before the first run. Use loop-owned `--skip-build` only when another wrapper has already built those artifacts. Use loop-owned `--child-timeout-seconds` to bound the outer supervisor child process when running long watches; keep it long enough for the whole supervisor invocation, including actor preflights and actor commands, so the supervisor remains alive to enforce its own `--command-timeout-seconds` process-group cleanup.
By default the loop prebuilds bot, tester, and supervisor runtime before the first run. Use loop-owned `--skip-build` only when another wrapper has already built those artifacts. Use loop-owned `--child-timeout-seconds` to bound the outer supervisor child process when running long watches; keep it long enough for the whole supervisor invocation, including actor preflights and actor commands, so the supervisor remains alive to enforce its own `--command-timeout-seconds` process-group cleanup.

For continuous live matching, use the dynamic external loop. It reads only tester preflight balance summaries, chooses `all-ckb-limit-order` when `CKB.available >= 3001`, otherwise chooses `ickb-to-ckb-limit-order` with `--tester-fee 1 --tester-fee-base 1000` when `CKB.available >= 2100` and `ICKB.available >= 100`, otherwise leaves the tester scenario as `auto`, then runs bounded `scripts/ickb-supervisor-loop.mjs` chunks:

Expand Down
4 changes: 2 additions & 2 deletions apps/bot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@ sudo -u ickb-bot-testnet git clone <repo-url> /opt/ickb-stack-testnet
sudo -u ickb-bot-mainnet git clone <repo-url> /opt/ickb-stack-mainnet
sudo -u ickb-bot-testnet pnpm -C /opt/ickb-stack-testnet bot:install
sudo -u ickb-bot-mainnet pnpm -C /opt/ickb-stack-mainnet bot:install
sudo -u ickb-bot-testnet pnpm -C /opt/ickb-stack-testnet bot:ccc
sudo -u ickb-bot-mainnet pnpm -C /opt/ickb-stack-mainnet bot:ccc
sudo -u ickb-bot-testnet pnpm -C /opt/ickb-stack-testnet bot:build
sudo -u ickb-bot-mainnet pnpm -C /opt/ickb-stack-mainnet bot:build
```

The install step resolves CCC through normal package dependencies from the lockfile; no separate CCC fork build is required.

If `/opt/ickb-stack-testnet` or `/opt/ickb-stack-mainnet` already exists from the install script, clone into a temporary path and move the checkout into place, or initialize the existing directory with your normal deployment tooling. The update script expects each deploy directory to be a clean git checkout.

Create encrypted config credentials on the VM. The tested Ubuntu 24.04 VM has `systemd-creds` and no TPM device, so host-key credentials are the compatible unattended option. If a future VM exposes a TPM, replace `--with-key=host` with the TPM-backed mode selected for that host. The helper prompts for the private key, optional RPC URL, sleep interval, optional max iterations, and max retryable attempts, validates the same strict JSON schema that the app reads, and encrypts that JSON as one systemd credential.
Expand Down
6 changes: 3 additions & 3 deletions apps/interface/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ git clone https://github.com/ickb/stack.git
cd stack
```

3. Install dependencies and materialize the local CCC workspace:
3. Install dependencies:

```bash
pnpm forks:bootstrap
pnpm install
pnpm forks:ccc
```

CCC packages are normal package dependencies resolved through the workspace catalog and lockfile; no local CCC fork, build step, or workspace alias is required.

4. Start the interface dev server from the repo root:

```bash
Expand Down
5 changes: 0 additions & 5 deletions apps/interface/src/transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,6 @@ describe("buildTransactionPreview", () => {
calls.push("fee");
return Promise.resolve([0, false]);
});
const daoLimit = vi.spyOn(ccc, "isDaoOutputLimitExceeded").mockImplementation(() => {
calls.push("dao-limit");
return Promise.resolve(false);
});
const completeTransaction = vi
.fn<WalletConfig["sdk"]["completeTransaction"]>()
.mockImplementation(async (txLike) => {
Expand All @@ -254,7 +250,6 @@ describe("buildTransactionPreview", () => {

expect(completeTransaction).toHaveBeenCalledTimes(1);
expect(completeFeeBy).not.toHaveBeenCalled();
expect(daoLimit).not.toHaveBeenCalled();
expect(calls).toEqual(["sdk-complete"]);
});

Expand Down
4 changes: 2 additions & 2 deletions apps/interface/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ES2022",
"target": "ES2024",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"lib": ["ES2024", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

Expand Down
2 changes: 1 addition & 1 deletion apps/sampler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ An utility to help sampling iCKB rate across time.

## Run the sampler on mainnet

From a plain checkout, follow the root [Local CCC Workflow](../../README.md#local-ccc-workflow) first so `forks/ccc/repo` is materialized. If you are working against patched local CCC packages, rerun `pnpm forks:ccc` or keep `pnpm forks:ccc --watch` running. The app build commands below then build the runtime workspace package closure they import.
From a plain checkout, run `pnpm install`; CCC packages are normal package dependencies resolved through the workspace catalog and lockfile. The app build commands below then build the runtime workspace package closure they import.

From the repo root:

Expand Down
6 changes: 3 additions & 3 deletions apps/supervisor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ The supervisor is a deterministic operator app for funded testnet validation. It

## Run

Build the local CCC fork, shared packages, live apps, and supervisor first:
From a plain checkout, install dependencies and build shared packages, live apps, and supervisor first:

```bash
pnpm forks:ccc
pnpm install
pnpm --filter @ickb/utils --filter @ickb/dao --filter @ickb/core --filter @ickb/order --filter @ickb/sdk --filter @ickb/node-utils build
pnpm --filter ./apps/bot build
pnpm --filter ./apps/tester build
Expand Down Expand Up @@ -83,7 +83,7 @@ node scripts/ickb-supervisor-loop.mjs --max-runs 1 --stable-limit 2 --backoff-se

Loop-owned options go before `--`; supervisor options go after `--`. If using `pnpm live:supervisor:loop`, keep loop-owned options before the first `--` so they are not passed through to the supervisor. The loop owns child run directories through `--out-root`, so do not pass supervisor `--out-dir` after `--`. The loop stops on supervisor nonzero exit, incident artifacts listed in `summary.json`, tx-creating outcomes or tx hashes for tx-creating outcomes, a new outcome after the first run, repeated no-progress signatures, or `--max-runs`. `-- --help` and `-- -h` are child help passthroughs: the delegated help is printed and the wrapper exits with the child status.

By default the loop prebuilds the local CCC fork plus bot, tester, and supervisor runtime before the first run. Use loop-owned `--skip-build` only when another wrapper has already built those artifacts. The external loop also has a loop-owned `--child-timeout-seconds` guard for the supervisor child process. Keep it long enough for the whole delegated supervisor run, including actor preflights and actor commands, not just one `--command-timeout-seconds` window. The dynamic loop defaults this guard to the supervisor-loop default so the supervisor keeps ownership of killing funded actor process groups on command timeout.
By default the loop prebuilds bot, tester, and supervisor runtime before the first run. Use loop-owned `--skip-build` only when another wrapper has already built those artifacts. The external loop also has a loop-owned `--child-timeout-seconds` guard for the supervisor child process. Keep it long enough for the whole delegated supervisor run, including actor preflights and actor commands, not just one `--command-timeout-seconds` window. The dynamic loop defaults this guard to the supervisor-loop default so the supervisor keeps ownership of killing funded actor process groups on command timeout.

For continuous tester-bot matching, use `node scripts/ickb-supervisor-dynamic-loop.mjs` or `pnpm live:supervisor:dynamic-loop`. This remains outside `apps/supervisor`: it reads tester preflight balance summaries, chooses `all-ckb-limit-order` when `CKB.available >= 3001`, otherwise chooses `ickb-to-ckb-limit-order` with `--tester-fee 1 --tester-fee-base 1000` when `CKB.available >= 2100` and `ICKB.available >= 100`, otherwise leaves tester selection as `auto`, and delegates each bounded chunk to `scripts/ickb-supervisor-loop.mjs`. When `--target-outcome tester_fresh_order_skip` is passed through, supervisor auto-planning can choose `tester-fresh-skip-two-pass`; the dynamic loop itself only chooses fundable tester stimuli. The dynamic loop also treats `-- --help` and `-- -h` as child help passthroughs and exits with the delegated status.

Expand Down
4 changes: 2 additions & 2 deletions apps/supervisor/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ describe("supervisor CLI", () => {
let createdOutputDirectory = false;

await expect(supervise(args, plan, {
existsSync: (path) => !pathToString(path).endsWith("forks/ccc/repo/packages/udt/dist/index.js"),
existsSync: (path) => !pathToString(path).endsWith("packages/sdk/dist/index.js"),
spawnCommand: (() => {
spawned = true;
return fakeChild("");
Expand All @@ -803,7 +803,7 @@ describe("supervisor CLI", () => {
createdOutputDirectory = true;
return Promise.resolve(undefined);
},
})).rejects.toThrow("Missing built CCC UDT: forks/ccc/repo/packages/udt/dist/index.js");
})).rejects.toThrow("Missing built SDK package: packages/sdk/dist/index.js");
expect(spawned).toBe(false);
expect(createdOutputDirectory).toBe(false);
});
Expand Down
2 changes: 0 additions & 2 deletions apps/supervisor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1005,8 +1005,6 @@ async function assertRealOutputDirectory(plan: SupervisorPlan, dependencies: Dep

function assertBuiltRuntime(plan: SupervisorPlan, dependencies: Dependencies): void {
const required = [
["CCC core", join(plan.rootDir, "forks/ccc/repo/packages/core/dist/index.js")],
["CCC UDT", join(plan.rootDir, "forks/ccc/repo/packages/udt/dist/index.js")],
["utils package", join(plan.rootDir, "packages/utils/dist/index.js")],
["DAO package", join(plan.rootDir, "packages/dao/dist/index.js")],
["core package", join(plan.rootDir, "packages/core/dist/index.js")],
Expand Down
2 changes: 1 addition & 1 deletion apps/tester/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Current network support:

## Run

From a plain checkout, follow the root [Local CCC Workflow](../../README.md#local-ccc-workflow) first so `forks/ccc/repo` is materialized. If you are working against patched local CCC packages, rerun `pnpm forks:ccc` or keep `pnpm forks:ccc --watch` running. The app build commands below then build the runtime workspace package closure they import.
From a plain checkout, run `pnpm install`; CCC packages are normal package dependencies resolved through the workspace catalog and lockfile. The app build commands below then build the runtime workspace package closure they import.

```bash
pnpm install
Expand Down
7 changes: 5 additions & 2 deletions apps/tester/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ describe("planTesterTransaction", () => {
)).toBeUndefined();
});

it("treats auto with capital but no actionable scenario as a nonterminal estimate skip", () => {
it("auto-selects random orders when near-reserve capital can fund actionable iCKB stimulus", () => {
const liveNearReserveState = testerState({
availableCkbBalance: 229423868188n,
availableIckbBalance: 147394003472899n,
Expand All @@ -390,7 +390,10 @@ describe("planTesterTransaction", () => {
undefined,
11845567055823n,
() => 0,
)).toBeUndefined();
)).toBe("random-order");
});

it("formats auto with no actionable scenario as a nonterminal estimate skip", () => {
expect(testerNoActionableAutoScenarioSkip()).toEqual({
reason: "estimated-conversion-too-small",
requestedTesterScenario: "auto",
Expand Down
3 changes: 0 additions & 3 deletions forks/.gitignore

This file was deleted.

1 change: 0 additions & 1 deletion forks/ccc/pin/HEAD

This file was deleted.

1 change: 0 additions & 1 deletion forks/ccc/pin/LOCAL_BASE

This file was deleted.

5 changes: 0 additions & 5 deletions forks/ccc/pin/manifest

This file was deleted.

5 changes: 0 additions & 5 deletions forks/ccc/pin/res-4.resolution

This file was deleted.

18 changes: 0 additions & 18 deletions forks/config.json

This file was deleted.

19 changes: 5 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,19 @@
"type": "module",
"scripts": {
"build": "pnpm -r --filter !./apps/** --filter '!./forks/**' build",
"build:all": "pnpm -r --filter '!./forks/**' build",
"build:all": "pnpm build && pnpm -r --workspace-concurrency=1 --filter './apps/*' build",
"audit": "pnpm audit",
"bot:install": "CI=true pnpm --filter @ickb/bot... --filter @ckb-ccc/core... --filter @ckb-ccc/udt... install --frozen-lockfile",
"bot:ccc": "pnpm --dir forks/ccc/repo -r --filter @ckb-ccc/core... --filter @ckb-ccc/udt... run build",
"bot:install": "CI=true pnpm --filter @ickb/bot... install --frozen-lockfile",
"bot:build": "pnpm --filter @ickb/bot... build",
"check": "CI=true pnpm check:base",
"check:base": "pnpm clean:deep && pnpm check:ccc-overrides && pnpm forks:bootstrap && pnpm install && pnpm audit && pnpm forks:ccc && pnpm forks:ccc:smoke && pnpm madge && pnpm lint && pnpm build:all && pnpm test:ci",
"check:ccc-overrides": "node scripts/check-ccc-overrides.mjs",
"check:base": "pnpm clean:deep && pnpm install && pnpm audit && pnpm madge && pnpm lint && pnpm build:all && pnpm test:ci",
"check:fresh": "rm -f pnpm-lock.yaml && pnpm check",
"madge": "madge --circular --extensions ts,tsx --ts-config ./tsconfig.json --exclude '^forks/' packages apps",
"test": "vitest",
"test:ci": "vitest run && node --test scripts/*.test.mjs && pnpm test:ccc",
"test:ccc": "vitest run --root forks/ccc/repo --project @ckb-ccc/core && vitest run --root forks/ccc/repo/packages/udt -t 'infoFrom|isUdt'",
"test:ci": "vitest run && node --test scripts/*.test.mjs",
"lint": "pnpm -r --filter '!./forks/**' lint",
"clean": "rm -fr dist packages/*/dist apps/*/dist",
"clean:deep": "pnpm clean && rm -fr node_modules packages/*/node_modules apps/*/node_modules forks/ccc/repo/packages/*/tsconfig.tsbuildinfo",
"forks:bootstrap": "node scripts/forks-bootstrap.mjs",
"forks:ccc": "node scripts/forks-ccc.mjs",
"forks:ccc:build": "node scripts/forks-ccc.mjs",
"forks:ccc:plan": "node scripts/forks-ccc.mjs --plan",
"forks:ccc:smoke": "node scripts/forks-ccc-smoke.mjs",
"forks:ccc:watch": "node scripts/forks-ccc.mjs --watch",
"clean:deep": "pnpm clean && rm -fr node_modules packages/*/node_modules apps/*/node_modules",
"live:generate-config": "node scripts/ickb-generate-config.mjs",
"live:config-from-env": "node scripts/ickb-live-config-from-env.mjs",
"live:preflight": "node scripts/ickb-live-preflight.mjs",
Expand Down
6 changes: 5 additions & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ graph TD;
If a caller will send the returned transaction, it still must:

1. Complete the transaction before send.
2. Prefer the shared stack path in `@ickb/sdk`: `sdk.completeTransaction(...)` or `completeIckbTransaction(...)`.
2. Prefer the shared stack path in `@ickb/sdk`: `sdk.completeTransaction(...)`.
3. Only use lower-level manual completion when the caller intentionally owns UDT completion, CCC-native fee/capacity completion, and the DAO output-limit check itself.

## Receipt Capacity

`LogicManager.deposit(...)` sizes receipt cells for the next required phase transition. A receipt is created with `minXudtCell(actualLock) + minPlainCell(actualLock) + 1 CKB`, so a wallet that spent all other CKB can still complete the receipt into iCKB xUDT plus a plain capacity cell.

## Epoch Semantic Versioning

This repository follows [Epoch Semantic Versioning](https://antfu.me/posts/epoch-semver). In short ESV aims to provide a more nuanced and effective way to communicate software changes, allowing for better user understanding and smoother upgrades.
Expand Down
5 changes: 5 additions & 0 deletions packages/core/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../../api-extractor.base.json",
"mainEntryPointFilePath": "<projectFolder>/dist/index.d.ts"
}
Loading
Loading